@tanstack/db 0.0.1

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 (154) hide show
  1. package/README.md +37 -0
  2. package/dist/cjs/SortedMap.cjs +140 -0
  3. package/dist/cjs/SortedMap.cjs.map +1 -0
  4. package/dist/cjs/SortedMap.d.cts +91 -0
  5. package/dist/cjs/collection.cjs +597 -0
  6. package/dist/cjs/collection.cjs.map +1 -0
  7. package/dist/cjs/collection.d.cts +176 -0
  8. package/dist/cjs/deferred.cjs +25 -0
  9. package/dist/cjs/deferred.cjs.map +1 -0
  10. package/dist/cjs/deferred.d.cts +20 -0
  11. package/dist/cjs/errors.cjs +10 -0
  12. package/dist/cjs/errors.cjs.map +1 -0
  13. package/dist/cjs/errors.d.cts +3 -0
  14. package/dist/cjs/index.cjs +33 -0
  15. package/dist/cjs/index.cjs.map +1 -0
  16. package/dist/cjs/index.d.cts +9 -0
  17. package/dist/cjs/proxy.cjs +654 -0
  18. package/dist/cjs/proxy.cjs.map +1 -0
  19. package/dist/cjs/proxy.d.cts +59 -0
  20. package/dist/cjs/query/compiled-query.cjs +162 -0
  21. package/dist/cjs/query/compiled-query.cjs.map +1 -0
  22. package/dist/cjs/query/compiled-query.d.cts +22 -0
  23. package/dist/cjs/query/evaluators.cjs +146 -0
  24. package/dist/cjs/query/evaluators.cjs.map +1 -0
  25. package/dist/cjs/query/evaluators.d.cts +9 -0
  26. package/dist/cjs/query/extractors.cjs +122 -0
  27. package/dist/cjs/query/extractors.cjs.map +1 -0
  28. package/dist/cjs/query/extractors.d.cts +22 -0
  29. package/dist/cjs/query/functions.cjs +152 -0
  30. package/dist/cjs/query/functions.cjs.map +1 -0
  31. package/dist/cjs/query/functions.d.cts +21 -0
  32. package/dist/cjs/query/group-by.cjs +91 -0
  33. package/dist/cjs/query/group-by.cjs.map +1 -0
  34. package/dist/cjs/query/group-by.d.cts +40 -0
  35. package/dist/cjs/query/index.d.cts +5 -0
  36. package/dist/cjs/query/joins.cjs +155 -0
  37. package/dist/cjs/query/joins.cjs.map +1 -0
  38. package/dist/cjs/query/joins.d.cts +14 -0
  39. package/dist/cjs/query/key-by.cjs +43 -0
  40. package/dist/cjs/query/key-by.cjs.map +1 -0
  41. package/dist/cjs/query/key-by.d.cts +3 -0
  42. package/dist/cjs/query/order-by.cjs +229 -0
  43. package/dist/cjs/query/order-by.cjs.map +1 -0
  44. package/dist/cjs/query/order-by.d.cts +3 -0
  45. package/dist/cjs/query/pipeline-compiler.cjs +94 -0
  46. package/dist/cjs/query/pipeline-compiler.cjs.map +1 -0
  47. package/dist/cjs/query/pipeline-compiler.d.cts +9 -0
  48. package/dist/cjs/query/query-builder.cjs +314 -0
  49. package/dist/cjs/query/query-builder.cjs.map +1 -0
  50. package/dist/cjs/query/query-builder.d.cts +219 -0
  51. package/dist/cjs/query/schema.d.cts +98 -0
  52. package/dist/cjs/query/select.cjs +107 -0
  53. package/dist/cjs/query/select.cjs.map +1 -0
  54. package/dist/cjs/query/select.d.cts +3 -0
  55. package/dist/cjs/query/types.d.cts +188 -0
  56. package/dist/cjs/query/utils.cjs +154 -0
  57. package/dist/cjs/query/utils.cjs.map +1 -0
  58. package/dist/cjs/query/utils.d.cts +37 -0
  59. package/dist/cjs/transactions.cjs +137 -0
  60. package/dist/cjs/transactions.cjs.map +1 -0
  61. package/dist/cjs/transactions.d.cts +27 -0
  62. package/dist/cjs/types.d.cts +94 -0
  63. package/dist/cjs/utils.cjs +17 -0
  64. package/dist/cjs/utils.cjs.map +1 -0
  65. package/dist/cjs/utils.d.cts +3 -0
  66. package/dist/esm/SortedMap.d.ts +91 -0
  67. package/dist/esm/SortedMap.js +140 -0
  68. package/dist/esm/SortedMap.js.map +1 -0
  69. package/dist/esm/collection.d.ts +176 -0
  70. package/dist/esm/collection.js +597 -0
  71. package/dist/esm/collection.js.map +1 -0
  72. package/dist/esm/deferred.d.ts +20 -0
  73. package/dist/esm/deferred.js +25 -0
  74. package/dist/esm/deferred.js.map +1 -0
  75. package/dist/esm/errors.d.ts +3 -0
  76. package/dist/esm/errors.js +10 -0
  77. package/dist/esm/errors.js.map +1 -0
  78. package/dist/esm/index.d.ts +9 -0
  79. package/dist/esm/index.js +33 -0
  80. package/dist/esm/index.js.map +1 -0
  81. package/dist/esm/proxy.d.ts +59 -0
  82. package/dist/esm/proxy.js +654 -0
  83. package/dist/esm/proxy.js.map +1 -0
  84. package/dist/esm/query/compiled-query.d.ts +22 -0
  85. package/dist/esm/query/compiled-query.js +162 -0
  86. package/dist/esm/query/compiled-query.js.map +1 -0
  87. package/dist/esm/query/evaluators.d.ts +9 -0
  88. package/dist/esm/query/evaluators.js +146 -0
  89. package/dist/esm/query/evaluators.js.map +1 -0
  90. package/dist/esm/query/extractors.d.ts +22 -0
  91. package/dist/esm/query/extractors.js +122 -0
  92. package/dist/esm/query/extractors.js.map +1 -0
  93. package/dist/esm/query/functions.d.ts +21 -0
  94. package/dist/esm/query/functions.js +152 -0
  95. package/dist/esm/query/functions.js.map +1 -0
  96. package/dist/esm/query/group-by.d.ts +40 -0
  97. package/dist/esm/query/group-by.js +91 -0
  98. package/dist/esm/query/group-by.js.map +1 -0
  99. package/dist/esm/query/index.d.ts +5 -0
  100. package/dist/esm/query/joins.d.ts +14 -0
  101. package/dist/esm/query/joins.js +155 -0
  102. package/dist/esm/query/joins.js.map +1 -0
  103. package/dist/esm/query/key-by.d.ts +3 -0
  104. package/dist/esm/query/key-by.js +43 -0
  105. package/dist/esm/query/key-by.js.map +1 -0
  106. package/dist/esm/query/order-by.d.ts +3 -0
  107. package/dist/esm/query/order-by.js +229 -0
  108. package/dist/esm/query/order-by.js.map +1 -0
  109. package/dist/esm/query/pipeline-compiler.d.ts +9 -0
  110. package/dist/esm/query/pipeline-compiler.js +94 -0
  111. package/dist/esm/query/pipeline-compiler.js.map +1 -0
  112. package/dist/esm/query/query-builder.d.ts +219 -0
  113. package/dist/esm/query/query-builder.js +314 -0
  114. package/dist/esm/query/query-builder.js.map +1 -0
  115. package/dist/esm/query/schema.d.ts +98 -0
  116. package/dist/esm/query/select.d.ts +3 -0
  117. package/dist/esm/query/select.js +107 -0
  118. package/dist/esm/query/select.js.map +1 -0
  119. package/dist/esm/query/types.d.ts +188 -0
  120. package/dist/esm/query/utils.d.ts +37 -0
  121. package/dist/esm/query/utils.js +154 -0
  122. package/dist/esm/query/utils.js.map +1 -0
  123. package/dist/esm/transactions.d.ts +27 -0
  124. package/dist/esm/transactions.js +137 -0
  125. package/dist/esm/transactions.js.map +1 -0
  126. package/dist/esm/types.d.ts +94 -0
  127. package/dist/esm/utils.d.ts +3 -0
  128. package/dist/esm/utils.js +17 -0
  129. package/dist/esm/utils.js.map +1 -0
  130. package/package.json +57 -0
  131. package/src/SortedMap.ts +163 -0
  132. package/src/collection.ts +919 -0
  133. package/src/deferred.ts +47 -0
  134. package/src/errors.ts +6 -0
  135. package/src/index.ts +12 -0
  136. package/src/proxy.ts +1104 -0
  137. package/src/query/compiled-query.ts +193 -0
  138. package/src/query/evaluators.ts +222 -0
  139. package/src/query/extractors.ts +211 -0
  140. package/src/query/functions.ts +297 -0
  141. package/src/query/group-by.ts +137 -0
  142. package/src/query/index.ts +5 -0
  143. package/src/query/joins.ts +247 -0
  144. package/src/query/key-by.ts +61 -0
  145. package/src/query/order-by.ts +312 -0
  146. package/src/query/pipeline-compiler.ts +152 -0
  147. package/src/query/query-builder.ts +898 -0
  148. package/src/query/schema.ts +255 -0
  149. package/src/query/select.ts +173 -0
  150. package/src/query/types.ts +417 -0
  151. package/src/query/utils.ts +245 -0
  152. package/src/transactions.ts +198 -0
  153. package/src/types.ts +125 -0
  154. package/src/utils.ts +15 -0
