Skip to content

Commit 91685fe

Browse files
committed
wip
1 parent 1bea938 commit 91685fe

File tree

5 files changed

+190
-112
lines changed

5 files changed

+190
-112
lines changed

src/PostgrestClient.ts

Lines changed: 1 addition & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -5,81 +5,8 @@ import {
55
GenericSchema,
66
ClientServerOptions,
77
GetGenericDatabaseWithOptions,
8-
GenericFunction,
9-
GenericSetofOption,
8+
GetRpcFunctionFilterBuilderByArgs,
109
} from './types'
11-
import { FindMatchingFunctionByArgs, IsAny } from './select-query-parser/utils'
12-
import { LastOf } from './select-query-parser/types'
13-
14-
type ExactMatch<T, S> = [T] extends [S] ? ([S] extends [T] ? true : false) : false
15-
16-
type ExtractExactFunction<Fns, Args> = Fns extends infer F
17-
? F extends GenericFunction
18-
? ExactMatch<F['Args'], Args> extends true
19-
? F
20-
: never
21-
: never
22-
: never
23-
24-
type IsNever<T> = [T] extends [never] ? true : false
25-
26-
export type GetRpcFunctionFilterBuilderByArgs<
27-
Schema extends GenericSchema,
28-
FnName extends string & keyof Schema['Functions'],
29-
Args
30-
> = {
31-
0: Schema['Functions'][FnName]
32-
// If the Args is exactly never (function call without any params)
33-
1: IsNever<Args> extends true
34-
? ExtractExactFunction<Schema['Functions'][FnName], Args>
35-
: // Otherwise, we attempt to match with one of the function definition in the union based
36-
// on the function arguments provided
37-
Args extends GenericFunction['Args']
38-
? LastOf<FindMatchingFunctionByArgs<Schema['Functions'][FnName], Args>>
39-
: // If we can't find a matching function by args, we try to find one by function name
40-
ExtractExactFunction<Schema['Functions'][FnName], Args> extends GenericFunction
41-
? ExtractExactFunction<Schema['Functions'][FnName], Args>
42-
: any
43-
}[1] extends infer Fn
44-
? // If we are dealing with an non-typed client everything is any
45-
IsAny<Fn> extends true
46-
? { Row: any; Result: any; RelationName: FnName; Relationships: null }
47-
: // Otherwise, we use the arguments based function definition narrowing to get the rigt value
48-
Fn extends GenericFunction
49-
? {
50-
Row: Fn['Returns'] extends any[]
51-
? Fn['Returns'][number] extends Record<string, unknown>
52-
? Fn['Returns'][number]
53-
: never
54-
: Fn['Returns'] extends Record<string, unknown>
55-
? Fn['Returns']
56-
: never
57-
Result: Fn['SetofOptions'] extends GenericSetofOption
58-
? Fn['SetofOptions']['isSetofReturn'] extends true
59-
? Fn['SetofOptions']['isOneToOne'] extends true
60-
? Fn['Returns'][]
61-
: Fn['Returns']
62-
: Fn['Returns']
63-
: Fn['Returns']
64-
RelationName: Fn['SetofOptions'] extends GenericSetofOption
65-
? Fn['SetofOptions']['to']
66-
: FnName
67-
Relationships: Fn['SetofOptions'] extends GenericSetofOption
68-
? Fn['SetofOptions']['to'] extends keyof Schema['Tables']
69-
? Schema['Tables'][Fn['SetofOptions']['to']]['Relationships']
70-
: Schema['Views'][Fn['SetofOptions']['to']]['Relationships']
71-
: null
72-
}
73-
: // If we failed to find the function by argument, we still pass with any but also add an overridable
74-
Fn extends false
75-
? {
76-
Row: any
77-
Result: { error: true } & "Couldn't infer function definition matching provided arguments"
78-
RelationName: FnName
79-
Relationships: null
80-
}
81-
: never
82-
: never
8310

