xcraft-core-pickaxe 0.1.5 → 0.1.7
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/lib/operator-to-sql.js +27 -0
- package/lib/operators.js +48 -0
- package/lib/picks.js +68 -4
- package/lib/query-builder.js +5 -16
- package/lib/query-to-sql.js +6 -4
- package/package.json +1 -1
package/lib/operator-to-sql.js
CHANGED
|
@@ -124,6 +124,24 @@ const operators = {
|
|
|
124
124
|
return `(${sqlConditions.join(' OR ')})`;
|
|
125
125
|
},
|
|
126
126
|
|
|
127
|
+
abs({value}, values) {
|
|
128
|
+
return `ABS(${sql(value, values)})`;
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
plus({values: list}, values) {
|
|
132
|
+
return `(${list
|
|
133
|
+
.map((value) => sql(value, values))
|
|
134
|
+
.filter(Boolean)
|
|
135
|
+
.join(' + ')})`;
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
minus({values: list}, values) {
|
|
139
|
+
return `(${list
|
|
140
|
+
.map((value) => sql(value, values))
|
|
141
|
+
.filter(Boolean)
|
|
142
|
+
.join(' - ')})`;
|
|
143
|
+
},
|
|
144
|
+
|
|
127
145
|
length({list}, values) {
|
|
128
146
|
return `json_array_length(${sql(list, values)})`;
|
|
129
147
|
},
|
|
@@ -148,6 +166,15 @@ const operators = {
|
|
|
148
166
|
)`;
|
|
149
167
|
},
|
|
150
168
|
|
|
169
|
+
query({query}, values) {
|
|
170
|
+
const {queryToSql} = require('./query-to-sql.js');
|
|
171
|
+
return `(${queryToSql(query, values).sql})`;
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
each({value}, values) {
|
|
175
|
+
return `json_each(${sql(value, values)})`;
|
|
176
|
+
},
|
|
177
|
+
|
|
151
178
|
eachValue(_, values) {
|
|
152
179
|
return 'json_each.value';
|
|
153
180
|
},
|
package/lib/operators.js
CHANGED
|
@@ -168,6 +168,33 @@ const operators = {
|
|
|
168
168
|
});
|
|
169
169
|
},
|
|
170
170
|
|
|
171
|
+
abs(value) {
|
|
172
|
+
value = op(value);
|
|
173
|
+
return /** @type {const} */ ({
|
|
174
|
+
operator: 'abs',
|
|
175
|
+
type: number,
|
|
176
|
+
value,
|
|
177
|
+
});
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
plus(...values) {
|
|
181
|
+
values = values.map(op);
|
|
182
|
+
return /** @type {const} */ ({
|
|
183
|
+
operator: 'plus',
|
|
184
|
+
type: number,
|
|
185
|
+
values,
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
minus(...values) {
|
|
190
|
+
values = values.map(op);
|
|
191
|
+
return /** @type {const} */ ({
|
|
192
|
+
operator: 'minus',
|
|
193
|
+
type: number,
|
|
194
|
+
values,
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
|
|
171
198
|
length(list) {
|
|
172
199
|
return /** @type {const} */ ({
|
|
173
200
|
operator: 'length',
|
|
@@ -192,6 +219,20 @@ const operators = {
|
|
|
192
219
|
});
|
|
193
220
|
},
|
|
194
221
|
|
|
222
|
+
query(query) {
|
|
223
|
+
return /** @type {const} */ ({
|
|
224
|
+
operator: 'query',
|
|
225
|
+
query,
|
|
226
|
+
});
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
each(value) {
|
|
230
|
+
return /** @type {const} */ ({
|
|
231
|
+
operator: 'each',
|
|
232
|
+
value,
|
|
233
|
+
});
|
|
234
|
+
},
|
|
235
|
+
|
|
195
236
|
eachValue() {
|
|
196
237
|
return /** @type {const} */ ({
|
|
197
238
|
operator: 'eachValue',
|
|
@@ -315,4 +356,11 @@ const operators = {
|
|
|
315
356
|
* @typedef {Values<{[k in keyof typeof operators] : ReturnType<typeof operators[k]>}>} Operator
|
|
316
357
|
*/
|
|
317
358
|
|
|
359
|
+
/**
|
|
360
|
+
* @typedef {Operators["count"] | Operators["avg"] | Operators["max"] | Operators["min"] | Operators["sum"] | Operators["groupArray"]} Aggregator
|
|
361
|
+
*/
|
|
362
|
+
/**
|
|
363
|
+
* @typedef {Operators["abs"] | Operators["plus"] | Operators["minus"]} MathOperator
|
|
364
|
+
*/
|
|
365
|
+
|
|
318
366
|
module.exports = operators;
|
package/lib/picks.js
CHANGED
|
@@ -12,15 +12,15 @@ const {
|
|
|
12
12
|
number,
|
|
13
13
|
StringType,
|
|
14
14
|
string,
|
|
15
|
+
NumberType,
|
|
15
16
|
} = require('xcraft-core-stones');
|
|
16
17
|
|
|
17
18
|
const $o = require('./operators.js');
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* @typedef {import('./operators.js').Operators} Operators
|
|
21
|
-
*/
|
|
22
|
-
/**
|
|
23
22
|
* @typedef {import('./operators.js').Operator} Operator
|
|
23
|
+
* @typedef {import('./operators.js').Aggregator} Aggregator
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -49,7 +49,7 @@ const $o = require('./operators.js');
|
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* @template {Type} T
|
|
52
|
-
* @typedef { [T] extends [ArrayType<infer V>] ? ArrayPick<V> : [T] extends [ObjectType<infer S>] ? ObjectPick<S> : [T] extends [ObjectMapType<infer V>] ? RecordPick<StringType,V> : [T] extends [RecordType<infer K,infer V>] ? RecordPick<K,V> : ValuePick<T>} PickOfType
|
|
52
|
+
* @typedef { [T] extends [ArrayType<infer V>] ? ArrayPick<V> : [T] extends [ObjectType<infer S>] ? ObjectPick<S> : [T] extends [ObjectMapType<infer V>] ? RecordPick<StringType,V> : [T] extends [RecordType<infer K,infer V>] ? RecordPick<K,V> : [T] extends [NumberType] ? NumberPick : ValuePick<T>} PickOfType
|
|
53
53
|
*/
|
|
54
54
|
/**
|
|
55
55
|
* @template {AnyTypeOrShape} T
|
|
@@ -155,6 +155,29 @@ class ValuePick {
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
/**
|
|
159
|
+
* @extends {ValuePick<NumberType>}
|
|
160
|
+
*/
|
|
161
|
+
class NumberPick extends ValuePick {
|
|
162
|
+
abs() {
|
|
163
|
+
return $o.abs(this.value);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param {number | ValuePick<NumberType>} value
|
|
168
|
+
*/
|
|
169
|
+
plus(value) {
|
|
170
|
+
return $o.plus(this.value, value);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @param {number | ValuePick<NumberType>} value
|
|
175
|
+
*/
|
|
176
|
+
minus(value) {
|
|
177
|
+
return $o.minus(this.value, value);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
158
181
|
/**
|
|
159
182
|
* @template {ObjectShape} T
|
|
160
183
|
*/
|
|
@@ -277,6 +300,27 @@ class RecordPick {
|
|
|
277
300
|
return $o.not(this.some((...args) => $o.not(func(...args))));
|
|
278
301
|
}
|
|
279
302
|
|
|
303
|
+
/**
|
|
304
|
+
* @param {(value: PickOf<V>, key: PickOf<K>) => Aggregator} fct
|
|
305
|
+
*/
|
|
306
|
+
select(fct) {
|
|
307
|
+
return $o.query({
|
|
308
|
+
from: $o.each(this.value),
|
|
309
|
+
select: [
|
|
310
|
+
fct(
|
|
311
|
+
makePick(this.#type.valuesType, {
|
|
312
|
+
field: $o.eachValue(),
|
|
313
|
+
path: [],
|
|
314
|
+
}),
|
|
315
|
+
makePick(this.#type.keysType, {
|
|
316
|
+
field: $o.eachKey(),
|
|
317
|
+
path: [],
|
|
318
|
+
})
|
|
319
|
+
),
|
|
320
|
+
],
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
280
324
|
/**
|
|
281
325
|
* @returns {ArrayPick<K>}
|
|
282
326
|
*/
|
|
@@ -340,7 +384,7 @@ class ArrayPick {
|
|
|
340
384
|
}
|
|
341
385
|
|
|
342
386
|
get length() {
|
|
343
|
-
return new
|
|
387
|
+
return new NumberPick(number, {
|
|
344
388
|
field: $o.length(this.value),
|
|
345
389
|
path: [],
|
|
346
390
|
});
|
|
@@ -374,6 +418,23 @@ class ArrayPick {
|
|
|
374
418
|
every(func) {
|
|
375
419
|
return $o.not(this.some((...args) => $o.not(func(...args))));
|
|
376
420
|
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* @param {(value: PickOf<T>) => Aggregator} fct
|
|
424
|
+
*/
|
|
425
|
+
select(fct) {
|
|
426
|
+
return $o.query({
|
|
427
|
+
from: $o.each(this.value),
|
|
428
|
+
select: [
|
|
429
|
+
fct(
|
|
430
|
+
makePick(this.#type.valuesType, {
|
|
431
|
+
field: $o.eachValue(),
|
|
432
|
+
path: [],
|
|
433
|
+
})
|
|
434
|
+
),
|
|
435
|
+
],
|
|
436
|
+
});
|
|
437
|
+
}
|
|
377
438
|
}
|
|
378
439
|
|
|
379
440
|
/**
|
|
@@ -437,6 +498,9 @@ function makeTypePick(type, context) {
|
|
|
437
498
|
if (type instanceof RecordType) {
|
|
438
499
|
return /** @type {any} */ (new RecordPick(type, context));
|
|
439
500
|
}
|
|
501
|
+
if (type instanceof NumberType) {
|
|
502
|
+
return /** @type {any} */ (new NumberPick(type, context));
|
|
503
|
+
}
|
|
440
504
|
return /** @type {any} */ (new ValuePick(type, context));
|
|
441
505
|
}
|
|
442
506
|
|
package/lib/query-builder.js
CHANGED
|
@@ -10,30 +10,19 @@ const {
|
|
|
10
10
|
const operators = require('./operators.js');
|
|
11
11
|
const {rowPick, ValuePick, RowPick, ObjectPick} = require('./picks.js');
|
|
12
12
|
const {queryToSql} = require('./query-to-sql.js');
|
|
13
|
-
/**
|
|
14
|
-
* @typedef {import("./operators.js").Operator} Operator
|
|
15
|
-
*/
|
|
16
13
|
/**
|
|
17
14
|
* @typedef {import("./operators.js").Operators} Operators
|
|
15
|
+
* @typedef {import("./operators.js").Operator} Operator
|
|
16
|
+
* @typedef {import("./operators.js").Aggregator} Aggregator
|
|
17
|
+
* @typedef {import("./operators.js").MathOperator} MathOperator
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
* @template {AnyTypeOrShape} T
|
|
22
|
-
* @typedef {import("./picks.js").PickOf<T>} PickOf
|
|
23
|
-
*/
|
|
24
20
|
/**
|
|
25
21
|
* @typedef {import("./picks.js").AnyPick} AnyPick
|
|
26
22
|
*/
|
|
27
|
-
/**
|
|
28
|
-
* @typedef {import("./picks.js").Path} Path
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @typedef {Operators["count"] | Operators["avg"] | Operators["max"] | Operators["min"] | Operators["sum"] | Operators["groupArray"]} Aggregator
|
|
33
|
-
*/
|
|
34
23
|
|
|
35
24
|
/**
|
|
36
|
-
* @typedef {AnyPick | Aggregator} SelectValue
|
|
25
|
+
* @typedef {AnyPick | Aggregator | MathOperator} SelectValue
|
|
37
26
|
*/
|
|
38
27
|
/**
|
|
39
28
|
* @template T
|
|
@@ -185,7 +174,7 @@ class FinalQuery {
|
|
|
185
174
|
}
|
|
186
175
|
|
|
187
176
|
sql() {
|
|
188
|
-
return queryToSql(this.#queryParts,
|
|
177
|
+
return queryToSql(this.#queryParts, null).sql;
|
|
189
178
|
}
|
|
190
179
|
|
|
191
180
|
/**
|
package/lib/query-to-sql.js
CHANGED
|
@@ -45,14 +45,16 @@ function groupByFields(groupBy, values) {
|
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* @param {QueryObj} query
|
|
48
|
-
* @param {
|
|
48
|
+
* @param {any[] | null} [values]
|
|
49
49
|
* @returns {{sql: string, values: any[] | null}}
|
|
50
50
|
*/
|
|
51
|
-
function queryToSql(query,
|
|
52
|
-
const values = useBindedValues ? [] : null;
|
|
51
|
+
function queryToSql(query, values = []) {
|
|
53
52
|
const distinct = query.distinct ? 'DISTINCT ' : '';
|
|
53
|
+
// Note: query.from is not validated
|
|
54
|
+
const from =
|
|
55
|
+
typeof query.from === 'string' ? query.from : sql(query.from, values);
|
|
54
56
|
let result = `SELECT ${distinct}${selectFields(query.select, values)}`;
|
|
55
|
-
result += '\n' + `FROM ${
|
|
57
|
+
result += '\n' + `FROM ${from}`;
|
|
56
58
|
if (query.where) {
|
|
57
59
|
result += '\n' + `WHERE ${sql(query.where, values)}`;
|
|
58
60
|
}
|