xcraft-core-pickaxe 0.1.23 → 0.1.26
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/examples.js +3 -3
- package/lib/level-set-utils.js +3 -2
- package/lib/operator-to-sql.js +47 -22
- package/lib/operators.js +26 -50
- package/lib/optional-object-type.js +38 -0
- package/lib/pick-operators.js +128 -0
- package/lib/pick-or-value.js +76 -0
- package/lib/picks.js +244 -295
- package/lib/query-builder.js +140 -65
- package/lib/query-to-sql.js +8 -8
- package/package.json +1 -1
- package/test/sql.spec.js +38 -6
package/lib/examples.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-inner-declarations */
|
|
2
2
|
// @ts-check
|
|
3
|
-
const {
|
|
3
|
+
const {expressionToSql} = require('./operator-to-sql.js');
|
|
4
4
|
const {
|
|
5
5
|
string,
|
|
6
6
|
number,
|
|
@@ -80,8 +80,8 @@ example1: {
|
|
|
80
80
|
user.get('address').get('streetName').eq('Mine road')
|
|
81
81
|
);
|
|
82
82
|
|
|
83
|
-
console.log(
|
|
84
|
-
console.log(
|
|
83
|
+
console.log(expressionToSql(filter1));
|
|
84
|
+
console.log(expressionToSql(filter2));
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
example2: {
|
package/lib/level-set-utils.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/* eslint-disable jsdoc/require-returns */
|
|
2
2
|
// @ts-check
|
|
3
3
|
|
|
4
|
-
const $ = require('xcraft-core-pickaxe/lib/operators.js');
|
|
4
|
+
const {pickOperators: $} = require('xcraft-core-pickaxe/lib/pick-operators.js');
|
|
5
5
|
const {RecordPick, ValuePick} = require('./picks.js');
|
|
6
6
|
const {StringType, NumberType} = require('xcraft-core-stones');
|
|
7
|
+
const {pickFromValue} = require('./pick-or-value.js');
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @typedef {Record<string, number>} LevelSet
|
|
@@ -36,7 +37,7 @@ function levelSetHasValue2(set, key, value) {
|
|
|
36
37
|
*/
|
|
37
38
|
function levelSetIsEmpty(set) {
|
|
38
39
|
if (!(set instanceof RecordPick)) {
|
|
39
|
-
return
|
|
40
|
+
return pickFromValue(Object.keys(set).length === 0);
|
|
40
41
|
}
|
|
41
42
|
return set.keys().length.eq(0);
|
|
42
43
|
}
|
package/lib/operator-to-sql.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
-
const {isAnyPick} = require('./picks.js');
|
|
3
|
+
const {isAnyPick, BasePick} = require('./picks.js');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @typedef {import("./operators.js").
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* @typedef {import('./picks.js').AnyPick} AnyPick
|
|
6
|
+
* @typedef {import("./operators.js").Expression} Expression
|
|
10
7
|
*/
|
|
11
8
|
|
|
12
9
|
function escape(value) {
|
|
@@ -16,6 +13,16 @@ function escape(value) {
|
|
|
16
13
|
return value;
|
|
17
14
|
}
|
|
18
15
|
|
|
16
|
+
function squashValueAndPath(value, path) {
|
|
17
|
+
if (value) {
|
|
18
|
+
const operatorName = value.operator;
|
|
19
|
+
if (operatorName === 'get') {
|
|
20
|
+
return squashValueAndPath(value.value, [value.path, ...path]);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return [value, path];
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
const operators = {
|
|
20
27
|
unsafeSql({sql}, context) {
|
|
21
28
|
return sql;
|
|
@@ -23,7 +30,12 @@ const operators = {
|
|
|
23
30
|
|
|
24
31
|
value({value}, context) {
|
|
25
32
|
if (typeof value === 'boolean') {
|
|
26
|
-
return value ? 'TRUE' : 'FALSE';
|
|
33
|
+
// return value ? 'TRUE' : 'FALSE';
|
|
34
|
+
//
|
|
35
|
+
// Value 1 and 0 works better with indexed content.
|
|
36
|
+
// For example, "json_extract(action, '$.path.to.value') IS FALSE"
|
|
37
|
+
// does not use the corresponding json_extract index.
|
|
38
|
+
return value ? 1 : 0;
|
|
27
39
|
}
|
|
28
40
|
if (!context.values) {
|
|
29
41
|
return escape(value);
|
|
@@ -55,6 +67,8 @@ const operators = {
|
|
|
55
67
|
// TODO: try values.push(path) => '?'
|
|
56
68
|
// return `json_extract(${field}, ${sql(path, values)})`;
|
|
57
69
|
|
|
70
|
+
[value, path] = squashValueAndPath(value, path);
|
|
71
|
+
|
|
58
72
|
if (value) {
|
|
59
73
|
return `json_extract(${sql(value, context)}, ${escape(
|
|
60
74
|
'$.' + path.join('.')
|
|
@@ -160,6 +174,17 @@ const operators = {
|
|
|
160
174
|
return `(${sqlConditions.join(' OR ')})`;
|
|
161
175
|
},
|
|
162
176
|
|
|
177
|
+
ifNull({a, b}, context) {
|
|
178
|
+
return `IFNULL(${sql(a, context)},${sql(b, context)})`;
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
if({condition, a, b}, context) {
|
|
182
|
+
return `IF(${sql(condition, context)},${sql(a, context)},${sql(
|
|
183
|
+
b,
|
|
184
|
+
context
|
|
185
|
+
)})`;
|
|
186
|
+
},
|
|
187
|
+
|
|
163
188
|
abs({value}, context) {
|
|
164
189
|
return `ABS(${sql(value, context)})`;
|
|
165
190
|
},
|
|
@@ -270,14 +295,14 @@ const operators = {
|
|
|
270
295
|
};
|
|
271
296
|
|
|
272
297
|
/**
|
|
273
|
-
* @param {
|
|
274
|
-
* @returns {
|
|
298
|
+
* @param {Expression | BasePick} expressionOrPick
|
|
299
|
+
* @returns {Expression}
|
|
275
300
|
*/
|
|
276
|
-
function
|
|
277
|
-
if (isAnyPick(
|
|
278
|
-
return
|
|
301
|
+
function getExpression(expressionOrPick) {
|
|
302
|
+
if (isAnyPick(expressionOrPick)) {
|
|
303
|
+
return expressionOrPick.expression;
|
|
279
304
|
}
|
|
280
|
-
return
|
|
305
|
+
return expressionOrPick;
|
|
281
306
|
}
|
|
282
307
|
|
|
283
308
|
/**
|
|
@@ -286,24 +311,24 @@ function getOperator(operatorOrPick) {
|
|
|
286
311
|
* scope?: any,
|
|
287
312
|
* useTableNames?: boolean,
|
|
288
313
|
* equalOperator: 'IS' | '=',
|
|
289
|
-
* }}
|
|
314
|
+
* }} ExpressionToSqlContext
|
|
290
315
|
*/
|
|
291
316
|
|
|
292
317
|
/**
|
|
293
|
-
* @param {
|
|
294
|
-
* @param {
|
|
318
|
+
* @param {Expression | BasePick} expressionOrPick
|
|
319
|
+
* @param {ExpressionToSqlContext} context
|
|
295
320
|
* @returns {string}
|
|
296
321
|
*/
|
|
297
|
-
function sql(
|
|
298
|
-
const
|
|
299
|
-
const operatorName =
|
|
322
|
+
function sql(expressionOrPick, context) {
|
|
323
|
+
const expression = getExpression(expressionOrPick);
|
|
324
|
+
const operatorName = expression.operator;
|
|
300
325
|
if (!(operatorName in operators)) {
|
|
301
|
-
throw new Error(`Unknown operator '${JSON.stringify(
|
|
326
|
+
throw new Error(`Unknown operator for '${JSON.stringify(expression)}'`);
|
|
302
327
|
}
|
|
303
|
-
return operators[operatorName](
|
|
328
|
+
return operators[operatorName](expression, context);
|
|
304
329
|
}
|
|
305
330
|
|
|
306
|
-
function
|
|
331
|
+
function expressionToSql(operator) {
|
|
307
332
|
const context = {
|
|
308
333
|
values: [],
|
|
309
334
|
};
|
|
@@ -315,5 +340,5 @@ function operatorToSql(operator) {
|
|
|
315
340
|
|
|
316
341
|
module.exports = {
|
|
317
342
|
sql,
|
|
318
|
-
|
|
343
|
+
expressionToSql,
|
|
319
344
|
};
|
package/lib/operators.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
/* eslint-disable jsdoc/require-returns */
|
|
2
2
|
// @ts-check
|
|
3
3
|
|
|
4
|
-
const {number
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @template {AnyTypeOrShape} T
|
|
8
|
-
* @typedef {import("./picks.js").ValuePick<T>} ValuePick
|
|
9
|
-
*/
|
|
4
|
+
const {number} = require('xcraft-core-stones');
|
|
10
5
|
|
|
11
6
|
function op(value) {
|
|
12
7
|
if (value === null) {
|
|
@@ -19,9 +14,9 @@ function op(value) {
|
|
|
19
14
|
if (type === 'object' && 'operator' in value) {
|
|
20
15
|
return value;
|
|
21
16
|
}
|
|
22
|
-
const {isAnyPick} = require('./picks.js');
|
|
17
|
+
const {isAnyPick} = /** @type {any} */ (require('./picks.js'));
|
|
23
18
|
if (isAnyPick(value)) {
|
|
24
|
-
return value.
|
|
19
|
+
return value.expression;
|
|
25
20
|
}
|
|
26
21
|
|
|
27
22
|
throw new Error(`Bad value '${value}'`);
|
|
@@ -222,6 +217,23 @@ const operators = {
|
|
|
222
217
|
});
|
|
223
218
|
},
|
|
224
219
|
|
|
220
|
+
ifNull(a, b) {
|
|
221
|
+
return /** @type {const} */ ({
|
|
222
|
+
operator: 'ifNull',
|
|
223
|
+
a,
|
|
224
|
+
b,
|
|
225
|
+
});
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
if(condition, a, b) {
|
|
229
|
+
return /** @type {const} */ ({
|
|
230
|
+
operator: 'if',
|
|
231
|
+
condition: op(condition),
|
|
232
|
+
a: op(a),
|
|
233
|
+
b: op(b),
|
|
234
|
+
});
|
|
235
|
+
},
|
|
236
|
+
|
|
225
237
|
abs(value) {
|
|
226
238
|
value = op(value);
|
|
227
239
|
return /** @type {const} */ ({
|
|
@@ -330,69 +342,43 @@ const operators = {
|
|
|
330
342
|
count(field, distinct) {
|
|
331
343
|
return /** @type {const} */ ({
|
|
332
344
|
operator: 'count',
|
|
333
|
-
type: number,
|
|
334
345
|
field,
|
|
335
346
|
distinct,
|
|
336
347
|
});
|
|
337
348
|
},
|
|
338
349
|
|
|
339
|
-
/**
|
|
340
|
-
* @template {AnyTypeOrShape} T
|
|
341
|
-
* @param {ValuePick<T>} field
|
|
342
|
-
*/
|
|
343
350
|
avg(field) {
|
|
344
351
|
return /** @type {const} */ ({
|
|
345
352
|
operator: 'avg',
|
|
346
|
-
|
|
347
|
-
field: field.value,
|
|
353
|
+
field,
|
|
348
354
|
});
|
|
349
355
|
},
|
|
350
356
|
|
|
351
|
-
/**
|
|
352
|
-
* @template {AnyTypeOrShape} T
|
|
353
|
-
* @param {ValuePick<T>} field
|
|
354
|
-
*/
|
|
355
357
|
max(field) {
|
|
356
358
|
return /** @type {const} */ ({
|
|
357
359
|
operator: 'max',
|
|
358
|
-
|
|
359
|
-
field: field.value,
|
|
360
|
+
field,
|
|
360
361
|
});
|
|
361
362
|
},
|
|
362
363
|
|
|
363
|
-
/**
|
|
364
|
-
* @template {AnyTypeOrShape} T
|
|
365
|
-
* @param {ValuePick<T>} field
|
|
366
|
-
*/
|
|
367
364
|
min(field) {
|
|
368
365
|
return /** @type {const} */ ({
|
|
369
366
|
operator: 'min',
|
|
370
|
-
|
|
371
|
-
field: field.value,
|
|
367
|
+
field,
|
|
372
368
|
});
|
|
373
369
|
},
|
|
374
370
|
|
|
375
|
-
/**
|
|
376
|
-
* @template {AnyTypeOrShape} T
|
|
377
|
-
* @param {ValuePick<T>} field
|
|
378
|
-
*/
|
|
379
371
|
sum(field) {
|
|
380
372
|
return /** @type {const} */ ({
|
|
381
373
|
operator: 'sum',
|
|
382
|
-
|
|
383
|
-
field: field.value,
|
|
374
|
+
field,
|
|
384
375
|
});
|
|
385
376
|
},
|
|
386
377
|
|
|
387
|
-
/**
|
|
388
|
-
* @template {AnyTypeOrShape} T
|
|
389
|
-
* @param {ValuePick<T>} field
|
|
390
|
-
*/
|
|
391
378
|
groupArray(field) {
|
|
392
379
|
return /** @type {const} */ ({
|
|
393
380
|
operator: 'groupArray',
|
|
394
|
-
|
|
395
|
-
field: field.value,
|
|
381
|
+
field,
|
|
396
382
|
});
|
|
397
383
|
},
|
|
398
384
|
};
|
|
@@ -407,17 +393,7 @@ const operators = {
|
|
|
407
393
|
*/
|
|
408
394
|
|
|
409
395
|
/**
|
|
410
|
-
* @typedef {Values<{[k in keyof typeof operators] : ReturnType<typeof operators[k]>}>}
|
|
411
|
-
*/
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* @typedef {Operators["count"] | Operators["avg"] | Operators["max"] | Operators["min"] | Operators["sum"] | Operators["groupArray"]} Aggregator
|
|
415
|
-
*/
|
|
416
|
-
/**
|
|
417
|
-
* @typedef {Operators["eq"] | Operators["neq"] | Operators["and"] | Operators["or"] | Operators["not"] | Operators["gt"] | Operators["gte"] | Operators["lt"] | Operators["lte"] | Operators["in"] | Operators["includes"] | Operators["some"] | Operators["glob"] | Operators["like"] | Operators["match"] | Operators["unsafeSql"]} BooleanOperator
|
|
418
|
-
*/
|
|
419
|
-
/**
|
|
420
|
-
* @typedef {Operators["abs"] | Operators["plus"] | Operators["minus"]} MathOperator
|
|
396
|
+
* @typedef {Values<{[k in keyof typeof operators] : ReturnType<typeof operators[k]>}>} Expression
|
|
421
397
|
*/
|
|
422
398
|
|
|
423
399
|
module.exports = operators;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template {AnyTypeOrShape} T
|
|
3
|
+
* @typedef {T extends OptionType ? T : OptionType<T>} WrapOption
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const {toObjectType, OptionType, option} = require('xcraft-core-stones');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @template {ObjectShape} T
|
|
10
|
+
* @typedef {{[K in keyof T]: WrapOption<T[K]>}} OptionalObjectShape
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @template {ObjectShape} T
|
|
15
|
+
* @param {ObjectType<T>} type
|
|
16
|
+
* @returns {ObjectType<OptionalObjectShape<T>>}
|
|
17
|
+
*/
|
|
18
|
+
function optionalObjectType(type) {
|
|
19
|
+
return type.map((subType) =>
|
|
20
|
+
subType instanceof OptionType ? subType : option(subType)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @template {AnyObjectShape} T
|
|
26
|
+
* @param {T} shape
|
|
27
|
+
* @returns {OptionalObjectShape<GetShape<T>>}
|
|
28
|
+
*/
|
|
29
|
+
function optionalObjectShape(shape) {
|
|
30
|
+
const type = toObjectType(shape);
|
|
31
|
+
const optionalType = optionalObjectType(type);
|
|
32
|
+
return optionalType.properties;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
optionalObjectType,
|
|
37
|
+
optionalObjectShape,
|
|
38
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/* eslint-disable jsdoc/require-returns */
|
|
2
|
+
// @ts-check
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
array,
|
|
6
|
+
number,
|
|
7
|
+
boolean,
|
|
8
|
+
union,
|
|
9
|
+
UnionType,
|
|
10
|
+
any,
|
|
11
|
+
} = require('xcraft-core-stones');
|
|
12
|
+
const $o = require('./operators.js');
|
|
13
|
+
const {
|
|
14
|
+
BasePick,
|
|
15
|
+
ValuePick,
|
|
16
|
+
BooleanPick,
|
|
17
|
+
NumberPick,
|
|
18
|
+
makePick,
|
|
19
|
+
ArrayPick,
|
|
20
|
+
} = require('./picks.js');
|
|
21
|
+
const {getPickOrValueType} = require('./pick-or-value.js');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {import('./pick-or-value.js').PickOrValue} PickOrValue
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @template {PickOrValue} T
|
|
29
|
+
* @typedef {import('./pick-or-value.js').PickOrValueType<T>} PickOrValueType
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const pickOperators = {
|
|
33
|
+
...$o,
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {string} sql
|
|
37
|
+
*/
|
|
38
|
+
unsafeSql(sql) {
|
|
39
|
+
return new BasePick(any, $o.unsafeSql(sql));
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {BooleanPick} value
|
|
44
|
+
* @returns {BooleanPick}
|
|
45
|
+
*/
|
|
46
|
+
not(value) {
|
|
47
|
+
return new BooleanPick(boolean, $o.not(value));
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {BooleanPick[]} conditions
|
|
52
|
+
* @returns {BooleanPick}
|
|
53
|
+
*/
|
|
54
|
+
and(...conditions) {
|
|
55
|
+
return new BooleanPick(boolean, $o.and(...conditions));
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {BooleanPick[]} conditions
|
|
60
|
+
* @returns {BooleanPick}
|
|
61
|
+
*/
|
|
62
|
+
or(...conditions) {
|
|
63
|
+
return new BooleanPick(boolean, $o.or(...conditions));
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @template {PickOrValue} T
|
|
68
|
+
* @template {PickOrValue} U
|
|
69
|
+
* @param {BooleanPick} condition
|
|
70
|
+
* @param {T} a
|
|
71
|
+
* @param {U} b
|
|
72
|
+
* @returns {ValuePick<UnionType<[PickOrValueType<T>, PickOrValueType<U>]>>}
|
|
73
|
+
*/
|
|
74
|
+
if(condition, a, b) {
|
|
75
|
+
const newType = union(getPickOrValueType(a), getPickOrValueType(b));
|
|
76
|
+
return new ValuePick(newType, $o.if(condition, a, b));
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {BasePick} [field]
|
|
81
|
+
* @param {boolean} [distinct]
|
|
82
|
+
*/
|
|
83
|
+
count(field, distinct) {
|
|
84
|
+
return new NumberPick(number, $o.count(field, distinct));
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {NumberPick} field
|
|
89
|
+
*/
|
|
90
|
+
avg(field) {
|
|
91
|
+
return new NumberPick(number, $o.avg(field));
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @template {AnyTypeOrShape} T
|
|
96
|
+
* @param {ValuePick<T>} field
|
|
97
|
+
*/
|
|
98
|
+
max(field) {
|
|
99
|
+
return makePick(field.type, $o.max(field));
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @template {AnyTypeOrShape} T
|
|
104
|
+
* @param {ValuePick<T>} field
|
|
105
|
+
*/
|
|
106
|
+
min(field) {
|
|
107
|
+
return makePick(field.type, $o.min(field));
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param {NumberPick} field
|
|
112
|
+
*/
|
|
113
|
+
sum(field) {
|
|
114
|
+
return new NumberPick(number, $o.sum(field));
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @template {AnyTypeOrShape} T
|
|
119
|
+
* @param {ValuePick<T>} field
|
|
120
|
+
*/
|
|
121
|
+
groupArray(field) {
|
|
122
|
+
return new ArrayPick(array(field.type), $o.groupArray(field));
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
module.exports = {
|
|
127
|
+
pickOperators,
|
|
128
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* eslint-disable jsdoc/require-returns */
|
|
2
|
+
// @ts-check
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
number,
|
|
6
|
+
NumberType,
|
|
7
|
+
string,
|
|
8
|
+
StringType,
|
|
9
|
+
boolean,
|
|
10
|
+
BooleanType,
|
|
11
|
+
} = require('xcraft-core-stones');
|
|
12
|
+
const {BasePick, makeTypePick} = require('./picks.js');
|
|
13
|
+
const $o = require('./operators.js');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {string | number | boolean} PickValue
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {BasePick<any> | PickValue} PickOrValue
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @template {PickValue} T
|
|
25
|
+
* @typedef {T extends boolean ? BooleanType : T extends number ? NumberType : T extends string ? StringType : never} GetValueType
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @template {PickOrValue} T
|
|
30
|
+
* @typedef {T extends BasePick<infer U> ? U : T extends PickValue ? GetValueType<T> : never} PickOrValueType
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @template {PickValue} T
|
|
35
|
+
* @param {T} value
|
|
36
|
+
* @returns {GetValueType<T>}
|
|
37
|
+
*/
|
|
38
|
+
function getValueType(value) {
|
|
39
|
+
if (typeof value === 'string') {
|
|
40
|
+
return /** @type {any} */ (string);
|
|
41
|
+
}
|
|
42
|
+
if (typeof value === 'number') {
|
|
43
|
+
return /** @type {any} */ (number);
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === 'boolean') {
|
|
46
|
+
return /** @type {any} */ (boolean);
|
|
47
|
+
}
|
|
48
|
+
throw new Error('Unknown value type');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @template {PickOrValue} T
|
|
53
|
+
* @param {T} pickOrValue
|
|
54
|
+
* @returns {PickOrValueType<T>}
|
|
55
|
+
*/
|
|
56
|
+
function getPickOrValueType(pickOrValue) {
|
|
57
|
+
if (pickOrValue instanceof BasePick) {
|
|
58
|
+
return pickOrValue.type;
|
|
59
|
+
}
|
|
60
|
+
return /** @type {any} */ (getValueType(pickOrValue));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @template {PickValue} T
|
|
65
|
+
* @param {T} value
|
|
66
|
+
*/
|
|
67
|
+
function pickFromValue(value) {
|
|
68
|
+
const type = getValueType(value);
|
|
69
|
+
return makeTypePick(type, $o.value(value));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = {
|
|
73
|
+
getPickOrValueType,
|
|
74
|
+
getValueType,
|
|
75
|
+
pickFromValue,
|
|
76
|
+
};
|