@tanstack/db 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +35 -13
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +0 -1
- package/dist/cjs/query/builder/functions.cjs +107 -0
- package/dist/cjs/query/builder/functions.cjs.map +1 -0
- package/dist/cjs/query/builder/functions.d.cts +38 -0
- package/dist/cjs/query/builder/index.cjs +499 -0
- package/dist/cjs/query/builder/index.cjs.map +1 -0
- package/dist/cjs/query/builder/index.d.cts +324 -0
- package/dist/cjs/query/builder/ref-proxy.cjs +96 -0
- package/dist/cjs/query/builder/ref-proxy.cjs.map +1 -0
- package/dist/cjs/query/builder/ref-proxy.d.cts +28 -0
- package/dist/cjs/query/builder/types.d.cts +80 -0
- package/dist/cjs/query/compiler/evaluators.cjs +261 -0
- package/dist/cjs/query/compiler/evaluators.cjs.map +1 -0
- package/dist/cjs/query/compiler/evaluators.d.cts +11 -0
- package/dist/cjs/query/compiler/group-by.cjs +271 -0
- package/dist/cjs/query/compiler/group-by.cjs.map +1 -0
- package/dist/cjs/query/compiler/group-by.d.cts +7 -0
- package/dist/cjs/query/compiler/index.cjs +181 -0
- package/dist/cjs/query/compiler/index.cjs.map +1 -0
- package/dist/cjs/query/compiler/index.d.cts +15 -0
- package/dist/cjs/query/compiler/joins.cjs +116 -0
- package/dist/cjs/query/compiler/joins.cjs.map +1 -0
- package/dist/cjs/query/compiler/joins.d.cts +11 -0
- package/dist/cjs/query/compiler/order-by.cjs +89 -0
- package/dist/cjs/query/compiler/order-by.cjs.map +1 -0
- package/dist/cjs/query/compiler/order-by.d.cts +9 -0
- package/dist/cjs/query/compiler/select.cjs +57 -0
- package/dist/cjs/query/compiler/select.cjs.map +1 -0
- package/dist/cjs/query/compiler/select.d.cts +15 -0
- package/dist/cjs/query/index.d.cts +6 -5
- package/dist/cjs/query/ir.cjs +57 -0
- package/dist/cjs/query/ir.cjs.map +1 -0
- package/dist/cjs/query/ir.d.cts +81 -0
- package/dist/cjs/query/live-query-collection.cjs +224 -0
- package/dist/cjs/query/live-query-collection.cjs.map +1 -0
- package/dist/cjs/query/live-query-collection.d.cts +124 -0
- package/dist/cjs/transactions.cjs +20 -13
- package/dist/cjs/transactions.cjs.map +1 -1
- package/dist/cjs/transactions.d.cts +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 +34 -12
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/query/builder/functions.d.ts +38 -0
- package/dist/esm/query/builder/functions.js +107 -0
- package/dist/esm/query/builder/functions.js.map +1 -0
- package/dist/esm/query/builder/index.d.ts +324 -0
- package/dist/esm/query/builder/index.js +499 -0
- package/dist/esm/query/builder/index.js.map +1 -0
- package/dist/esm/query/builder/ref-proxy.d.ts +28 -0
- package/dist/esm/query/builder/ref-proxy.js +96 -0
- package/dist/esm/query/builder/ref-proxy.js.map +1 -0
- package/dist/esm/query/builder/types.d.ts +80 -0
- package/dist/esm/query/compiler/evaluators.d.ts +11 -0
- package/dist/esm/query/compiler/evaluators.js +261 -0
- package/dist/esm/query/compiler/evaluators.js.map +1 -0
- package/dist/esm/query/compiler/group-by.d.ts +7 -0
- package/dist/esm/query/compiler/group-by.js +271 -0
- package/dist/esm/query/compiler/group-by.js.map +1 -0
- package/dist/esm/query/compiler/index.d.ts +15 -0
- package/dist/esm/query/compiler/index.js +181 -0
- package/dist/esm/query/compiler/index.js.map +1 -0
- package/dist/esm/query/compiler/joins.d.ts +11 -0
- package/dist/esm/query/compiler/joins.js +116 -0
- package/dist/esm/query/compiler/joins.js.map +1 -0
- package/dist/esm/query/compiler/order-by.d.ts +9 -0
- package/dist/esm/query/compiler/order-by.js +89 -0
- package/dist/esm/query/compiler/order-by.js.map +1 -0
- package/dist/esm/query/compiler/select.d.ts +15 -0
- package/dist/esm/query/compiler/select.js +57 -0
- package/dist/esm/query/compiler/select.js.map +1 -0
- package/dist/esm/query/index.d.ts +6 -5
- package/dist/esm/query/ir.d.ts +81 -0
- package/dist/esm/query/ir.js +57 -0
- package/dist/esm/query/ir.js.map +1 -0
- package/dist/esm/query/live-query-collection.d.ts +124 -0
- package/dist/esm/query/live-query-collection.js +224 -0
- package/dist/esm/query/live-query-collection.js.map +1 -0
- package/dist/esm/transactions.d.ts +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 +278 -0
- package/src/query/compiler/evaluators.ts +315 -0
- package/src/query/compiler/group-by.ts +428 -0
- package/src/query/compiler/index.ts +276 -0
- package/src/query/compiler/joins.ts +228 -0
- package/src/query/compiler/order-by.ts +139 -0
- package/src/query/compiler/select.ts +173 -0
- package/src/query/index.ts +64 -5
- package/src/query/ir.ts +128 -0
- package/src/query/live-query-collection.ts +509 -0
- package/src/transactions.ts +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
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const d2mini = require("@electric-sql/d2mini");
|
|
4
|
-
const extractors = require("./extractors.cjs");
|
|
5
|
-
const utils = require("./utils.cjs");
|
|
6
|
-
function processOrderBy(resultPipeline, query, mainTableAlias) {
|
|
7
|
-
let hasOrderIndexColumn = false;
|
|
8
|
-
let orderIndexType = `numeric`;
|
|
9
|
-
let orderIndexAlias = ``;
|
|
10
|
-
for (const item of query.select) {
|
|
11
|
-
if (typeof item === `object`) {
|
|
12
|
-
for (const [alias, expr] of Object.entries(item)) {
|
|
13
|
-
if (typeof expr === `object` && utils.isOrderIndexFunctionCall(expr)) {
|
|
14
|
-
hasOrderIndexColumn = true;
|
|
15
|
-
orderIndexAlias = alias;
|
|
16
|
-
orderIndexType = getOrderIndexType(expr);
|
|
17
|
-
break;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
if (hasOrderIndexColumn) break;
|
|
22
|
-
}
|
|
23
|
-
const orderByItems = [];
|
|
24
|
-
if (typeof query.orderBy === `string`) {
|
|
25
|
-
orderByItems.push({
|
|
26
|
-
operand: query.orderBy,
|
|
27
|
-
direction: `asc`
|
|
28
|
-
});
|
|
29
|
-
} else if (Array.isArray(query.orderBy)) {
|
|
30
|
-
for (const item of query.orderBy) {
|
|
31
|
-
if (typeof item === `string`) {
|
|
32
|
-
orderByItems.push({
|
|
33
|
-
operand: item,
|
|
34
|
-
direction: `asc`
|
|
35
|
-
});
|
|
36
|
-
} else if (typeof item === `object`) {
|
|
37
|
-
for (const [column, direction] of Object.entries(item)) {
|
|
38
|
-
orderByItems.push({
|
|
39
|
-
operand: column,
|
|
40
|
-
direction
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
} else if (typeof query.orderBy === `object`) {
|
|
46
|
-
for (const [column, direction] of Object.entries(query.orderBy)) {
|
|
47
|
-
orderByItems.push({
|
|
48
|
-
operand: column,
|
|
49
|
-
direction
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
const valueExtractor = (namespacedRow) => {
|
|
54
|
-
if (orderByItems.length > 1) {
|
|
55
|
-
return orderByItems.map(
|
|
56
|
-
(item) => extractors.evaluateOperandOnNamespacedRow(
|
|
57
|
-
namespacedRow,
|
|
58
|
-
item.operand,
|
|
59
|
-
mainTableAlias
|
|
60
|
-
)
|
|
61
|
-
);
|
|
62
|
-
} else if (orderByItems.length === 1) {
|
|
63
|
-
const item = orderByItems[0];
|
|
64
|
-
const val = extractors.evaluateOperandOnNamespacedRow(
|
|
65
|
-
namespacedRow,
|
|
66
|
-
item.operand,
|
|
67
|
-
mainTableAlias
|
|
68
|
-
);
|
|
69
|
-
return val;
|
|
70
|
-
}
|
|
71
|
-
return null;
|
|
72
|
-
};
|
|
73
|
-
const ascComparator = (a, b) => {
|
|
74
|
-
if (typeof a === `string` && typeof b === `string`) {
|
|
75
|
-
return a.localeCompare(b);
|
|
76
|
-
}
|
|
77
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
78
|
-
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
79
|
-
const result = ascComparator(a[i], b[i]);
|
|
80
|
-
if (result !== 0) {
|
|
81
|
-
return result;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return a.length - b.length;
|
|
85
|
-
}
|
|
86
|
-
const bothObjects = typeof a === `object` && typeof b === `object`;
|
|
87
|
-
const bothDates = a instanceof Date && b instanceof Date;
|
|
88
|
-
const notNull = a !== null && b !== null;
|
|
89
|
-
if (bothObjects && !bothDates && notNull) {
|
|
90
|
-
return a.toString().localeCompare(b.toString());
|
|
91
|
-
}
|
|
92
|
-
if (a < b) return -1;
|
|
93
|
-
if (a > b) return 1;
|
|
94
|
-
return 0;
|
|
95
|
-
};
|
|
96
|
-
const descComparator = (a, b) => {
|
|
97
|
-
return ascComparator(b, a);
|
|
98
|
-
};
|
|
99
|
-
const makeComparator = (orderByProps) => {
|
|
100
|
-
return (a, b) => {
|
|
101
|
-
if (orderByProps.length > 1) {
|
|
102
|
-
const arrayA = a;
|
|
103
|
-
const arrayB = b;
|
|
104
|
-
for (let i = 0; i < orderByProps.length; i++) {
|
|
105
|
-
const direction = orderByProps[i].direction;
|
|
106
|
-
const compareFn = direction === `desc` ? descComparator : ascComparator;
|
|
107
|
-
const result = compareFn(arrayA[i], arrayB[i]);
|
|
108
|
-
if (result !== 0) {
|
|
109
|
-
return result;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return arrayA.length - arrayB.length;
|
|
113
|
-
}
|
|
114
|
-
if (orderByProps.length === 1) {
|
|
115
|
-
const direction = orderByProps[0].direction;
|
|
116
|
-
return direction === `desc` ? descComparator(a, b) : ascComparator(a, b);
|
|
117
|
-
}
|
|
118
|
-
return ascComparator(a, b);
|
|
119
|
-
};
|
|
120
|
-
};
|
|
121
|
-
const comparator = makeComparator(orderByItems);
|
|
122
|
-
if (hasOrderIndexColumn) {
|
|
123
|
-
if (orderIndexType === `numeric`) {
|
|
124
|
-
resultPipeline = resultPipeline.pipe(
|
|
125
|
-
d2mini.orderByWithIndex(valueExtractor, {
|
|
126
|
-
limit: query.limit,
|
|
127
|
-
offset: query.offset,
|
|
128
|
-
comparator
|
|
129
|
-
}),
|
|
130
|
-
d2mini.map(([key, [value, index]]) => {
|
|
131
|
-
const result = {
|
|
132
|
-
...value,
|
|
133
|
-
[mainTableAlias]: {
|
|
134
|
-
...value[mainTableAlias],
|
|
135
|
-
[orderIndexAlias]: index
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
return [key, result];
|
|
139
|
-
})
|
|
140
|
-
);
|
|
141
|
-
} else {
|
|
142
|
-
resultPipeline = resultPipeline.pipe(
|
|
143
|
-
d2mini.orderByWithFractionalIndex(valueExtractor, {
|
|
144
|
-
limit: query.limit,
|
|
145
|
-
offset: query.offset,
|
|
146
|
-
comparator
|
|
147
|
-
}),
|
|
148
|
-
d2mini.map(([key, [value, index]]) => {
|
|
149
|
-
const result = {
|
|
150
|
-
...value,
|
|
151
|
-
[mainTableAlias]: {
|
|
152
|
-
...value[mainTableAlias],
|
|
153
|
-
[orderIndexAlias]: index
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
return [key, result];
|
|
157
|
-
})
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
} else {
|
|
161
|
-
resultPipeline = resultPipeline.pipe(
|
|
162
|
-
d2mini.orderBy(valueExtractor, {
|
|
163
|
-
limit: query.limit,
|
|
164
|
-
offset: query.offset,
|
|
165
|
-
comparator
|
|
166
|
-
})
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
return resultPipeline;
|
|
170
|
-
}
|
|
171
|
-
function getOrderIndexType(obj) {
|
|
172
|
-
if (!utils.isOrderIndexFunctionCall(obj)) {
|
|
173
|
-
throw new Error(`Not an ORDER_INDEX function call`);
|
|
174
|
-
}
|
|
175
|
-
const arg = obj[`ORDER_INDEX`];
|
|
176
|
-
if (arg === `numeric` || arg === true || arg === `default`) {
|
|
177
|
-
return `numeric`;
|
|
178
|
-
} else if (arg === `fractional`) {
|
|
179
|
-
return `fractional`;
|
|
180
|
-
} else {
|
|
181
|
-
throw new Error(`Invalid ORDER_INDEX type: ` + arg);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
exports.processOrderBy = processOrderBy;
|
|
185
|
-
//# sourceMappingURL=order-by.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"order-by.cjs","sources":["../../../src/query/order-by.ts"],"sourcesContent":["import {\n map,\n orderBy,\n orderByWithFractionalIndex,\n orderByWithIndex,\n} from \"@electric-sql/d2mini\"\nimport { evaluateOperandOnNamespacedRow } from \"./extractors\"\nimport { isOrderIndexFunctionCall } from \"./utils\"\nimport type { ConditionOperand, Query } from \"./schema\"\nimport type {\n KeyedNamespacedRow,\n NamespacedAndKeyedStream,\n NamespacedRow,\n} from \"../types\"\n\ntype OrderByItem = {\n operand: ConditionOperand\n direction: `asc` | `desc`\n}\n\ntype OrderByItems = Array<OrderByItem>\n\nexport function processOrderBy(\n resultPipeline: NamespacedAndKeyedStream,\n query: Query,\n mainTableAlias: string\n) {\n // Check if any column in the SELECT clause is an ORDER_INDEX function call\n let hasOrderIndexColumn = false\n let orderIndexType: `numeric` | `fractional` = `numeric`\n let orderIndexAlias = ``\n\n // Scan the SELECT clause for ORDER_INDEX functions\n // TODO: Select is going to be optional in future - we will automatically add an\n // attribute for the index column\n for (const item of query.select!) {\n if (typeof item === `object`) {\n for (const [alias, expr] of Object.entries(item)) {\n if (typeof expr === `object` && isOrderIndexFunctionCall(expr)) {\n hasOrderIndexColumn = true\n orderIndexAlias = alias\n orderIndexType = getOrderIndexType(expr)\n break\n }\n }\n }\n if (hasOrderIndexColumn) break\n }\n\n // Normalize orderBy to an array of objects\n const orderByItems: OrderByItems = []\n\n if (typeof query.orderBy === `string`) {\n // Handle string format: '@column'\n orderByItems.push({\n operand: query.orderBy,\n direction: `asc`,\n })\n } else if (Array.isArray(query.orderBy)) {\n // Handle array format: ['@column1', { '@column2': 'desc' }]\n for (const item of query.orderBy) {\n if (typeof item === `string`) {\n orderByItems.push({\n operand: item,\n direction: `asc`,\n })\n } else if (typeof item === `object`) {\n for (const [column, direction] of Object.entries(item)) {\n orderByItems.push({\n operand: column,\n direction: direction as `asc` | `desc`,\n })\n }\n }\n }\n } else if (typeof query.orderBy === `object`) {\n // Handle object format: { '@column': 'desc' }\n for (const [column, direction] of Object.entries(query.orderBy)) {\n orderByItems.push({\n operand: column,\n direction: direction as `asc` | `desc`,\n })\n }\n }\n\n // Create a value extractor function for the orderBy operator\n // const valueExtractor = ([key, namespacedRow]: [\n const valueExtractor = (namespacedRow: NamespacedRow) => {\n // For multiple orderBy columns, create a composite key\n if (orderByItems.length > 1) {\n return orderByItems.map((item) =>\n evaluateOperandOnNamespacedRow(\n namespacedRow,\n item.operand,\n mainTableAlias\n )\n )\n } else if (orderByItems.length === 1) {\n // For a single orderBy column, use the value directly\n const item = orderByItems[0]\n const val = evaluateOperandOnNamespacedRow(\n namespacedRow,\n item!.operand,\n mainTableAlias\n )\n return val\n }\n\n // Default case - no ordering\n return null\n }\n\n const ascComparator = (a: any, b: any): number => {\n // if a and b are both strings, compare them based on locale\n if (typeof a === `string` && typeof b === `string`) {\n return a.localeCompare(b)\n }\n\n // if a and b are both arrays, compare them element by element\n if (Array.isArray(a) && Array.isArray(b)) {\n for (let i = 0; i < Math.min(a.length, b.length); i++) {\n // Compare the values\n const result = ascComparator(a[i], b[i])\n\n if (result !== 0) {\n return result\n }\n }\n // All elements are equal up to the minimum length\n return a.length - b.length\n }\n\n // If at least one of the values is an object then we don't really know how to meaningfully compare them\n // therefore we turn them into strings and compare those\n // There are 2 exceptions:\n // 1) if both objects are dates then we can compare them\n // 2) if either object is nullish then we can't call toString on it\n const bothObjects = typeof a === `object` && typeof b === `object`\n const bothDates = a instanceof Date && b instanceof Date\n const notNull = a !== null && b !== null\n if (bothObjects && !bothDates && notNull) {\n // Every object should support `toString`\n return a.toString().localeCompare(b.toString())\n }\n\n if (a < b) return -1\n if (a > b) return 1\n return 0\n }\n\n const descComparator = (a: unknown, b: unknown): number => {\n return ascComparator(b, a)\n }\n\n // Create a multi-property comparator that respects the order and direction of each property\n const makeComparator = (orderByProps: OrderByItems) => {\n return (a: unknown, b: unknown) => {\n // If we're comparing arrays (multiple properties), compare each property in order\n if (orderByProps.length > 1) {\n // `a` and `b` must be arrays since `orderByItems.length > 1`\n // hence the extracted values must be arrays\n const arrayA = a as Array<unknown>\n const arrayB = b as Array<unknown>\n for (let i = 0; i < orderByProps.length; i++) {\n const direction = orderByProps[i]!.direction\n const compareFn =\n direction === `desc` ? descComparator : ascComparator\n const result = compareFn(arrayA[i], arrayB[i])\n if (result !== 0) {\n return result\n }\n }\n // should normally always be 0 because\n // both values are extracted based on orderByItems\n return arrayA.length - arrayB.length\n }\n\n // Single property comparison\n if (orderByProps.length === 1) {\n const direction = orderByProps[0]!.direction\n return direction === `desc` ? descComparator(a, b) : ascComparator(a, b)\n }\n\n return ascComparator(a, b)\n }\n }\n const comparator = makeComparator(orderByItems)\n\n // Apply the appropriate orderBy operator based on whether an ORDER_INDEX column is requested\n if (hasOrderIndexColumn) {\n if (orderIndexType === `numeric`) {\n // Use orderByWithIndex for numeric indices\n resultPipeline = resultPipeline.pipe(\n orderByWithIndex(valueExtractor, {\n limit: query.limit,\n offset: query.offset,\n comparator,\n }),\n map(([key, [value, index]]) => {\n // Add the index to the result\n // We add this to the main table alias for now\n // TODO: re are going to need to refactor the whole order by pipeline\n const result = {\n ...(value as Record<string, unknown>),\n [mainTableAlias]: {\n ...value[mainTableAlias],\n [orderIndexAlias]: index,\n },\n }\n return [key, result] as KeyedNamespacedRow\n })\n )\n } else {\n // Use orderByWithFractionalIndex for fractional indices\n resultPipeline = resultPipeline.pipe(\n orderByWithFractionalIndex(valueExtractor, {\n limit: query.limit,\n offset: query.offset,\n comparator,\n }),\n map(([key, [value, index]]) => {\n // Add the index to the result\n // We add this to the main table alias for now\n // TODO: re are going to need to refactor the whole order by pipeline\n const result = {\n ...(value as Record<string, unknown>),\n [mainTableAlias]: {\n ...value[mainTableAlias],\n [orderIndexAlias]: index,\n },\n }\n return [key, result] as KeyedNamespacedRow\n })\n )\n }\n } else {\n // Use regular orderBy if no index column is requested\n resultPipeline = resultPipeline.pipe(\n orderBy(valueExtractor, {\n limit: query.limit,\n offset: query.offset,\n comparator,\n })\n )\n }\n\n return resultPipeline\n}\n\n// Helper function to extract the ORDER_INDEX type from a function call\nfunction getOrderIndexType(obj: any): `numeric` | `fractional` {\n if (!isOrderIndexFunctionCall(obj)) {\n throw new Error(`Not an ORDER_INDEX function call`)\n }\n\n const arg = obj[`ORDER_INDEX`]\n if (arg === `numeric` || arg === true || arg === `default`) {\n return `numeric`\n } else if (arg === `fractional`) {\n return `fractional`\n } else {\n throw new Error(`Invalid ORDER_INDEX type: ` + arg)\n }\n}\n"],"names":["isOrderIndexFunctionCall","evaluateOperandOnNamespacedRow","orderByWithIndex","map","orderByWithFractionalIndex","orderBy"],"mappings":"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"}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const d2mini = require("@electric-sql/d2mini");
|
|
4
|
-
const evaluators = require("./evaluators.cjs");
|
|
5
|
-
const joins = require("./joins.cjs");
|
|
6
|
-
const groupBy = require("./group-by.cjs");
|
|
7
|
-
const orderBy = require("./order-by.cjs");
|
|
8
|
-
const select = require("./select.cjs");
|
|
9
|
-
function compileQueryPipeline(query, inputs) {
|
|
10
|
-
const allInputs = { ...inputs };
|
|
11
|
-
if (query.with && query.with.length > 0) {
|
|
12
|
-
for (const withQuery of query.with) {
|
|
13
|
-
if (!withQuery.as) {
|
|
14
|
-
throw new Error(`WITH query must have an "as" property`);
|
|
15
|
-
}
|
|
16
|
-
if (allInputs[withQuery.as]) {
|
|
17
|
-
throw new Error(`CTE with name "${withQuery.as}" already exists`);
|
|
18
|
-
}
|
|
19
|
-
const withQueryWithoutWith = { ...withQuery, with: void 0 };
|
|
20
|
-
const compiledWithQuery = compileQueryPipeline(
|
|
21
|
-
withQueryWithoutWith,
|
|
22
|
-
allInputs
|
|
23
|
-
);
|
|
24
|
-
allInputs[withQuery.as] = compiledWithQuery;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
const tables = {};
|
|
28
|
-
const mainTableAlias = query.as || query.from;
|
|
29
|
-
const input = allInputs[query.from];
|
|
30
|
-
if (!input) {
|
|
31
|
-
throw new Error(`Input for table "${query.from}" not found in inputs map`);
|
|
32
|
-
}
|
|
33
|
-
tables[mainTableAlias] = input;
|
|
34
|
-
let pipeline = input.pipe(
|
|
35
|
-
d2mini.map(([key, row]) => {
|
|
36
|
-
const ret = [key, { [mainTableAlias]: row }];
|
|
37
|
-
return ret;
|
|
38
|
-
})
|
|
39
|
-
);
|
|
40
|
-
if (query.join) {
|
|
41
|
-
pipeline = joins.processJoinClause(
|
|
42
|
-
pipeline,
|
|
43
|
-
query,
|
|
44
|
-
tables,
|
|
45
|
-
mainTableAlias,
|
|
46
|
-
allInputs
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
if (query.where) {
|
|
50
|
-
pipeline = pipeline.pipe(
|
|
51
|
-
d2mini.filter(([_key, row]) => {
|
|
52
|
-
const result = evaluators.evaluateWhereOnNamespacedRow(
|
|
53
|
-
row,
|
|
54
|
-
query.where,
|
|
55
|
-
mainTableAlias
|
|
56
|
-
);
|
|
57
|
-
return result;
|
|
58
|
-
})
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
if (query.groupBy) {
|
|
62
|
-
pipeline = groupBy.processGroupBy(pipeline, query, mainTableAlias);
|
|
63
|
-
}
|
|
64
|
-
if (query.having) {
|
|
65
|
-
pipeline = pipeline.pipe(
|
|
66
|
-
d2mini.filter(([_key, row]) => {
|
|
67
|
-
const result = evaluators.evaluateWhereOnNamespacedRow(
|
|
68
|
-
row,
|
|
69
|
-
query.having,
|
|
70
|
-
mainTableAlias
|
|
71
|
-
);
|
|
72
|
-
return result;
|
|
73
|
-
})
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
if (query.orderBy) {
|
|
77
|
-
pipeline = orderBy.processOrderBy(pipeline, query, mainTableAlias);
|
|
78
|
-
} else if (query.limit !== void 0 || query.offset !== void 0) {
|
|
79
|
-
throw new Error(
|
|
80
|
-
`LIMIT and OFFSET require an ORDER BY clause to ensure deterministic results`
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
const resultPipeline = query.select ? select.processSelect(pipeline, query, mainTableAlias, allInputs) : !query.join && !query.groupBy ? pipeline.pipe(
|
|
84
|
-
d2mini.map(([key, row]) => [key, row[mainTableAlias]])
|
|
85
|
-
) : pipeline;
|
|
86
|
-
return resultPipeline;
|
|
87
|
-
}
|
|
88
|
-
exports.compileQueryPipeline = compileQueryPipeline;
|
|
89
|
-
//# sourceMappingURL=pipeline-compiler.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-compiler.cjs","sources":["../../../src/query/pipeline-compiler.ts"],"sourcesContent":["import { filter, map } from \"@electric-sql/d2mini\"\nimport { evaluateWhereOnNamespacedRow } from \"./evaluators.js\"\nimport { processJoinClause } from \"./joins.js\"\nimport { processGroupBy } from \"./group-by.js\"\nimport { processOrderBy } from \"./order-by.js\"\nimport { processSelect } from \"./select.js\"\nimport type { Query } from \"./schema.js\"\nimport type { IStreamBuilder } from \"@electric-sql/d2mini\"\nimport type {\n InputRow,\n KeyedStream,\n NamespacedAndKeyedStream,\n} from \"../types.js\"\n\n/**\n * Compiles a query into a D2 pipeline\n * @param query The query to compile\n * @param inputs Mapping of table names to input streams\n * @returns A stream builder representing the compiled query\n */\nexport function compileQueryPipeline<T extends IStreamBuilder<unknown>>(\n query: Query,\n inputs: Record<string, KeyedStream>\n): T {\n // Create a copy of the inputs map to avoid modifying the original\n const allInputs = { ...inputs }\n\n // Process WITH queries if they exist\n if (query.with && query.with.length > 0) {\n // Process each WITH query in order\n for (const withQuery of query.with) {\n // Ensure the WITH query has an alias\n if (!withQuery.as) {\n throw new Error(`WITH query must have an \"as\" property`)\n }\n\n // Check if this CTE name already exists in the inputs\n if (allInputs[withQuery.as]) {\n throw new Error(`CTE with name \"${withQuery.as}\" already exists`)\n }\n\n // Create a new query without the 'with' property to avoid circular references\n const withQueryWithoutWith = { ...withQuery, with: undefined }\n\n // Compile the WITH query using the current set of inputs\n // (which includes previously compiled WITH queries)\n const compiledWithQuery = compileQueryPipeline(\n withQueryWithoutWith,\n allInputs\n )\n\n // Add the compiled query to the inputs map using its alias\n allInputs[withQuery.as] = compiledWithQuery as KeyedStream\n }\n }\n\n // Create a map of table aliases to inputs\n const tables: Record<string, KeyedStream> = {}\n\n // The main table is the one in the FROM clause\n const mainTableAlias = query.as || query.from\n\n // Get the main input from the inputs map (now including CTEs)\n const input = allInputs[query.from]\n if (!input) {\n throw new Error(`Input for table \"${query.from}\" not found in inputs map`)\n }\n\n tables[mainTableAlias] = input\n\n // Prepare the initial pipeline with the main table wrapped in its alias\n let pipeline: NamespacedAndKeyedStream = input.pipe(\n map(([key, row]) => {\n // Initialize the record with a nested structure\n const ret = [key, { [mainTableAlias]: row }] as [\n string,\n Record<string, typeof row>,\n ]\n return ret\n })\n )\n\n // Process JOIN clauses if they exist\n if (query.join) {\n pipeline = processJoinClause(\n pipeline,\n query,\n tables,\n mainTableAlias,\n allInputs\n )\n }\n\n // Process the WHERE clause if it exists\n if (query.where) {\n pipeline = pipeline.pipe(\n filter(([_key, row]) => {\n const result = evaluateWhereOnNamespacedRow(\n row,\n query.where!,\n mainTableAlias\n )\n return result\n })\n )\n }\n\n // Process the GROUP BY clause if it exists\n if (query.groupBy) {\n pipeline = processGroupBy(pipeline, query, mainTableAlias)\n }\n\n // Process the HAVING clause if it exists\n // This works similarly to WHERE but is applied after any aggregations\n if (query.having) {\n pipeline = pipeline.pipe(\n filter(([_key, row]) => {\n // For HAVING, we're working with the flattened row that contains both\n // the group by keys and the aggregate results directly\n const result = evaluateWhereOnNamespacedRow(\n row,\n query.having!,\n mainTableAlias\n )\n return result\n })\n )\n }\n\n // Process orderBy parameter if it exists\n if (query.orderBy) {\n pipeline = processOrderBy(pipeline, query, mainTableAlias)\n } else if (query.limit !== undefined || query.offset !== undefined) {\n // If there's a limit or offset without orderBy, throw an error\n throw new Error(\n `LIMIT and OFFSET require an ORDER BY clause to ensure deterministic results`\n )\n }\n\n // Process the SELECT clause - this is where we flatten the structure\n const resultPipeline: KeyedStream | NamespacedAndKeyedStream = query.select\n ? processSelect(pipeline, query, mainTableAlias, allInputs)\n : !query.join && !query.groupBy\n ? pipeline.pipe(\n map(([key, row]) => [key, row[mainTableAlias]] as InputRow)\n )\n : pipeline\n return resultPipeline as T\n}\n"],"names":["map","processJoinClause","filter","evaluateWhereOnNamespacedRow","processGroupBy","processOrderBy","processSelect"],"mappings":";;;;;;;;AAoBgB,SAAA,qBACd,OACA,QACG;AAEG,QAAA,YAAY,EAAE,GAAG,OAAO;AAG9B,MAAI,MAAM,QAAQ,MAAM,KAAK,SAAS,GAAG;AAE5B,eAAA,aAAa,MAAM,MAAM;AAE9B,UAAA,CAAC,UAAU,IAAI;AACX,cAAA,IAAI,MAAM,uCAAuC;AAAA,MAAA;AAIrD,UAAA,UAAU,UAAU,EAAE,GAAG;AAC3B,cAAM,IAAI,MAAM,kBAAkB,UAAU,EAAE,kBAAkB;AAAA,MAAA;AAIlE,YAAM,uBAAuB,EAAE,GAAG,WAAW,MAAM,OAAU;AAI7D,YAAM,oBAAoB;AAAA,QACxB;AAAA,QACA;AAAA,MACF;AAGU,gBAAA,UAAU,EAAE,IAAI;AAAA,IAAA;AAAA,EAC5B;AAIF,QAAM,SAAsC,CAAC;AAGvC,QAAA,iBAAiB,MAAM,MAAM,MAAM;AAGnC,QAAA,QAAQ,UAAU,MAAM,IAAI;AAClC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,oBAAoB,MAAM,IAAI,2BAA2B;AAAA,EAAA;AAG3E,SAAO,cAAc,IAAI;AAGzB,MAAI,WAAqC,MAAM;AAAA,IAC7CA,OAAAA,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM;AAEZ,YAAA,MAAM,CAAC,KAAK,EAAE,CAAC,cAAc,GAAG,KAAK;AAIpC,aAAA;AAAA,IACR,CAAA;AAAA,EACH;AAGA,MAAI,MAAM,MAAM;AACH,eAAAC,MAAA;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EAAA;AAIF,MAAI,MAAM,OAAO;AACf,eAAW,SAAS;AAAA,MAClBC,OAAAA,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM;AACtB,cAAM,SAASC,WAAA;AAAA,UACb;AAAA,UACA,MAAM;AAAA,UACN;AAAA,QACF;AACO,eAAA;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EAAA;AAIF,MAAI,MAAM,SAAS;AACN,eAAAC,QAAA,eAAe,UAAU,OAAO,cAAc;AAAA,EAAA;AAK3D,MAAI,MAAM,QAAQ;AAChB,eAAW,SAAS;AAAA,MAClBF,OAAAA,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM;AAGtB,cAAM,SAASC,WAAA;AAAA,UACb;AAAA,UACA,MAAM;AAAA,UACN;AAAA,QACF;AACO,eAAA;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EAAA;AAIF,MAAI,MAAM,SAAS;AACN,eAAAE,QAAA,eAAe,UAAU,OAAO,cAAc;AAAA,EAAA,WAChD,MAAM,UAAU,UAAa,MAAM,WAAW,QAAW;AAElE,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EAAA;AAIF,QAAM,iBAAyD,MAAM,SACjEC,OAAAA,cAAc,UAAU,OAAO,gBAAgB,SAAS,IACxD,CAAC,MAAM,QAAQ,CAAC,MAAM,UACpB,SAAS;AAAA,IACPN,WAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,cAAc,CAAC,CAAa;AAAA,EAAA,IAE5D;AACC,SAAA;AACT;;"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Query } from './schema.js';
|
|
2
|
-
import { IStreamBuilder } from '@electric-sql/d2mini';
|
|
3
|
-
import { KeyedStream } from '../types.js';
|
|
4
|
-
/**
|
|
5
|
-
* Compiles a query into a D2 pipeline
|
|
6
|
-
* @param query The query to compile
|
|
7
|
-
* @param inputs Mapping of table names to input streams
|
|
8
|
-
* @returns A stream builder representing the compiled query
|
|
9
|
-
*/
|
|
10
|
-
export declare function compileQueryPipeline<T extends IStreamBuilder<unknown>>(query: Query, inputs: Record<string, KeyedStream>): T;
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
class BaseQueryBuilder {
|
|
4
|
-
/**
|
|
5
|
-
* Create a new QueryBuilder instance.
|
|
6
|
-
*/
|
|
7
|
-
constructor(query = {}) {
|
|
8
|
-
this.query = {};
|
|
9
|
-
this.query = query;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Specify the collection to query from.
|
|
13
|
-
* This is the first method that must be called in the chain.
|
|
14
|
-
*
|
|
15
|
-
* @param collection The collection name to query from
|
|
16
|
-
* @param as Optional alias for the collection
|
|
17
|
-
* @returns A new QueryBuilder with the from clause set
|
|
18
|
-
*/
|
|
19
|
-
from(collection, as) {
|
|
20
|
-
if (typeof collection === `object` && collection !== null) {
|
|
21
|
-
return this.fromCollectionRef(collection);
|
|
22
|
-
} else if (typeof collection === `string`) {
|
|
23
|
-
return this.fromInputReference(
|
|
24
|
-
collection,
|
|
25
|
-
as
|
|
26
|
-
);
|
|
27
|
-
} else {
|
|
28
|
-
throw new Error(`Invalid collection type`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
fromCollectionRef(collectionRef) {
|
|
32
|
-
var _a;
|
|
33
|
-
const keys = Object.keys(collectionRef);
|
|
34
|
-
if (keys.length !== 1) {
|
|
35
|
-
throw new Error(`Expected exactly one key`);
|
|
36
|
-
}
|
|
37
|
-
const key = keys[0];
|
|
38
|
-
const collection = collectionRef[key];
|
|
39
|
-
const newBuilder = new BaseQueryBuilder();
|
|
40
|
-
Object.assign(newBuilder.query, this.query);
|
|
41
|
-
newBuilder.query.from = key;
|
|
42
|
-
(_a = newBuilder.query).collections ?? (_a.collections = {});
|
|
43
|
-
newBuilder.query.collections[key] = collection;
|
|
44
|
-
return newBuilder;
|
|
45
|
-
}
|
|
46
|
-
fromInputReference(collection, as) {
|
|
47
|
-
const newBuilder = new BaseQueryBuilder();
|
|
48
|
-
Object.assign(newBuilder.query, this.query);
|
|
49
|
-
newBuilder.query.from = collection;
|
|
50
|
-
if (as) {
|
|
51
|
-
newBuilder.query.as = as;
|
|
52
|
-
}
|
|
53
|
-
return newBuilder;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Specify what columns to select.
|
|
57
|
-
* Overwrites any previous select clause.
|
|
58
|
-
* Also supports callback functions that receive the row context and return selected data.
|
|
59
|
-
*
|
|
60
|
-
* @param selects The columns to select (can include callbacks)
|
|
61
|
-
* @returns A new QueryBuilder with the select clause set
|
|
62
|
-
*/
|
|
63
|
-
select(...selects) {
|
|
64
|
-
const validatedSelects = selects.map((select) => {
|
|
65
|
-
if (typeof select === `object` && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
66
|
-
select !== null && !Array.isArray(select)) {
|
|
67
|
-
const result = {};
|
|
68
|
-
for (const [key, value] of Object.entries(select)) {
|
|
69
|
-
if (typeof value === `object` && value !== null && !Array.isArray(value)) {
|
|
70
|
-
const keys = Object.keys(value);
|
|
71
|
-
if (keys.length === 1) {
|
|
72
|
-
const funcName = keys[0];
|
|
73
|
-
const allowedFunctions = [
|
|
74
|
-
`SUM`,
|
|
75
|
-
`COUNT`,
|
|
76
|
-
`AVG`,
|
|
77
|
-
`MIN`,
|
|
78
|
-
`MAX`,
|
|
79
|
-
`DATE`,
|
|
80
|
-
`JSON_EXTRACT`,
|
|
81
|
-
`JSON_EXTRACT_PATH`,
|
|
82
|
-
`UPPER`,
|
|
83
|
-
`LOWER`,
|
|
84
|
-
`COALESCE`,
|
|
85
|
-
`CONCAT`,
|
|
86
|
-
`LENGTH`,
|
|
87
|
-
`ORDER_INDEX`
|
|
88
|
-
];
|
|
89
|
-
if (!allowedFunctions.includes(funcName)) {
|
|
90
|
-
console.warn(
|
|
91
|
-
`Unsupported function: ${funcName}. Expected one of: ${allowedFunctions.join(`, `)}`
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
result[key] = value;
|
|
97
|
-
}
|
|
98
|
-
return result;
|
|
99
|
-
}
|
|
100
|
-
return select;
|
|
101
|
-
});
|
|
102
|
-
if (this._query.orderBy) {
|
|
103
|
-
validatedSelects.push({ _orderByIndex: { ORDER_INDEX: `fractional` } });
|
|
104
|
-
}
|
|
105
|
-
const newBuilder = new BaseQueryBuilder(
|
|
106
|
-
this.query
|
|
107
|
-
);
|
|
108
|
-
newBuilder.query.select = validatedSelects;
|
|
109
|
-
return newBuilder;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Add a where clause to filter the results.
|
|
113
|
-
* Can be called multiple times to add AND conditions.
|
|
114
|
-
* Also supports callback functions that receive the row context.
|
|
115
|
-
*
|
|
116
|
-
* @param leftOrConditionOrCallback The left operand, complete condition, or callback function
|
|
117
|
-
* @param operator Optional comparison operator
|
|
118
|
-
* @param right Optional right operand
|
|
119
|
-
* @returns A new QueryBuilder with the where clause added
|
|
120
|
-
*/
|
|
121
|
-
where(leftOrConditionOrCallback, operator, right) {
|
|
122
|
-
const newBuilder = new BaseQueryBuilder();
|
|
123
|
-
Object.assign(newBuilder.query, this.query);
|
|
124
|
-
let condition;
|
|
125
|
-
if (typeof leftOrConditionOrCallback === `function`) {
|
|
126
|
-
condition = leftOrConditionOrCallback;
|
|
127
|
-
} else if (operator !== void 0 && right !== void 0) {
|
|
128
|
-
condition = [leftOrConditionOrCallback, operator, right];
|
|
129
|
-
} else {
|
|
130
|
-
condition = leftOrConditionOrCallback;
|
|
131
|
-
}
|
|
132
|
-
if (!newBuilder.query.where) {
|
|
133
|
-
newBuilder.query.where = [condition];
|
|
134
|
-
} else {
|
|
135
|
-
newBuilder.query.where = [...newBuilder.query.where, condition];
|
|
136
|
-
}
|
|
137
|
-
return newBuilder;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Add a having clause to filter the grouped results.
|
|
141
|
-
* Can be called multiple times to add AND conditions.
|
|
142
|
-
* Also supports callback functions that receive the row context.
|
|
143
|
-
*
|
|
144
|
-
* @param leftOrConditionOrCallback The left operand, complete condition, or callback function
|
|
145
|
-
* @param operator Optional comparison operator
|
|
146
|
-
* @param right Optional right operand
|
|
147
|
-
* @returns A new QueryBuilder with the having clause added
|
|
148
|
-
*/
|
|
149
|
-
having(leftOrConditionOrCallback, operator, right) {
|
|
150
|
-
const newBuilder = new BaseQueryBuilder();
|
|
151
|
-
Object.assign(newBuilder.query, this.query);
|
|
152
|
-
let condition;
|
|
153
|
-
if (typeof leftOrConditionOrCallback === `function`) {
|
|
154
|
-
condition = leftOrConditionOrCallback;
|
|
155
|
-
} else if (operator !== void 0 && right !== void 0) {
|
|
156
|
-
condition = [leftOrConditionOrCallback, operator, right];
|
|
157
|
-
} else {
|
|
158
|
-
condition = leftOrConditionOrCallback;
|
|
159
|
-
}
|
|
160
|
-
if (!newBuilder.query.having) {
|
|
161
|
-
newBuilder.query.having = [condition];
|
|
162
|
-
} else {
|
|
163
|
-
newBuilder.query.having = [...newBuilder.query.having, condition];
|
|
164
|
-
}
|
|
165
|
-
return newBuilder;
|
|
166
|
-
}
|
|
167
|
-
join(joinClause) {
|
|
168
|
-
if (typeof joinClause.from === `object` && joinClause.from !== null) {
|
|
169
|
-
return this.joinCollectionRef(
|
|
170
|
-
joinClause
|
|
171
|
-
);
|
|
172
|
-
} else {
|
|
173
|
-
return this.joinInputReference(
|
|
174
|
-
joinClause
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
joinCollectionRef(joinClause) {
|
|
179
|
-
var _a;
|
|
180
|
-
const newBuilder = new BaseQueryBuilder();
|
|
181
|
-
Object.assign(newBuilder.query, this.query);
|
|
182
|
-
const keys = Object.keys(joinClause.from);
|
|
183
|
-
if (keys.length !== 1) {
|
|
184
|
-
throw new Error(`Expected exactly one key in CollectionRef`);
|
|
185
|
-
}
|
|
186
|
-
const key = keys[0];
|
|
187
|
-
const collection = joinClause.from[key];
|
|
188
|
-
if (!collection) {
|
|
189
|
-
throw new Error(`Collection not found for key: ${key}`);
|
|
190
|
-
}
|
|
191
|
-
const joinClauseCopy = {
|
|
192
|
-
type: joinClause.type,
|
|
193
|
-
from: key,
|
|
194
|
-
on: joinClause.on,
|
|
195
|
-
where: joinClause.where
|
|
196
|
-
};
|
|
197
|
-
if (!newBuilder.query.join) {
|
|
198
|
-
newBuilder.query.join = [joinClauseCopy];
|
|
199
|
-
} else {
|
|
200
|
-
newBuilder.query.join = [...newBuilder.query.join, joinClauseCopy];
|
|
201
|
-
}
|
|
202
|
-
(_a = newBuilder.query).collections ?? (_a.collections = {});
|
|
203
|
-
newBuilder.query.collections[key] = collection;
|
|
204
|
-
return newBuilder;
|
|
205
|
-
}
|
|
206
|
-
joinInputReference(joinClause) {
|
|
207
|
-
const newBuilder = new BaseQueryBuilder();
|
|
208
|
-
Object.assign(newBuilder.query, this.query);
|
|
209
|
-
const joinClauseCopy = { ...joinClause };
|
|
210
|
-
if (!newBuilder.query.join) {
|
|
211
|
-
newBuilder.query.join = [joinClauseCopy];
|
|
212
|
-
} else {
|
|
213
|
-
newBuilder.query.join = [...newBuilder.query.join, joinClauseCopy];
|
|
214
|
-
}
|
|
215
|
-
joinClause.as ?? joinClause.from;
|
|
216
|
-
return newBuilder;
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Add an orderBy clause to sort the results.
|
|
220
|
-
* Overwrites any previous orderBy clause.
|
|
221
|
-
*
|
|
222
|
-
* @param orderBy The order specification
|
|
223
|
-
* @returns A new QueryBuilder with the orderBy clause set
|
|
224
|
-
*/
|
|
225
|
-
orderBy(orderBy) {
|
|
226
|
-
const newBuilder = new BaseQueryBuilder();
|
|
227
|
-
Object.assign(newBuilder.query, this.query);
|
|
228
|
-
newBuilder.query.orderBy = orderBy;
|
|
229
|
-
newBuilder.query.select = [
|
|
230
|
-
...newBuilder.query.select ?? [],
|
|
231
|
-
{ _orderByIndex: { ORDER_INDEX: `fractional` } }
|
|
232
|
-
];
|
|
233
|
-
return newBuilder;
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Set a limit on the number of results returned.
|
|
237
|
-
*
|
|
238
|
-
* @param limit Maximum number of results to return
|
|
239
|
-
* @returns A new QueryBuilder with the limit set
|
|
240
|
-
*/
|
|
241
|
-
limit(limit) {
|
|
242
|
-
const newBuilder = new BaseQueryBuilder();
|
|
243
|
-
Object.assign(newBuilder.query, this.query);
|
|
244
|
-
newBuilder.query.limit = limit;
|
|
245
|
-
return newBuilder;
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Set an offset to skip a number of results.
|
|
249
|
-
*
|
|
250
|
-
* @param offset Number of results to skip
|
|
251
|
-
* @returns A new QueryBuilder with the offset set
|
|
252
|
-
*/
|
|
253
|
-
offset(offset) {
|
|
254
|
-
const newBuilder = new BaseQueryBuilder();
|
|
255
|
-
Object.assign(newBuilder.query, this.query);
|
|
256
|
-
newBuilder.query.offset = offset;
|
|
257
|
-
return newBuilder;
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Add a groupBy clause to group the results by one or more columns.
|
|
261
|
-
*
|
|
262
|
-
* @param groupBy The column(s) to group by
|
|
263
|
-
* @returns A new QueryBuilder with the groupBy clause set
|
|
264
|
-
*/
|
|
265
|
-
groupBy(groupBy) {
|
|
266
|
-
const newBuilder = new BaseQueryBuilder();
|
|
267
|
-
Object.assign(newBuilder.query, this.query);
|
|
268
|
-
newBuilder.query.groupBy = groupBy;
|
|
269
|
-
return newBuilder;
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Define a Common Table Expression (CTE) that can be referenced in the main query.
|
|
273
|
-
* This allows referencing the CTE by name in subsequent from/join clauses.
|
|
274
|
-
*
|
|
275
|
-
* @param name The name of the CTE
|
|
276
|
-
* @param queryBuilderCallback A function that builds the CTE query
|
|
277
|
-
* @returns A new QueryBuilder with the CTE added
|
|
278
|
-
*/
|
|
279
|
-
with(name, queryBuilderCallback) {
|
|
280
|
-
const newBuilder = new BaseQueryBuilder();
|
|
281
|
-
Object.assign(newBuilder.query, this.query);
|
|
282
|
-
const cteBuilder = new BaseQueryBuilder();
|
|
283
|
-
const cteQueryBuilder = queryBuilderCallback(
|
|
284
|
-
cteBuilder
|
|
285
|
-
);
|
|
286
|
-
const cteQuery = cteQueryBuilder._query;
|
|
287
|
-
const withQuery = {
|
|
288
|
-
...cteQuery,
|
|
289
|
-
as: name
|
|
290
|
-
};
|
|
291
|
-
if (!newBuilder.query.with) {
|
|
292
|
-
newBuilder.query.with = [withQuery];
|
|
293
|
-
} else {
|
|
294
|
-
newBuilder.query.with = [...newBuilder.query.with, withQuery];
|
|
295
|
-
}
|
|
296
|
-
return newBuilder;
|
|
297
|
-
}
|
|
298
|
-
get _query() {
|
|
299
|
-
return this.query;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
function queryBuilder() {
|
|
303
|
-
return new BaseQueryBuilder();
|
|
304
|
-
}
|
|
305
|
-
exports.BaseQueryBuilder = BaseQueryBuilder;
|
|
306
|
-
exports.queryBuilder = queryBuilder;
|
|
307
|
-
//# sourceMappingURL=query-builder.cjs.map
|