json-fs-query 2.1.1 → 2.2.0
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/README.md +8 -0
- package/browser/jsonFsQuery.js +29 -18
- package/browser/jsonFsQuery.min.js +1 -1
- package/dist/data/queries/sortBy.d.ts +6 -0
- package/dist/data/queries/sortBy.js +13 -4
- package/dist/data/queries/sortBy.min.js +1 -1
- package/dist/data/queries/where.js +8 -6
- package/dist/data/queries/where.min.js +1 -1
- package/dist/data/utilities/parsers/findSortClauses.d.ts +1 -0
- package/dist/data/utilities/runQuery.js +7 -7
- package/dist/data/utilities/runQuery.min.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -148,6 +148,14 @@ read workouts where reps > 8 and where date = '2024-06-02'
|
|
|
148
148
|
`or where` is not supported yet, and is an error (in 1.x it was silently read as `and where`). And/or with grouping
|
|
149
149
|
and precedence is planned.
|
|
150
150
|
|
|
151
|
+
### Comparing by the field's type
|
|
152
|
+
|
|
153
|
+
Conditions compare by the field's declared type, whatever type the stored value or the literal has: in a `string`
|
|
154
|
+
or `int` field, `'3'` and `3` are equal. Ordering (`>`, `>=`, `<`, `<=`, `between`) and `sort` follow it too: a
|
|
155
|
+
`string` field orders as text, so `'10'` comes before `'9'` (even ids stored as numbers), and an `int` field as
|
|
156
|
+
numbers. A field with no declared type, or an `object` or `array` one, compares the stored values as they are.
|
|
157
|
+
`like` only matches values stored as text.
|
|
158
|
+
|
|
151
159
|
### Null and missing fields
|
|
152
160
|
|
|
153
161
|
A field can be missing (left out) or hold `null`, and both are their own cases, as in SQL: they match no
|
package/browser/jsonFsQuery.js
CHANGED
|
@@ -1211,6 +1211,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
1211
1211
|
value: true
|
|
1212
1212
|
});
|
|
1213
1213
|
exports.sortBy = void 0;
|
|
1214
|
+
var _compareAs = require("../utilities/compareAs");
|
|
1214
1215
|
// Where a value sorts before any other, ascending: missing first, then null, then the values (MySQL's null placement,
|
|
1215
1216
|
// with missing below null). Descending reverses it.
|
|
1216
1217
|
const presence = (data, property) => {
|
|
@@ -1219,6 +1220,12 @@ const presence = (data, property) => {
|
|
|
1219
1220
|
}
|
|
1220
1221
|
return data[property] === null ? 1 : 2;
|
|
1221
1222
|
};
|
|
1223
|
+
/**
|
|
1224
|
+
* Sort by each clause in turn: missing, then null, then the values, compared by the field's declared type when the
|
|
1225
|
+
* clause has one (see compareAs), so a string field sorts as text ('10' before '9') and an int field as numbers.
|
|
1226
|
+
* @param dataSet
|
|
1227
|
+
* @param sortClauses
|
|
1228
|
+
*/
|
|
1222
1229
|
const sortBy = (dataSet = [], sortClauses = []) => {
|
|
1223
1230
|
if (!sortClauses.length) {
|
|
1224
1231
|
return dataSet;
|
|
@@ -1232,13 +1239,15 @@ const sortBy = (dataSet = [], sortClauses = []) => {
|
|
|
1232
1239
|
if (rankA !== rankB) {
|
|
1233
1240
|
return direction === 'asc' ? rankA - rankB : rankB - rankA;
|
|
1234
1241
|
}
|
|
1235
|
-
//
|
|
1236
|
-
//
|
|
1242
|
+
// Values compare by the declared type, so numeric ids in a string field sort as text ('10' before '9'). Loose so
|
|
1243
|
+
// '3' and 3 still tie in an untyped field, as do two nulls or two missing.
|
|
1244
|
+
const valueA = (0, _compareAs.compareAs)(sortClause.type, a[property]);
|
|
1245
|
+
const valueB = (0, _compareAs.compareAs)(sortClause.type, b[property]);
|
|
1237
1246
|
// eslint-disable-next-line eqeqeq
|
|
1238
|
-
if (
|
|
1247
|
+
if (valueA == valueB) {
|
|
1239
1248
|
continue;
|
|
1240
1249
|
}
|
|
1241
|
-
const result =
|
|
1250
|
+
const result = valueA < valueB ? -1 : 1;
|
|
1242
1251
|
return direction === 'asc' ? result : result * -1;
|
|
1243
1252
|
}
|
|
1244
1253
|
return 0;
|
|
@@ -1246,7 +1255,7 @@ const sortBy = (dataSet = [], sortClauses = []) => {
|
|
|
1246
1255
|
return dataSet;
|
|
1247
1256
|
};
|
|
1248
1257
|
exports.sortBy = sortBy;
|
|
1249
|
-
},{}],32:[function(require,module,exports){
|
|
1258
|
+
},{"../utilities/compareAs":34}],32:[function(require,module,exports){
|
|
1250
1259
|
"use strict";
|
|
1251
1260
|
|
|
1252
1261
|
Object.defineProperty(exports, "__esModule", {
|
|
@@ -1514,7 +1523,8 @@ const likeMatch = (dataValue, pattern) => {
|
|
|
1514
1523
|
};
|
|
1515
1524
|
/**
|
|
1516
1525
|
* Equality (=, !=, <>, in) compares by the field's declared type when given one (see sameValue), so
|
|
1517
|
-
* '3' and 3 match in a string or int field. Ordering (>, <, between
|
|
1526
|
+
* '3' and 3 match in a string or int field. Ordering (>, >=, <, <=, between) compares by it too (see compareAs): a
|
|
1527
|
+
* string field orders as text ('10' < '9'), an int field as numbers. like compares the raw values.
|
|
1518
1528
|
*
|
|
1519
1529
|
* Null and missing are their own cases, as in SQL: a field that is null or missing matches no comparison (not even
|
|
1520
1530
|
* `!=`), and a null never equals anything, not even another null. Only these test for them:
|
|
@@ -1543,6 +1553,7 @@ const makeCondition = (data, property, comparator, value, type = undefined) => {
|
|
|
1543
1553
|
return false;
|
|
1544
1554
|
}
|
|
1545
1555
|
const dataValue = data[property];
|
|
1556
|
+
const typedValue = (0, _compareAs.compareAs)(type, dataValue);
|
|
1546
1557
|
switch (comparator) {
|
|
1547
1558
|
case '=':
|
|
1548
1559
|
return (0, _compareAs.sameValue)(type, dataValue, value);
|
|
@@ -1550,18 +1561,18 @@ const makeCondition = (data, property, comparator, value, type = undefined) => {
|
|
|
1550
1561
|
case '<>':
|
|
1551
1562
|
return !(0, _compareAs.sameValue)(type, dataValue, value);
|
|
1552
1563
|
case '>':
|
|
1553
|
-
return
|
|
1564
|
+
return typedValue > (0, _compareAs.compareAs)(type, value);
|
|
1554
1565
|
case '>=':
|
|
1555
|
-
return
|
|
1566
|
+
return typedValue >= (0, _compareAs.compareAs)(type, value);
|
|
1556
1567
|
case '<':
|
|
1557
|
-
return
|
|
1568
|
+
return typedValue < (0, _compareAs.compareAs)(type, value);
|
|
1558
1569
|
case '<=':
|
|
1559
|
-
return
|
|
1570
|
+
return typedValue <= (0, _compareAs.compareAs)(type, value);
|
|
1560
1571
|
case 'in':
|
|
1561
1572
|
return Array.isArray(value) && (type ? value.some(item => (0, _compareAs.sameValue)(type, dataValue, item)) : value.includes(dataValue));
|
|
1562
1573
|
case 'between':
|
|
1563
1574
|
// A null bound would act as 0 in >= / <=: it bounds nothing, so nothing matches (the parser refuses it)
|
|
1564
|
-
return Array.isArray(value) && value.length === 2 && !value.includes(null) &&
|
|
1575
|
+
return Array.isArray(value) && value.length === 2 && !value.includes(null) && typedValue >= (0, _compareAs.compareAs)(type, value[0]) && typedValue <= (0, _compareAs.compareAs)(type, value[1]);
|
|
1565
1576
|
case 'like':
|
|
1566
1577
|
return likeMatch(dataValue, value);
|
|
1567
1578
|
}
|
|
@@ -3849,15 +3860,15 @@ var _isEntityProperty = require("./parsers/isEntityProperty");
|
|
|
3849
3860
|
var _splitEntityProperty = require("./parsers/splitEntityProperty");
|
|
3850
3861
|
var _fieldType = require("./fieldType");
|
|
3851
3862
|
/**
|
|
3852
|
-
* Give each condition its field's declared type, so where
|
|
3853
|
-
* is looked up on that entity's record).
|
|
3863
|
+
* Give each condition and sort clause its field's declared type, so where and sortBy compare by it
|
|
3864
|
+
* (a joined entity's field is looked up on that entity's record).
|
|
3854
3865
|
* @param parsed
|
|
3855
3866
|
* @param recordData
|
|
3856
3867
|
*/
|
|
3857
|
-
const
|
|
3858
|
-
for (const
|
|
3868
|
+
const typeClauses = async (parsed, recordData) => {
|
|
3869
|
+
for (const clause of [...parsed.conditions, ...parsed.sortClauses]) {
|
|
3859
3870
|
let entity = parsed.entity;
|
|
3860
|
-
let property =
|
|
3871
|
+
let property = clause.property;
|
|
3861
3872
|
if ((0, _isEntityProperty.isEntityProperty)(property)) {
|
|
3862
3873
|
({
|
|
3863
3874
|
entity,
|
|
@@ -3867,7 +3878,7 @@ const typeConditions = async (parsed, recordData) => {
|
|
|
3867
3878
|
if (!Object.prototype.hasOwnProperty.call(recordData, entity)) {
|
|
3868
3879
|
recordData[entity] = await (0, _retrieveRecord.retrieveRecord)(entity);
|
|
3869
3880
|
}
|
|
3870
|
-
|
|
3881
|
+
clause.type = (0, _fieldType.fieldType)(recordData[entity], property);
|
|
3871
3882
|
}
|
|
3872
3883
|
};
|
|
3873
3884
|
const runQuery = async parsed => {
|
|
@@ -3896,7 +3907,7 @@ const runQuery = async parsed => {
|
|
|
3896
3907
|
if (typeof parsed.joinEntity !== 'undefined') {
|
|
3897
3908
|
recordData[parsed.joinEntity] = await (0, _retrieveRecord.retrieveRecord)(parsed.joinEntity);
|
|
3898
3909
|
}
|
|
3899
|
-
await
|
|
3910
|
+
await typeClauses(parsed, recordData);
|
|
3900
3911
|
let dataSet = {
|
|
3901
3912
|
[parsed.entity]: []
|
|
3902
3913
|
};
|