Skip to content

Commit b9cd2b1

Browse files
committed
fix(typegen): avoid possible infinite recursion error
- Add a fixed max depth to recursive types allowing Typescript to not raise possible infinite recursion error too early. - Add test to ensure that the provided fix remove this error from a recursive embeding Related: supabase/supabase-js#1354 supabase/supabase-js#1372 supabase/supabase-js#808
1 parent e4fcebf commit b9cd2b1

File tree

4 files changed

+346
-34
lines changed

4 files changed

+346
-34
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@
4040
"test": "run-s format:check test:types db:clean db:run test:run db:clean && node test/smoke.cjs && node test/smoke.mjs",
4141
"test:run": "jest --runInBand --coverage",
4242
"test:update": "run-s db:clean db:run db:generate-test-types && jest --runInBand --updateSnapshot && run-s db:clean",
43-
"test:types": "run-s build && tsd --files 'test/**/*.test-d.ts'",
44-
"test:types:watch": "run-s build && tsd --files 'test/**/*.test-d.ts' --watch",
43+
"test:types": "tsd --files 'test/**/*.test*.ts'",
44+
"test:types:watch": "tsd --files 'test/**/*.test*.ts' --watch",
4545
"type-check": "tsc --noEmit --project tsconfig.json",
4646
"type-check:test": "tsc --noEmit --project tsconfig.test.json",
4747
"db:clean": "cd test/db && docker compose down --volumes",

src/select-query-parser/result.ts

Lines changed: 85 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,89 @@ export type RPCCallNodes<
167167
: SelectQueryError<'Invalid first node in RPC call'>
168168
: Prettify<Acc>
169169

170+
type SplitArray<
171+
T extends readonly unknown[],
172+
N extends number,
173+
Acc extends readonly unknown[] = []
174+
> = Acc['length'] extends N
175+
? [Acc, T]
176+
: T extends readonly [infer Head, ...infer Tail]
177+
? SplitArray<Tail, N, [...Acc, Head]>
178+
: [Acc, T]
179+
180+
type ProcessBatch<
181+
ClientOptions extends ClientServerOptions,
182+
Schema extends GenericSchema,
183+
Row extends Record<string, unknown>,
184+
RelationName extends string,
185+
Relationships extends GenericRelationship[],
186+
Batch extends Ast.Node[],
187+
Acc extends Record<string, unknown>
188+
> = Batch extends [infer Head, ...infer Tail]
189+
? Head extends Ast.Node
190+
? Tail extends Ast.Node[]
191+
? ProcessNode<
192+
ClientOptions,
193+
Schema,
194+
Row,
195+
RelationName,
196+
Relationships,
197+
Head
198+
> extends infer Result
199+
? Result extends Record<string, unknown>
200+
? ProcessBatch<
201+
ClientOptions,
202+
Schema,
203+
Row,
204+
RelationName,
205+
Relationships,
206+
Tail,
207+
Omit<Acc, keyof Result> & Result
208+
>
209+
: Result
210+
: SelectQueryError<'Node processing failed'>
211+
: Acc
212+
: Acc
213+
: Acc
214+
215+
type ProcessNodesBatched<
216+
ClientOptions extends ClientServerOptions,
217+
Schema extends GenericSchema,
218+
Row extends Record<string, unknown>,
219+
RelationName extends string,
220+
Relationships extends GenericRelationship[],
221+
Nodes extends Ast.Node[],
222+
Acc extends Record<string, unknown> = {}
223+
> = Nodes extends []
224+
? Prettify<Acc>
225+
: SplitArray<Nodes, 5> extends [infer Batch, infer Remaining]
226+
? Batch extends Ast.Node[]
227+
? Remaining extends Ast.Node[]
228+
? ProcessBatch<
229+
ClientOptions,
230+
Schema,
231+
Row,
232+
RelationName,
233+
Relationships,
234+
Batch,
235+
Acc
236+
> extends infer BatchResult
237+
? BatchResult extends Record<string, unknown>
238+
? ProcessNodesBatched<
239+
ClientOptions,
240+
Schema,
241+
Row,
242+
RelationName,
243+
Relationships,
244+
Remaining,
245+
BatchResult
246+
>
247+
: BatchResult
248+
: SelectQueryError<'Batch processing failed'>
249+
: SelectQueryError<'Invalid remaining nodes'>
250+
: SelectQueryError<'Invalid batch nodes'>
251+
: SelectQueryError<'Array splitting failed'>
252+
170253
/**
171254
* Recursively processes an array of Nodes and accumulates the resulting TypeScript type.
172255
*
@@ -183,38 +266,9 @@ export type ProcessNodes<
183266
Row extends Record<string, unknown>,
184267
RelationName extends string,
185268
Relationships extends GenericRelationship[],
186-
Nodes extends Ast.Node[],
187-
Acc extends Record<string, unknown> = {} // Acc is now an object
269+
Nodes extends Ast.Node[]
188270
> = CheckDuplicateEmbededReference<Schema, RelationName, Relationships, Nodes> extends false
189-
? Nodes extends [infer FirstNode, ...infer RestNodes]
190-
? FirstNode extends Ast.Node
191-
? RestNodes extends Ast.Node[]
192-
? ProcessNode<
193-
ClientOptions,
194-
Schema,
195-
Row,
196-
RelationName,
197-
Relationships,
198-
FirstNode
199-
> extends infer FieldResult
200-
? FieldResult extends Record<string, unknown>
201-
? ProcessNodes<
202-
ClientOptions,
203-
Schema,
204-
Row,
205-
RelationName,
206-
Relationships,
207-
RestNodes,
208-
// Replace fields that exist in both Acc and FieldResult instead of intersecting
209-
Omit<Acc, keyof FieldResult> & FieldResult
210-
>
211-
: FieldResult extends SelectQueryError<infer E>
212-
? SelectQueryError<E>
213-
: SelectQueryError<'Could not retrieve a valid record or error value'>
214-
: SelectQueryError<'Processing node failed.'>
215-
: SelectQueryError<'Invalid rest nodes array type in ProcessNodes'>
216-
: SelectQueryError<'Invalid first node type in ProcessNodes'>
217-
: Prettify<Acc>
271+
? ProcessNodesBatched<ClientOptions, Schema, Row, RelationName, Relationships, Nodes>
218272
: Prettify<CheckDuplicateEmbededReference<Schema, RelationName, Relationships, Nodes>>
219273

220274
/**

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ type MergeExplicit<New, Row> = {
194194
: never
195195
}
196196

197-
type MergeDeep<New, Row> = Simplify<
197+
export type MergeDeep<New, Row> = Simplify<
198198
MergeExplicit<New, Row> &
199199
// Intersection here is to restore dynamic keys into the merging result
200200
// eg:

0 commit comments

Comments
 (0)