@tanstack/db 0.0.14 → 0.0.16

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 (197) 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 +31 -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 +92 -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 +81 -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 +5 -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 +30 -12
  51. package/dist/esm/query/builder/functions.d.ts +38 -0
  52. package/dist/esm/query/builder/functions.js +107 -0
  53. package/dist/esm/query/builder/functions.js.map +1 -0
  54. package/dist/esm/query/builder/index.d.ts +324 -0
  55. package/dist/esm/query/builder/index.js +499 -0
  56. package/dist/esm/query/builder/index.js.map +1 -0
  57. package/dist/esm/query/builder/ref-proxy.d.ts +28 -0
  58. package/dist/esm/query/builder/ref-proxy.js +92 -0
  59. package/dist/esm/query/builder/ref-proxy.js.map +1 -0
  60. package/dist/esm/query/builder/types.d.ts +81 -0
  61. package/dist/esm/query/compiler/evaluators.d.ts +11 -0
  62. package/dist/esm/query/compiler/evaluators.js +261 -0
  63. package/dist/esm/query/compiler/evaluators.js.map +1 -0
  64. package/dist/esm/query/compiler/group-by.d.ts +7 -0
  65. package/dist/esm/query/compiler/group-by.js +271 -0
  66. package/dist/esm/query/compiler/group-by.js.map +1 -0
  67. package/dist/esm/query/compiler/index.d.ts +15 -0
  68. package/dist/esm/query/compiler/index.js +181 -0
  69. package/dist/esm/query/compiler/index.js.map +1 -0
  70. package/dist/esm/query/compiler/joins.d.ts +11 -0
  71. package/dist/esm/query/compiler/joins.js +116 -0
  72. package/dist/esm/query/compiler/joins.js.map +1 -0
  73. package/dist/esm/query/compiler/order-by.d.ts +9 -0
  74. package/dist/esm/query/compiler/order-by.js +89 -0
  75. package/dist/esm/query/compiler/order-by.js.map +1 -0
  76. package/dist/esm/query/compiler/select.d.ts +15 -0
  77. package/dist/esm/query/compiler/select.js +57 -0
  78. package/dist/esm/query/compiler/select.js.map +1 -0
  79. package/dist/esm/query/index.d.ts +5 -5
  80. package/dist/esm/query/ir.d.ts +81 -0
  81. package/dist/esm/query/ir.js +57 -0
  82. package/dist/esm/query/ir.js.map +1 -0
  83. package/dist/esm/query/live-query-collection.d.ts +124 -0
  84. package/dist/esm/query/live-query-collection.js +224 -0
  85. package/dist/esm/query/live-query-collection.js.map +1 -0
  86. package/dist/esm/transactions.d.ts +10 -1
  87. package/dist/esm/transactions.js +20 -13
  88. package/dist/esm/transactions.js.map +1 -1
  89. package/dist/esm/types.d.ts +13 -0
  90. package/package.json +3 -4
  91. package/src/collection.ts +152 -129
  92. package/src/index.ts +0 -1
  93. package/src/query/builder/functions.ts +267 -0
  94. package/src/query/builder/index.ts +648 -0
  95. package/src/query/builder/ref-proxy.ts +156 -0
  96. package/src/query/builder/types.ts +282 -0
  97. package/src/query/compiler/evaluators.ts +315 -0
  98. package/src/query/compiler/group-by.ts +428 -0
  99. package/src/query/compiler/index.ts +276 -0
  100. package/src/query/compiler/joins.ts +228 -0
  101. package/src/query/compiler/order-by.ts +139 -0
  102. package/src/query/compiler/select.ts +173 -0
  103. package/src/query/index.ts +54 -5
  104. package/src/query/ir.ts +128 -0
  105. package/src/query/live-query-collection.ts +512 -0
  106. package/src/transactions.ts +27 -16
  107. package/src/types.ts +15 -0
  108. package/dist/cjs/query/compiled-query.cjs +0 -160
  109. package/dist/cjs/query/compiled-query.cjs.map +0 -1
  110. package/dist/cjs/query/compiled-query.d.cts +0 -20
  111. package/dist/cjs/query/evaluators.cjs +0 -161
  112. package/dist/cjs/query/evaluators.cjs.map +0 -1
  113. package/dist/cjs/query/evaluators.d.cts +0 -14
  114. package/dist/cjs/query/extractors.cjs +0 -122
  115. package/dist/cjs/query/extractors.cjs.map +0 -1
  116. package/dist/cjs/query/extractors.d.cts +0 -22
  117. package/dist/cjs/query/functions.cjs +0 -152
  118. package/dist/cjs/query/functions.cjs.map +0 -1
  119. package/dist/cjs/query/functions.d.cts +0 -21
  120. package/dist/cjs/query/group-by.cjs +0 -88
  121. package/dist/cjs/query/group-by.cjs.map +0 -1
  122. package/dist/cjs/query/group-by.d.cts +0 -40
  123. package/dist/cjs/query/joins.cjs +0 -141
  124. package/dist/cjs/query/joins.cjs.map +0 -1
  125. package/dist/cjs/query/joins.d.cts +0 -14
  126. package/dist/cjs/query/order-by.cjs +0 -185
  127. package/dist/cjs/query/order-by.cjs.map +0 -1
  128. package/dist/cjs/query/order-by.d.cts +0 -3
  129. package/dist/cjs/query/pipeline-compiler.cjs +0 -89
  130. package/dist/cjs/query/pipeline-compiler.cjs.map +0 -1
  131. package/dist/cjs/query/pipeline-compiler.d.cts +0 -10
  132. package/dist/cjs/query/query-builder.cjs +0 -307
  133. package/dist/cjs/query/query-builder.cjs.map +0 -1
  134. package/dist/cjs/query/query-builder.d.cts +0 -225
  135. package/dist/cjs/query/schema.d.cts +0 -100
  136. package/dist/cjs/query/select.cjs +0 -130
  137. package/dist/cjs/query/select.cjs.map +0 -1
  138. package/dist/cjs/query/select.d.cts +0 -3
  139. package/dist/cjs/query/types.d.cts +0 -189
  140. package/dist/cjs/query/utils.cjs +0 -154
  141. package/dist/cjs/query/utils.cjs.map +0 -1
  142. package/dist/cjs/query/utils.d.cts +0 -37
  143. package/dist/cjs/utils.cjs +0 -17
  144. package/dist/cjs/utils.cjs.map +0 -1
  145. package/dist/cjs/utils.d.cts +0 -3
  146. package/dist/esm/query/compiled-query.d.ts +0 -20
  147. package/dist/esm/query/compiled-query.js +0 -160
  148. package/dist/esm/query/compiled-query.js.map +0 -1
  149. package/dist/esm/query/evaluators.d.ts +0 -14
  150. package/dist/esm/query/evaluators.js +0 -161
  151. package/dist/esm/query/evaluators.js.map +0 -1
  152. package/dist/esm/query/extractors.d.ts +0 -22
  153. package/dist/esm/query/extractors.js +0 -122
  154. package/dist/esm/query/extractors.js.map +0 -1
  155. package/dist/esm/query/functions.d.ts +0 -21
  156. package/dist/esm/query/functions.js +0 -152
  157. package/dist/esm/query/functions.js.map +0 -1
  158. package/dist/esm/query/group-by.d.ts +0 -40
  159. package/dist/esm/query/group-by.js +0 -88
  160. package/dist/esm/query/group-by.js.map +0 -1
  161. package/dist/esm/query/joins.d.ts +0 -14
  162. package/dist/esm/query/joins.js +0 -141
  163. package/dist/esm/query/joins.js.map +0 -1
  164. package/dist/esm/query/order-by.d.ts +0 -3
  165. package/dist/esm/query/order-by.js +0 -185
  166. package/dist/esm/query/order-by.js.map +0 -1
  167. package/dist/esm/query/pipeline-compiler.d.ts +0 -10
  168. package/dist/esm/query/pipeline-compiler.js +0 -89
  169. package/dist/esm/query/pipeline-compiler.js.map +0 -1
  170. package/dist/esm/query/query-builder.d.ts +0 -225
  171. package/dist/esm/query/query-builder.js +0 -307
  172. package/dist/esm/query/query-builder.js.map +0 -1
  173. package/dist/esm/query/schema.d.ts +0 -100
  174. package/dist/esm/query/select.d.ts +0 -3
  175. package/dist/esm/query/select.js +0 -130
  176. package/dist/esm/query/select.js.map +0 -1
  177. package/dist/esm/query/types.d.ts +0 -189
  178. package/dist/esm/query/utils.d.ts +0 -37
  179. package/dist/esm/query/utils.js +0 -154
  180. package/dist/esm/query/utils.js.map +0 -1
  181. package/dist/esm/utils.d.ts +0 -3
  182. package/dist/esm/utils.js +0 -17
  183. package/dist/esm/utils.js.map +0 -1
  184. package/src/query/compiled-query.ts +0 -234
  185. package/src/query/evaluators.ts +0 -250
  186. package/src/query/extractors.ts +0 -214
  187. package/src/query/functions.ts +0 -297
  188. package/src/query/group-by.ts +0 -139
  189. package/src/query/joins.ts +0 -260
  190. package/src/query/order-by.ts +0 -264
  191. package/src/query/pipeline-compiler.ts +0 -149
  192. package/src/query/query-builder.ts +0 -902
  193. package/src/query/schema.ts +0 -268
  194. package/src/query/select.ts +0 -208
  195. package/src/query/types.ts +0 -418
  196. package/src/query/utils.ts +0 -245
  197. package/src/utils.ts +0 -15
