Skip to content

Commit e96bafd

Browse files
committed
checkpoint
1 parent 9f57dd6 commit e96bafd

File tree

4 files changed

+202
-239
lines changed

4 files changed

+202
-239
lines changed

packages/db/src/query/builder/functions.ts

Lines changed: 81 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,68 @@ import type { Ref } from "./types.js"
77
// Helper type for any expression-like value
88
type ExpressionLike = BasicExpression | RefProxy<any> | Ref<any> | any
99

10+
// Helper type to extract the underlying type from various expression types
11+
type ExtractType<T> =
12+
T extends RefProxy<infer U> ? U
13+
: T extends Ref<infer U> ? U
14+
: T extends BasicExpression<infer U> ? U
15+
: T extends undefined ? undefined
16+
: T extends null ? null
17+
: T
18+
19+
// Helper type to determine aggregate return type based on input nullability
20+
type AggregateReturnType<T> = ExtractType<T> extends infer U
21+
? U extends number | undefined | null
22+
? Aggregate<U>
23+
: U extends number
24+
? Aggregate<number>
25+
: Aggregate<number | undefined | null>
26+
: Aggregate<number | undefined | null>
27+
28+
// Helper type to determine string function return type based on input nullability
29+
type StringFunctionReturnType<T> = ExtractType<T> extends infer U
30+
? U extends string | undefined | null
31+
? BasicExpression<U>
32+
: U extends string
33+
? BasicExpression<string>
34+
: BasicExpression<string | undefined | null>
35+
: BasicExpression<string | undefined | null>
36+
37+
// Helper type to determine numeric function return type based on input nullability
38+
type NumericFunctionReturnType<T> = ExtractType<T> extends infer U
39+
? U extends number | undefined | null
40+
? BasicExpression<U>
41+
: U extends number
42+
? BasicExpression<number>
43+
: BasicExpression<number | undefined | null>
44+
: BasicExpression<number | undefined | null>
45+
46+
// Helper type for binary numeric operations (combines nullability of both operands)
47+
type BinaryNumericReturnType<T1, T2> =
48+
ExtractType<T1> extends infer U1
49+
? ExtractType<T2> extends infer U2
50+
? U1 extends number
51+
? U2 extends number
52+
? BasicExpression<number>
53+
: U2 extends number | undefined
54+
? BasicExpression<number | undefined>
55+
: U2 extends number | null
56+
? BasicExpression<number | null>
57+
: BasicExpression<number | undefined | null>
58+
: U1 extends number | undefined
59+
? U2 extends number
60+
? BasicExpression<number | undefined>
61+
: U2 extends number | undefined
62+
? BasicExpression<number | undefined>
63+
: BasicExpression<number | undefined | null>
64+
: U1 extends number | null
65+
? U2 extends number
66+
? BasicExpression<number | null>
67+
: BasicExpression<number | undefined | null>
68+
: BasicExpression<number | undefined | null>
69+
: BasicExpression<number | undefined | null>
70+
: BasicExpression<number | undefined | null>
71+
1072
// Operators
1173