8411
/**
8512
* PostgREST client.

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export type {
3030
PostgrestMaybeSingleResponse,
3131
ClientServerOptions,
3232
GetGenericDatabaseWithOptions,
33+
GetRpcFunctionFilterBuilderByArgs,
3334
} from './types'
3435
// https://github.com/supabase/postgrest-js/issues/551
3536
// To be replaced with a helper type that only uses public types

src/select-query-parser/result.ts

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

170+
// Helper types for optimization
171+
type SplitArray<
172+
T extends readonly unknown[],
173+
N extends number,
174+
Acc extends readonly unknown[] = []
175+
> = Acc['length'] extends N
176+
? [Acc, T]
177+
: T extends readonly [infer Head, ...infer Tail]
178+
? SplitArray<Tail, N, [...Acc, Head]>
179+
: [Acc, T]
180+
181+
type ProcessBatch<
182+
ClientOptions extends ClientServerOptions,
183+
Schema extends GenericSchema,
184+
Row extends Record<string, unknown>,
185+
RelationName extends string,
186+
Relationships extends GenericRelationship[],
187+
Batch extends Ast.Node[],
188+
Acc extends Record<string, unknown>
189+
> = Batch extends [infer Head, ...infer Tail]
190+
? Head extends Ast.Node
191+
? Tail extends Ast.Node[]
192+
? ProcessNode<
193+
ClientOptions,
194+
Schema,
195+
Row,
196+
RelationName,
197+
Relationships,
198+
Head
199+
> extends infer Result
200+
? Result extends Record<string, unknown>
201+
? ProcessBatch<
202+
ClientOptions,
203+
Schema,
204+
Row,
205+
RelationName,
206+
Relationships,
207+
Tail,
208+
Acc & Result
209+
>
210+
: Result
211+
: SelectQueryError<'Node processing failed'>
212+
: Acc
213+
: Acc
214+
: Acc
215+
216+
type ProcessSingleNode<
217+
ClientOptions extends ClientServerOptions,
218+
Schema extends GenericSchema,
219+
Row extends Record<string, unknown>,
220+
RelationName extends string,
221+
Relationships extends GenericRelationship[],
222+
Node extends Ast.Node
223+
> = ProcessNode<ClientOptions, Schema, Row, RelationName, Relationships, Node>
224+
225+
type ProcessNodesBatched<
226+
ClientOptions extends ClientServerOptions,
227+
Schema extends GenericSchema,
228+
Row extends Record<string, unknown>,
229+
RelationName extends string,
230+
Relationships extends GenericRelationship[],
231+
Nodes extends Ast.Node[],
232+
Acc extends Record<string, unknown> = {}
233+
> = Nodes extends []
234+
? Prettify<Acc>
235+
: SplitArray<Nodes, 5> extends [infer Batch, infer Remaining]
236+
? Batch extends Ast.Node[]
237+
? Remaining extends Ast.Node[]
238+
? ProcessBatch<
239+
ClientOptions,
240+
Schema,
241+
Row,
242+
RelationName,
243+
Relationships,
244+
Batch,
245+
Acc
246+
> extends infer BatchResult
247+
? BatchResult extends Record<string, unknown>
248+
? ProcessNodesBatched<
249+
ClientOptions,
250+
Schema,
251+
Row,
252+
RelationName,
253+
Relationships,
254+
Remaining,
255+
BatchResult
256+
>
257+
: BatchResult
258+
: SelectQueryError<'Batch processing failed'>
259+
: SelectQueryError<'Invalid remaining nodes'>
260+
: SelectQueryError<'Invalid batch nodes'>
261+
: SelectQueryError<'Array splitting failed'>
262+
170263
/**
171264
* Recursively processes an array of Nodes and accumulates the resulting TypeScript type.
172265
*
@@ -183,38 +276,24 @@ export type ProcessNodes<
183276
Row extends Record<string, unknown>,
184277
RelationName extends string,
185278
Relationships extends GenericRelationship[],
186-
Nodes extends Ast.Node[],
187-
Acc extends Record<string, unknown> = {} // Acc is now an object
279+
Nodes extends Ast.Node[]
188280
> = 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>
281+
? Nodes['length'] extends 0
282+
? {}
283+
: Nodes['length'] extends 1
284+
? Prettify<ProcessSingleNode<ClientOptions, Schema, Row, RelationName, Relationships, Nodes[0]>>
285+
: // : Nodes['length'] extends 2
286+
// ? Prettify<
287+
// ProcessTwoNodes<
288+
// ClientOptions,
289+
// Schema,
290+
// Row,
291+
// RelationName,
292+
// Relationships,
293+
// [Nodes[0], Nodes[1]]
294+
// >
295+
// >
296+
ProcessNodesBatched<ClientOptions, Schema, Row, RelationName, Relationships, Nodes>
218297
: Prettify<CheckDuplicateEmbededReference<Schema, RelationName, Relationships, Nodes>>
219298

220299
/**

src/types.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,80 @@
11
import PostgrestError from './PostgrestError'
22
import { ContainsNull } from './select-query-parser/types'
3-
import { IsAny, SelectQueryError } from './select-query-parser/utils'
3+
import { FindMatchingFunctionByArgs, IsAny, SelectQueryError } from './select-query-parser/utils'
4+
import { LastOf } from './select-query-parser/types'
45

56
export type Fetch = typeof fetch
67

8+
type ExactMatch<T, S> = [T] extends [S] ? ([S] extends [T] ? true : false) : false
9+
10+
type ExtractExactFunction<Fns, Args> = Fns extends infer F
11+
? F extends GenericFunction
12+
? ExactMatch<F['Args'], Args> extends true
13+
? F
14+
: never
15+
: never
16+
: never
17+
18+
type IsNever<T> = [T] extends [never] ? true : false
19+
20+
export type GetRpcFunctionFilterBuilderByArgs<
21+
Schema extends GenericSchema,
22+
FnName extends string & keyof Schema['Functions'],
23+
Args
24+
> = {
25+
0: Schema['Functions'][FnName]
26+
// If the Args is exactly never (function call without any params)
27+
1: IsNever<Args> extends true
28+
? ExtractExactFunction<Schema['Functions'][FnName], Args>
29+
: // Otherwise, we attempt to match with one of the function definition in the union based
30+
// on the function arguments provided
31+
Args extends GenericFunction['Args']
32+
? LastOf<FindMatchingFunctionByArgs<Schema['Functions'][FnName], Args>>
33+
: // If we can't find a matching function by args, we try to find one by function name
34+
ExtractExactFunction<Schema['Functions'][FnName], Args> extends GenericFunction
35+
? ExtractExactFunction<Schema['Functions'][FnName], Args>
36+
: any
37+
}[1] extends infer Fn
38+
? // If we are dealing with an non-typed client everything is any
39+
IsAny<Fn> extends true
40+
? { Row: any; Result: any; RelationName: FnName; Relationships: null }
41+
: // Otherwise, we use the arguments based function definition narrowing to get the rigt value
42+
Fn extends GenericFunction
43+
? {
44+
Row: Fn['Returns'] extends any[]
45+
? Fn['Returns'][number] extends Record<string, unknown>
46+
? Fn['Returns'][number]
47+
: never
48+
: Fn['Returns'] extends Record<string, unknown>
49+
? Fn['Returns']
50+
: never
51+
Result: Fn['SetofOptions'] extends GenericSetofOption
52+
? Fn['SetofOptions']['isSetofReturn'] extends true
53+
? Fn['SetofOptions']['isOneToOne'] extends true
54+
? Fn['Returns'][]
55+
: Fn['Returns']
56+
: Fn['Returns']
57+
: Fn['Returns']
58+
RelationName: Fn['SetofOptions'] extends GenericSetofOption
59+
? Fn['SetofOptions']['to']
60+
: FnName
61+
Relationships: Fn['SetofOptions'] extends GenericSetofOption
62+
? Fn['SetofOptions']['to'] extends keyof Schema['Tables']
63+
? Schema['Tables'][Fn['SetofOptions']['to']]['Relationships']
64+
: Schema['Views'][Fn['SetofOptions']['to']]['Relationships']
65+
: null
66+
}
67+
: // If we failed to find the function by argument, we still pass with any but also add an overridable
68+
Fn extends false
69+
? {
70+
Row: any
71+
Result: { error: true } & "Couldn't infer function definition matching provided arguments"
72+
RelationName: FnName
73+
Relationships: null
74+
}
75+
: never
76+
: never
77+
778
/**
879
* Response format
980
*

test/db/docker-compose.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ services:
4040
POSTGRES_PASSWORD: postgres
4141
POSTGRES_HOST: /var/run/postgresql
4242
POSTGRES_PORT: 5432
43-
pgmeta:
44-
image: local-pg-meta
45-
ports:
46-
- '8080:8080'
47-
environment:
48-
- PG_META_DB_HOST=db
43+
# pgmeta:
44+
# image: local-pg-meta
45+
# ports:
46+
# - '8080:8080'
47+
# environment:
48+
# - PG_META_DB_HOST=db

0 commit comments

Comments
 (0)