@@ -1,3 +0,0 @@
1
- export declare function getLockedObjects(): Set<string>;
2
- export declare function getGlobalVersion(): number;
3
- export declare function advanceGlobalVersion(): number;
package/dist/esm/utils.js DELETED
@@ -1,17 +0,0 @@
1
- function getLockedObjects() {
2
- return /* @__PURE__ */ new Set();
3
- }
4
- let globalVersion = 0;
5
- function getGlobalVersion() {
6
- return globalVersion;
7
- }
8
- function advanceGlobalVersion() {
9
- console.log(`==== advancing global version`, globalVersion + 1);
10
- return globalVersion++;
11
- }
12
- export {
13
- advanceGlobalVersion,
14
- getGlobalVersion,
15
- getLockedObjects
16
- };
17
- //# sourceMappingURL=utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["export function getLockedObjects(): Set<string> {\n // Stub implementation that returns an empty Set\n return new Set()\n}\n\nlet globalVersion = 0\n\nexport function getGlobalVersion(): number {\n return globalVersion\n}\n\nexport function advanceGlobalVersion(): number {\n console.log(`==== advancing global version`, globalVersion + 1)\n return globalVersion++\n}\n"],"names":[],"mappings":"AAAO,SAAS,mBAAgC;AAE9C,6BAAW,IAAI;AACjB;AAEA,IAAI,gBAAgB;AAEb,SAAS,mBAA2B;AAClC,SAAA;AACT;AAEO,SAAS,uBAA+B;AACrC,UAAA,IAAI,iCAAiC,gBAAgB,CAAC;AACvD,SAAA;AACT;"}
@@ -1,234 +0,0 @@
1
- import { D2, MultiSet, output } from "@electric-sql/d2mini"
2
- import { createCollection } from "../collection.js"
3
- import { compileQueryPipeline } from "./pipeline-compiler.js"
4
- import type { StandardSchemaV1 } from "@standard-schema/spec"
5
- import type { Collection } from "../collection.js"
6
- import type { ChangeMessage, ResolveType, SyncConfig } from "../types.js"
7
- import type {
8
- IStreamBuilder,
9
- MultiSetArray,
10
- RootStreamBuilder,
11
- } from "@electric-sql/d2mini"
12
- import type { QueryBuilder, ResultsFromContext } from "./query-builder.js"
13
- import type { Context, Schema } from "./types.js"
14
-
15
- export function compileQuery<TContext extends Context<Schema>>(
16
- queryBuilder: QueryBuilder<TContext>
17
- ) {
18
- return new CompiledQuery<
19
- ResultsFromContext<TContext> & { _key?: string | number }
20
- >(queryBuilder)
21
- }
22
-
23
- export class CompiledQuery<TResults extends object = Record<string, unknown>> {
24
- private graph: D2
25
- private inputs: Record<string, RootStreamBuilder<any>>
26
- private inputCollections: Record<string, Collection<any>>
27
- private resultCollection: Collection<TResults>
28
- public state: `compiled` | `running` | `stopped` = `compiled`
29
- private unsubscribeCallbacks: Array<() => void> = []
30
-
31
- constructor(queryBuilder: QueryBuilder<Context<Schema>>) {
32
- const query = queryBuilder._query
33
- const collections = query.collections
34
-
35
- if (!collections) {
36
- throw new Error(`No collections provided`)
37
- }
38
-
39
- this.inputCollections = collections
40
-
41
- const graph = new D2()
42
- const inputs = Object.fromEntries(
43
- Object.entries(collections).map(([key]) => [key, graph.newInput<any>()])
44
- )
45
-
46
- // Use TResults directly to ensure type compatibility
47
- const sync: SyncConfig<TResults>[`sync`] = ({
48
- begin,
49
- write,
50
- commit,
51
- collection,
52
- }) => {
53
- compileQueryPipeline<IStreamBuilder<[unknown, TResults]>>(
54
- query,
55
- inputs
56
- ).pipe(
57
- output((data) => {
58
- begin()
59
- data
60
- .getInner()
61
- .reduce((acc, [[key, value], multiplicity]) => {
62
- const changes = acc.get(key) || {
63
- deletes: 0,
64
- inserts: 0,
65
- value,
66
- }
67
- if (multiplicity < 0) {
68
- changes.deletes += Math.abs(multiplicity)
69
- } else if (multiplicity > 0) {
70
- changes.inserts += multiplicity
71
- changes.value = value
72
- }
73
- acc.set(key, changes)
74
- return acc
75
- }, new Map<unknown, { deletes: number; inserts: number; value: TResults }>())
76
- .forEach((changes, rawKey) => {
77
- const { deletes, inserts, value } = changes
78
- const valueWithKey = { ...value, _key: rawKey }
79
-
80
- // Simple singular insert.
81
- if (inserts && deletes === 0) {
82
- write({
83
- value: valueWithKey,
84
- type: `insert`,
85
- })
86
- } else if (
87
- // Insert & update(s) (updates are a delete & insert)
88
- inserts > deletes ||
89
- // Just update(s) but the item is already in the collection (so
90
- // was inserted previously).
91
- (inserts === deletes &&
92
- collection.has(valueWithKey._key as string | number))
93
- ) {
94
- write({
95
- value: valueWithKey,
96
- type: `update`,
97
- })
98
- // Only delete is left as an option
99
- } else if (deletes > 0) {
100
- write({
101
- value: valueWithKey,
102
- type: `delete`,
103
- })
104
- } else {
105
- throw new Error(
106
- `This should never happen ${JSON.stringify(changes)}`
107
- )
108
- }
109
- })
110
- commit()
111
- })
112
- )
113
- graph.finalize()
114
- }
115
-
116
- this.graph = graph
117
- this.inputs = inputs
118
-
119
- const compare = query.orderBy
120
- ? (
121
- val1: ResolveType<
122
- TResults,
123
- StandardSchemaV1,
124
- Record<string, unknown>
125
- >,
126
- val2: ResolveType<TResults, StandardSchemaV1, Record<string, unknown>>
127
- ): number => {
128
- // The query builder always adds an _orderByIndex property if the results are ordered
129
- const x = val1 as TResults & { _orderByIndex: number }
130
- const y = val2 as TResults & { _orderByIndex: number }
131
- if (x._orderByIndex < y._orderByIndex) {
132
- return -1
133
- } else if (x._orderByIndex > y._orderByIndex) {
134
- return 1
135
- } else {
136
- return 0
137
- }
138
- }
139
- : undefined
140
-
141
- this.resultCollection = createCollection<TResults>({
142
- getKey: (val: unknown) => {
143
- return (val as any)._key
144
- },
145
- gcTime: 0,
146
- startSync: true,
147
- compare,
148
- sync: {
149
- sync: sync as unknown as (params: {
150
- collection: Collection<
151
- ResolveType<TResults, never, Record<string, unknown>>,
152
- string | number,
153
- {}
154
- >
155
- begin: () => void
156
- write: (
157
- message: Omit<
158
- ChangeMessage<
159
- ResolveType<TResults, never, Record<string, unknown>>,
160
- string | number
161
- >,
162
- `key`
163
- >
164
- ) => void
165
- commit: () => void
166
- }) => void,
167
- },
168
- }) as unknown as Collection<TResults, string | number, {}>
169
- }
170
-
171
- get results() {
172
- return this.resultCollection
173
- }
174
-
175
- private sendChangesToInput(
176
- inputKey: string,
177
- changes: Array<ChangeMessage>,
178
- getKey: (item: ChangeMessage[`value`]) => any
179
- ) {
180
- const input = this.inputs[inputKey]!
181
- const multiSetArray: MultiSetArray<unknown> = []
182
- for (const change of changes) {
183
- const key = getKey(change.value)
184
- if (change.type === `insert`) {
185
- multiSetArray.push([[key, change.value], 1])
186
- } else if (change.type === `update`) {
187
- multiSetArray.push([[key, change.previousValue], -1])
188
- multiSetArray.push([[key, change.value], 1])
189
- } else {
190
- // change.type === `delete`
191
- multiSetArray.push([[key, change.value], -1])
192
- }
193
- }
194
- input.sendData(new MultiSet(multiSetArray))
195
- }
196
-
197
- private runGraph() {
198
- this.graph.run()
199
- }
200
-
201
- start() {
202
- if (this.state === `running`) {
203
- throw new Error(`Query is already running`)
204
- } else if (this.state === `stopped`) {
205
- throw new Error(`Query is stopped`)
206
- }
207
-
208
- // Subscribe to changes
209
- Object.entries(this.inputCollections).forEach(([key, collection]) => {
210
- const unsubscribe = collection.subscribeChanges(
211
- (changes) => {
212
- this.sendChangesToInput(key, changes, collection.config.getKey)
213
- this.runGraph()
214
- },
215
- { includeInitialState: true }
216
- )
217
-
218
- this.unsubscribeCallbacks.push(unsubscribe)
219
- })
220
-
221
- this.runGraph()
222
-
223
- this.state = `running`
224
- return () => {
225
- this.stop()
226
- }
227
- }
228
-
229
- stop() {
230
- this.unsubscribeCallbacks.forEach((unsubscribe) => unsubscribe())
231
- this.unsubscribeCallbacks = []
232
- this.state = `stopped`
233
- }
234
- }
@@ -1,250 +0,0 @@
1
- import { evaluateOperandOnNamespacedRow } from "./extractors.js"
2
- import { compareValues, convertLikeToRegex, isValueInArray } from "./utils.js"
3
- import type {
4
- Comparator,
5
- Condition,
6
- ConditionOperand,
7
- LogicalOperator,
8
- SimpleCondition,
9
- Where,
10
- WhereCallback,
11
- } from "./schema.js"
12
- import type { NamespacedRow } from "../types.js"
13
-
14
- /**
15
- * Evaluates a Where clause (which is always an array of conditions and/or callbacks) against a nested row structure
16
- */
17
- export function evaluateWhereOnNamespacedRow(
18
- namespacedRow: NamespacedRow,
19
- where: Where,
20
- mainTableAlias?: string,
21
- joinedTableAlias?: string
22
- ): boolean {
23
- // Where is always an array of conditions and/or callbacks
24
- // Evaluate all items and combine with AND logic
25
- return where.every((item) => {
26
- if (typeof item === `function`) {
27
- return (item as WhereCallback)(namespacedRow)
28
- } else {
29
- return evaluateConditionOnNamespacedRow(
30
- namespacedRow,
31
- item as Condition,
32
- mainTableAlias,
33
- joinedTableAlias
34
- )
35
- }
36
- })
37
- }
38
-
39
- /**
40
- * Evaluates a condition against a nested row structure
41
- */
42
- export function evaluateConditionOnNamespacedRow(
43
- namespacedRow: NamespacedRow,
44
- condition: Condition,
45
- mainTableAlias?: string,
46
- joinedTableAlias?: string
47
- ): boolean {
48
- // Handle simple conditions with exactly 3 elements
49
- if (condition.length === 3 && !Array.isArray(condition[0])) {
50
- const [left, comparator, right] = condition as SimpleCondition
51
- return evaluateSimpleConditionOnNamespacedRow(
52
- namespacedRow,
53
- left,
54
- comparator,
55
- right,
56
- mainTableAlias,
57
- joinedTableAlias
58
- )
59
- }
60
-
61
- // Handle flat composite conditions (multiple conditions in a single array)
62
- if (
63
- condition.length > 3 &&
64
- !Array.isArray(condition[0]) &&
65
- typeof condition[1] === `string` &&
66
- ![`and`, `or`].includes(condition[1] as string)
67
- ) {
68
- // Start with the first condition (first 3 elements)
69
- let result = evaluateSimpleConditionOnNamespacedRow(
70
- namespacedRow,
71
- condition[0],
72
- condition[1] as Comparator,
73
- condition[2],
74
- mainTableAlias,
75
- joinedTableAlias
76
- )
77
-
78
- // Process the rest in groups: logical operator, then 3 elements for each condition
79
- for (let i = 3; i < condition.length; i += 4) {
80
- const logicalOp = condition[i] as LogicalOperator
81
-
82
- // Make sure we have a complete condition to evaluate
83
- if (i + 3 <= condition.length) {
84
- const nextResult = evaluateSimpleConditionOnNamespacedRow(
85
- namespacedRow,
86
- condition[i + 1],
87
- condition[i + 2] as Comparator,
88
- condition[i + 3],
89
- mainTableAlias,
90
- joinedTableAlias
91
- )
92
-
93
- // Apply the logical operator
94
- if (logicalOp === `and`) {
95
- result = result && nextResult
96
- } else {
97
- // logicalOp === `or`
98
- result = result || nextResult
99
- }
100
- }
101
- }
102
-
103
- return result
104
- }
105
-
106
- // Handle nested composite conditions where the first element is an array
107
- if (condition.length > 0 && Array.isArray(condition[0])) {
108
- // Start with the first condition
109
- let result = evaluateConditionOnNamespacedRow(
110
- namespacedRow,
111
- condition[0] as Condition,
112
- mainTableAlias,
113
- joinedTableAlias
114
- )
115
-
116
- // Process the rest of the conditions and logical operators in pairs
117
- for (let i = 1; i < condition.length; i += 2) {
118
- if (i + 1 >= condition.length) break // Make sure we have a pair
119
-
120
- const operator = condition[i] as LogicalOperator
121
- const nextCondition = condition[i + 1] as Condition
122
-
123
- // Apply the logical operator
124
- if (operator === `and`) {
125
- result =
126
- result &&
127
- evaluateConditionOnNamespacedRow(
128
- namespacedRow,
129
- nextCondition,
130
- mainTableAlias,
131
- joinedTableAlias
132
- )
133
- } else {
134
- // logicalOp === `or`
135
- result =
136
- result ||
137
- evaluateConditionOnNamespacedRow(
138
- namespacedRow,
139
- nextCondition,
140
- mainTableAlias,
141
- joinedTableAlias
142
- )
143
- }
144
- }
145
-
146
- return result
147
- }
148
-
149
- // Fallback - this should not happen with valid conditions
150
- return true
151
- }
152
-
153
- /**
154
- * Evaluates a simple condition against a nested row structure
155
- */
156
- export function evaluateSimpleConditionOnNamespacedRow(
157
- namespacedRow: Record<string, unknown>,
158
- left: ConditionOperand,
159
- comparator: Comparator,
160
- right: ConditionOperand,
161
- mainTableAlias?: string,
162
- joinedTableAlias?: string
163
- ): boolean {
164
- const leftValue = evaluateOperandOnNamespacedRow(
165
- namespacedRow,
166
- left,
167
- mainTableAlias,
168
- joinedTableAlias
169
- )
170
-
171
- const rightValue = evaluateOperandOnNamespacedRow(
172
- namespacedRow,
173
- right,
174
- mainTableAlias,
175
- joinedTableAlias
176
- )
177
-
178
- // The rest of the function remains the same as evaluateSimpleCondition
179
- switch (comparator) {
180
- case `=`:
181
- return leftValue === rightValue
182
- case `!=`:
183
- return leftValue !== rightValue
184
- case `<`:
185
- return compareValues(leftValue, rightValue, `<`)
186
- case `<=`:
187
- return compareValues(leftValue, rightValue, `<=`)
188
- case `>`:
189
- return compareValues(leftValue, rightValue, `>`)
190
- case `>=`:
191
- return compareValues(leftValue, rightValue, `>=`)
192
- case `like`:
193
- case `not like`:
194
- if (typeof leftValue === `string` && typeof rightValue === `string`) {
195
- // Convert SQL LIKE pattern to proper regex pattern
196
- const pattern = convertLikeToRegex(rightValue)
197
- const matches = new RegExp(`^${pattern}$`, `i`).test(leftValue)
198
- return comparator === `like` ? matches : !matches
199
- }
200
- return comparator === `like` ? false : true
201
- case `in`:
202
- // If right value is not an array, we can't do an IN operation
203
- if (!Array.isArray(rightValue)) {
204
- return false
205
- }
206
-
207
- // For empty arrays, nothing is contained in them
208
- if (rightValue.length === 0) {
209
- return false
210
- }
211
-
212
- // Handle array-to-array comparison (check if any element in leftValue exists in rightValue)
213
- if (Array.isArray(leftValue)) {
214
- return leftValue.some((item) => isValueInArray(item, rightValue))
215
- }
216
-
217
- // Handle single value comparison
218
- return isValueInArray(leftValue, rightValue)
219
-
220
- case `not in`:
221
- // If right value is not an array, everything is "not in" it
222
- if (!Array.isArray(rightValue)) {
223
- return true
224
- }
225
-
226
- // For empty arrays, everything is "not in" them
227
- if (rightValue.length === 0) {
228
- return true
229
- }
230
-
231
- // Handle array-to-array comparison (check if no element in leftValue exists in rightValue)
232
- if (Array.isArray(leftValue)) {
233
- return !leftValue.some((item) => isValueInArray(item, rightValue))
234
- }
235
-
236
- // Handle single value comparison
237
- return !isValueInArray(leftValue, rightValue)
238
-
239
- case `is`:
240
- return leftValue === rightValue
241
- case `is not`:
242
- // Properly handle null/undefined checks
243
- if (rightValue === null) {
244
- return leftValue !== null && leftValue !== undefined
245
- }
246
- return leftValue !== rightValue
247
- default:
248
- return false
249
- }
250
- }