Skip to content

Commit fdb62fe

Browse files
samwillisKyleAMathewsclaude
authored andcommitted
Refactor select improving spread (...obj) and enabling nested projection. (TanStack#389)
Co-authored-by: Kyle Mathews <mathews.kyle@gmail.com> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 629929b commit fdb62fe

5 files changed

Lines changed: 215 additions & 358 deletions

File tree

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ import { toExpression } from "./ref-proxy.js"
33
import type { RefProxyFor } from "./types"
44
import type { BasicExpression } from "../ir"
55
import type { RefProxy } from "./ref-proxy.js"
6-
import type { Ref } from "./types.js"
6+
import type { RefLeaf } from "./types.js"
77

8-
type StringRef = Ref<string> | Ref<string | null> | Ref<string | undefined>
8+
type StringRef =
9+
| RefLeaf<string>
10+
| RefLeaf<string | null>
11+
| RefLeaf<string | undefined>
912
type StringRefProxy =
1013
| RefProxy<string>
1114
| RefProxy<string | null>
@@ -24,7 +27,7 @@ type StringLike =
2427

2528
type ComparisonOperand<T> =
2629
| RefProxy<T>
27-
| Ref<T>
30+
| RefLeaf<T>
2831
| T
2932
| BasicExpression<T>
3033
| undefined
@@ -36,13 +39,13 @@ type ComparisonOperandPrimitive<T extends string | number | boolean> =
3639
| null
3740

3841
// Helper type for any expression-like value
39-
type ExpressionLike = BasicExpression | RefProxy<any> | Ref<any> | any
42+
type ExpressionLike = BasicExpression | RefProxy<any> | RefLeaf<any> | any
4043

4144
// Helper type to extract the underlying type from various expression types
4245
type ExtractType<T> =
4346
T extends RefProxy<infer U>
4447
? U
45-
: T extends Ref<infer U>
48+
: T extends RefLeaf<infer U>
4649
? U
4750
: T extends BasicExpression<infer U>
4851
? U

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

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ export class BaseQueryBuilder<TContext extends Context = Context> {
171171
// Create a temporary context for the callback
172172
const currentAliases = this._getCurrentAliases()
173173
const newAliases = [...currentAliases, alias]
174-
const refProxy = createRefProxy(newAliases) as RefProxyForContext<
174+
const refProxy = createRefProxy(newAliases) as RefsForContext<
175175
MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>
176176
>
177177

@@ -439,34 +439,7 @@ export class BaseQueryBuilder<TContext extends Context = Context> {
439439
const refProxy = createRefProxy(aliases) as RefsForContext<TContext>
440440
const refProxy = createRefProxy(aliases) as RefsForContext<TContext>
441441
const selectObject = callback(refProxy)
442-
443-
// Check if any tables were spread during the callback
444-
const spreadSentinels = (refProxy as any).__spreadSentinels as Set<string>
445-
446-
// Convert the select object to use expressions, including spread sentinels
447-
const select: Record<string, BasicExpression | Aggregate> = {}
448-
449-
// First, add spread sentinels for any tables that were spread
450-
for (const spreadAlias of spreadSentinels) {
451-
const sentinelKey = `__SPREAD_SENTINEL__${spreadAlias}`
452-
select[sentinelKey] = toExpression(spreadAlias) // Use alias as a simple reference
453-
}
454-
455-
// Then add the explicit select fields
456-
for (const [key, value] of Object.entries(selectObject)) {
457-
if (isRefProxy(value)) {
458-
select[key] = toExpression(value)
459-
} else if (
460-
typeof value === `object` &&
461-
value !== null &&
462-
`type` in value &&
463-
(value.type === `agg` || value.type === `func`)
464-
) {
465-
select[key] = value as BasicExpression | Aggregate
466-
} else {
467-
select[key] = toExpression(value)
468-
}
469-
}
442+
const select = buildNestedSelect(selectObject)
470443

471444
return new BaseQueryBuilder({
472445
...this.query,
@@ -899,4 +872,4 @@ export type ExtractContext<T> =
899872
: never
900873

901874
// Export the types from types.ts for convenience
902-
export type { Context, Source, GetResult, Ref } from "./types.js"
875+
export type { Context, Source, GetResult, RefLeaf as Ref } from "./types.js"

packages/db/src/query/builder/ref-proxy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PropRef, Value } from "../ir.js"
22
import type { BasicExpression } from "../ir.js"
3-
import type { Ref } from "./types.js"
3+
import type { RefLeaf } from "./types.js"
44

55
export interface RefProxy<T = any> {
66
/** @internal */
@@ -20,7 +20,7 @@ export type SingleRowRefProxy<T> =
2020
? {
2121
[K in keyof T]: T[K] extends Record<string, any>
2222
? SingleRowRefProxy<T[K]> & RefProxy<T[K]>
23-
: Ref<T[K]>
23+
: RefLeaf<T[K]>
2424
} & RefProxy<T>
2525
: RefProxy<T>
2626

0 commit comments

Comments
 (0)