Skip to content

Commit e06c168

Browse files
committed
Enable cyclic dependencies
1 parent 82c31df commit e06c168

File tree

7 files changed

+1126
-64
lines changed

7 files changed

+1126
-64
lines changed

src/cyclic.d.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Type definitions using a type mapping approach
2+
type EntityMap = {
3+
Order: {
4+
id: string;
5+
date: Date;
6+
total: number;
7+
};
8+
Line: {
9+
id: string;
10+
quantity: number;
11+
price: number;
12+
};
13+
Package: {
14+
id: string;
15+
trackingNumber: string;
16+
weight: number;
17+
};
18+
Customer: {
19+
id: string;
20+
name: string;
21+
email: string;
22+
};
23+
};
24+
25+
// Enhanced relation mapping that includes cardinality information
26+
type RelationMap = {
27+
Order: {
28+
lines: { type: 'Line'; isArray: true };
29+
customer: { type: 'Customer'; isArray: false };
30+
};
31+
Line: {
32+
packages: { type: 'Package'; isArray: true };
33+
order: { type: 'Order'; isArray: false };
34+
};
35+
Customer: {
36+
orders: { type: 'Order'; isArray: true };
37+
};
38+
Package: {};
39+
};
40+
41+
// Helper type to extract the entity type from a relation
42+
type RelationEntityType<R> = R extends { type: infer T extends keyof EntityMap } ? T : never;
43+
44+
// Helper type to determine if a relation is an array
45+
type IsArray<R> = R extends { isArray: infer A extends boolean } ? A : false;
46+
47+
// Generic deep type resolver
48+
type Depth = [never, 0, 1, 2, 3, 4, 5];
49+
50+
// RecursiveType generic with improved depth handling
51+
type RecursiveType<
52+
T extends keyof EntityMap,
53+
D extends number = 5
54+
> = {
55+
// Always include base properties
56+
[K in keyof EntityMap[T]]: EntityMap[T][K];
57+
} & (D extends 0
58+
? // At max depth, only include base properties (which are already included above)
59+
{}
60+
: // Otherwise include relations with appropriate depth reduction
61+
{
62+
[K in keyof RelationMap[T]]: IsArray<RelationMap[T][K]> extends true
63+
? RecursiveType<
64+
RelationEntityType<RelationMap[T][K]>,
65+
Depth[D]
66+
>[]
67+
: RecursiveType<
68+
RelationEntityType<RelationMap[T][K]>,
69+
Depth[D]
70+
>;
71+
});
72+
73+
// Generate the entity types with relationships resolved to the specified depth
74+
type Order = RecursiveType<'Order', 6>;
75+
76+
type Line = RecursiveType<'Line'>;
77+
type Package = RecursiveType<'Package'>;
78+
type Customer = RecursiveType<'Customer'>;
79+
80+
// Example usage
81+
function processOrder(order: Order, line: Line) {
82+
// Can access nested properties up to depth 5
83+
// const trackingNumber = order.customer.orders[0].lines[0].order.lines[0].packages[0].
84+
// const orderId = order.customer.orders[0].customer.orders[0].lines[0].
85+
line.order.customer.orders[0].lines[0].packages[0].
86+
87+
console.log(trackingNumber, orderId);
88+
}
89+
90+
// Allow custom depth control per entity type
91+
type OrderWithDepth1 = RecursiveType<'Order', 4>;
92+
93+
// Example with custom depth
94+
function processOrderWithLimitedDepth(order: OrderWithDepth1) {
95+
// This would work (depth 1)
96+
97+
console.log(order.customer.id); // Can access base properties at max depth
98+
console.log(order.customer.name); // Can access base properties at max depth
99+
100+
// This would error - beyond depth 1
101+
// console.log(order.customer.orders[0].id);
102+
}
103+
104+
// Example of creating an instance with this type system
105+
const sampleOrder: Order = {
106+
id: "ORD-123",
107+
date: new Date(),
108+
total: 299.99,
109+
customer: {
110+
id: "CUST-456",
111+
name: "John Doe",
112+
email: "john@example.com",
113+
orders: [
114+
/* would be recursive orders */
115+
]
116+
},
117+
lines: [
118+
{
119+
id: "LINE-789",
120+
quantity: 2,
121+
price: 149.99,
122+
order: /* circular reference */,
123+
packages: [
124+
{
125+
id: "PKG-101",
126+
trackingNumber: "TRK123456789",
127+
weight: 1.5
128+
}
129+
]
130+
}
131+
]
132+
};

