@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.
- package/dist/cjs/collection.cjs +117 -104
- package/dist/cjs/collection.cjs.map +1 -1
- package/dist/cjs/collection.d.cts +18 -21
- package/dist/cjs/index.cjs +31 -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 +92 -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 +81 -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 +5 -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 +10 -1
- package/dist/cjs/types.d.cts +13 -0
- package/dist/esm/collection.d.ts +18 -21
- 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 +30 -12
- 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 +92 -0
- package/dist/esm/query/builder/ref-proxy.js.map +1 -0
- package/dist/esm/query/builder/types.d.ts +81 -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 +5 -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 +10 -1
- package/dist/esm/transactions.js +20 -13
- package/dist/esm/transactions.js.map +1 -1
- package/dist/esm/types.d.ts +13 -0
- 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 +282 -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 +54 -5
- package/src/query/ir.ts +128 -0
- package/src/query/live-query-collection.ts +512 -0
- package/src/transactions.ts +27 -16
- package/src/types.ts +15 -0
- 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,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
function compileExpression(expr) {
|
|
4
|
+
switch (expr.type) {
|
|
5
|
+
case `val`: {
|
|
6
|
+
const value = expr.value;
|
|
7
|
+
return () => value;
|
|
8
|
+
}
|
|
9
|
+
case `ref`: {
|
|
10
|
+
return compileRef(expr);
|
|
11
|
+
}
|
|
12
|
+
case `func`: {
|
|
13
|
+
return compileFunction(expr);
|
|
14
|
+
}
|
|
15
|
+
default:
|
|
16
|
+
throw new Error(`Unknown expression type: ${expr.type}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function compileRef(ref) {
|
|
20
|
+
const [tableAlias, ...propertyPath] = ref.path;
|
|
21
|
+
if (!tableAlias) {
|
|
22
|
+
throw new Error(`Reference path cannot be empty`);
|
|
23
|
+
}
|
|
24
|
+
if (propertyPath.length === 0) {
|
|
25
|
+
return (namespacedRow) => namespacedRow[tableAlias];
|
|
26
|
+
} else if (propertyPath.length === 1) {
|
|
27
|
+
const prop = propertyPath[0];
|
|
28
|
+
return (namespacedRow) => {
|
|
29
|
+
const tableData = namespacedRow[tableAlias];
|
|
30
|
+
return tableData == null ? void 0 : tableData[prop];
|
|
31
|
+
};
|
|
32
|
+
} else {
|
|
33
|
+
return (namespacedRow) => {
|
|
34
|
+
const tableData = namespacedRow[tableAlias];
|
|
35
|
+
if (tableData === void 0) {
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
let value = tableData;
|
|
39
|
+
for (const prop of propertyPath) {
|
|
40
|
+
if (value == null) {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
value = value[prop];
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function compileFunction(func) {
|
|
50
|
+
const compiledArgs = func.args.map(compileExpression);
|
|
51
|
+
switch (func.name) {
|
|
52
|
+
// Comparison operators
|
|
53
|
+
case `eq`: {
|
|
54
|
+
const argA = compiledArgs[0];
|
|
55
|
+
const argB = compiledArgs[1];
|
|
56
|
+
return (namespacedRow) => {
|
|
57
|
+
const a = argA(namespacedRow);
|
|
58
|
+
const b = argB(namespacedRow);
|
|
59
|
+
return a === b;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
case `gt`: {
|
|
63
|
+
const argA = compiledArgs[0];
|
|
64
|
+
const argB = compiledArgs[1];
|
|
65
|
+
return (namespacedRow) => {
|
|
66
|
+
const a = argA(namespacedRow);
|
|
67
|
+
const b = argB(namespacedRow);
|
|
68
|
+
return a > b;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
case `gte`: {
|
|
72
|
+
const argA = compiledArgs[0];
|
|
73
|
+
const argB = compiledArgs[1];
|
|
74
|
+
return (namespacedRow) => {
|
|
75
|
+
const a = argA(namespacedRow);
|
|
76
|
+
const b = argB(namespacedRow);
|
|
77
|
+
return a >= b;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
case `lt`: {
|
|
81
|
+
const argA = compiledArgs[0];
|
|
82
|
+
const argB = compiledArgs[1];
|
|
83
|
+
return (namespacedRow) => {
|
|
84
|
+
const a = argA(namespacedRow);
|
|
85
|
+
const b = argB(namespacedRow);
|
|
86
|
+
return a < b;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
case `lte`: {
|
|
90
|
+
const argA = compiledArgs[0];
|
|
91
|
+
const argB = compiledArgs[1];
|
|
92
|
+
return (namespacedRow) => {
|
|
93
|
+
const a = argA(namespacedRow);
|
|
94
|
+
const b = argB(namespacedRow);
|
|
95
|
+
return a <= b;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// Boolean operators
|
|
99
|
+
case `and`:
|
|
100
|
+
return (namespacedRow) => {
|
|
101
|
+
for (const compiledArg of compiledArgs) {
|
|
102
|
+
if (!compiledArg(namespacedRow)) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
};
|
|
108
|
+
case `or`:
|
|
109
|
+
return (namespacedRow) => {
|
|
110
|
+
for (const compiledArg of compiledArgs) {
|
|
111
|
+
if (compiledArg(namespacedRow)) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
};
|
|
117
|
+
case `not`: {
|
|
118
|
+
const arg = compiledArgs[0];
|
|
119
|
+
return (namespacedRow) => !arg(namespacedRow);
|
|
120
|
+
}
|
|
121
|
+
// Array operators
|
|
122
|
+
case `in`: {
|
|
123
|
+
const valueEvaluator = compiledArgs[0];
|
|
124
|
+
const arrayEvaluator = compiledArgs[1];
|
|
125
|
+
return (namespacedRow) => {
|
|
126
|
+
const value = valueEvaluator(namespacedRow);
|
|
127
|
+
const array = arrayEvaluator(namespacedRow);
|
|
128
|
+
if (!Array.isArray(array)) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
return array.includes(value);
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// String operators
|
|
135
|
+
case `like`: {
|
|
136
|
+
const valueEvaluator = compiledArgs[0];
|
|
137
|
+
const patternEvaluator = compiledArgs[1];
|
|
138
|
+
return (namespacedRow) => {
|
|
139
|
+
const value = valueEvaluator(namespacedRow);
|
|
140
|
+
const pattern = patternEvaluator(namespacedRow);
|
|
141
|
+
return evaluateLike(value, pattern, false);
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
case `ilike`: {
|
|
145
|
+
const valueEvaluator = compiledArgs[0];
|
|
146
|
+
const patternEvaluator = compiledArgs[1];
|
|
147
|
+
return (namespacedRow) => {
|
|
148
|
+
const value = valueEvaluator(namespacedRow);
|
|
149
|
+
const pattern = patternEvaluator(namespacedRow);
|
|
150
|
+
return evaluateLike(value, pattern, true);
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
// String functions
|
|
154
|
+
case `upper`: {
|
|
155
|
+
const arg = compiledArgs[0];
|
|
156
|
+
return (namespacedRow) => {
|
|
157
|
+
const value = arg(namespacedRow);
|
|
158
|
+
return typeof value === `string` ? value.toUpperCase() : value;
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
case `lower`: {
|
|
162
|
+
const arg = compiledArgs[0];
|
|
163
|
+
return (namespacedRow) => {
|
|
164
|
+
const value = arg(namespacedRow);
|
|
165
|
+
return typeof value === `string` ? value.toLowerCase() : value;
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
case `length`: {
|
|
169
|
+
const arg = compiledArgs[0];
|
|
170
|
+
return (namespacedRow) => {
|
|
171
|
+
const value = arg(namespacedRow);
|
|
172
|
+
if (typeof value === `string`) {
|
|
173
|
+
return value.length;
|
|
174
|
+
}
|
|
175
|
+
if (Array.isArray(value)) {
|
|
176
|
+
return value.length;
|
|
177
|
+
}
|
|
178
|
+
return 0;
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
case `concat`:
|
|
182
|
+
return (namespacedRow) => {
|
|
183
|
+
return compiledArgs.map((evaluator) => {
|
|
184
|
+
const arg = evaluator(namespacedRow);
|
|
185
|
+
try {
|
|
186
|
+
return String(arg ?? ``);
|
|
187
|
+
} catch {
|
|
188
|
+
try {
|
|
189
|
+
return JSON.stringify(arg) || ``;
|
|
190
|
+
} catch {
|
|
191
|
+
return `[object]`;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}).join(``);
|
|
195
|
+
};
|
|
196
|
+
case `coalesce`:
|
|
197
|
+
return (namespacedRow) => {
|
|
198
|
+
for (const evaluator of compiledArgs) {
|
|
199
|
+
const value = evaluator(namespacedRow);
|
|
200
|
+
if (value !== null && value !== void 0) {
|
|
201
|
+
return value;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
};
|
|
206
|
+
// Math functions
|
|
207
|
+
case `add`: {
|
|
208
|
+
const argA = compiledArgs[0];
|
|
209
|
+
const argB = compiledArgs[1];
|
|
210
|
+
return (namespacedRow) => {
|
|
211
|
+
const a = argA(namespacedRow);
|
|
212
|
+
const b = argB(namespacedRow);
|
|
213
|
+
return (a ?? 0) + (b ?? 0);
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
case `subtract`: {
|
|
217
|
+
const argA = compiledArgs[0];
|
|
218
|
+
const argB = compiledArgs[1];
|
|
219
|
+
return (namespacedRow) => {
|
|
220
|
+
const a = argA(namespacedRow);
|
|
221
|
+
const b = argB(namespacedRow);
|
|
222
|
+
return (a ?? 0) - (b ?? 0);
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
case `multiply`: {
|
|
226
|
+
const argA = compiledArgs[0];
|
|
227
|
+
const argB = compiledArgs[1];
|
|
228
|
+
return (namespacedRow) => {
|
|
229
|
+
const a = argA(namespacedRow);
|
|
230
|
+
const b = argB(namespacedRow);
|
|
231
|
+
return (a ?? 0) * (b ?? 0);
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
case `divide`: {
|
|
235
|
+
const argA = compiledArgs[0];
|
|
236
|
+
const argB = compiledArgs[1];
|
|
237
|
+
return (namespacedRow) => {
|
|
238
|
+
const a = argA(namespacedRow);
|
|
239
|
+
const b = argB(namespacedRow);
|
|
240
|
+
const divisor = b ?? 0;
|
|
241
|
+
return divisor !== 0 ? (a ?? 0) / divisor : null;
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
default:
|
|
245
|
+
throw new Error(`Unknown function: ${func.name}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function evaluateLike(value, pattern, caseInsensitive) {
|
|
249
|
+
if (typeof value !== `string` || typeof pattern !== `string`) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
const searchValue = caseInsensitive ? value.toLowerCase() : value;
|
|
253
|
+
const searchPattern = caseInsensitive ? pattern.toLowerCase() : pattern;
|
|
254
|
+
let regexPattern = searchPattern.replace(/[.*+?^${}()|[\]\\]/g, `\\$&`);
|
|
255
|
+
regexPattern = regexPattern.replace(/%/g, `.*`);
|
|
256
|
+
regexPattern = regexPattern.replace(/_/g, `.`);
|
|
257
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
258
|
+
return regex.test(searchValue);
|
|
259
|
+
}
|
|
260
|
+
exports.compileExpression = compileExpression;
|
|
261
|
+
//# sourceMappingURL=evaluators.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluators.cjs","sources":["../../../../src/query/compiler/evaluators.ts"],"sourcesContent":["import type { BasicExpression, Func, PropRef } from \"../ir.js\"\nimport type { NamespacedRow } from \"../../types.js\"\n\n/**\n * Compiled expression evaluator function type\n */\nexport type CompiledExpression = (namespacedRow: NamespacedRow) => any\n\n/**\n * Compiles an expression into an optimized evaluator function.\n * This eliminates branching during evaluation by pre-compiling the expression structure.\n */\nexport function compileExpression(expr: BasicExpression): CompiledExpression {\n switch (expr.type) {\n case `val`: {\n // For constant values, return a function that just returns the value\n const value = expr.value\n return () => value\n }\n\n case `ref`: {\n // For references, pre-compile the property path navigation\n return compileRef(expr)\n }\n\n case `func`: {\n // For functions, pre-compile the function and its arguments\n return compileFunction(expr)\n }\n\n default:\n throw new Error(`Unknown expression type: ${(expr as any).type}`)\n }\n}\n\n/**\n * Compiles a reference expression into an optimized evaluator\n */\nfunction compileRef(ref: PropRef): CompiledExpression {\n const [tableAlias, ...propertyPath] = ref.path\n\n if (!tableAlias) {\n throw new Error(`Reference path cannot be empty`)\n }\n\n // Pre-compile the property path navigation\n if (propertyPath.length === 0) {\n // Simple table reference\n return (namespacedRow) => namespacedRow[tableAlias]\n } else if (propertyPath.length === 1) {\n // Single property access - most common case\n const prop = propertyPath[0]!\n return (namespacedRow) => {\n const tableData = namespacedRow[tableAlias]\n return tableData?.[prop]\n }\n } else {\n // Multiple property navigation\n return (namespacedRow) => {\n const tableData = namespacedRow[tableAlias]\n if (tableData === undefined) {\n return undefined\n }\n\n let value: any = tableData\n for (const prop of propertyPath) {\n if (value == null) {\n return value\n }\n value = value[prop]\n }\n return value\n }\n }\n}\n\n/**\n * Compiles a function expression into an optimized evaluator\n */\nfunction compileFunction(func: Func): CompiledExpression {\n // Pre-compile all arguments\n const compiledArgs = func.args.map(compileExpression)\n\n switch (func.name) {\n // Comparison operators\n case `eq`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return a === b\n }\n }\n case `gt`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return a > b\n }\n }\n case `gte`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return a >= b\n }\n }\n case `lt`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return a < b\n }\n }\n case `lte`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return a <= b\n }\n }\n\n // Boolean operators\n case `and`:\n return (namespacedRow) => {\n for (const compiledArg of compiledArgs) {\n if (!compiledArg(namespacedRow)) {\n return false\n }\n }\n return true\n }\n case `or`:\n return (namespacedRow) => {\n for (const compiledArg of compiledArgs) {\n if (compiledArg(namespacedRow)) {\n return true\n }\n }\n return false\n }\n case `not`: {\n const arg = compiledArgs[0]!\n return (namespacedRow) => !arg(namespacedRow)\n }\n\n // Array operators\n case `in`: {\n const valueEvaluator = compiledArgs[0]!\n const arrayEvaluator = compiledArgs[1]!\n return (namespacedRow) => {\n const value = valueEvaluator(namespacedRow)\n const array = arrayEvaluator(namespacedRow)\n if (!Array.isArray(array)) {\n return false\n }\n return array.includes(value)\n }\n }\n\n // String operators\n case `like`: {\n const valueEvaluator = compiledArgs[0]!\n const patternEvaluator = compiledArgs[1]!\n return (namespacedRow) => {\n const value = valueEvaluator(namespacedRow)\n const pattern = patternEvaluator(namespacedRow)\n return evaluateLike(value, pattern, false)\n }\n }\n case `ilike`: {\n const valueEvaluator = compiledArgs[0]!\n const patternEvaluator = compiledArgs[1]!\n return (namespacedRow) => {\n const value = valueEvaluator(namespacedRow)\n const pattern = patternEvaluator(namespacedRow)\n return evaluateLike(value, pattern, true)\n }\n }\n\n // String functions\n case `upper`: {\n const arg = compiledArgs[0]!\n return (namespacedRow) => {\n const value = arg(namespacedRow)\n return typeof value === `string` ? value.toUpperCase() : value\n }\n }\n case `lower`: {\n const arg = compiledArgs[0]!\n return (namespacedRow) => {\n const value = arg(namespacedRow)\n return typeof value === `string` ? value.toLowerCase() : value\n }\n }\n case `length`: {\n const arg = compiledArgs[0]!\n return (namespacedRow) => {\n const value = arg(namespacedRow)\n if (typeof value === `string`) {\n return value.length\n }\n if (Array.isArray(value)) {\n return value.length\n }\n return 0\n }\n }\n case `concat`:\n return (namespacedRow) => {\n return compiledArgs\n .map((evaluator) => {\n const arg = evaluator(namespacedRow)\n try {\n return String(arg ?? ``)\n } catch {\n try {\n return JSON.stringify(arg) || ``\n } catch {\n return `[object]`\n }\n }\n })\n .join(``)\n }\n case `coalesce`:\n return (namespacedRow) => {\n for (const evaluator of compiledArgs) {\n const value = evaluator(namespacedRow)\n if (value !== null && value !== undefined) {\n return value\n }\n }\n return null\n }\n\n // Math functions\n case `add`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return (a ?? 0) + (b ?? 0)\n }\n }\n case `subtract`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return (a ?? 0) - (b ?? 0)\n }\n }\n case `multiply`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return (a ?? 0) * (b ?? 0)\n }\n }\n case `divide`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n const divisor = b ?? 0\n return divisor !== 0 ? (a ?? 0) / divisor : null\n }\n }\n\n default:\n throw new Error(`Unknown function: ${func.name}`)\n }\n}\n\n/**\n * Evaluates LIKE/ILIKE patterns\n */\nfunction evaluateLike(\n value: any,\n pattern: any,\n caseInsensitive: boolean\n): boolean {\n if (typeof value !== `string` || typeof pattern !== `string`) {\n return false\n }\n\n const searchValue = caseInsensitive ? value.toLowerCase() : value\n const searchPattern = caseInsensitive ? pattern.toLowerCase() : pattern\n\n // Convert SQL LIKE pattern to regex\n // First escape all regex special chars except % and _\n let regexPattern = searchPattern.replace(/[.*+?^${}()|[\\]\\\\]/g, `\\\\$&`)\n\n // Then convert SQL wildcards to regex\n regexPattern = regexPattern.replace(/%/g, `.*`) // % matches any sequence\n regexPattern = regexPattern.replace(/_/g, `.`) // _ matches any single char\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(searchValue)\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BasicExpression } from '../ir.js';
|
|
2
|
+
import { NamespacedRow } from '../../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Compiled expression evaluator function type
|
|
5
|
+
*/
|
|
6
|
+
export type CompiledExpression = (namespacedRow: NamespacedRow) => any;
|
|
7
|
+
/**
|
|
8
|
+
* Compiles an expression into an optimized evaluator function.
|
|
9
|
+
* This eliminates branching during evaluation by pre-compiling the expression structure.
|
|
10
|
+
*/
|
|
11
|
+
export declare function compileExpression(expr: BasicExpression): CompiledExpression;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const d2mini = require("@electric-sql/d2mini");
|
|
4
|
+
const ir = require("../ir.cjs");
|
|
5
|
+
const evaluators = require("./evaluators.cjs");
|
|
6
|
+
const { sum, count, avg, min, max } = d2mini.groupByOperators;
|
|
7
|
+
function validateAndCreateMapping(groupByClause, selectClause) {
|
|
8
|
+
const selectToGroupByIndex = /* @__PURE__ */ new Map();
|
|
9
|
+
const groupByExpressions = [...groupByClause];
|
|
10
|
+
if (!selectClause) {
|
|
11
|
+
return { selectToGroupByIndex, groupByExpressions };
|
|
12
|
+
}
|
|
13
|
+
for (const [alias, expr] of Object.entries(selectClause)) {
|
|
14
|
+
if (expr.type === `agg`) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const groupIndex = groupByExpressions.findIndex(
|
|
18
|
+
(groupExpr) => expressionsEqual(expr, groupExpr)
|
|
19
|
+
);
|
|
20
|
+
if (groupIndex === -1) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Non-aggregate expression '${alias}' in SELECT must also appear in GROUP BY clause`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
selectToGroupByIndex.set(alias, groupIndex);
|
|
26
|
+
}
|
|
27
|
+
return { selectToGroupByIndex, groupByExpressions };
|
|
28
|
+
}
|
|
29
|
+
function processGroupBy(pipeline, groupByClause, havingClauses, selectClause, fnHavingClauses) {
|
|
30
|
+
if (groupByClause.length === 0) {
|
|
31
|
+
const aggregates2 = {};
|
|
32
|
+
if (selectClause) {
|
|
33
|
+
for (const [alias, expr] of Object.entries(selectClause)) {
|
|
34
|
+
if (expr.type === `agg`) {
|
|
35
|
+
const aggExpr = expr;
|
|
36
|
+
aggregates2[alias] = getAggregateFunction(aggExpr);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const keyExtractor2 = () => ({ __singleGroup: true });
|
|
41
|
+
pipeline = pipeline.pipe(
|
|
42
|
+
d2mini.groupBy(keyExtractor2, aggregates2)
|
|
43
|
+
);
|
|
44
|
+
pipeline = pipeline.pipe(
|
|
45
|
+
d2mini.map(([, aggregatedRow]) => {
|
|
46
|
+
const selectResults = aggregatedRow.__select_results || {};
|
|
47
|
+
const finalResults = { ...selectResults };
|
|
48
|
+
if (selectClause) {
|
|
49
|
+
for (const [alias, expr] of Object.entries(selectClause)) {
|
|
50
|
+
if (expr.type === `agg`) {
|
|
51
|
+
finalResults[alias] = aggregatedRow[alias];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return [
|
|
56
|
+
`single_group`,
|
|
57
|
+
{
|
|
58
|
+
...aggregatedRow,
|
|
59
|
+
__select_results: finalResults
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
if (havingClauses && havingClauses.length > 0) {
|
|
65
|
+
for (const havingClause of havingClauses) {
|
|
66
|
+
const transformedHavingClause = transformHavingClause(
|
|
67
|
+
havingClause,
|
|
68
|
+
selectClause || {}
|
|
69
|
+
);
|
|
70
|
+
const compiledHaving = evaluators.compileExpression(transformedHavingClause);
|
|
71
|
+
pipeline = pipeline.pipe(
|
|
72
|
+
d2mini.filter(([, row]) => {
|
|
73
|
+
const namespacedRow = { result: row.__select_results };
|
|
74
|
+
return compiledHaving(namespacedRow);
|
|
75
|
+
})
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (fnHavingClauses && fnHavingClauses.length > 0) {
|
|
80
|
+
for (const fnHaving of fnHavingClauses) {
|
|
81
|
+
pipeline = pipeline.pipe(
|
|
82
|
+
d2mini.filter(([, row]) => {
|
|
83
|
+
const namespacedRow = { result: row.__select_results };
|
|
84
|
+
return fnHaving(namespacedRow);
|
|
85
|
+
})
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return pipeline;
|
|
90
|
+
}
|
|
91
|
+
const mapping = validateAndCreateMapping(groupByClause, selectClause);
|
|
92
|
+
const compiledGroupByExpressions = groupByClause.map(evaluators.compileExpression);
|
|
93
|
+
const keyExtractor = ([, row]) => {
|
|
94
|
+
const namespacedRow = { ...row };
|
|
95
|
+
delete namespacedRow.__select_results;
|
|
96
|
+
const key = {};
|
|
97
|
+
for (let i = 0; i < groupByClause.length; i++) {
|
|
98
|
+
const compiledExpr = compiledGroupByExpressions[i];
|
|
99
|
+
const value = compiledExpr(namespacedRow);
|
|
100
|
+
key[`__key_${i}`] = value;
|
|
101
|
+
}
|
|
102
|
+
return key;
|
|
103
|
+
};
|
|
104
|
+
const aggregates = {};
|
|
105
|
+
if (selectClause) {
|
|
106
|
+
for (const [alias, expr] of Object.entries(selectClause)) {
|
|
107
|
+
if (expr.type === `agg`) {
|
|
108
|
+
const aggExpr = expr;
|
|
109
|
+
aggregates[alias] = getAggregateFunction(aggExpr);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
pipeline = pipeline.pipe(d2mini.groupBy(keyExtractor, aggregates));
|
|
114
|
+
pipeline = pipeline.pipe(
|
|
115
|
+
d2mini.map(([, aggregatedRow]) => {
|
|
116
|
+
const selectResults = aggregatedRow.__select_results || {};
|
|
117
|
+
const finalResults = {};
|
|
118
|
+
if (selectClause) {
|
|
119
|
+
for (const [alias, expr] of Object.entries(selectClause)) {
|
|
120
|
+
if (expr.type !== `agg`) {
|
|
121
|
+
const groupIndex = mapping.selectToGroupByIndex.get(alias);
|
|
122
|
+
if (groupIndex !== void 0) {
|
|
123
|
+
finalResults[alias] = aggregatedRow[`__key_${groupIndex}`];
|
|
124
|
+
} else {
|
|
125
|
+
finalResults[alias] = selectResults[alias];
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
finalResults[alias] = aggregatedRow[alias];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
for (let i = 0; i < groupByClause.length; i++) {
|
|
133
|
+
finalResults[`__key_${i}`] = aggregatedRow[`__key_${i}`];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
let finalKey;
|
|
137
|
+
if (groupByClause.length === 1) {
|
|
138
|
+
finalKey = aggregatedRow[`__key_0`];
|
|
139
|
+
} else {
|
|
140
|
+
const keyParts = [];
|
|
141
|
+
for (let i = 0; i < groupByClause.length; i++) {
|
|
142
|
+
keyParts.push(aggregatedRow[`__key_${i}`]);
|
|
143
|
+
}
|
|
144
|
+
finalKey = JSON.stringify(keyParts);
|
|
145
|
+
}
|
|
146
|
+
return [
|
|
147
|
+
finalKey,
|
|
148
|
+
{
|
|
149
|
+
...aggregatedRow,
|
|
150
|
+
__select_results: finalResults
|
|
151
|
+
}
|
|
152
|
+
];
|
|
153
|
+
})
|
|
154
|
+
);
|
|
155
|
+
if (havingClauses && havingClauses.length > 0) {
|
|
156
|
+
for (const havingClause of havingClauses) {
|
|
157
|
+
const transformedHavingClause = transformHavingClause(
|
|
158
|
+
havingClause,
|
|
159
|
+
selectClause || {}
|
|
160
|
+
);
|
|
161
|
+
const compiledHaving = evaluators.compileExpression(transformedHavingClause);
|
|
162
|
+
pipeline = pipeline.pipe(
|
|
163
|
+
d2mini.filter(([, row]) => {
|
|
164
|
+
const namespacedRow = { result: row.__select_results };
|
|
165
|
+
return compiledHaving(namespacedRow);
|
|
166
|
+
})
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (fnHavingClauses && fnHavingClauses.length > 0) {
|
|
171
|
+
for (const fnHaving of fnHavingClauses) {
|
|
172
|
+
pipeline = pipeline.pipe(
|
|
173
|
+
d2mini.filter(([, row]) => {
|
|
174
|
+
const namespacedRow = { result: row.__select_results };
|
|
175
|
+
return fnHaving(namespacedRow);
|
|
176
|
+
})
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return pipeline;
|
|
181
|
+
}
|
|
182
|
+
function expressionsEqual(expr1, expr2) {
|
|
183
|
+
var _a, _b, _c, _d;
|
|
184
|
+
if (!expr1 || !expr2) return false;
|
|
185
|
+
if (expr1.type !== expr2.type) return false;
|
|
186
|
+
switch (expr1.type) {
|
|
187
|
+
case `ref`:
|
|
188
|
+
if (!expr1.path || !expr2.path) return false;
|
|
189
|
+
if (expr1.path.length !== expr2.path.length) return false;
|
|
190
|
+
return expr1.path.every(
|
|
191
|
+
(segment, i) => segment === expr2.path[i]
|
|
192
|
+
);
|
|
193
|
+
case `val`:
|
|
194
|
+
return expr1.value === expr2.value;
|
|
195
|
+
case `func`:
|
|
196
|
+
return expr1.name === expr2.name && ((_a = expr1.args) == null ? void 0 : _a.length) === ((_b = expr2.args) == null ? void 0 : _b.length) && (expr1.args || []).every(
|
|
197
|
+
(arg, i) => expressionsEqual(arg, expr2.args[i])
|
|
198
|
+
);
|
|
199
|
+
case `agg`:
|
|
200
|
+
return expr1.name === expr2.name && ((_c = expr1.args) == null ? void 0 : _c.length) === ((_d = expr2.args) == null ? void 0 : _d.length) && (expr1.args || []).every(
|
|
201
|
+
(arg, i) => expressionsEqual(arg, expr2.args[i])
|
|
202
|
+
);
|
|
203
|
+
default:
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function getAggregateFunction(aggExpr) {
|
|
208
|
+
const compiledExpr = evaluators.compileExpression(aggExpr.args[0]);
|
|
209
|
+
const valueExtractor = ([, namespacedRow]) => {
|
|
210
|
+
const value = compiledExpr(namespacedRow);
|
|
211
|
+
return typeof value === `number` ? value : value != null ? Number(value) : 0;
|
|
212
|
+
};
|
|
213
|
+
switch (aggExpr.name.toLowerCase()) {
|
|
214
|
+
case `sum`:
|
|
215
|
+
return sum(valueExtractor);
|
|
216
|
+
case `count`:
|
|
217
|
+
return count();
|
|
218
|
+
// count() doesn't need a value extractor
|
|
219
|
+
case `avg`:
|
|
220
|
+
return avg(valueExtractor);
|
|
221
|
+
case `min`:
|
|
222
|
+
return min(valueExtractor);
|
|
223
|
+
case `max`:
|
|
224
|
+
return max(valueExtractor);
|
|
225
|
+
default:
|
|
226
|
+
throw new Error(`Unsupported aggregate function: ${aggExpr.name}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function transformHavingClause(havingExpr, selectClause) {
|
|
230
|
+
switch (havingExpr.type) {
|
|
231
|
+
case `agg`: {
|
|
232
|
+
const aggExpr = havingExpr;
|
|
233
|
+
for (const [alias, selectExpr] of Object.entries(selectClause)) {
|
|
234
|
+
if (selectExpr.type === `agg` && aggregatesEqual(aggExpr, selectExpr)) {
|
|
235
|
+
return new ir.PropRef([`result`, alias]);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
throw new Error(
|
|
239
|
+
`Aggregate function in HAVING clause must also be in SELECT clause: ${aggExpr.name}`
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
case `func`: {
|
|
243
|
+
const funcExpr = havingExpr;
|
|
244
|
+
const transformedArgs = funcExpr.args.map(
|
|
245
|
+
(arg) => transformHavingClause(arg, selectClause)
|
|
246
|
+
);
|
|
247
|
+
return new ir.Func(funcExpr.name, transformedArgs);
|
|
248
|
+
}
|
|
249
|
+
case `ref`: {
|
|
250
|
+
const refExpr = havingExpr;
|
|
251
|
+
if (refExpr.path.length === 1) {
|
|
252
|
+
const alias = refExpr.path[0];
|
|
253
|
+
if (selectClause[alias]) {
|
|
254
|
+
return new ir.PropRef([`result`, alias]);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return havingExpr;
|
|
258
|
+
}
|
|
259
|
+
case `val`:
|
|
260
|
+
return havingExpr;
|
|
261
|
+
default:
|
|
262
|
+
throw new Error(
|
|
263
|
+
`Unknown expression type in HAVING clause: ${havingExpr.type}`
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function aggregatesEqual(agg1, agg2) {
|
|
268
|
+
return agg1.name === agg2.name && agg1.args.length === agg2.args.length && agg1.args.every((arg, i) => expressionsEqual(arg, agg2.args[i]));
|
|
269
|
+
}
|
|
270
|
+
exports.processGroupBy = processGroupBy;
|
|
271
|
+
//# sourceMappingURL=group-by.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-by.cjs","sources":["../../../../src/query/compiler/group-by.ts"],"sourcesContent":["import { filter, groupBy, groupByOperators, map } from \"@electric-sql/d2mini\"\nimport { Func, PropRef } from \"../ir.js\"\nimport { compileExpression } from \"./evaluators.js\"\nimport type {\n Aggregate,\n BasicExpression,\n GroupBy,\n Having,\n Select,\n} from \"../ir.js\"\nimport type { NamespacedAndKeyedStream, NamespacedRow } from \"../../types.js\"\n\nconst { sum, count, avg, min, max } = groupByOperators\n\n/**\n * Interface for caching the mapping between GROUP BY expressions and SELECT expressions\n */\ninterface GroupBySelectMapping {\n selectToGroupByIndex: Map<string, number> // Maps SELECT alias to GROUP BY expression index\n groupByExpressions: Array<any> // The GROUP BY expressions for reference\n}\n\n/**\n * Validates that all non-aggregate expressions in SELECT are present in GROUP BY\n * and creates a cached mapping for efficient lookup during processing\n */\nfunction validateAndCreateMapping(\n groupByClause: GroupBy,\n selectClause?: Select\n): GroupBySelectMapping {\n const selectToGroupByIndex = new Map<string, number>()\n const groupByExpressions = [...groupByClause]\n\n if (!selectClause) {\n return { selectToGroupByIndex, groupByExpressions }\n }\n\n // Validate each SELECT expression\n for (const [alias, expr] of Object.entries(selectClause)) {\n if (expr.type === `agg`) {\n // Aggregate expressions are allowed and don't need to be in GROUP BY\n continue\n }\n\n // Non-aggregate expression must be in GROUP BY\n const groupIndex = groupByExpressions.findIndex((groupExpr) =>\n expressionsEqual(expr, groupExpr)\n )\n\n if (groupIndex === -1) {\n throw new Error(\n `Non-aggregate expression '${alias}' in SELECT must also appear in GROUP BY clause`\n )\n }\n\n // Cache the mapping\n selectToGroupByIndex.set(alias, groupIndex)\n }\n\n return { selectToGroupByIndex, groupByExpressions }\n}\n\n/**\n * Processes the GROUP BY clause with optional HAVING and SELECT\n * Works with the new __select_results structure from early SELECT processing\n */\nexport function processGroupBy(\n pipeline: NamespacedAndKeyedStream,\n groupByClause: GroupBy,\n havingClauses?: Array<Having>,\n selectClause?: Select,\n fnHavingClauses?: Array<(row: any) => any>\n): NamespacedAndKeyedStream {\n // Handle empty GROUP BY (single-group aggregation)\n if (groupByClause.length === 0) {\n // For single-group aggregation, create a single group with all data\n const aggregates: Record<string, any> = {}\n\n if (selectClause) {\n // Scan the SELECT clause for aggregate functions\n for (const [alias, expr] of Object.entries(selectClause)) {\n if (expr.type === `agg`) {\n const aggExpr = expr\n aggregates[alias] = getAggregateFunction(aggExpr)\n }\n }\n }\n\n // Use a constant key for single group\n const keyExtractor = () => ({ __singleGroup: true })\n\n // Apply the groupBy operator with single group\n pipeline = pipeline.pipe(\n groupBy(keyExtractor, aggregates)\n ) as NamespacedAndKeyedStream\n\n // Update __select_results to include aggregate values\n pipeline = pipeline.pipe(\n map(([, aggregatedRow]) => {\n // Start with the existing __select_results from early SELECT processing\n const selectResults = (aggregatedRow as any).__select_results || {}\n const finalResults: Record<string, any> = { ...selectResults }\n\n if (selectClause) {\n // Update with aggregate results\n for (const [alias, expr] of Object.entries(selectClause)) {\n if (expr.type === `agg`) {\n finalResults[alias] = aggregatedRow[alias]\n }\n // Non-aggregates keep their original values from early SELECT processing\n }\n }\n\n // Use a single key for the result and update __select_results\n return [\n `single_group`,\n {\n ...aggregatedRow,\n __select_results: finalResults,\n },\n ] as [unknown, Record<string, any>]\n })\n )\n\n // Apply HAVING clauses if present\n if (havingClauses && havingClauses.length > 0) {\n for (const havingClause of havingClauses) {\n const transformedHavingClause = transformHavingClause(\n havingClause,\n selectClause || {}\n )\n const compiledHaving = compileExpression(transformedHavingClause)\n\n pipeline = pipeline.pipe(\n filter(([, row]) => {\n // Create a namespaced row structure for HAVING evaluation\n const namespacedRow = { result: (row as any).__select_results }\n return compiledHaving(namespacedRow)\n })\n )\n }\n }\n\n // Apply functional HAVING clauses if present\n if (fnHavingClauses && fnHavingClauses.length > 0) {\n for (const fnHaving of fnHavingClauses) {\n pipeline = pipeline.pipe(\n filter(([, row]) => {\n // Create a namespaced row structure for functional HAVING evaluation\n const namespacedRow = { result: (row as any).__select_results }\n return fnHaving(namespacedRow)\n })\n )\n }\n }\n\n return pipeline\n }\n\n // Multi-group aggregation logic...\n // Validate and create mapping for non-aggregate expressions in SELECT\n const mapping = validateAndCreateMapping(groupByClause, selectClause)\n\n // Pre-compile groupBy expressions\n const compiledGroupByExpressions = groupByClause.map(compileExpression)\n\n // Create a key extractor function using simple __key_X format\n const keyExtractor = ([, row]: [\n string,\n NamespacedRow & { __select_results?: any },\n ]) => {\n // Use the original namespaced row for GROUP BY expressions, not __select_results\n const namespacedRow = { ...row }\n delete (namespacedRow as any).__select_results\n\n const key: Record<string, unknown> = {}\n\n // Use simple __key_X format for each groupBy expression\n for (let i = 0; i < groupByClause.length; i++) {\n const compiledExpr = compiledGroupByExpressions[i]!\n const value = compiledExpr(namespacedRow)\n key[`__key_${i}`] = value\n }\n\n return key\n }\n\n // Create aggregate functions for any aggregated columns in the SELECT clause\n const aggregates: Record<string, any> = {}\n\n if (selectClause) {\n // Scan the SELECT clause for aggregate functions\n for (const [alias, expr] of Object.entries(selectClause)) {\n if (expr.type === `agg`) {\n const aggExpr = expr\n aggregates[alias] = getAggregateFunction(aggExpr)\n }\n }\n }\n\n // Apply the groupBy operator\n pipeline = pipeline.pipe(groupBy(keyExtractor, aggregates))\n\n // Update __select_results to handle GROUP BY results\n pipeline = pipeline.pipe(\n map(([, aggregatedRow]) => {\n // Start with the existing __select_results from early SELECT processing\n const selectResults = (aggregatedRow as any).__select_results || {}\n const finalResults: Record<string, any> = {}\n\n if (selectClause) {\n // Process each SELECT expression\n for (const [alias, expr] of Object.entries(selectClause)) {\n if (expr.type !== `agg`) {\n // Use cached mapping to get the corresponding __key_X for non-aggregates\n const groupIndex = mapping.selectToGroupByIndex.get(alias)\n if (groupIndex !== undefined) {\n finalResults[alias] = aggregatedRow[`__key_${groupIndex}`]\n } else {\n // Fallback to original SELECT results\n finalResults[alias] = selectResults[alias]\n }\n } else {\n // Use aggregate results\n finalResults[alias] = aggregatedRow[alias]\n }\n }\n } else {\n // No SELECT clause - just use the group keys\n for (let i = 0; i < groupByClause.length; i++) {\n finalResults[`__key_${i}`] = aggregatedRow[`__key_${i}`]\n }\n }\n\n // Generate a simple key for the live collection using group values\n let finalKey: unknown\n if (groupByClause.length === 1) {\n finalKey = aggregatedRow[`__key_0`]\n } else {\n const keyParts: Array<unknown> = []\n for (let i = 0; i < groupByClause.length; i++) {\n keyParts.push(aggregatedRow[`__key_${i}`])\n }\n finalKey = JSON.stringify(keyParts)\n }\n\n return [\n finalKey,\n {\n ...aggregatedRow,\n __select_results: finalResults,\n },\n ] as [unknown, Record<string, any>]\n })\n )\n\n // Apply HAVING clauses if present\n if (havingClauses && havingClauses.length > 0) {\n for (const havingClause of havingClauses) {\n const transformedHavingClause = transformHavingClause(\n havingClause,\n selectClause || {}\n )\n const compiledHaving = compileExpression(transformedHavingClause)\n\n pipeline = pipeline.pipe(\n filter(([, row]) => {\n // Create a namespaced row structure for HAVING evaluation\n const namespacedRow = { result: (row as any).__select_results }\n return compiledHaving(namespacedRow)\n })\n )\n }\n }\n\n // Apply functional HAVING clauses if present\n if (fnHavingClauses && fnHavingClauses.length > 0) {\n for (const fnHaving of fnHavingClauses) {\n pipeline = pipeline.pipe(\n filter(([, row]) => {\n // Create a namespaced row structure for functional HAVING evaluation\n const namespacedRow = { result: (row as any).__select_results }\n return fnHaving(namespacedRow)\n })\n )\n }\n }\n\n return pipeline\n}\n\n/**\n * Helper function to check if two expressions are equal\n */\nfunction expressionsEqual(expr1: any, expr2: any): boolean {\n if (!expr1 || !expr2) return false\n if (expr1.type !== expr2.type) return false\n\n switch (expr1.type) {\n case `ref`:\n // Compare paths as arrays\n if (!expr1.path || !expr2.path) return false\n if (expr1.path.length !== expr2.path.length) return false\n return expr1.path.every(\n (segment: string, i: number) => segment === expr2.path[i]\n )\n case `val`:\n return expr1.value === expr2.value\n case `func`:\n return (\n expr1.name === expr2.name &&\n expr1.args?.length === expr2.args?.length &&\n (expr1.args || []).every((arg: any, i: number) =>\n expressionsEqual(arg, expr2.args[i])\n )\n )\n case `agg`:\n return (\n expr1.name === expr2.name &&\n expr1.args?.length === expr2.args?.length &&\n (expr1.args || []).every((arg: any, i: number) =>\n expressionsEqual(arg, expr2.args[i])\n )\n )\n default:\n return false\n }\n}\n\n/**\n * Helper function to get an aggregate function based on the Agg expression\n */\nfunction getAggregateFunction(aggExpr: Aggregate) {\n // Pre-compile the value extractor expression\n const compiledExpr = compileExpression(aggExpr.args[0]!)\n\n // Create a value extractor function for the expression to aggregate\n const valueExtractor = ([, namespacedRow]: [string, NamespacedRow]) => {\n const value = compiledExpr(namespacedRow)\n // Ensure we return a number for numeric aggregate functions\n return typeof value === `number` ? value : value != null ? Number(value) : 0\n }\n\n // Return the appropriate aggregate function\n switch (aggExpr.name.toLowerCase()) {\n case `sum`:\n return sum(valueExtractor)\n case `count`:\n return count() // count() doesn't need a value extractor\n case `avg`:\n return avg(valueExtractor)\n case `min`:\n return min(valueExtractor)\n case `max`:\n return max(valueExtractor)\n default:\n throw new Error(`Unsupported aggregate function: ${aggExpr.name}`)\n }\n}\n\n/**\n * Transforms a HAVING clause to replace Agg expressions with references to computed values\n */\nfunction transformHavingClause(\n havingExpr: BasicExpression | Aggregate,\n selectClause: Select\n): BasicExpression {\n switch (havingExpr.type) {\n case `agg`: {\n const aggExpr = havingExpr\n // Find matching aggregate in SELECT clause\n for (const [alias, selectExpr] of Object.entries(selectClause)) {\n if (selectExpr.type === `agg` && aggregatesEqual(aggExpr, selectExpr)) {\n // Replace with a reference to the computed aggregate\n return new PropRef([`result`, alias])\n }\n }\n // If no matching aggregate found in SELECT, throw error\n throw new Error(\n `Aggregate function in HAVING clause must also be in SELECT clause: ${aggExpr.name}`\n )\n }\n\n case `func`: {\n const funcExpr = havingExpr\n // Transform function arguments recursively\n const transformedArgs = funcExpr.args.map(\n (arg: BasicExpression | Aggregate) =>\n transformHavingClause(arg, selectClause)\n )\n return new Func(funcExpr.name, transformedArgs)\n }\n\n case `ref`: {\n const refExpr = havingExpr\n // Check if this is a direct reference to a SELECT alias\n if (refExpr.path.length === 1) {\n const alias = refExpr.path[0]!\n if (selectClause[alias]) {\n // This is a reference to a SELECT alias, convert to result.alias\n return new PropRef([`result`, alias])\n }\n }\n // Return as-is for other refs\n return havingExpr as BasicExpression\n }\n\n case `val`:\n // Return as-is\n return havingExpr as BasicExpression\n\n default:\n throw new Error(\n `Unknown expression type in HAVING clause: ${(havingExpr as any).type}`\n )\n }\n}\n\n/**\n * Checks if two aggregate expressions are equal\n */\nfunction aggregatesEqual(agg1: Aggregate, agg2: Aggregate): boolean {\n return (\n agg1.name === agg2.name &&\n agg1.args.length === agg2.args.length &&\n agg1.args.every((arg, i) => expressionsEqual(arg, agg2.args[i]))\n )\n}\n"],"names":["groupByOperators","aggregates","keyExtractor","groupBy","map","compileExpression","filter","PropRef","Func"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { GroupBy, Having, Select } from '../ir.js';
|
|
2
|
+
import { NamespacedAndKeyedStream } from '../../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Processes the GROUP BY clause with optional HAVING and SELECT
|
|
5
|
+
* Works with the new __select_results structure from early SELECT processing
|
|
6
|
+
*/
|
|
7
|
+
export declare function processGroupBy(pipeline: NamespacedAndKeyedStream, groupByClause: GroupBy, havingClauses?: Array<Having>, selectClause?: Select, fnHavingClauses?: Array<(row: any) => any>): NamespacedAndKeyedStream;
|