@tanstack/db 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/collection.cjs +117 -104
- package/dist/cjs/collection.cjs.map +1 -1
- package/dist/cjs/collection.d.cts +19 -22
- package/dist/cjs/index.cjs +35 -13
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +0 -1
- package/dist/cjs/query/builder/functions.cjs +107 -0
- package/dist/cjs/query/builder/functions.cjs.map +1 -0
- package/dist/cjs/query/builder/functions.d.cts +38 -0
- package/dist/cjs/query/builder/index.cjs +499 -0
- package/dist/cjs/query/builder/index.cjs.map +1 -0
- package/dist/cjs/query/builder/index.d.cts +324 -0
- package/dist/cjs/query/builder/ref-proxy.cjs +96 -0
- package/dist/cjs/query/builder/ref-proxy.cjs.map +1 -0
- package/dist/cjs/query/builder/ref-proxy.d.cts +28 -0
- package/dist/cjs/query/builder/types.d.cts +80 -0
- package/dist/cjs/query/compiler/evaluators.cjs +261 -0
- package/dist/cjs/query/compiler/evaluators.cjs.map +1 -0
- package/dist/cjs/query/compiler/evaluators.d.cts +11 -0
- package/dist/cjs/query/compiler/group-by.cjs +271 -0
- package/dist/cjs/query/compiler/group-by.cjs.map +1 -0
- package/dist/cjs/query/compiler/group-by.d.cts +7 -0
- package/dist/cjs/query/compiler/index.cjs +181 -0
- package/dist/cjs/query/compiler/index.cjs.map +1 -0
- package/dist/cjs/query/compiler/index.d.cts +15 -0
- package/dist/cjs/query/compiler/joins.cjs +116 -0
- package/dist/cjs/query/compiler/joins.cjs.map +1 -0
- package/dist/cjs/query/compiler/joins.d.cts +11 -0
- package/dist/cjs/query/compiler/order-by.cjs +89 -0
- package/dist/cjs/query/compiler/order-by.cjs.map +1 -0
- package/dist/cjs/query/compiler/order-by.d.cts +9 -0
- package/dist/cjs/query/compiler/select.cjs +57 -0
- package/dist/cjs/query/compiler/select.cjs.map +1 -0
- package/dist/cjs/query/compiler/select.d.cts +15 -0
- package/dist/cjs/query/index.d.cts +6 -5
- package/dist/cjs/query/ir.cjs +57 -0
- package/dist/cjs/query/ir.cjs.map +1 -0
- package/dist/cjs/query/ir.d.cts +81 -0
- package/dist/cjs/query/live-query-collection.cjs +224 -0
- package/dist/cjs/query/live-query-collection.cjs.map +1 -0
- package/dist/cjs/query/live-query-collection.d.cts +124 -0
- package/dist/cjs/transactions.cjs +20 -13
- package/dist/cjs/transactions.cjs.map +1 -1
- package/dist/cjs/transactions.d.cts +13 -4
- package/dist/cjs/types.d.cts +14 -1
- package/dist/esm/collection.d.ts +19 -22
- package/dist/esm/collection.js +118 -105
- package/dist/esm/collection.js.map +1 -1
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.js +34 -12
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/query/builder/functions.d.ts +38 -0
- package/dist/esm/query/builder/functions.js +107 -0
- package/dist/esm/query/builder/functions.js.map +1 -0
- package/dist/esm/query/builder/index.d.ts +324 -0
- package/dist/esm/query/builder/index.js +499 -0
- package/dist/esm/query/builder/index.js.map +1 -0
- package/dist/esm/query/builder/ref-proxy.d.ts +28 -0
- package/dist/esm/query/builder/ref-proxy.js +96 -0
- package/dist/esm/query/builder/ref-proxy.js.map +1 -0
- package/dist/esm/query/builder/types.d.ts +80 -0
- package/dist/esm/query/compiler/evaluators.d.ts +11 -0
- package/dist/esm/query/compiler/evaluators.js +261 -0
- package/dist/esm/query/compiler/evaluators.js.map +1 -0
- package/dist/esm/query/compiler/group-by.d.ts +7 -0
- package/dist/esm/query/compiler/group-by.js +271 -0
- package/dist/esm/query/compiler/group-by.js.map +1 -0
- package/dist/esm/query/compiler/index.d.ts +15 -0
- package/dist/esm/query/compiler/index.js +181 -0
- package/dist/esm/query/compiler/index.js.map +1 -0
- package/dist/esm/query/compiler/joins.d.ts +11 -0
- package/dist/esm/query/compiler/joins.js +116 -0
- package/dist/esm/query/compiler/joins.js.map +1 -0
- package/dist/esm/query/compiler/order-by.d.ts +9 -0
- package/dist/esm/query/compiler/order-by.js +89 -0
- package/dist/esm/query/compiler/order-by.js.map +1 -0
- package/dist/esm/query/compiler/select.d.ts +15 -0
- package/dist/esm/query/compiler/select.js +57 -0
- package/dist/esm/query/compiler/select.js.map +1 -0
- package/dist/esm/query/index.d.ts +6 -5
- package/dist/esm/query/ir.d.ts +81 -0
- package/dist/esm/query/ir.js +57 -0
- package/dist/esm/query/ir.js.map +1 -0
- package/dist/esm/query/live-query-collection.d.ts +124 -0
- package/dist/esm/query/live-query-collection.js +224 -0
- package/dist/esm/query/live-query-collection.js.map +1 -0
- package/dist/esm/transactions.d.ts +13 -4
- package/dist/esm/transactions.js +20 -13
- package/dist/esm/transactions.js.map +1 -1
- package/dist/esm/types.d.ts +14 -1
- package/package.json +3 -4
- package/src/collection.ts +152 -129
- package/src/index.ts +0 -1
- package/src/query/builder/functions.ts +267 -0
- package/src/query/builder/index.ts +648 -0
- package/src/query/builder/ref-proxy.ts +156 -0
- package/src/query/builder/types.ts +278 -0
- package/src/query/compiler/evaluators.ts +315 -0
- package/src/query/compiler/group-by.ts +428 -0
- package/src/query/compiler/index.ts +276 -0
- package/src/query/compiler/joins.ts +228 -0
- package/src/query/compiler/order-by.ts +139 -0
- package/src/query/compiler/select.ts +173 -0
- package/src/query/index.ts +64 -5
- package/src/query/ir.ts +128 -0
- package/src/query/live-query-collection.ts +509 -0
- package/src/transactions.ts +34 -19
- package/src/types.ts +16 -1
- package/dist/cjs/query/compiled-query.cjs +0 -160
- package/dist/cjs/query/compiled-query.cjs.map +0 -1
- package/dist/cjs/query/compiled-query.d.cts +0 -20
- package/dist/cjs/query/evaluators.cjs +0 -161
- package/dist/cjs/query/evaluators.cjs.map +0 -1
- package/dist/cjs/query/evaluators.d.cts +0 -14
- package/dist/cjs/query/extractors.cjs +0 -122
- package/dist/cjs/query/extractors.cjs.map +0 -1
- package/dist/cjs/query/extractors.d.cts +0 -22
- package/dist/cjs/query/functions.cjs +0 -152
- package/dist/cjs/query/functions.cjs.map +0 -1
- package/dist/cjs/query/functions.d.cts +0 -21
- package/dist/cjs/query/group-by.cjs +0 -88
- package/dist/cjs/query/group-by.cjs.map +0 -1
- package/dist/cjs/query/group-by.d.cts +0 -40
- package/dist/cjs/query/joins.cjs +0 -141
- package/dist/cjs/query/joins.cjs.map +0 -1
- package/dist/cjs/query/joins.d.cts +0 -14
- package/dist/cjs/query/order-by.cjs +0 -185
- package/dist/cjs/query/order-by.cjs.map +0 -1
- package/dist/cjs/query/order-by.d.cts +0 -3
- package/dist/cjs/query/pipeline-compiler.cjs +0 -89
- package/dist/cjs/query/pipeline-compiler.cjs.map +0 -1
- package/dist/cjs/query/pipeline-compiler.d.cts +0 -10
- package/dist/cjs/query/query-builder.cjs +0 -307
- package/dist/cjs/query/query-builder.cjs.map +0 -1
- package/dist/cjs/query/query-builder.d.cts +0 -225
- package/dist/cjs/query/schema.d.cts +0 -100
- package/dist/cjs/query/select.cjs +0 -130
- package/dist/cjs/query/select.cjs.map +0 -1
- package/dist/cjs/query/select.d.cts +0 -3
- package/dist/cjs/query/types.d.cts +0 -189
- package/dist/cjs/query/utils.cjs +0 -154
- package/dist/cjs/query/utils.cjs.map +0 -1
- package/dist/cjs/query/utils.d.cts +0 -37
- package/dist/cjs/utils.cjs +0 -17
- package/dist/cjs/utils.cjs.map +0 -1
- package/dist/cjs/utils.d.cts +0 -3
- package/dist/esm/query/compiled-query.d.ts +0 -20
- package/dist/esm/query/compiled-query.js +0 -160
- package/dist/esm/query/compiled-query.js.map +0 -1
- package/dist/esm/query/evaluators.d.ts +0 -14
- package/dist/esm/query/evaluators.js +0 -161
- package/dist/esm/query/evaluators.js.map +0 -1
- package/dist/esm/query/extractors.d.ts +0 -22
- package/dist/esm/query/extractors.js +0 -122
- package/dist/esm/query/extractors.js.map +0 -1
- package/dist/esm/query/functions.d.ts +0 -21
- package/dist/esm/query/functions.js +0 -152
- package/dist/esm/query/functions.js.map +0 -1
- package/dist/esm/query/group-by.d.ts +0 -40
- package/dist/esm/query/group-by.js +0 -88
- package/dist/esm/query/group-by.js.map +0 -1
- package/dist/esm/query/joins.d.ts +0 -14
- package/dist/esm/query/joins.js +0 -141
- package/dist/esm/query/joins.js.map +0 -1
- package/dist/esm/query/order-by.d.ts +0 -3
- package/dist/esm/query/order-by.js +0 -185
- package/dist/esm/query/order-by.js.map +0 -1
- package/dist/esm/query/pipeline-compiler.d.ts +0 -10
- package/dist/esm/query/pipeline-compiler.js +0 -89
- package/dist/esm/query/pipeline-compiler.js.map +0 -1
- package/dist/esm/query/query-builder.d.ts +0 -225
- package/dist/esm/query/query-builder.js +0 -307
- package/dist/esm/query/query-builder.js.map +0 -1
- package/dist/esm/query/schema.d.ts +0 -100
- package/dist/esm/query/select.d.ts +0 -3
- package/dist/esm/query/select.js +0 -130
- package/dist/esm/query/select.js.map +0 -1
- package/dist/esm/query/types.d.ts +0 -189
- package/dist/esm/query/utils.d.ts +0 -37
- package/dist/esm/query/utils.js +0 -154
- package/dist/esm/query/utils.js.map +0 -1
- package/dist/esm/utils.d.ts +0 -3
- package/dist/esm/utils.js +0 -17
- package/dist/esm/utils.js.map +0 -1
- package/src/query/compiled-query.ts +0 -234
- package/src/query/evaluators.ts +0 -250
- package/src/query/extractors.ts +0 -214
- package/src/query/functions.ts +0 -297
- package/src/query/group-by.ts +0 -139
- package/src/query/joins.ts +0 -260
- package/src/query/order-by.ts +0 -264
- package/src/query/pipeline-compiler.ts +0 -149
- package/src/query/query-builder.ts +0 -902
- package/src/query/schema.ts +0 -268
- package/src/query/select.ts +0 -208
- package/src/query/types.ts +0 -418
- package/src/query/utils.ts +0 -245
- package/src/utils.ts +0 -15
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Ref, Value } from "../ir.js"
|
|
2
|
+
import type { BasicExpression } from "../ir.js"
|
|
3
|
+
|
|
4
|
+
export interface RefProxy<T = any> {
|
|
5
|
+
/** @internal */
|
|
6
|
+
readonly __refProxy: true
|
|
7
|
+
/** @internal */
|
|
8
|
+
readonly __path: Array<string>
|
|
9
|
+
/** @internal */
|
|
10
|
+
readonly __type: T
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a proxy object that records property access paths
|
|
15
|
+
* Used in callbacks like where, select, etc. to create type-safe references
|
|
16
|
+
*/
|
|
17
|
+
export function createRefProxy<T extends Record<string, any>>(
|
|
18
|
+
aliases: Array<string>
|
|
19
|
+
): RefProxy<T> & T {
|
|
20
|
+
const cache = new Map<string, any>()
|
|
21
|
+
const spreadSentinels = new Set<string>() // Track which aliases have been spread
|
|
22
|
+
|
|
23
|
+
function createProxy(path: Array<string>): any {
|
|
24
|
+
const pathKey = path.join(`.`)
|
|
25
|
+
if (cache.has(pathKey)) {
|
|
26
|
+
return cache.get(pathKey)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const proxy = new Proxy({} as any, {
|
|
30
|
+
get(target, prop, receiver) {
|
|
31
|
+
if (prop === `__refProxy`) return true
|
|
32
|
+
if (prop === `__path`) return path
|
|
33
|
+
if (prop === `__type`) return undefined // Type is only for TypeScript inference
|
|
34
|
+
if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver)
|
|
35
|
+
|
|
36
|
+
const newPath = [...path, String(prop)]
|
|
37
|
+
return createProxy(newPath)
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
has(target, prop) {
|
|
41
|
+
if (prop === `__refProxy` || prop === `__path` || prop === `__type`)
|
|
42
|
+
return true
|
|
43
|
+
return Reflect.has(target, prop)
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
ownKeys(target) {
|
|
47
|
+
// If this is a table-level proxy (path length 1), mark it as spread
|
|
48
|
+
if (path.length === 1) {
|
|
49
|
+
const aliasName = path[0]!
|
|
50
|
+
spreadSentinels.add(aliasName)
|
|
51
|
+
}
|
|
52
|
+
return Reflect.ownKeys(target)
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
56
|
+
if (prop === `__refProxy` || prop === `__path` || prop === `__type`) {
|
|
57
|
+
return { enumerable: false, configurable: true }
|
|
58
|
+
}
|
|
59
|
+
return Reflect.getOwnPropertyDescriptor(target, prop)
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
cache.set(pathKey, proxy)
|
|
64
|
+
return proxy
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Create the root proxy with all aliases as top-level properties
|
|
68
|
+
const rootProxy = new Proxy({} as any, {
|
|
69
|
+
get(target, prop, receiver) {
|
|
70
|
+
if (prop === `__refProxy`) return true
|
|
71
|
+
if (prop === `__path`) return []
|
|
72
|
+
if (prop === `__type`) return undefined // Type is only for TypeScript inference
|
|
73
|
+
if (prop === `__spreadSentinels`) return spreadSentinels // Expose spread sentinels
|
|
74
|
+
if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver)
|
|
75
|
+
|
|
76
|
+
const propStr = String(prop)
|
|
77
|
+
if (aliases.includes(propStr)) {
|
|
78
|
+
return createProxy([propStr])
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return undefined
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
has(target, prop) {
|
|
85
|
+
if (
|
|
86
|
+
prop === `__refProxy` ||
|
|
87
|
+
prop === `__path` ||
|
|
88
|
+
prop === `__type` ||
|
|
89
|
+
prop === `__spreadSentinels`
|
|
90
|
+
)
|
|
91
|
+
return true
|
|
92
|
+
if (typeof prop === `string` && aliases.includes(prop)) return true
|
|
93
|
+
return Reflect.has(target, prop)
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
ownKeys(_target) {
|
|
97
|
+
return [...aliases, `__refProxy`, `__path`, `__type`, `__spreadSentinels`]
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
101
|
+
if (
|
|
102
|
+
prop === `__refProxy` ||
|
|
103
|
+
prop === `__path` ||
|
|
104
|
+
prop === `__type` ||
|
|
105
|
+
prop === `__spreadSentinels`
|
|
106
|
+
) {
|
|
107
|
+
return { enumerable: false, configurable: true }
|
|
108
|
+
}
|
|
109
|
+
if (typeof prop === `string` && aliases.includes(prop)) {
|
|
110
|
+
return { enumerable: true, configurable: true }
|
|
111
|
+
}
|
|
112
|
+
return undefined
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
return rootProxy
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Converts a value to an Expression
|
|
121
|
+
* If it's a RefProxy, creates a Ref, otherwise creates a Value
|
|
122
|
+
*/
|
|
123
|
+
export function toExpression<T = any>(value: T): BasicExpression<T>
|
|
124
|
+
export function toExpression(value: RefProxy<any>): BasicExpression<any>
|
|
125
|
+
export function toExpression(value: any): BasicExpression<any> {
|
|
126
|
+
if (isRefProxy(value)) {
|
|
127
|
+
return new Ref(value.__path)
|
|
128
|
+
}
|
|
129
|
+
// If it's already an Expression (Func, Ref, Value) or Agg, return it directly
|
|
130
|
+
if (
|
|
131
|
+
value &&
|
|
132
|
+
typeof value === `object` &&
|
|
133
|
+
`type` in value &&
|
|
134
|
+
(value.type === `func` ||
|
|
135
|
+
value.type === `ref` ||
|
|
136
|
+
value.type === `val` ||
|
|
137
|
+
value.type === `agg`)
|
|
138
|
+
) {
|
|
139
|
+
return value
|
|
140
|
+
}
|
|
141
|
+
return new Value(value)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Type guard to check if a value is a RefProxy
|
|
146
|
+
*/
|
|
147
|
+
export function isRefProxy(value: any): value is RefProxy {
|
|
148
|
+
return value && typeof value === `object` && value.__refProxy === true
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Helper to create a Value expression from a literal
|
|
153
|
+
*/
|
|
154
|
+
export function val<T>(value: T): BasicExpression<T> {
|
|
155
|
+
return new Value(value)
|
|
156
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import type { CollectionImpl } from "../../collection.js"
|
|
2
|
+
import type { Aggregate, BasicExpression } from "../ir.js"
|
|
3
|
+
import type { QueryBuilder } from "./index.js"
|
|
4
|
+
|
|
5
|
+
export interface Context {
|
|
6
|
+
// The collections available in the base schema
|
|
7
|
+
baseSchema: ContextSchema
|
|
8
|
+
// The current schema available (includes joined collections)
|
|
9
|
+
schema: ContextSchema
|
|
10
|
+
// the name of the source that was used in the from clause
|
|
11
|
+
fromSourceName: string
|
|
12
|
+
// Whether this query has joins
|
|
13
|
+
hasJoins?: boolean
|
|
14
|
+
// Mapping of table alias to join type for easy lookup
|
|
15
|
+
joinTypes?: Record<
|
|
16
|
+
string,
|
|
17
|
+
`inner` | `left` | `right` | `full` | `outer` | `cross`
|
|
18
|
+
>
|
|
19
|
+
// The result type after select (if select has been called)
|
|
20
|
+
result?: any
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type ContextSchema = Record<string, unknown>
|
|
24
|
+
|
|
25
|
+
export type Source = {
|
|
26
|
+
[alias: string]: CollectionImpl<any, any> | QueryBuilder<Context>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Helper type to infer collection type from CollectionImpl
|
|
30
|
+
export type InferCollectionType<T> =
|
|
31
|
+
T extends CollectionImpl<infer U> ? U : never
|
|
32
|
+
|
|
33
|
+
// Helper type to create schema from source
|
|
34
|
+
export type SchemaFromSource<T extends Source> = Prettify<{
|
|
35
|
+
[K in keyof T]: T[K] extends CollectionImpl<infer U>
|
|
36
|
+
? U
|
|
37
|
+
: T[K] extends QueryBuilder<infer TContext>
|
|
38
|
+
? GetResult<TContext>
|
|
39
|
+
: never
|
|
40
|
+
}>
|
|
41
|
+
|
|
42
|
+
// Helper type to get all aliases from a context
|
|
43
|
+
export type GetAliases<TContext extends Context> = keyof TContext[`schema`]
|
|
44
|
+
|
|
45
|
+
// Callback type for where/having clauses
|
|
46
|
+
export type WhereCallback<TContext extends Context> = (
|
|
47
|
+
refs: RefProxyForContext<TContext>
|
|
48
|
+
) => any
|
|
49
|
+
|
|
50
|
+
// Callback return type for select clauses
|
|
51
|
+
export type SelectObject<
|
|
52
|
+
T extends Record<
|
|
53
|
+
string,
|
|
54
|
+
BasicExpression | Aggregate | RefProxy | RefProxyFor<any>
|
|
55
|
+
> = Record<string, BasicExpression | Aggregate | RefProxy | RefProxyFor<any>>,
|
|
56
|
+
> = T
|
|
57
|
+
|
|
58
|
+
// Helper type to get the result type from a select object
|
|
59
|
+
export type ResultTypeFromSelect<TSelectObject> = {
|
|
60
|
+
[K in keyof TSelectObject]: TSelectObject[K] extends RefProxy<infer T>
|
|
61
|
+
? // For RefProxy, preserve the type as-is (including optionality from joins)
|
|
62
|
+
T
|
|
63
|
+
: TSelectObject[K] extends BasicExpression<infer T>
|
|
64
|
+
? T
|
|
65
|
+
: TSelectObject[K] extends Aggregate<infer T>
|
|
66
|
+
? T
|
|
67
|
+
: TSelectObject[K] extends RefProxyFor<infer T>
|
|
68
|
+
? // For RefProxyFor, preserve the type as-is (including optionality from joins)
|
|
69
|
+
T
|
|
70
|
+
: never
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Callback type for orderBy clauses
|
|
74
|
+
export type OrderByCallback<TContext extends Context> = (
|
|
75
|
+
refs: RefProxyForContext<TContext>
|
|
76
|
+
) => any
|
|
77
|
+
|
|
78
|
+
// Callback type for groupBy clauses
|
|
79
|
+
export type GroupByCallback<TContext extends Context> = (
|
|
80
|
+
refs: RefProxyForContext<TContext>
|
|
81
|
+
) => any
|
|
82
|
+
|
|
83
|
+
// Callback type for join on clauses
|
|
84
|
+
export type JoinOnCallback<TContext extends Context> = (
|
|
85
|
+
refs: RefProxyForContext<TContext>
|
|
86
|
+
) => any
|
|
87
|
+
|
|
88
|
+
// Type for creating RefProxy objects based on context
|
|
89
|
+
export type RefProxyForContext<TContext extends Context> = {
|
|
90
|
+
[K in keyof TContext[`schema`]]: RefProxyFor<TContext[`schema`][K]>
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Helper type to check if T is exactly undefined
|
|
94
|
+
type IsExactlyUndefined<T> = [T] extends [undefined] ? true : false
|
|
95
|
+
|
|
96
|
+
// Helper type to check if T includes undefined (is optional)
|
|
97
|
+
type IsOptional<T> = undefined extends T ? true : false
|
|
98
|
+
|
|
99
|
+
// Helper type to extract non-undefined type
|
|
100
|
+
type NonUndefined<T> = T extends undefined ? never : T
|
|
101
|
+
|
|
102
|
+
// Helper type to create RefProxy for a specific type with optionality passthrough
|
|
103
|
+
// This is used to create the RefProxy object that is used in the query builder.
|
|
104
|
+
// Much of the complexity here is due to the fact that we need to handle optionality
|
|
105
|
+
// from joins. A left join will make the joined table optional, a right join will make
|
|
106
|
+
// the main table optional etc. This is applied to the schema, with the new namespaced
|
|
107
|
+
// source being `SourceType | undefined`.
|
|
108
|
+
// We then follow this through the ref proxy system so that accessing a property on
|
|
109
|
+
// and optional source will itsself be optional.
|
|
110
|
+
// If for example we join in `joinedTable` with a left join, then
|
|
111
|
+
// `where(({ joinedTable }) => joinedTable.name === `John`)`
|
|
112
|
+
// we want the the type of `name` to be `RefProxy<string | undefined>` to indicate that
|
|
113
|
+
// the `name` property is optional, as the joinedTable is also optional.
|
|
114
|
+
export type RefProxyFor<T> = OmitRefProxy<
|
|
115
|
+
IsExactlyUndefined<T> extends true
|
|
116
|
+
? // T is exactly undefined
|
|
117
|
+
RefProxy<T>
|
|
118
|
+
: IsOptional<T> extends true
|
|
119
|
+
? // T is optional (T | undefined) but not exactly undefined
|
|
120
|
+
NonUndefined<T> extends Record<string, any>
|
|
121
|
+
? {
|
|
122
|
+
// Properties are accessible and their types become optional
|
|
123
|
+
[K in keyof NonUndefined<T>]: NonUndefined<T>[K] extends Record<
|
|
124
|
+
string,
|
|
125
|
+
any
|
|
126
|
+
>
|
|
127
|
+
? RefProxyFor<NonUndefined<T>[K] | undefined> &
|
|
128
|
+
RefProxy<NonUndefined<T>[K] | undefined>
|
|
129
|
+
: RefProxy<NonUndefined<T>[K] | undefined>
|
|
130
|
+
} & RefProxy<T>
|
|
131
|
+
: RefProxy<T>
|
|
132
|
+
: // T is not optional
|
|
133
|
+
T extends Record<string, any>
|
|
134
|
+
? {
|
|
135
|
+
[K in keyof T]: T[K] extends Record<string, any>
|
|
136
|
+
? RefProxyFor<T[K]> & RefProxy<T[K]>
|
|
137
|
+
: RefProxy<T[K]>
|
|
138
|
+
} & RefProxy<T>
|
|
139
|
+
: RefProxy<T>
|
|
140
|
+
>
|
|
141
|
+
|
|
142
|
+
type OmitRefProxy<T> = Omit<T, `__refProxy` | `__path` | `__type`>
|
|
143
|
+
|
|
144
|
+
// The core RefProxy interface
|
|
145
|
+
export interface RefProxy<T = any> {
|
|
146
|
+
/** @internal */
|
|
147
|
+
readonly __refProxy: true
|
|
148
|
+
/** @internal */
|
|
149
|
+
readonly __path: Array<string>
|
|
150
|
+
/** @internal */
|
|
151
|
+
readonly __type: T
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Helper type to apply join optionality immediately when merging contexts
|
|
155
|
+
export type MergeContextWithJoinType<
|
|
156
|
+
TContext extends Context,
|
|
157
|
+
TNewSchema extends ContextSchema,
|
|
158
|
+
TJoinType extends `inner` | `left` | `right` | `full` | `outer` | `cross`,
|
|
159
|
+
> = {
|
|
160
|
+
baseSchema: TContext[`baseSchema`]
|
|
161
|
+
// Apply optionality immediately to the schema
|
|
162
|
+
schema: ApplyJoinOptionalityToMergedSchema<
|
|
163
|
+
TContext[`schema`],
|
|
164
|
+
TNewSchema,
|
|
165
|
+
TJoinType,
|
|
166
|
+
TContext[`fromSourceName`]
|
|
167
|
+
>
|
|
168
|
+
fromSourceName: TContext[`fromSourceName`]
|
|
169
|
+
hasJoins: true
|
|
170
|
+
// Track join types for reference
|
|
171
|
+
joinTypes: (TContext[`joinTypes`] extends Record<string, any>
|
|
172
|
+
? TContext[`joinTypes`]
|
|
173
|
+
: {}) & {
|
|
174
|
+
[K in keyof TNewSchema & string]: TJoinType
|
|
175
|
+
}
|
|
176
|
+
result: TContext[`result`]
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Helper type to apply join optionality when merging new schema
|
|
180
|
+
export type ApplyJoinOptionalityToMergedSchema<
|
|
181
|
+
TExistingSchema extends ContextSchema,
|
|
182
|
+
TNewSchema extends ContextSchema,
|
|
183
|
+
TJoinType extends `inner` | `left` | `right` | `full` | `outer` | `cross`,
|
|
184
|
+
TFromSourceName extends string,
|
|
185
|
+
> = {
|
|
186
|
+
// Apply optionality to existing schema based on new join type
|
|
187
|
+
[K in keyof TExistingSchema]: K extends TFromSourceName
|
|
188
|
+
? // Main table becomes optional if the new join is a right or full join
|
|
189
|
+
TJoinType extends `right` | `full`
|
|
190
|
+
? TExistingSchema[K] | undefined
|
|
191
|
+
: TExistingSchema[K]
|
|
192
|
+
: // Other tables remain as they are (already have their optionality applied)
|
|
193
|
+
TExistingSchema[K]
|
|
194
|
+
} & {
|
|
195
|
+
// Apply optionality to new schema based on join type
|
|
196
|
+
[K in keyof TNewSchema]: TJoinType extends `left` | `full`
|
|
197
|
+
? // New table becomes optional for left and full joins
|
|
198
|
+
TNewSchema[K] | undefined
|
|
199
|
+
: // New table is required for inner and right joins
|
|
200
|
+
TNewSchema[K]
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Helper type to get the result type from a context
|
|
204
|
+
export type GetResult<TContext extends Context> = Prettify<
|
|
205
|
+
TContext[`result`] extends object
|
|
206
|
+
? TContext[`result`]
|
|
207
|
+
: TContext[`hasJoins`] extends true
|
|
208
|
+
? // Optionality is already applied in the schema, just return it
|
|
209
|
+
TContext[`schema`]
|
|
210
|
+
: // Single table query - return the specific table
|
|
211
|
+
TContext[`schema`][TContext[`fromSourceName`]]
|
|
212
|
+
>
|
|
213
|
+
|
|
214
|
+
// Helper type to apply join optionality to the schema based on joinTypes
|
|
215
|
+
export type ApplyJoinOptionalityToSchema<
|
|
216
|
+
TSchema extends ContextSchema,
|
|
217
|
+
TJoinTypes extends Record<string, string>,
|
|
218
|
+
TFromSourceName extends string,
|
|
219
|
+
> = {
|
|
220
|
+
[K in keyof TSchema]: K extends TFromSourceName
|
|
221
|
+
? // Main table (from source) - becomes optional if ANY right or full join exists
|
|
222
|
+
HasJoinType<TJoinTypes, `right` | `full`> extends true
|
|
223
|
+
? TSchema[K] | undefined
|
|
224
|
+
: TSchema[K]
|
|
225
|
+
: // Joined table - check its specific join type AND if it's affected by subsequent joins
|
|
226
|
+
K extends keyof TJoinTypes
|
|
227
|
+
? TJoinTypes[K] extends `left` | `full`
|
|
228
|
+
? TSchema[K] | undefined
|
|
229
|
+
: // For inner/right joins, check if this table becomes optional due to subsequent right/full joins
|
|
230
|
+
// that don't include this table
|
|
231
|
+
IsTableMadeOptionalBySubsequentJoins<
|
|
232
|
+
K,
|
|
233
|
+
TJoinTypes,
|
|
234
|
+
TFromSourceName
|
|
235
|
+
> extends true
|
|
236
|
+
? TSchema[K] | undefined
|
|
237
|
+
: TSchema[K]
|
|
238
|
+
: TSchema[K]
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Helper type to check if a table becomes optional due to subsequent joins
|
|
242
|
+
type IsTableMadeOptionalBySubsequentJoins<
|
|
243
|
+
TTableAlias extends string | number | symbol,
|
|
244
|
+
TJoinTypes extends Record<string, string>,
|
|
245
|
+
TFromSourceName extends string,
|
|
246
|
+
> = TTableAlias extends TFromSourceName
|
|
247
|
+
? // Main table becomes optional if there are any right or full joins
|
|
248
|
+
HasJoinType<TJoinTypes, `right` | `full`>
|
|
249
|
+
: // Joined tables are not affected by subsequent joins in our current implementation
|
|
250
|
+
false
|
|
251
|
+
|
|
252
|
+
// Helper type to check if any join has one of the specified types
|
|
253
|
+
export type HasJoinType<
|
|
254
|
+
TJoinTypes extends Record<string, string>,
|
|
255
|
+
TTargetTypes extends string,
|
|
256
|
+
> = true extends {
|
|
257
|
+
[K in keyof TJoinTypes]: TJoinTypes[K] extends TTargetTypes ? true : false
|
|
258
|
+
}[keyof TJoinTypes]
|
|
259
|
+
? true
|
|
260
|
+
: false
|
|
261
|
+
|
|
262
|
+
// Helper type to merge contexts (for joins) - backward compatibility
|
|
263
|
+
export type MergeContext<
|
|
264
|
+
TContext extends Context,
|
|
265
|
+
TNewSchema extends ContextSchema,
|
|
266
|
+
> = MergeContextWithJoinType<TContext, TNewSchema, `left`>
|
|
267
|
+
|
|
268
|
+
// Helper type for updating context with result type
|
|
269
|
+
export type WithResult<TContext extends Context, TResult> = Prettify<
|
|
270
|
+
Omit<TContext, `result`> & {
|
|
271
|
+
result: Prettify<TResult>
|
|
272
|
+
}
|
|
273
|
+
>
|
|
274
|
+
|
|
275
|
+
// Helper type to simplify complex types for better editor hints
|
|
276
|
+
export type Prettify<T> = {
|
|
277
|
+
[K in keyof T]: T[K]
|
|
278
|
+
} & {}
|