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.
@@ -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 ValuePick(number, {
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
 
@@ -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, false).sql;
177
+ return queryToSql(this.#queryParts, null).sql;
189
178
  }
190
179
 
191
180
  /**
@@ -45,14 +45,16 @@ function groupByFields(groupBy, values) {
45
45
 
46
46
  /**
47
47
  * @param {QueryObj} query
48
- * @param {boolean} [useBindedValues=true]
48
+ * @param {any[] | null} [values]
49
49
  * @returns {{sql: string, values: any[] | null}}
50
50
  */
51
- function queryToSql(query, useBindedValues = true) {
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 ${query.from}`;
57
+ result += '\n' + `FROM ${from}`;
56
58
  if (query.where) {
57
59
  result += '\n' + `WHERE ${sql(query.where, values)}`;
58
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xcraft-core-pickaxe",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Query builder",
5
5
  "main": "index.js",
6
6
  "scripts": {