1274
export function eq<T>(
@@ -207,67 +269,16 @@ export function ilike(
207269

208270
// Functions
209271

210-
export function upper(
211-
arg:
212-
| RefProxy<string>
213-
| RefProxy<string | undefined>
214-
| RefProxy<string | null>
215-
| Ref<string>
216-
| Ref<string | undefined>
217-
| Ref<string | null>
218-
| string
219-
| string | undefined
220-
| string | null
221-
| BasicExpression<string>
222-
| BasicExpression<string | undefined>
223-
| BasicExpression<string | null>
224-
| undefined
225-
| null
226-
): BasicExpression<string | undefined | null> {
227-
return new Func(`upper`, [toExpression(arg)])
272+
export function upper<T extends ExpressionLike>(arg: T): StringFunctionReturnType<T> {
273+
return new Func(`upper`, [toExpression(arg)]) as StringFunctionReturnType<T>
228274
}
229275

230-
export function lower(
231-
arg:
232-
| RefProxy<string>
233-
| RefProxy<string | undefined>
234-
| RefProxy<string | null>
235-
| string
236-
| string | undefined
237-
| string | null
238-
| BasicExpression<string>
239-
| BasicExpression<string | undefined>
240-
| BasicExpression<string | null>
241-
| undefined
242-
| null
243-
): BasicExpression<string | undefined | null> {
244-
return new Func(`lower`, [toExpression(arg)])
276+
export function lower<T extends ExpressionLike>(arg: T): StringFunctionReturnType<T> {
277+
return new Func(`lower`, [toExpression(arg)]) as StringFunctionReturnType<T>
245278
}
246279

247-
export function length(
248-
arg:
249-
| RefProxy<string>
250-
| RefProxy<string | undefined>
251-
| RefProxy<string | null>
252-
| RefProxy<Array<any>>
253-
| RefProxy<Array<any> | undefined>
254-
| RefProxy<Array<any> | null>
255-
| string
256-
| string | undefined
257-
| string | null
258-
| Array<any>
259-
| Array<any> | undefined
260-
| Array<any> | null
261-
| BasicExpression<string>
262-
| BasicExpression<string | undefined>
263-
| BasicExpression<string | null>
264-
| BasicExpression<Array<any>>
265-
| BasicExpression<Array<any> | undefined>
266-
| BasicExpression<Array<any> | null>
267-
| undefined
268-
| null
269-
): BasicExpression<number | undefined | null> {
270-
return new Func(`length`, [toExpression(arg)])
280+
export function length<T extends ExpressionLike>(arg: T): NumericFunctionReturnType<T> {
281+
return new Func(`length`, [toExpression(arg)]) as NumericFunctionReturnType<T>
271282
}
272283

273284
export function concat(
@@ -286,33 +297,11 @@ export function coalesce(...args: Array<ExpressionLike>): BasicExpression<any> {
286297
)
287298
}
288299

289-
export function add(
290-
left:
291-
| RefProxy<number>
292-
| RefProxy<number | undefined>
293-
| RefProxy<number | null>
294-
| number
295-
| number | undefined
296-
| number | null
297-
| BasicExpression<number>
298-
| BasicExpression<number | undefined>
299-
| BasicExpression<number | null>
300-
| undefined
301-
| null,
302-
right:
303-
| RefProxy<number>
304-
| RefProxy<number | undefined>
305-
| RefProxy<number | null>
306-
| number
307-
| number | undefined
308-
| number | null
309-
| BasicExpression<number>
310-
| BasicExpression<number | undefined>
311-
| BasicExpression<number | null>
312-
| undefined
313-
| null
314-
): BasicExpression<number | undefined | null> {
315-
return new Func(`add`, [toExpression(left), toExpression(right)])
300+
export function add<T1 extends ExpressionLike, T2 extends ExpressionLike>(
301+
left: T1,
302+
right: T2
303+
): BinaryNumericReturnType<T1, T2> {
304+
return new Func(`add`, [toExpression(left), toExpression(right)]) as BinaryNumericReturnType<T1, T2>
316305
}
317306

318307
// Aggregates
@@ -321,72 +310,20 @@ export function count(arg: ExpressionLike): Aggregate<number> {
321310
return new Aggregate(`count`, [toExpression(arg)])
322311
}
323312

324-
export function avg(
325-
arg:
326-
| RefProxy<number>
327-
| RefProxy<number | undefined>
328-
| RefProxy<number | null>
329-
| number
330-
| number | undefined
331-
| number | null
332-
| BasicExpression<number>
333-
| BasicExpression<number | undefined>
334-
| BasicExpression<number | null>
335-
| undefined
336-
| null
337-
): Aggregate<number | undefined | null> {
338-
return new Aggregate(`avg`, [toExpression(arg)])
313+
export function avg<T extends ExpressionLike>(arg: T): AggregateReturnType<T> {
314+
return new Aggregate(`avg`, [toExpression(arg)]) as AggregateReturnType<T>
339315
}
340316

341-
export function sum(
342-
arg:
343-
| RefProxy<number>
344-
| RefProxy<number | undefined>
345-
| RefProxy<number | null>
346-
| number
347-
| number | undefined
348-
| number | null
349-
| BasicExpression<number>
350-
| BasicExpression<number | undefined>
351-
| BasicExpression<number | null>
352-
| undefined
353-
| null
354-
): Aggregate<number | undefined | null> {
355-
return new Aggregate(`sum`, [toExpression(arg)])
317+
export function sum<T extends ExpressionLike>(arg: T): AggregateReturnType<T> {
318+
return new Aggregate(`sum`, [toExpression(arg)]) as AggregateReturnType<T>
356319
}
357320

358-
export function min(
359-
arg:
360-
| RefProxy<number>
361-
| RefProxy<number | undefined>
362-
| RefProxy<number | null>
363-
| number
364-
| number | undefined
365-
| number | null
366-
| BasicExpression<number>
367-
| BasicExpression<number | undefined>
368-
| BasicExpression<number | null>
369-
| undefined
370-
| null
371-
): Aggregate<number | undefined | null> {
372-
return new Aggregate(`min`, [toExpression(arg)])
321+
export function min<T extends ExpressionLike>(arg: T): AggregateReturnType<T> {
322+
return new Aggregate(`min`, [toExpression(arg)]) as AggregateReturnType<T>
373323
}
374324

375-
export function max(
376-
arg:
377-
| RefProxy<number>
378-
| RefProxy<number | undefined>
379-
| RefProxy<number | null>
380-
| number
381-
| number | undefined
382-
| number | null
383-
| BasicExpression<number>
384-
| BasicExpression<number | undefined>
385-
| BasicExpression<number | null>
386-
| undefined
387-
| null
388-
): Aggregate<number | undefined | null> {
389-
return new Aggregate(`max`, [toExpression(arg)])
325+
export function max<T extends ExpressionLike>(arg: T): AggregateReturnType<T> {
326+
return new Aggregate(`max`, [toExpression(arg)]) as AggregateReturnType<T>
390327
}
391328

392329
/**

packages/db/src/query/builder/types.ts

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -72,21 +72,27 @@ export type SelectObject<
7272
export type ResultTypeFromSelect<TSelectObject> = {
7373
[K in keyof TSelectObject]: TSelectObject[K] extends RefProxy<infer T>
7474
? T
75+
: TSelectObject[K] extends Ref<infer T>
76+
? T
77+
: TSelectObject[K] extends Ref<infer T> | undefined
78+
? T | undefined
79+
: TSelectObject[K] extends RefProxy<infer T> | undefined
80+
? T | undefined
7581
: TSelectObject[K] extends BasicExpression<infer T>
7682
? T
77-
: TSelectObject[K] extends Aggregate<infer T>
78-
? T
79-
: TSelectObject[K] extends RefProxyFor<infer T>
80-
? T
81-
: TSelectObject[K] extends undefined
82-
? undefined
83-
: TSelectObject[K] extends { __type: infer U }
84-
? U
85-
: TSelectObject[K] extends Record<string, any>
86-
? TSelectObject[K] extends { __refProxy: true }
87-
? never // This is a RefProxy, handled above
88-
: ResultTypeFromSelect<TSelectObject[K]> // Recursive for nested objects
89-
: never
83+
: TSelectObject[K] extends Aggregate<infer T>
84+
? T
85+
: TSelectObject[K] extends RefProxyFor<infer T>
86+
? T
87+
: TSelectObject[K] extends undefined
88+
? undefined
89+
: TSelectObject[K] extends { __type: infer U }
90+
? U
91+
: TSelectObject[K] extends Record<string, any>
92+
? TSelectObject[K] extends { __refProxy: true }
93+
? never // This is a RefProxy, handled above
94+
: ResultTypeFromSelect<TSelectObject[K]> // Recursive for nested objects
95+
: never
9096
}
9197

9298
// Callback type for orderBy clauses
@@ -135,13 +141,9 @@ export type RefProxyForContext<TContext extends Context> = {
135141
RefProxy<TContext[`schema`][K]>
136142
: IsOptional<TContext[`schema`][K]> extends true
137143
? // T is optional (T | undefined) but not exactly undefined
138-
NonUndefined<TContext[`schema`][K]> extends Record<string, any>
139-
? PrecomputeRefStructure<NonUndefined<TContext[`schema`][K]>> | undefined
140-
: RefProxy<NonUndefined<TContext[`schema`][K]>> | undefined
141-
: // T is not optional
142-
TContext[`schema`][K] extends Record<string, any>
143-
? PrecomputeRefStructure<TContext[`schema`][K]>
144-
: RefProxy<TContext[`schema`][K]>
144+
RefProxy<NonUndefined<TContext[`schema`][K]>> | undefined
145+
: // T is not optional - always wrap in RefProxy for top-level schema types
146+
RefProxy<TContext[`schema`][K]>
145147
}
146148

147149
// Helper type to check if T is exactly undefined
@@ -195,9 +197,15 @@ export type RefProxy<T = any> = {
195197
? {}
196198
: T extends Record<string, any>
197199
? {
198-
[K in keyof T]: T[K] extends Record<string, any>
199-
? RefProxy<T[K]>
200-
: RefProxy<T[K]>
200+
[K in keyof T]: IsExactlyUndefined<T[K]> extends true
201+
? Ref<T[K]>
202+
: IsOptional<T[K]> extends true
203+
? NonUndefined<T[K]> extends Record<string, any>
204+
? RefProxy<NonUndefined<T[K]>> | undefined
205+
: Ref<NonUndefined<T[K]>> | undefined
206+
: T[K] extends Record<string, any>
207+
? RefProxy<T[K]>
208+
: Ref<T[K]>
201209
}
202210
: {})
203211

0 commit comments

Comments
 (0)