src/index.d.ts

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import type { RequestHandler } from 'express';
44
import type { D1Database } from '@cloudflare/workers-types';
55
import type { ConnectionConfiguration } from 'tedious';
66
import type { PoolAttributes } from 'oracledb';
7-
import type { AllowedDbMap, DbMapper, MappedDbDef } from './map';
7+
import type { AllowedDbMap, DbMapper, MappedDbDef, MergeProperties } from './map';
8+
import type { Filter as MapFilter, RawFilter as MapRawFilter, Pool as MapPool, PoolOptions as MapPoolOptions } from './map2';
89

910
declare function r(config: r.Config): unknown;
1011

@@ -26,12 +27,12 @@ declare namespace r {
2627
function off(type: 'query', cb: (e: QueryEvent) => void): void;
2728
function map<V extends AllowedDbMap<V>>(
2829
fn: (mapper: DbMapper<{}>) => V
29-
): MappedDbDef<V>;
30+
): MappedDbDef<MergeProperties<V, V>>;
3031
function createPatch(original: any[], modified: any[]): JsonPatch;
3132
function createPatch(original: any, modified: any): JsonPatch;
3233

3334
type JsonPatch = Array<{
34-
op: "add" | "remove" | "replace" | "copy" | "move" | "test";
35+
op: 'add' | 'remove' | 'replace' | 'copy' | 'move' | 'test';
3536
path: string;
3637
value?: any;
3738
from?: string;
@@ -48,13 +49,8 @@ declare namespace r {
4849
result: []
4950
}
5051

51-
export interface Pool {
52-
end(): Promise<void>;
53-
}
54-
55-
export interface PoolOptions {
56-
size?: number;
57-
}
52+
export type Pool = MapPool;
53+
export type PoolOptions = MapPoolOptions;
5854

5955
export interface Join {
6056
by(...columns: string[]): JoinBy;
@@ -65,8 +61,8 @@ declare namespace r {
6561
}
6662

6763
export abstract class JoinRelation {
68-
columns: ColumnDef[];
69-
childTable: Table;
64+
columns: ColumnDef[];
65+
childTable: Table;
7066
}
7167

7268
export interface Table {
@@ -155,17 +151,10 @@ declare namespace r {
155151
as(dbName: string): ColumnNotNullOf<T>;
156152
}
157153

158-
var filter: Filter;
159-
export interface RawFilter {
160-
sql: string | (() => string);
161-
parameters?: any[];
162-
}
154+
const filter: Filter;
163155

164-
export interface Filter extends RawFilter {
165-
and(filter: Filter, ...filters: Filter[]): Filter;
166-
or(filter: Filter, ...filters: Filter[]): Filter;
167-
not(): Filter;
168-
}
156+
export type RawFilter = MapRawFilter;
157+
export type Filter = MapFilter;
169158

170159
export type Concurrency = 'optimistic' | 'skipOnConflict' | 'overwrite';
171160

@@ -223,11 +212,11 @@ declare namespace r {
223212
*/
224213
iEqual(value: string | null): Filter;
225214
/**
226-
* ignore case, postgres only
215+
* ignore case, postgres only
227216
* */
228217
iEq(value: string | null): Filter;
229218
/**
230-
* ignore case, postgres only
219+
* ignore case, postgres only
231220
*/
232221
iEq(value: string | null): Filter;
233222
}

0 commit comments

Comments
 (0)