@tanstack/db 0.0.14 → 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.
Files changed (198) hide show
  1. package/dist/cjs/collection.cjs +117 -104
  2. package/dist/cjs/collection.cjs.map +1 -1
  3. package/dist/cjs/collection.d.cts +18 -21
  4. package/dist/cjs/index.cjs +35 -13
  5. package/dist/cjs/index.cjs.map +1 -1
  6. package/dist/cjs/index.d.cts +0 -1
  7. package/dist/cjs/query/builder/functions.cjs +107 -0
  8. package/dist/cjs/query/builder/functions.cjs.map +1 -0
  9. package/dist/cjs/query/builder/functions.d.cts +38 -0
  10. package/dist/cjs/query/builder/index.cjs +499 -0
  11. package/dist/cjs/query/builder/index.cjs.map +1 -0
  12. package/dist/cjs/query/builder/index.d.cts +324 -0
  13. package/dist/cjs/query/builder/ref-proxy.cjs +96 -0
  14. package/dist/cjs/query/builder/ref-proxy.cjs.map +1 -0
  15. package/dist/cjs/query/builder/ref-proxy.d.cts +28 -0
  16. package/dist/cjs/query/builder/types.d.cts +80 -0
  17. package/dist/cjs/query/compiler/evaluators.cjs +261 -0
  18. package/dist/cjs/query/compiler/evaluators.cjs.map +1 -0
  19. package/dist/cjs/query/compiler/evaluators.d.cts +11 -0
  20. package/dist/cjs/query/compiler/group-by.cjs +271 -0
  21. package/dist/cjs/query/compiler/group-by.cjs.map +1 -0
  22. package/dist/cjs/query/compiler/group-by.d.cts +7 -0
  23. package/dist/cjs/query/compiler/index.cjs +181 -0
  24. package/dist/cjs/query/compiler/index.cjs.map +1 -0
  25. package/dist/cjs/query/compiler/index.d.cts +15 -0
  26. package/dist/cjs/query/compiler/joins.cjs +116 -0
  27. package/dist/cjs/query/compiler/joins.cjs.map +1 -0
  28. package/dist/cjs/query/compiler/joins.d.cts +11 -0
  29. package/dist/cjs/query/compiler/order-by.cjs +89 -0
  30. package/dist/cjs/query/compiler/order-by.cjs.map +1 -0
  31. package/dist/cjs/query/compiler/order-by.d.cts +9 -0
  32. package/dist/cjs/query/compiler/select.cjs +57 -0
  33. package/dist/cjs/query/compiler/select.cjs.map +1 -0
  34. package/dist/cjs/query/compiler/select.d.cts +15 -0
  35. package/dist/cjs/query/index.d.cts +6 -5
  36. package/dist/cjs/query/ir.cjs +57 -0
  37. package/dist/cjs/query/ir.cjs.map +1 -0
  38. package/dist/cjs/query/ir.d.cts +81 -0
  39. package/dist/cjs/query/live-query-collection.cjs +224 -0
  40. package/dist/cjs/query/live-query-collection.cjs.map +1 -0
  41. package/dist/cjs/query/live-query-collection.d.cts +124 -0
  42. package/dist/cjs/transactions.cjs +20 -13
  43. package/dist/cjs/transactions.cjs.map +1 -1
  44. package/dist/cjs/transactions.d.cts +10 -1
  45. package/dist/cjs/types.d.cts +13 -0
  46. package/dist/esm/collection.d.ts +18 -21
  47. package/dist/esm/collection.js +118 -105
  48. package/dist/esm/collection.js.map +1 -1
  49. package/dist/esm/index.d.ts +0 -1
  50. package/dist/esm/index.js +34 -12
  51. package/dist/esm/index.js.map +1 -1
  52. package/dist/esm/query/builder/functions.d.ts +38 -0
  53. package/dist/esm/query/builder/functions.js +107 -0
  54. package/dist/esm/query/builder/functions.js.map +1 -0
  55. package/dist/esm/query/builder/index.d.ts +324 -0
  56. package/dist/esm/query/builder/index.js +499 -0
  57. package/dist/esm/query/builder/index.js.map +1 -0
  58. package/dist/esm/query/builder/ref-proxy.d.ts +28 -0
  59. package/dist/esm/query/builder/ref-proxy.js +96 -0
  60. package/dist/esm/query/builder/ref-proxy.js.map +1 -0
  61. package/dist/esm/query/builder/types.d.ts +80 -0
  62. package/dist/esm/query/compiler/evaluators.d.ts +11 -0
  63. package/dist/esm/query/compiler/evaluators.js +261 -0
  64. package/dist/esm/query/compiler/evaluators.js.map +1 -0
  65. package/dist/esm/query/compiler/group-by.d.ts +7 -0
  66. package/dist/esm/query/compiler/group-by.js +271 -0
  67. package/dist/esm/query/compiler/group-by.js.map +1 -0
  68. package/dist/esm/query/compiler/index.d.ts +15 -0
  69. package/dist/esm/query/compiler/index.js +181 -0
  70. package/dist/esm/query/compiler/index.js.map +1 -0
  71. package/dist/esm/query/compiler/joins.d.ts +11 -0
  72. package/dist/esm/query/compiler/joins.js +116 -0
  73. package/dist/esm/query/compiler/joins.js.map +1 -0
  74. package/dist/esm/query/compiler/order-by.d.ts +9 -0
  75. package/dist/esm/query/compiler/order-by.js +89 -0
  76. package/dist/esm/query/compiler/order-by.js.map +1 -0
  77. package/dist/esm/query/compiler/select.d.ts +15 -0
  78. package/dist/esm/query/compiler/select.js +57 -0
  79. package/dist/esm/query/compiler/select.js.map +1 -0
  80. package/dist/esm/query/index.d.ts +6 -5
  81. package/dist/esm/query/ir.d.ts +81 -0
  82. package/dist/esm/query/ir.js +57 -0
  83. package/dist/esm/query/ir.js.map +1 -0
  84. package/dist/esm/query/live-query-collection.d.ts +124 -0
  85. package/dist/esm/query/live-query-collection.js +224 -0
  86. package/dist/esm/query/live-query-collection.js.map +1 -0
  87. package/dist/esm/transactions.d.ts +10 -1
  88. package/dist/esm/transactions.js +20 -13
  89. package/dist/esm/transactions.js.map +1 -1
  90. package/dist/esm/types.d.ts +13 -0
  91. package/package.json +3 -4
  92. package/src/collection.ts +152 -129
  93. package/src/index.ts +0 -1
  94. package/src/query/builder/functions.ts +267 -0
  95. package/src/query/builder/index.ts +648 -0
  96. package/src/query/builder/ref-proxy.ts +156 -0
  97. package/src/query/builder/types.ts +278 -0
  98. package/src/query/compiler/evaluators.ts +315 -0
  99. package/src/query/compiler/group-by.ts +428 -0
  100. package/src/query/compiler/index.ts +276 -0
  101. package/src/query/compiler/joins.ts +228 -0
  102. package/src/query/compiler/order-by.ts +139 -0
  103. package/src/query/compiler/select.ts +173 -0
  104. package/src/query/index.ts +64 -5
  105. package/src/query/ir.ts +128 -0
  106. package/src/query/live-query-collection.ts +509 -0
  107. package/src/transactions.ts +27 -16
  108. package/src/types.ts +15 -0
  109. package/dist/cjs/query/compiled-query.cjs +0 -160
  110. package/dist/cjs/query/compiled-query.cjs.map +0 -1
  111. package/dist/cjs/query/compiled-query.d.cts +0 -20
  112. package/dist/cjs/query/evaluators.cjs +0 -161
  113. package/dist/cjs/query/evaluators.cjs.map +0 -1
  114. package/dist/cjs/query/evaluators.d.cts +0 -14
  115. package/dist/cjs/query/extractors.cjs +0 -122
  116. package/dist/cjs/query/extractors.cjs.map +0 -1
  117. package/dist/cjs/query/extractors.d.cts +0 -22
  118. package/dist/cjs/query/functions.cjs +0 -152
  119. package/dist/cjs/query/functions.cjs.map +0 -1
  120. package/dist/cjs/query/functions.d.cts +0 -21
  121. package/dist/cjs/query/group-by.cjs +0 -88
  122. package/dist/cjs/query/group-by.cjs.map +0 -1
  123. package/dist/cjs/query/group-by.d.cts +0 -40
  124. package/dist/cjs/query/joins.cjs +0 -141
  125. package/dist/cjs/query/joins.cjs.map +0 -1
  126. package/dist/cjs/query/joins.d.cts +0 -14
  127. package/dist/cjs/query/order-by.cjs +0 -185
  128. package/dist/cjs/query/order-by.cjs.map +0 -1
  129. package/dist/cjs/query/order-by.d.cts +0 -3
  130. package/dist/cjs/query/pipeline-compiler.cjs +0 -89
  131. package/dist/cjs/query/pipeline-compiler.cjs.map +0 -1
  132. package/dist/cjs/query/pipeline-compiler.d.cts +0 -10
  133. package/dist/cjs/query/query-builder.cjs +0 -307
  134. package/dist/cjs/query/query-builder.cjs.map +0 -1
  135. package/dist/cjs/query/query-builder.d.cts +0 -225
  136. package/dist/cjs/query/schema.d.cts +0 -100
  137. package/dist/cjs/query/select.cjs +0 -130
  138. package/dist/cjs/query/select.cjs.map +0 -1
  139. package/dist/cjs/query/select.d.cts +0 -3
  140. package/dist/cjs/query/types.d.cts +0 -189
  141. package/dist/cjs/query/utils.cjs +0 -154
  142. package/dist/cjs/query/utils.cjs.map +0 -1
  143. package/dist/cjs/query/utils.d.cts +0 -37
  144. package/dist/cjs/utils.cjs +0 -17
  145. package/dist/cjs/utils.cjs.map +0 -1
  146. package/dist/cjs/utils.d.cts +0 -3
  147. package/dist/esm/query/compiled-query.d.ts +0 -20
  148. package/dist/esm/query/compiled-query.js +0 -160
  149. package/dist/esm/query/compiled-query.js.map +0 -1
  150. package/dist/esm/query/evaluators.d.ts +0 -14
  151. package/dist/esm/query/evaluators.js +0 -161
  152. package/dist/esm/query/evaluators.js.map +0 -1
  153. package/dist/esm/query/extractors.d.ts +0 -22
  154. package/dist/esm/query/extractors.js +0 -122
  155. package/dist/esm/query/extractors.js.map +0 -1
  156. package/dist/esm/query/functions.d.ts +0 -21
  157. package/dist/esm/query/functions.js +0 -152
  158. package/dist/esm/query/functions.js.map +0 -1
  159. package/dist/esm/query/group-by.d.ts +0 -40
  160. package/dist/esm/query/group-by.js +0 -88
  161. package/dist/esm/query/group-by.js.map +0 -1
  162. package/dist/esm/query/joins.d.ts +0 -14
  163. package/dist/esm/query/joins.js +0 -141
  164. package/dist/esm/query/joins.js.map +0 -1
  165. package/dist/esm/query/order-by.d.ts +0 -3
  166. package/dist/esm/query/order-by.js +0 -185
  167. package/dist/esm/query/order-by.js.map +0 -1
  168. package/dist/esm/query/pipeline-compiler.d.ts +0 -10
  169. package/dist/esm/query/pipeline-compiler.js +0 -89
  170. package/dist/esm/query/pipeline-compiler.js.map +0 -1
  171. package/dist/esm/query/query-builder.d.ts +0 -225
  172. package/dist/esm/query/query-builder.js +0 -307
  173. package/dist/esm/query/query-builder.js.map +0 -1
  174. package/dist/esm/query/schema.d.ts +0 -100
  175. package/dist/esm/query/select.d.ts +0 -3
  176. package/dist/esm/query/select.js +0 -130
  177. package/dist/esm/query/select.js.map +0 -1
  178. package/dist/esm/query/types.d.ts +0 -189
  179. package/dist/esm/query/utils.d.ts +0 -37
  180. package/dist/esm/query/utils.js +0 -154
  181. package/dist/esm/query/utils.js.map +0 -1
  182. package/dist/esm/utils.d.ts +0 -3
  183. package/dist/esm/utils.js +0 -17
  184. package/dist/esm/utils.js.map +0 -1
  185. package/src/query/compiled-query.ts +0 -234
  186. package/src/query/evaluators.ts +0 -250
  187. package/src/query/extractors.ts +0 -214
  188. package/src/query/functions.ts +0 -297
  189. package/src/query/group-by.ts +0 -139
  190. package/src/query/joins.ts +0 -260
  191. package/src/query/order-by.ts +0 -264
  192. package/src/query/pipeline-compiler.ts +0 -149
  193. package/src/query/query-builder.ts +0 -902
  194. package/src/query/schema.ts +0 -268
  195. package/src/query/select.ts +0 -208
  196. package/src/query/types.ts +0 -418
  197. package/src/query/utils.ts +0 -245
  198. 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
+ } & {}