@@ -0,0 +1,417 @@
1
+ import type {
2
+ ConditionOperand,
3
+ ExplicitLiteral,
4
+ FunctionCall,
5
+ LiteralValue,
6
+ Select,
7
+ } from "./schema.js"
8
+
9
+ // Input is analogous to a table in a SQL database
10
+ // A Schema is a set of named Inputs
11
+ export type Input = Record<string, unknown>
12
+ export type Schema = Record<string, Input>
13
+
14
+ // Context is a Schema with a default input
15
+ export type Context<
16
+ TBaseSchema extends Schema = Schema,
17
+ TSchema extends Schema = Schema,
18
+ > = {
19
+ baseSchema: TBaseSchema
20
+ schema: TSchema
21
+ default?: keyof TSchema
22
+ result?: Record<string, unknown>
23
+ }
24
+
25
+ // Helper types
26
+
27
+ export type Flatten<T> = {
28
+ [K in keyof T]: T[K]
29
+ } & {}
30
+
31
+ type UniqueSecondLevelKeys<T> = {
32
+ [K in keyof T]: Exclude<
33
+ keyof T[K],
34
+ // all keys in every branch except K
35
+ {
36
+ [P in Exclude<keyof T, K>]: keyof T[P]
37
+ }[Exclude<keyof T, K>]
38
+ >
39
+ }[keyof T]
40
+
41
+ type InputNames<TSchema extends Schema> = RemoveIndexSignature<{
42
+ [I in keyof TSchema]: I
43
+ }>[keyof RemoveIndexSignature<{
44
+ [I in keyof TSchema]: I
45
+ }>]
46
+
47
+ type UniquePropertyNames<TSchema extends Schema> = UniqueSecondLevelKeys<
48
+ RemoveIndexSignature<TSchema>
49
+ >
50
+
51
+ export type RemoveIndexSignature<T> = {
52
+ [K in keyof T as string extends K
53
+ ? never
54
+ : number extends K
55
+ ? never
56
+ : K]: T[K]
57
+ }
58
+
59
+ // Fully qualified references like "@employees.id"
60
+ type QualifiedReferencesOfSchemaString<TSchema extends Schema> =
61
+ RemoveIndexSignature<{
62
+ [I in keyof TSchema]: {
63
+ [P in keyof RemoveIndexSignature<
64
+ TSchema[I]
65
+ >]: `@${string & I}.${string & P}`
66
+ }[keyof RemoveIndexSignature<TSchema[I]>]
67
+ }>
68
+
69
+ type QualifiedReferenceString<TContext extends Context<Schema>> =
70
+ QualifiedReferencesOfSchemaString<
71
+ TContext[`schema`]
72
+ >[keyof QualifiedReferencesOfSchemaString<TContext[`schema`]>]
73
+
74
+ // Fully qualified references like { col: '@employees.id' }
75
+ type QualifiedReferencesOfSchemaObject<TSchema extends Schema> =
76
+ RemoveIndexSignature<{
77
+ [I in keyof TSchema]: {
78
+ [P in keyof RemoveIndexSignature<TSchema[I]>]: {
79
+ col: `${string & I}.${string & P}`
80
+ }
81
+ }[keyof RemoveIndexSignature<TSchema[I]>]
82
+ }>
83
+
84
+ type QualifiedReferenceObject<TContext extends Context<Schema>> =
85
+ QualifiedReferencesOfSchemaObject<
86
+ TContext[`schema`]
87
+ >[keyof QualifiedReferencesOfSchemaObject<TContext[`schema`]>]
88
+
89
+ type QualifiedReference<TContext extends Context<Schema>> =
90
+ | QualifiedReferenceString<TContext>
91
+ | QualifiedReferenceObject<TContext>
92
+
93
+ type DefaultReferencesOfSchemaString<
94
+ TSchema extends Schema,
95
+ TDefault extends keyof TSchema,
96
+ > = RemoveIndexSignature<{
97
+ [P in keyof TSchema[TDefault]]: `@${string & P}`
98
+ }>
99
+
100
+ type DefaultReferenceString<TContext extends Context<Schema>> =
101
+ TContext[`default`] extends undefined
102
+ ? never
103
+ : DefaultReferencesOfSchemaString<
104
+ TContext[`schema`],
105
+ Exclude<TContext[`default`], undefined>
106
+ >[keyof DefaultReferencesOfSchemaString<
107
+ TContext[`schema`],
108
+ Exclude<TContext[`default`], undefined>
109
+ >]
110
+
111
+ type DefaultReferencesOfSchemaObject<
112
+ TSchema extends Schema,
113
+ TDefault extends keyof TSchema,
114
+ > = RemoveIndexSignature<{
115
+ [P in keyof TSchema[TDefault]]: { col: `${string & P}` }
116
+ }>
117
+
118
+ type DefaultReferenceObject<TContext extends Context<Schema>> =
119
+ TContext[`default`] extends undefined
120
+ ? never
121
+ : DefaultReferencesOfSchemaObject<
122
+ TContext[`schema`],
123
+ Exclude<TContext[`default`], undefined>
124
+ >[keyof DefaultReferencesOfSchemaObject<
125
+ TContext[`schema`],
126
+ Exclude<TContext[`default`], undefined>
127
+ >]
128
+
129
+ type DefaultReference<TContext extends Context<Schema>> =
130
+ | DefaultReferenceString<TContext>
131
+ | DefaultReferenceObject<TContext>
132
+
133
+ type UniqueReferencesOfSchemaString<TSchema extends Schema> =
134
+ RemoveIndexSignature<{
135
+ [I in keyof TSchema]: {
136
+ [P in keyof TSchema[I]]: P extends UniquePropertyNames<TSchema>
137
+ ? `@${string & P}`
138
+ : never
139
+ }[keyof TSchema[I]]
140
+ }>
141
+
142
+ type UniqueReferenceString<TContext extends Context<Schema>> =
143
+ UniqueReferencesOfSchemaString<
144
+ TContext[`schema`]
145
+ >[keyof UniqueReferencesOfSchemaString<TContext[`schema`]>]
146
+
147
+ type UniqueReferencesOfSchemaObject<TSchema extends Schema> =
148
+ RemoveIndexSignature<{
149
+ [I in keyof TSchema]: {
150
+ [P in keyof TSchema[I]]: P extends UniquePropertyNames<TSchema>
151
+ ? { col: `${string & P}` }
152
+ : never
153
+ }[keyof TSchema[I]]
154
+ }>
155
+
156
+ type UniqueReferenceObject<TContext extends Context<Schema>> =
157
+ UniqueReferencesOfSchemaObject<
158
+ TContext[`schema`]
159
+ >[keyof UniqueReferencesOfSchemaObject<TContext[`schema`]>]
160
+
161
+ type UniqueReference<TContext extends Context<Schema>> =
162
+ | UniqueReferenceString<TContext>
163
+ | UniqueReferenceObject<TContext>
164
+
165
+ type InputWildcardString<TContext extends Context<Schema>> = Flatten<
166
+ {
167
+ [I in InputNames<TContext[`schema`]>]: `@${I}.*`
168
+ }[InputNames<TContext[`schema`]>]
169
+ >
170
+
171
+ type InputWildcardObject<TContext extends Context<Schema>> = Flatten<
172
+ {
173
+ [I in InputNames<TContext[`schema`]>]: { col: `${I}.*` }
174
+ }[InputNames<TContext[`schema`]>]
175
+ >
176
+
177
+ type InputWildcard<TContext extends Context<Schema>> =
178
+ | InputWildcardString<TContext>
179
+ | InputWildcardObject<TContext>
180
+
181
+ type AllWildcardString = `@*`
182
+ type AllWildcardObject = { col: `*` }
183
+ type AllWildcard = AllWildcardString | AllWildcardObject
184
+
185
+ export type PropertyReferenceString<TContext extends Context<Schema>> =
186
+ | DefaultReferenceString<TContext>
187
+ | QualifiedReferenceString<TContext>
188
+ | UniqueReferenceString<TContext>
189
+
190
+ export type WildcardReferenceString<TContext extends Context<Schema>> =
191
+ | InputWildcardString<TContext>
192
+ | AllWildcardString
193
+
194
+ export type PropertyReferenceObject<TContext extends Context<Schema>> =
195
+ | DefaultReferenceObject<TContext>
196
+ | QualifiedReferenceObject<TContext>
197
+ | UniqueReferenceObject<TContext>
198
+
199
+ export type WildcardReferenceObject<TContext extends Context<Schema>> =
200
+ | InputWildcardObject<TContext>
201
+ | AllWildcardObject
202
+
203
+ export type PropertyReference<TContext extends Context<Schema>> =
204
+ | DefaultReference<TContext>
205
+ | QualifiedReference<TContext>
206
+ | UniqueReference<TContext>
207
+
208
+ export type WildcardReference<TContext extends Context<Schema>> =
209
+ | InputWildcard<TContext>
210
+ | AllWildcard
211
+
212
+ type InputWithProperty<TSchema extends Schema, TProperty extends string> = {
213
+ [I in keyof RemoveIndexSignature<TSchema>]: TProperty extends keyof TSchema[I]
214
+ ? I
215
+ : never
216
+ }[keyof RemoveIndexSignature<TSchema>]
217
+
218
+ export type TypeFromPropertyReference<
219
+ TContext extends Context<Schema>,
220
+ TReference extends PropertyReference<TContext>,
221
+ > = TReference extends
222
+ | `@${infer InputName}.${infer PropName}`
223
+ | { col: `${infer InputName}.${infer PropName}` }
224
+ ? InputName extends keyof TContext[`schema`]
225
+ ? PropName extends keyof TContext[`schema`][InputName]
226
+ ? TContext[`schema`][InputName][PropName]
227
+ : never
228
+ : never
229
+ : TReference extends `@${infer PropName}` | { col: `${infer PropName}` }
230
+ ? PropName extends keyof TContext[`schema`][Exclude<
231
+ TContext[`default`],
232
+ undefined
233
+ >]
234
+ ? TContext[`schema`][Exclude<TContext[`default`], undefined>][PropName]
235
+ : TContext[`schema`][InputWithProperty<
236
+ TContext[`schema`],
237
+ PropName
238
+ >][PropName]
239
+ : never
240
+
241
+ /**
242
+ * Return the key that would be used in the result of the query for a given property
243
+ * reference.
244
+ * - `@id` -> `id`
245
+ * - `@employees.id` -> `id`
246
+ * - `{ col: 'id' }` -> `id`
247
+ * - `{ col: 'employees.id' }` -> `id`
248
+ */
249
+ export type ResultKeyFromPropertyReference<
250
+ TContext extends Context<Schema>,
251
+ TReference extends PropertyReference<TContext>,
252
+ > = TReference extends `@${infer _InputName}.${infer PropName}`
253
+ ? PropName
254
+ : TReference extends { col: `${infer _InputName}.${infer PropName}` }
255
+ ? PropName
256
+ : TReference extends `@${infer PropName}`
257
+ ? PropName
258
+ : TReference extends { col: `${infer PropName}` }
259
+ ? PropName
260
+ : never
261
+
262
+ export type InputReference<TContext extends Context<Schema>> = {
263
+ [I in InputNames<TContext[`schema`]>]: I
264
+ }[InputNames<TContext[`schema`]>]
265
+
266
+ export type RenameInput<
267
+ TSchema extends Schema,
268
+ TInput extends keyof TSchema,
269
+ TNewName extends string,
270
+ > = Flatten<
271
+ {
272
+ [K in Exclude<keyof TSchema, TInput>]: TSchema[K]
273
+ } & {
274
+ [P in TNewName]: TSchema[TInput]
275
+ }
276
+ >
277
+
278
+ export type MaybeRenameInput<
279
+ TSchema extends Schema,
280
+ TInput extends keyof TSchema,
281
+ TNewName extends string | undefined,
282
+ > = TNewName extends undefined
283
+ ? TSchema
284
+ : RenameInput<TSchema, TInput, Exclude<TNewName, undefined>>
285
+
286
+ /**
287
+ * Helper type to combine result types from each select item in a tuple
288
+ */
289
+ export type InferResultTypeFromSelectTuple<
290
+ TContext extends Context<Schema>,
291
+ TSelects extends ReadonlyArray<Select<TContext>>,
292
+ > = UnionToIntersection<
293
+ {
294
+ [K in keyof TSelects]: TSelects[K] extends Select<TContext>
295
+ ? InferResultType<TContext, TSelects[K]>
296
+ : never
297
+ }[number]
298
+ >
299
+
300
+ /**
301
+ * Convert a union type to an intersection type
302
+ */
303
+ type UnionToIntersection<TUnion> = (
304
+ TUnion extends any ? (x: TUnion) => void : never
305
+ ) extends (x: infer I) => void
306
+ ? I
307
+ : never
308
+
309
+ /**
310
+ * Infers the result type from a single select item
311
+ */
312
+ type InferResultType<
313
+ TContext extends Context<Schema>,
314
+ TSelect extends Select<TContext>,
315
+ > =
316
+ TSelect extends PropertyReferenceString<TContext>
317
+ ? {
318
+ [K in ResultKeyFromPropertyReference<
319
+ TContext,
320
+ TSelect
321
+ >]: TypeFromPropertyReference<TContext, TSelect>
322
+ }
323
+ : TSelect extends WildcardReferenceString<TContext>
324
+ ? TSelect extends `@*`
325
+ ? InferAllColumnsType<TContext>
326
+ : TSelect extends `@${infer TableName}.*`
327
+ ? TableName extends keyof TContext[`schema`]
328
+ ? InferTableColumnsType<TContext, TableName>
329
+ : {}
330
+ : {}
331
+ : TSelect extends {
332
+ [alias: string]:
333
+ | PropertyReference<TContext>
334
+ | FunctionCall<TContext>
335
+ }
336
+ ? {
337
+ [K in keyof TSelect]: TSelect[K] extends PropertyReference<TContext>
338
+ ? TypeFromPropertyReference<TContext, TSelect[K]>
339
+ : TSelect[K] extends FunctionCall<TContext>
340
+ ? InferFunctionCallResultType<TContext, TSelect[K]>
341
+ : never
342
+ }
343
+ : {}
344
+
345
+ /**
346
+ * Infers the result type for all columns from all tables
347
+ */
348
+ type InferAllColumnsType<TContext extends Context<Schema>> = {
349
+ [K in keyof TContext[`schema`]]: {
350
+ [P in keyof TContext[`schema`][K]]: TContext[`schema`][K][P]
351
+ }
352
+ }[keyof TContext[`schema`]]
353
+
354
+ /**
355
+ * Infers the result type for all columns from a specific table
356
+ */
357
+ type InferTableColumnsType<
358
+ TContext extends Context<Schema>,
359
+ TTable extends keyof TContext[`schema`],
360
+ > = {
361
+ [P in keyof TContext[`schema`][TTable]]: TContext[`schema`][TTable][P]
362
+ }
363
+
364
+ /**
365
+ * Infers the result type for a function call
366
+ */
367
+ type InferFunctionCallResultType<
368
+ TContext extends Context<Schema>,
369
+ TFunctionCall extends FunctionCall<TContext>,
370
+ > = TFunctionCall extends { SUM: any }
371
+ ? number
372
+ : TFunctionCall extends { COUNT: any }
373
+ ? number
374
+ : TFunctionCall extends { AVG: any }
375
+ ? number
376
+ : TFunctionCall extends { MIN: any }
377
+ ? InferOperandType<TContext, TFunctionCall[`MIN`]>
378
+ : TFunctionCall extends { MAX: any }
379
+ ? InferOperandType<TContext, TFunctionCall[`MAX`]>
380
+ : TFunctionCall extends { DATE: any }
381
+ ? string
382
+ : TFunctionCall extends { JSON_EXTRACT: any }
383
+ ? unknown
384
+ : TFunctionCall extends { JSON_EXTRACT_PATH: any }
385
+ ? unknown
386
+ : TFunctionCall extends { UPPER: any }
387
+ ? string
388
+ : TFunctionCall extends { LOWER: any }
389
+ ? string
390
+ : TFunctionCall extends { COALESCE: any }
391
+ ? InferOperandType<TContext, TFunctionCall[`COALESCE`]>
392
+ : TFunctionCall extends { CONCAT: any }
393
+ ? string
394
+ : TFunctionCall extends { LENGTH: any }
395
+ ? number
396
+ : TFunctionCall extends { ORDER_INDEX: any }
397
+ ? number
398
+ : unknown
399
+
400
+ /**
401
+ * Infers the type of an operand
402
+ */
403
+ type InferOperandType<
404
+ TContext extends Context<Schema>,
405
+ TOperand extends ConditionOperand<TContext>,
406
+ > =
407
+ TOperand extends PropertyReference<TContext>
408
+ ? TypeFromPropertyReference<TContext, TOperand>
409
+ : TOperand extends LiteralValue
410
+ ? TOperand
411
+ : TOperand extends ExplicitLiteral
412
+ ? TOperand[`value`]
413
+ : TOperand extends FunctionCall<TContext>
414
+ ? InferFunctionCallResultType<TContext, TOperand>
415
+ : TOperand extends Array<ConditionOperand<TContext>>
416
+ ? InferOperandType<TContext, TOperand[number]>
417
+ : unknown
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Helper function to determine if an object is a function call with an aggregate function
3
+ */
4
+ export function isAggregateFunctionCall(obj: any): boolean {
5
+ if (!obj || typeof obj !== `object`) return false
6
+
7
+ const aggregateFunctions = [
8
+ `SUM`,
9
+ `COUNT`,
10
+ `AVG`,
11
+ `MIN`,
12
+ `MAX`,
13
+ `MEDIAN`,
14
+ `MODE`,
15
+ ]
16
+ const keys = Object.keys(obj)
17
+
18
+ return keys.length === 1 && aggregateFunctions.includes(keys[0]!)
19
+ }
20
+
21
+ /**
22
+ * Helper function to determine if an object is an ORDER_INDEX function call
23
+ */
24
+ export function isOrderIndexFunctionCall(obj: any): boolean {
25
+ if (!obj || typeof obj !== `object`) return false
26
+
27
+ const keys = Object.keys(obj)
28
+ return keys.length === 1 && keys[0] === `ORDER_INDEX`
29
+ }
30
+
31
+ /**
32
+ * Type guard to check if a value is comparable (can be used with <, >, <=, >= operators)
33
+ * @param value The value to check
34
+ * @returns True if the value is comparable
35
+ */
36
+ export function isComparable(
37
+ value: unknown
38
+ ): value is number | string | Date | boolean {
39
+ return (
40
+ typeof value === `number` ||
41
+ typeof value === `string` ||
42
+ typeof value === `boolean` ||
43
+ value instanceof Date
44
+ )
45
+ }
46
+
47
+ /**
48
+ * Performs a comparison between two values, ensuring they are of compatible types
49
+ * @param left The left operand
50
+ * @param right The right operand
51
+ * @param operator The comparison operator
52
+ * @returns The result of the comparison
53
+ * @throws Error if the values are not comparable
54
+ */
55
+ export function compareValues(
56
+ left: unknown,
57
+ right: unknown,
58
+ operator: `<` | `<=` | `>` | `>=`
59
+ ): boolean {
60
+ // First check if both values are comparable
61
+ if (!isComparable(left) || !isComparable(right)) {
62
+ throw new Error(
63
+ `Cannot compare non-comparable values: ${typeof left} and ${typeof right}`
64
+ )
65
+ }
66
+
67
+ // If they're different types but both are strings or numbers, convert to strings
68
+ if (
69
+ typeof left !== typeof right &&
70
+ (typeof left === `string` || typeof left === `number`) &&
71
+ (typeof right === `string` || typeof right === `number`)
72
+ ) {
73
+ // Convert to strings for comparison (follows JavaScript's coercion rules)
74
+ const leftStr = String(left)
75
+ const rightStr = String(right)
76
+
77
+ switch (operator) {
78
+ case `<`:
79
+ return leftStr < rightStr
80
+ case `<=`:
81
+ return leftStr <= rightStr
82
+ case `>`:
83
+ return leftStr > rightStr
84
+ case `>=`:
85
+ return leftStr >= rightStr
86
+ }
87
+ }
88
+
89
+ // For Date objects, convert to timestamps
90
+ if (left instanceof Date && right instanceof Date) {
91
+ const leftTime = left.getTime()
92
+ const rightTime = right.getTime()
93
+
94
+ switch (operator) {
95
+ case `<`:
96
+ return leftTime < rightTime
97
+ case `<=`:
98
+ return leftTime <= rightTime
99
+ case `>`:
100
+ return leftTime > rightTime
101
+ case `>=`:
102
+ return leftTime >= rightTime
103
+ }
104
+ }
105
+
106
+ // For other cases where types match
107
+ if (typeof left === typeof right) {
108
+ switch (operator) {
109
+ case `<`:
110
+ return left < right
111
+ case `<=`:
112
+ return left <= right
113
+ case `>`:
114
+ return left > right
115
+ case `>=`:
116
+ return left >= right
117
+ }
118
+ }
119
+
120
+ // If we get here, it means the values are technically comparable but not compatible
121
+ throw new Error(
122
+ `Cannot compare incompatible types: ${typeof left} and ${typeof right}`
123
+ )
124
+ }
125
+
126
+ /**
127
+ * Converts a SQL LIKE pattern to a JavaScript regex pattern
128
+ * @param pattern The SQL LIKE pattern to convert
129
+ * @returns A regex-compatible pattern string
130
+ */
131
+ export function convertLikeToRegex(pattern: string): string {
132
+ let finalPattern = ``
133
+ let i = 0
134
+
135
+ while (i < pattern.length) {
136
+ const char = pattern[i]
137
+
138
+ // Handle escape character
139
+ if (char === `\\` && i + 1 < pattern.length) {
140
+ // Add the next character as a literal (escaped)
141
+ finalPattern += pattern[i + 1]
142
+ i += 2 // Skip both the escape and the escaped character
143
+ continue
144
+ }
145
+
146
+ // Handle SQL LIKE special characters
147
+ switch (char) {
148
+ case `%`:
149
+ // % matches any sequence of characters (including empty)
150
+ finalPattern += `.*`
151
+ break
152
+ case `_`:
153
+ // _ matches any single character
154
+ finalPattern += `.`
155
+ break
156
+ // Handle regex special characters
157
+ case `.`:
158
+ case `^`:
159
+ case `$`:
160
+ case `*`:
161
+ case `+`:
162
+ case `?`:
163
+ case `(`:
164
+ case `)`:
165
+ case `[`:
166
+ case `]`:
167
+ case `{`:
168
+ case `}`:
169
+ case `|`:
170
+ case `/`:
171
+ // Escape regex special characters
172
+ finalPattern += `\\` + char
173
+ break
174
+ default:
175
+ // Regular character, just add it
176
+ finalPattern += char
177
+ }
178
+
179
+ i++
180
+ }
181
+
182
+ return finalPattern
183
+ }
184
+
185
+ /**
186
+ * Helper function to check if a value is in an array, with special handling for various types
187
+ * @param value The value to check for
188
+ * @param array The array to search in
189
+ * @param caseInsensitive Optional flag to enable case-insensitive matching for strings (default: false)
190
+ * @returns True if the value is found in the array
191
+ */
192
+ export function isValueInArray(
193
+ value: unknown,
194
+ array: Array<unknown>,
195
+ caseInsensitive: boolean = false
196
+ ): boolean {
197
+ // Direct inclusion check first (fastest path)
198
+ if (array.includes(value)) {
199
+ return true
200
+ }
201
+
202
+ // Handle null/undefined
203
+ if (value === null || value === undefined) {
204
+ return array.some((item) => item === null || item === undefined)
205
+ }
206
+
207
+ // Handle numbers and strings with type coercion
208
+ if (typeof value === `number` || typeof value === `string`) {
209
+ return array.some((item) => {
210
+ // Same type, direct comparison
211
+ if (typeof item === typeof value) {
212
+ if (typeof value === `string` && caseInsensitive) {
213
+ // Case-insensitive comparison for strings (only if explicitly enabled)
214
+ return value.toLowerCase() === (item as string).toLowerCase()
215
+ }
216
+ return item === value
217
+ }
218
+
219
+ // Different types, try coercion for number/string
220
+ if (
221
+ (typeof item === `number` || typeof item === `string`) &&
222
+ (typeof value === `number` || typeof value === `string`)
223
+ ) {
224
+ // Convert both to strings for comparison
225
+ return String(item) === String(value)
226
+ }
227
+
228
+ return false
229
+ })
230
+ }
231
+
232
+ // Handle objects/arrays by comparing stringified versions
233
+ if (typeof value === `object`) {
234
+ const valueStr = JSON.stringify(value)
235
+ return array.some((item) => {
236
+ if (typeof item === `object` && item !== null) {
237
+ return JSON.stringify(item) === valueStr
238
+ }
239
+ return false
240
+ })
241
+ }
242
+
243
+ // Fallback
244
+ return false
245
+ }