json-fs-query 1.0.5 → 1.1.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.
Files changed (94) hide show
  1. package/browser/jsonFsQuery.js +520 -363
  2. package/browser/jsonFsQuery.min.js +1 -1
  3. package/dist/data/introspect/create.js +46 -46
  4. package/dist/data/introspect/definitions/field.js +35 -35
  5. package/dist/data/introspect/definitions/key.js +52 -52
  6. package/dist/data/introspect/definitions/keyReference.js +19 -19
  7. package/dist/data/introspect/definitions/record.js +31 -31
  8. package/dist/data/introspect/describe.js +14 -14
  9. package/dist/data/introspect/drop.js +36 -36
  10. package/dist/data/introspect/index.js +29 -29
  11. package/dist/data/introspect/policies/foreignKeyExists.js +5 -1
  12. package/dist/data/introspect/policies/foreignKeyExists.min.js +1 -1
  13. package/dist/data/introspect/policies/hasDependents.js +3 -1
  14. package/dist/data/introspect/policies/hasDependents.min.js +1 -1
  15. package/dist/data/introspect/policies/keyGenerate.js +16 -16
  16. package/dist/data/introspect/policies/keyUnique.js +5 -1
  17. package/dist/data/introspect/policies/keyUnique.min.js +1 -1
  18. package/dist/data/introspect/policies/typeCheck.js +56 -56
  19. package/dist/data/introspect/policies/typeEnum.js +13 -13
  20. package/dist/data/introspect/policies/useDefault.js +12 -12
  21. package/dist/data/queries/deleteEntity.js +2 -1
  22. package/dist/data/queries/deleteEntity.min.js +1 -1
  23. package/dist/data/queries/groupBy.js +21 -21
  24. package/dist/data/queries/insertEntity.js +2 -1
  25. package/dist/data/queries/insertEntity.min.js +1 -1
  26. package/dist/data/queries/joinEntity.js +31 -31
  27. package/dist/data/queries/limitOffset.js +20 -20
  28. package/dist/data/queries/mergeJoins.js +18 -18
  29. package/dist/data/queries/parser.js +29 -29
  30. package/dist/data/queries/query.js +17 -17
  31. package/dist/data/queries/readEntity.js +13 -13
  32. package/dist/data/queries/selectFields.js +35 -35
  33. package/dist/data/queries/sortBy.js +3 -0
  34. package/dist/data/queries/updateEntity.js +14 -10
  35. package/dist/data/queries/updateEntity.min.js +1 -1
  36. package/dist/data/queries/where.d.ts +7 -6
  37. package/dist/data/queries/where.js +18 -6
  38. package/dist/data/queries/where.min.js +1 -1
  39. package/dist/data/utilities/compareAs.d.ts +20 -0
  40. package/dist/data/utilities/compareAs.js +58 -0
  41. package/dist/data/utilities/compareAs.min.js +1 -0
  42. package/dist/data/utilities/computeKeyValue.js +25 -25
  43. package/dist/data/utilities/config.js +44 -44
  44. package/dist/data/utilities/deregisterRecord.js +33 -33
  45. package/dist/data/utilities/fieldType.d.ts +16 -0
  46. package/dist/data/utilities/fieldType.js +23 -0
  47. package/dist/data/utilities/fieldType.min.js +1 -0
  48. package/dist/data/utilities/getConditionIndexedList.js +2 -1
  49. package/dist/data/utilities/getConditionIndexedList.min.js +1 -1
  50. package/dist/data/utilities/getJoinIndexedList.js +75 -75
  51. package/dist/data/utilities/getMatchingIndexes.js +27 -27
  52. package/dist/data/utilities/matchIndexedJoins.js +3 -1
  53. package/dist/data/utilities/matchIndexedJoins.min.js +1 -1
  54. package/dist/data/utilities/mergeJoin.js +5 -1
  55. package/dist/data/utilities/mergeJoin.min.js +1 -1
  56. package/dist/data/utilities/parsers/findCommand.js +24 -24
  57. package/dist/data/utilities/parsers/findConditions.d.ts +15 -14
  58. package/dist/data/utilities/parsers/findConditions.js +27 -27
  59. package/dist/data/utilities/parsers/findGroupBy.js +21 -21
  60. package/dist/data/utilities/parsers/findInsertValues.js +33 -33
  61. package/dist/data/utilities/parsers/findJoinClauses.js +26 -26
  62. package/dist/data/utilities/parsers/findJoinEntity.js +21 -21
  63. package/dist/data/utilities/parsers/findLimit.js +21 -21
  64. package/dist/data/utilities/parsers/findMergeJoins.js +25 -25
  65. package/dist/data/utilities/parsers/findOffset.js +21 -21
  66. package/dist/data/utilities/parsers/findSelects.js +29 -29
  67. package/dist/data/utilities/parsers/findSortClauses.js +29 -29
  68. package/dist/data/utilities/parsers/findUpdateValues.js +33 -33
  69. package/dist/data/utilities/parsers/isEntityProperty.js +7 -7
  70. package/dist/data/utilities/parsers/parseLiteralValue.js +33 -33
  71. package/dist/data/utilities/parsers/parseQuery.js +50 -50
  72. package/dist/data/utilities/parsers/removeFromQuery.js +7 -7
  73. package/dist/data/utilities/parsers/splitEntityProperty.js +22 -22
  74. package/dist/data/utilities/parsers/splitQueries.js +10 -10
  75. package/dist/data/utilities/reconcileJoin.js +25 -25
  76. package/dist/data/utilities/reconcileJoins.js +25 -25
  77. package/dist/data/utilities/registerRecord.js +66 -66
  78. package/dist/data/utilities/removeFromIndex.d.ts +14 -13
  79. package/dist/data/utilities/removeFromIndex.js +4 -2
  80. package/dist/data/utilities/removeFromIndex.min.js +1 -1
  81. package/dist/data/utilities/restrictIndexedList.js +44 -44
  82. package/dist/data/utilities/retrieveFile.js +27 -27
  83. package/dist/data/utilities/retrieveIndexes.js +23 -23
  84. package/dist/data/utilities/retrieveRecord.js +8 -8
  85. package/dist/data/utilities/retrieveRecords.js +20 -20
  86. package/dist/data/utilities/runQuery.js +26 -0
  87. package/dist/data/utilities/runQuery.min.js +1 -1
  88. package/dist/data/utilities/updateIndex.d.ts +17 -16
  89. package/dist/data/utilities/updateIndex.js +4 -2
  90. package/dist/data/utilities/updateIndex.min.js +1 -1
  91. package/dist/data/utilities/useJoinClause.js +8 -2
  92. package/dist/data/utilities/useJoinClause.min.js +1 -1
  93. package/dist/index.js +41 -41
  94. package/package.json +14 -5
@@ -14,6 +14,8 @@ var _retrieveFile = require("../utilities/retrieveFile");
14
14
  var _updateIndex = require("../utilities/updateIndex");
15
15
  var _removeFromIndex = require("../utilities/removeFromIndex");
16
16
  var _computeKeyValue = require("../utilities/computeKeyValue");
17
+ var _fieldType = require("../utilities/fieldType");
18
+ var _compareAs = require("../utilities/compareAs");
17
19
  var _keyUnique = require("../introspect/policies/keyUnique");
18
20
  var _typeCheck = require("../introspect/policies/typeCheck");
19
21
  var _foreignKeyExists = require("../introspect/policies/foreignKeyExists");
@@ -34,7 +36,7 @@ const {
34
36
  const findEntryFile = async (record, primaryKey, primaryValue) => {
35
37
  for (const fileName of record.entries) {
36
38
  const data = await (0, _retrieveFile.retrieveFile)(`${record.path}/${fileName}`);
37
- if ((0, _computeKeyValue.computeKeyValue)(primaryKey.fields, data) == primaryValue) {
39
+ if ((0, _compareAs.sameValue)((0, _fieldType.keyValueType)(record, primaryKey), (0, _computeKeyValue.computeKeyValue)(primaryKey.fields, data), primaryValue)) {
38
40
  return fileName;
39
41
  }
40
42
  }
@@ -43,11 +45,12 @@ const findEntryFile = async (record, primaryKey, primaryValue) => {
43
45
  /**
44
46
  * True if the update actually changes at least one of this key's fields - a key none of whose
45
47
  * fields appear in newValues, or whose given values are all unchanged, doesn't need re-checking.
48
+ * @param record
46
49
  * @param key
47
50
  * @param oldData
48
51
  * @param newValues
49
52
  */
50
- const keyFieldsChanged = (key, oldData, newValues) => key.fields.some(field => Object.prototype.hasOwnProperty.call(newValues, field) && newValues[field] != oldData[field]);
53
+ const keyFieldsChanged = (record, key, oldData, newValues) => key.fields.some(field => Object.prototype.hasOwnProperty.call(newValues, field) && !(0, _compareAs.sameValue)((0, _fieldType.fieldType)(record, field), newValues[field], oldData[field]));
51
54
  /**
52
55
  * Only check uniqueness for a primary/unique key (single-field, or composite) whose value is
53
56
  * actually changing - checking an unchanged value would find the record's own existing entry and
@@ -60,7 +63,7 @@ const keyFieldsChanged = (key, oldData, newValues) => key.fields.some(field => O
60
63
  */
61
64
  const assertUniqueForUpdate = async (entity, record, oldData, newData, newValues) => {
62
65
  for (const key of record.keys) {
63
- if (key.type !== 'primary' && key.type !== 'unique' || !keyFieldsChanged(key, oldData, newValues)) {
66
+ if (key.type !== 'primary' && key.type !== 'unique' || !keyFieldsChanged(record, key, oldData, newValues)) {
64
67
  continue;
65
68
  }
66
69
  const checkKeys = key.fields.map(field => newData[field]);
@@ -85,7 +88,7 @@ const assertForeignKeysForUpdate = async (entity, record, oldData, newValues) =>
85
88
  continue;
86
89
  }
87
90
  const field = key.fields[0];
88
- if (!Object.prototype.hasOwnProperty.call(newValues, field) || newValues[field] == oldData[field]) {
91
+ if (!Object.prototype.hasOwnProperty.call(newValues, field) || (0, _compareAs.sameValue)((0, _fieldType.fieldType)(record, field), newValues[field], oldData[field])) {
89
92
  continue;
90
93
  }
91
94
  const {
@@ -104,12 +107,13 @@ const assertForeignKeysForUpdate = async (entity, record, oldData, newValues) =>
104
107
  * dangling, since the row itself isn't gone, just re-keyed. Only meaningful for a single-field
105
108
  * primary key, matching foreign key support's own single-field-only scope.
106
109
  * @param entity
110
+ * @param record
107
111
  * @param primaryKey
108
112
  * @param oldData
109
113
  * @param newValues
110
114
  */
111
- const assertNoDependentsForUpdate = async (entity, primaryKey, oldData, newValues) => {
112
- if (!(0, _config.getSetting)('enforceForeignKeys', true) || primaryKey.fields.length !== 1 || !keyFieldsChanged(primaryKey, oldData, newValues)) {
115
+ const assertNoDependentsForUpdate = async (entity, record, primaryKey, oldData, newValues) => {
116
+ if (!(0, _config.getSetting)('enforceForeignKeys', true) || primaryKey.fields.length !== 1 || !keyFieldsChanged(record, primaryKey, oldData, newValues)) {
113
117
  return;
114
118
  }
115
119
  const property = primaryKey.fields[0];
@@ -128,11 +132,11 @@ const assertNoDependentsForUpdate = async (entity, primaryKey, oldData, newValue
128
132
  */
129
133
  const reconcileIndexes = async (record, oldData, newData, newValues, fileName) => {
130
134
  for (const key of record.keys) {
131
- if (!keyFieldsChanged(key, oldData, newValues)) {
135
+ if (!keyFieldsChanged(record, key, oldData, newValues)) {
132
136
  continue;
133
137
  }
134
- await (0, _removeFromIndex.removeFromIndex)(record.path, key, (0, _computeKeyValue.computeKeyValue)(key.fields, oldData), fileName);
135
- await (0, _updateIndex.updateIndex)(record.path, key, (0, _computeKeyValue.computeKeyValue)(key.fields, newData), fileName);
138
+ await (0, _removeFromIndex.removeFromIndex)(record.path, key, (0, _computeKeyValue.computeKeyValue)(key.fields, oldData), fileName, (0, _fieldType.keyValueType)(record, key));
139
+ await (0, _updateIndex.updateIndex)(record.path, key, (0, _computeKeyValue.computeKeyValue)(key.fields, newData), fileName, (0, _fieldType.keyValueType)(record, key));
136
140
  }
137
141
  };
138
142
  const assertRequiredFields = (entity, record, newData) => {
@@ -178,7 +182,7 @@ const updateEntity = async (entity = '', values = {}, dataSet = {}) => {
178
182
  const newData = Object.assign({}, oldData, typedValues);
179
183
  await assertUniqueForUpdate(entity, record, oldData, newData, typedValues);
180
184
  await assertForeignKeysForUpdate(entity, record, oldData, typedValues);
181
- await assertNoDependentsForUpdate(entity, primaryKey, oldData, typedValues);
185
+ await assertNoDependentsForUpdate(entity, record, primaryKey, oldData, typedValues);
182
186
  assertRequiredFields(entity, record, newData);
183
187
  await reconcileIndexes(record, oldData, newData, typedValues, fileName);
184
188
  await writeFile(`${databasePath}${record.path}/${fileName}`, JSON.stringify(newData, null, 2));
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.updateEntity=void 0,require("core-js/modules/es.json.stringify.js"),require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.find.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.iterator.some.js");var _retrieveRecord=require("../utilities/retrieveRecord"),_retrieveFile=require("../utilities/retrieveFile"),_updateIndex=require("../utilities/updateIndex"),_removeFromIndex=require("../utilities/removeFromIndex"),_computeKeyValue=require("../utilities/computeKeyValue"),_keyUnique=require("../introspect/policies/keyUnique"),_typeCheck=require("../introspect/policies/typeCheck"),_foreignKeyExists=require("../introspect/policies/foreignKeyExists"),_hasDependents=require("../introspect/policies/hasDependents"),_splitEntityProperty=require("../utilities/parsers/splitEntityProperty"),_config=require("../utilities/config");const{writeFile:writeFile}=require("fs/promises"),findEntryFile=async(e,t,r)=>{for(const i of e.entries){const s=await(0,_retrieveFile.retrieveFile)(`${e.path}/${i}`);if((0,_computeKeyValue.computeKeyValue)(t.fields,s)==r)return i}return null},keyFieldsChanged=(e,t,r)=>e.fields.some((e=>Object.prototype.hasOwnProperty.call(r,e)&&r[e]!=t[e])),assertUniqueForUpdate=async(e,t,r,i,s)=>{for(const o of t.keys){if("primary"!==o.type&&"unique"!==o.type||!keyFieldsChanged(o,r,s))continue;const t=o.fields.map((e=>i[e]));if(!await(0,_keyUnique.keyUnique)(e,o.fields,t))throw new Error(`Duplicate value for ${o.type} key "${o.fields.join(", ")}" on ${e}`)}},assertForeignKeysForUpdate=async(e,t,r,i)=>{for(const s of t.keys){if("foreign"!==s.type||1!==s.fields.length||!s.references||1!==s.references.length)continue;const t=s.fields[0];if(!Object.prototype.hasOwnProperty.call(i,t)||i[t]==r[t])continue;const{entity:o,property:n}=(0,_splitEntityProperty.splitEntityProperty)(s.references[0].fields[0]);if(!await(0,_foreignKeyExists.foreignKeyExists)(o,n,i[t]))throw new Error(`Foreign key "${t}" on ${e} references a nonexistent ${o}.${n} = ${i[t]}`)}},assertNoDependentsForUpdate=async(e,t,r,i)=>{if(!(0,_config.getSetting)("enforceForeignKeys",!0)||1!==t.fields.length||!keyFieldsChanged(t,r,i))return;const s=t.fields[0];if(await(0,_hasDependents.hasDependents)(e,s,r[s]))throw new Error(`Cannot update "${e}" where "${s}" = ${r[s]} - other records still reference it`)},reconcileIndexes=async(e,t,r,i,s)=>{for(const o of e.keys)keyFieldsChanged(o,t,i)&&(await(0,_removeFromIndex.removeFromIndex)(e.path,o,(0,_computeKeyValue.computeKeyValue)(o.fields,t),s),await(0,_updateIndex.updateIndex)(e.path,o,(0,_computeKeyValue.computeKeyValue)(o.fields,r),s))},assertRequiredFields=(e,t,r)=>{for(const i of t.definition)if(!i.optional&&void 0===r[i.name])throw new Error(`Missing required field "${i.name}" for ${e}`)},applyFieldTypes=(e,t)=>{const r=Object.assign({},t);for(const t of e.definition)Object.prototype.hasOwnProperty.call(r,t.name)&&(r[t.name]=(0,_typeCheck.typeCheck)(t.type,r[t.name]));return r},updateEntity=async(e="",t={},r={})=>{const i=(0,_config.getSetting)("databasePath","database/"),s=await(0,_retrieveRecord.retrieveRecord)(e),o=s.keys.find((e=>"primary"===e.type));if(!o)throw new Error(`Cannot update "${e}" without a primary key`);const n=applyFieldTypes(s,t),a=r[e]||[],p=[];for(const t of a){const r=await findEntryFile(s,o,(0,_computeKeyValue.computeKeyValue)(o.fields,t));if(!r)throw new Error(`Could not find entry for ${e} where "${o.fields.join(", ")}" = ${(0,_computeKeyValue.computeKeyValue)(o.fields,t)}`);const a=await(0,_retrieveFile.retrieveFile)(`${s.path}/${r}`),u=Object.assign({},a,n);await assertUniqueForUpdate(e,s,a,u,n),await assertForeignKeysForUpdate(e,s,a,n),await assertNoDependentsForUpdate(e,o,a,n),assertRequiredFields(e,s,u),await reconcileIndexes(s,a,u,n,r),await writeFile(`${i}${s.path}/${r}`,JSON.stringify(u,null,2)),p.push(u)}return r[e]=p,r};exports.updateEntity=updateEntity;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.updateEntity=void 0,require("core-js/modules/es.json.stringify.js"),require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.find.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.iterator.some.js");var _retrieveRecord=require("../utilities/retrieveRecord"),_retrieveFile=require("../utilities/retrieveFile"),_updateIndex=require("../utilities/updateIndex"),_removeFromIndex=require("../utilities/removeFromIndex"),_computeKeyValue=require("../utilities/computeKeyValue"),_fieldType=require("../utilities/fieldType"),_compareAs=require("../utilities/compareAs"),_keyUnique=require("../introspect/policies/keyUnique"),_typeCheck=require("../introspect/policies/typeCheck"),_foreignKeyExists=require("../introspect/policies/foreignKeyExists"),_hasDependents=require("../introspect/policies/hasDependents"),_splitEntityProperty=require("../utilities/parsers/splitEntityProperty"),_config=require("../utilities/config");const{writeFile:writeFile}=require("fs/promises"),findEntryFile=async(e,t,i)=>{for(const r of e.entries){const s=await(0,_retrieveFile.retrieveFile)(`${e.path}/${r}`);if((0,_compareAs.sameValue)((0,_fieldType.keyValueType)(e,t),(0,_computeKeyValue.computeKeyValue)(t.fields,s),i))return r}return null},keyFieldsChanged=(e,t,i,r)=>t.fields.some((t=>Object.prototype.hasOwnProperty.call(r,t)&&!(0,_compareAs.sameValue)((0,_fieldType.fieldType)(e,t),r[t],i[t]))),assertUniqueForUpdate=async(e,t,i,r,s)=>{for(const o of t.keys){if("primary"!==o.type&&"unique"!==o.type||!keyFieldsChanged(t,o,i,s))continue;const n=o.fields.map((e=>r[e]));if(!await(0,_keyUnique.keyUnique)(e,o.fields,n))throw new Error(`Duplicate value for ${o.type} key "${o.fields.join(", ")}" on ${e}`)}},assertForeignKeysForUpdate=async(e,t,i,r)=>{for(const s of t.keys){if("foreign"!==s.type||1!==s.fields.length||!s.references||1!==s.references.length)continue;const o=s.fields[0];if(!Object.prototype.hasOwnProperty.call(r,o)||(0,_compareAs.sameValue)((0,_fieldType.fieldType)(t,o),r[o],i[o]))continue;const{entity:n,property:a}=(0,_splitEntityProperty.splitEntityProperty)(s.references[0].fields[0]);if(!await(0,_foreignKeyExists.foreignKeyExists)(n,a,r[o]))throw new Error(`Foreign key "${o}" on ${e} references a nonexistent ${n}.${a} = ${r[o]}`)}},assertNoDependentsForUpdate=async(e,t,i,r,s)=>{if(!(0,_config.getSetting)("enforceForeignKeys",!0)||1!==i.fields.length||!keyFieldsChanged(t,i,r,s))return;const o=i.fields[0];if(await(0,_hasDependents.hasDependents)(e,o,r[o]))throw new Error(`Cannot update "${e}" where "${o}" = ${r[o]} - other records still reference it`)},reconcileIndexes=async(e,t,i,r,s)=>{for(const o of e.keys)keyFieldsChanged(e,o,t,r)&&(await(0,_removeFromIndex.removeFromIndex)(e.path,o,(0,_computeKeyValue.computeKeyValue)(o.fields,t),s,(0,_fieldType.keyValueType)(e,o)),await(0,_updateIndex.updateIndex)(e.path,o,(0,_computeKeyValue.computeKeyValue)(o.fields,i),s,(0,_fieldType.keyValueType)(e,o)))},assertRequiredFields=(e,t,i)=>{for(const r of t.definition)if(!r.optional&&void 0===i[r.name])throw new Error(`Missing required field "${r.name}" for ${e}`)},applyFieldTypes=(e,t)=>{const i=Object.assign({},t);for(const t of e.definition)Object.prototype.hasOwnProperty.call(i,t.name)&&(i[t.name]=(0,_typeCheck.typeCheck)(t.type,i[t.name]));return i},updateEntity=async(e="",t={},i={})=>{const r=(0,_config.getSetting)("databasePath","database/"),s=await(0,_retrieveRecord.retrieveRecord)(e),o=s.keys.find((e=>"primary"===e.type));if(!o)throw new Error(`Cannot update "${e}" without a primary key`);const n=applyFieldTypes(s,t),a=i[e]||[],p=[];for(const t of a){const i=await findEntryFile(s,o,(0,_computeKeyValue.computeKeyValue)(o.fields,t));if(!i)throw new Error(`Could not find entry for ${e} where "${o.fields.join(", ")}" = ${(0,_computeKeyValue.computeKeyValue)(o.fields,t)}`);const a=await(0,_retrieveFile.retrieveFile)(`${s.path}/${i}`),l=Object.assign({},a,n);await assertUniqueForUpdate(e,s,a,l,n),await assertForeignKeysForUpdate(e,s,a,n),await assertNoDependentsForUpdate(e,s,o,a,n),assertRequiredFields(e,s,l),await reconcileIndexes(s,a,l,n,i),await writeFile(`${r}${s.path}/${i}`,JSON.stringify(l,null,2)),p.push(l)}return i[e]=p,i};exports.updateEntity=updateEntity;
@@ -1,7 +1,8 @@
1
- export declare const where: (dataSet?: any[], { property, joinEntity, comparator, value }?: {
2
- property?: string;
3
- joinEntity?: any;
4
- comparator?: string;
5
- value?: any;
6
- }) => any[];
1
+ export declare const where: (dataSet?: any[], { property, joinEntity, comparator, value, type }?: {
2
+ property?: string;
3
+ joinEntity?: any;
4
+ comparator?: string;
5
+ value?: any;
6
+ type?: any;
7
+ }) => any[];
7
8
  //# sourceMappingURL=where.d.ts.map
@@ -7,6 +7,8 @@ exports.where = void 0;
7
7
  require("core-js/modules/es.array.includes.js");
8
8
  require("core-js/modules/esnext.iterator.constructor.js");
9
9
  require("core-js/modules/esnext.iterator.filter.js");
10
+ require("core-js/modules/esnext.iterator.some.js");
11
+ var _compareAs = require("../utilities/compareAs");
10
12
  const likeMatch = (dataValue, pattern) => {
11
13
  if (typeof dataValue !== 'string' || typeof pattern !== 'string') {
12
14
  return false;
@@ -14,17 +16,26 @@ const likeMatch = (dataValue, pattern) => {
14
16
  const regexPattern = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/%/g, '.*').replace(/_/g, '.');
15
17
  return new RegExp(`^${regexPattern}$`, 'i').test(dataValue);
16
18
  };
17
- const makeCondition = (data, property, comparator, value) => {
19
+ /**
20
+ * Equality (=, !=, <>, in) compares by the field's declared type when given one (see sameValue), so
21
+ * '3' and 3 match in a string or int field. Ordering (>, <, between, like) compares the raw values.
22
+ * @param data
23
+ * @param property
24
+ * @param comparator
25
+ * @param value
26
+ * @param type
27
+ */
28
+ const makeCondition = (data, property, comparator, value, type = undefined) => {
18
29
  if (!Object.prototype.hasOwnProperty.call(data, property)) {
19
30
  return false;
20
31
  }
21
32
  const dataValue = data[property];
22
33
  switch (comparator) {
23
34
  case '=':
24
- return dataValue == value;
35
+ return (0, _compareAs.sameValue)(type, dataValue, value);
25
36
  case '!=':
26
37
  case '<>':
27
- return dataValue != value;
38
+ return !(0, _compareAs.sameValue)(type, dataValue, value);
28
39
  case '>':
29
40
  return dataValue > value;
30
41
  case '>=':
@@ -34,7 +45,7 @@ const makeCondition = (data, property, comparator, value) => {
34
45
  case '<=':
35
46
  return dataValue <= value;
36
47
  case 'in':
37
- return Array.isArray(value) && value.includes(dataValue);
48
+ return Array.isArray(value) && (type ? value.some(item => (0, _compareAs.sameValue)(type, dataValue, item)) : value.includes(dataValue));
38
49
  case 'between':
39
50
  return Array.isArray(value) && value.length === 2 && dataValue >= value[0] && dataValue <= value[1];
40
51
  case 'like':
@@ -46,11 +57,12 @@ const where = (dataSet = [], {
46
57
  property = '',
47
58
  joinEntity = undefined,
48
59
  comparator = '=',
49
- value = null
60
+ value = null,
61
+ type = undefined
50
62
  } = {}) => {
51
63
  return dataSet.filter(data => {
52
64
  const testProperty = joinEntity ? `${joinEntity}.${property}` : property;
53
- return makeCondition(data, testProperty, comparator, value);
65
+ return makeCondition(data, testProperty, comparator, value, type);
54
66
  });
55
67
  };
56
68
  exports.where = where;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.where=void 0,require("core-js/modules/es.array.includes.js"),require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.filter.js");const likeMatch=(e,r)=>{if("string"!=typeof e||"string"!=typeof r)return!1;const t=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/%/g,".*").replace(/_/g,".");return new RegExp(`^${t}$`,"i").test(e)},makeCondition=(e,r,t,s)=>{if(!Object.prototype.hasOwnProperty.call(e,r))return!1;const n=e[r];switch(t){case"=":return n==s;case"!=":case"<>":return n!=s;case">":return n>s;case">=":return n>=s;case"<":return n<s;case"<=":return n<=s;case"in":return Array.isArray(s)&&s.includes(n);case"between":return Array.isArray(s)&&2===s.length&&n>=s[0]&&n<=s[1];case"like":return likeMatch(n,s)}return!1},where=(e=[],{property:r="",joinEntity:t,comparator:s="=",value:n=null}={})=>e.filter((e=>makeCondition(e,t?`${t}.${r}`:r,s,n)));exports.where=where;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.where=void 0,require("core-js/modules/es.array.includes.js"),require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.filter.js"),require("core-js/modules/esnext.iterator.some.js");var _compareAs=require("../utilities/compareAs");const likeMatch=(e,r)=>{if("string"!=typeof e||"string"!=typeof r)return!1;const t=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/%/g,".*").replace(/_/g,".");return new RegExp(`^${t}$`,"i").test(e)},makeCondition=(e,r,t,s,a=void 0)=>{if(!Object.prototype.hasOwnProperty.call(e,r))return!1;const o=e[r];switch(t){case"=":return(0,_compareAs.sameValue)(a,o,s);case"!=":case"<>":return!(0,_compareAs.sameValue)(a,o,s);case">":return o>s;case">=":return o>=s;case"<":return o<s;case"<=":return o<=s;case"in":return Array.isArray(s)&&(a?s.some((e=>(0,_compareAs.sameValue)(a,o,e))):s.includes(o));case"between":return Array.isArray(s)&&2===s.length&&o>=s[0]&&o<=s[1];case"like":return likeMatch(o,s)}return!1},where=(e=[],{property:r="",joinEntity:t,comparator:s="=",value:a=null,type:o}={})=>e.filter((e=>makeCondition(e,t?`${t}.${r}`:r,s,a,o)));exports.where=where;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Normalize a value to a field's declared type for an equality comparison - never written back,
3
+ * only compared. Writes are coerced to the declared type (typeCheck), but values already stored
4
+ * may not match it (ids declared string, so they can hold an integer or a UUID, are often stored
5
+ * as numbers), and query literals carry their own type. A declared type is what says '3' and 3
6
+ * are the same value. A missing or unrecognized type returns the value unchanged.
7
+ * @param type
8
+ * @param value
9
+ */
10
+ export declare const compareAs: (type: string | undefined, value: any) => any;
11
+ /**
12
+ * Whether two values are equal for a field of the given declared type: both are normalized to
13
+ * that type (see compareAs) and compared strictly. A field with no declared type, or one that
14
+ * can't be normalized (object, array, or an unrecognized type), keeps loose equality.
15
+ * @param type
16
+ * @param a
17
+ * @param b
18
+ */
19
+ export declare const sameValue: (type: string | undefined, a: any, b: any) => boolean;
20
+ //# sourceMappingURL=compareAs.d.ts.map
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.sameValue = exports.compareAs = void 0;
7
+ require("core-js/modules/es.array.includes.js");
8
+ /**
9
+ * Normalize a value to a field's declared type for an equality comparison - never written back,
10
+ * only compared. Writes are coerced to the declared type (typeCheck), but values already stored
11
+ * may not match it (ids declared string, so they can hold an integer or a UUID, are often stored
12
+ * as numbers), and query literals carry their own type. A declared type is what says '3' and 3
13
+ * are the same value. A missing or unrecognized type returns the value unchanged.
14
+ * @param type
15
+ * @param value
16
+ */
17
+ const compareAs = (type, value) => {
18
+ if (value === null || typeof value === 'undefined') {
19
+ return value;
20
+ }
21
+ switch (type) {
22
+ case 'string':
23
+ return typeof value === 'object' ? value : String(value);
24
+ case 'int':
25
+ {
26
+ const coerced = Number(value);
27
+ return Number.isNaN(coerced) ? value : coerced;
28
+ }
29
+ case 'boolean':
30
+ if (value === 'true') {
31
+ return true;
32
+ }
33
+ if (value === 'false') {
34
+ return false;
35
+ }
36
+ return value;
37
+ default:
38
+ return value;
39
+ }
40
+ };
41
+ exports.compareAs = compareAs;
42
+ const comparableTypes = ['string', 'int', 'boolean'];
43
+ /**
44
+ * Whether two values are equal for a field of the given declared type: both are normalized to
45
+ * that type (see compareAs) and compared strictly. A field with no declared type, or one that
46
+ * can't be normalized (object, array, or an unrecognized type), keeps loose equality.
47
+ * @param type
48
+ * @param a
49
+ * @param b
50
+ */
51
+ const sameValue = (type, a, b) => {
52
+ if (!comparableTypes.includes(type)) {
53
+ // eslint-disable-next-line eqeqeq
54
+ return a == b;
55
+ }
56
+ return compareAs(type, a) === compareAs(type, b);
57
+ };
58
+ exports.sameValue = sameValue;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.sameValue=exports.compareAs=void 0,require("core-js/modules/es.array.includes.js");const compareAs=(e,r)=>{if(null==r)return r;switch(e){case"string":return"object"==typeof r?r:String(r);case"int":{const e=Number(r);return Number.isNaN(e)?r:e}case"boolean":return"true"===r||"false"!==r&&r;default:return r}};exports.compareAs=compareAs;const comparableTypes=["string","int","boolean"],sameValue=(e,r,s)=>comparableTypes.includes(e)?compareAs(e,r)===compareAs(e,s):r==s;exports.sameValue=sameValue;
@@ -1,26 +1,26 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.computeKeyValue = void 0;
7
- require("core-js/modules/es.json.stringify.js");
8
- require("core-js/modules/esnext.iterator.constructor.js");
9
- require("core-js/modules/esnext.iterator.map.js");
10
- /**
11
- * The value a key (of any field count) indexes and checks uniqueness by. A single-field key uses
12
- * the field's own raw value directly - this is the pre-existing, already-shipped index file
13
- * format (e.g. a plain "2024-06-02" or 1), and stays exactly as it was for backward compatibility
14
- * with real fixture data. A multi-field key has no single value to use, so its fields' values are
15
- * combined into one deterministic composite (a JSON array), in the same field order as key.fields
16
- * - two records only share a composite value if every field matches.
17
- * @param fields
18
- * @param values
19
- */
20
- const computeKeyValue = (fields, values) => {
21
- if (fields.length === 1) {
22
- return values[fields[0]];
23
- }
24
- return JSON.stringify(fields.map(field => values[field]));
25
- };
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.computeKeyValue = void 0;
7
+ require("core-js/modules/es.json.stringify.js");
8
+ require("core-js/modules/esnext.iterator.constructor.js");
9
+ require("core-js/modules/esnext.iterator.map.js");
10
+ /**
11
+ * The value a key (of any field count) indexes and checks uniqueness by. A single-field key uses
12
+ * the field's own raw value directly - this is the pre-existing, already-shipped index file
13
+ * format (e.g. a plain "2024-06-02" or 1), and stays exactly as it was for backward compatibility
14
+ * with real fixture data. A multi-field key has no single value to use, so its fields' values are
15
+ * combined into one deterministic composite (a JSON array), in the same field order as key.fields
16
+ * - two records only share a composite value if every field matches.
17
+ * @param fields
18
+ * @param values
19
+ */
20
+ const computeKeyValue = (fields, values) => {
21
+ if (fields.length === 1) {
22
+ return values[fields[0]];
23
+ }
24
+ return JSON.stringify(fields.map(field => values[field]));
25
+ };
26
26
  exports.computeKeyValue = computeKeyValue;
@@ -1,45 +1,45 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.getSetting = exports.configure = void 0;
7
- const defaults = {
8
- databasePath: 'database/',
9
- relativePath: '',
10
- enforceForeignKeys: true
11
- };
12
- let settings = {
13
- ...defaults
14
- };
15
- /**
16
- * Set where this package's data lives: databasePath (a filesystem path, used in Node) and/or
17
- * relativePath (a URL prefix prepended to databasePath, used when reading over fetch() in a
18
- * browser). Call this once before using create()/drop()/query() - a fresh consumer has no other
19
- * way to point this package at their own data directory.
20
- *
21
- * enforceForeignKeys (default true) controls whether deleteEntity/updateEntity block an operation
22
- * that would leave another record's foreign key pointing at a value that no longer exists -
23
- * mirroring MySQL's own foreign_key_checks setting, which is also toggleable rather than always
24
- * on, since strict enforcement isn't always what every consumer wants.
25
- * @param newSettings
26
- */
27
- const configure = newSettings => {
28
- settings = {
29
- ...settings,
30
- ...newSettings
31
- };
32
- };
33
- /**
34
- * Read one runtime setting, falling back to the given default if it was never configured. This is
35
- * the package's own lightweight replacement for reading settings via js-build-tools/gulp.config -
36
- * that module is a dev-time build tool, not something a published package should require at
37
- * runtime, and it isn't available at all once a consumer installs this package on its own.
38
- * @param key
39
- * @param defaultValue
40
- */
41
- exports.configure = configure;
42
- const getSetting = (key, defaultValue) => {
43
- return typeof settings[key] !== 'undefined' ? settings[key] : defaultValue;
44
- };
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getSetting = exports.configure = void 0;
7
+ const defaults = {
8
+ databasePath: 'database/',
9
+ relativePath: '',
10
+ enforceForeignKeys: true
11
+ };
12
+ let settings = {
13
+ ...defaults
14
+ };
15
+ /**
16
+ * Set where this package's data lives: databasePath (a filesystem path, used in Node) and/or
17
+ * relativePath (a URL prefix prepended to databasePath, used when reading over fetch() in a
18
+ * browser). Call this once before using create()/drop()/query() - a fresh consumer has no other
19
+ * way to point this package at their own data directory.
20
+ *
21
+ * enforceForeignKeys (default true) controls whether deleteEntity/updateEntity block an operation
22
+ * that would leave another record's foreign key pointing at a value that no longer exists -
23
+ * mirroring MySQL's own foreign_key_checks setting, which is also toggleable rather than always
24
+ * on, since strict enforcement isn't always what every consumer wants.
25
+ * @param newSettings
26
+ */
27
+ const configure = newSettings => {
28
+ settings = {
29
+ ...settings,
30
+ ...newSettings
31
+ };
32
+ };
33
+ /**
34
+ * Read one runtime setting, falling back to the given default if it was never configured. This is
35
+ * the package's own lightweight replacement for reading settings via js-build-tools/gulp.config -
36
+ * that module is a dev-time build tool, not something a published package should require at
37
+ * runtime, and it isn't available at all once a consumer installs this package on its own.
38
+ * @param key
39
+ * @param defaultValue
40
+ */
41
+ exports.configure = configure;
42
+ const getSetting = (key, defaultValue) => {
43
+ return typeof settings[key] !== 'undefined' ? settings[key] : defaultValue;
44
+ };
45
45
  exports.getSetting = getSetting;
@@ -1,34 +1,34 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.deregisterRecord = void 0;
7
- require("core-js/modules/es.json.stringify.js");
8
- require("core-js/modules/esnext.iterator.constructor.js");
9
- require("core-js/modules/esnext.iterator.filter.js");
10
- var _config = require("./config");
11
- const {
12
- readFile,
13
- writeFile
14
- } = require('fs/promises');
15
- /**
16
- * Remove a record's filename from the __RECORDS registry. A missing registry file is left
17
- * untouched rather than created, since there's nothing to remove from it.
18
- * @param recordName
19
- */
20
- const deregisterRecord = async recordName => {
21
- const databasePath = (0, _config.getSetting)('databasePath', 'database/');
22
- const registryPath = `${databasePath}__RECORDS.json`;
23
- let registry;
24
- try {
25
- registry = JSON.parse(await readFile(registryPath, 'utf8'));
26
- } catch (err) {
27
- return null;
28
- }
29
- const fileName = `${recordName}.json`;
30
- registry.entries = registry.entries.filter(entry => entry !== fileName);
31
- await writeFile(registryPath, JSON.stringify(registry, null, 2));
32
- return registry;
33
- };
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.deregisterRecord = void 0;
7
+ require("core-js/modules/es.json.stringify.js");
8
+ require("core-js/modules/esnext.iterator.constructor.js");
9
+ require("core-js/modules/esnext.iterator.filter.js");
10
+ var _config = require("./config");
11
+ const {
12
+ readFile,
13
+ writeFile
14
+ } = require('fs/promises');
15
+ /**
16
+ * Remove a record's filename from the __RECORDS registry. A missing registry file is left
17
+ * untouched rather than created, since there's nothing to remove from it.
18
+ * @param recordName
19
+ */
20
+ const deregisterRecord = async recordName => {
21
+ const databasePath = (0, _config.getSetting)('databasePath', 'database/');
22
+ const registryPath = `${databasePath}__RECORDS.json`;
23
+ let registry;
24
+ try {
25
+ registry = JSON.parse(await readFile(registryPath, 'utf8'));
26
+ } catch (err) {
27
+ return null;
28
+ }
29
+ const fileName = `${recordName}.json`;
30
+ registry.entries = registry.entries.filter(entry => entry !== fileName);
31
+ await writeFile(registryPath, JSON.stringify(registry, null, 2));
32
+ return registry;
33
+ };
34
34
  exports.deregisterRecord = deregisterRecord;
@@ -0,0 +1,16 @@
1
+ import { recordDefinition } from '../introspect/definitions/record';
2
+ import { keyDefinition } from '../introspect/definitions/key';
3
+ /**
4
+ * The declared type of one of a record's fields, or undefined when the record or field is unknown.
5
+ * @param record
6
+ * @param property
7
+ */
8
+ export declare const fieldType: (record: recordDefinition | undefined, property: string) => string | undefined;
9
+ /**
10
+ * The declared type of the value a key indexes: its field's type for a single-field key. A
11
+ * multi-field key's value is a composite (see computeKeyValue), so it has no single declared type.
12
+ * @param record
13
+ * @param key
14
+ */
15
+ export declare const keyValueType: (record: recordDefinition | undefined, key: keyDefinition) => string | undefined;
16
+ //# sourceMappingURL=fieldType.d.ts.map
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.keyValueType = exports.fieldType = void 0;
7
+ require("core-js/modules/esnext.iterator.constructor.js");
8
+ require("core-js/modules/esnext.iterator.find.js");
9
+ /**
10
+ * The declared type of one of a record's fields, or undefined when the record or field is unknown.
11
+ * @param record
12
+ * @param property
13
+ */
14
+ const fieldType = (record, property) => record?.definition?.find(field => field.name === property)?.type;
15
+ /**
16
+ * The declared type of the value a key indexes: its field's type for a single-field key. A
17
+ * multi-field key's value is a composite (see computeKeyValue), so it has no single declared type.
18
+ * @param record
19
+ * @param key
20
+ */
21
+ exports.fieldType = fieldType;
22
+ const keyValueType = (record, key) => key.fields.length === 1 ? fieldType(record, key.fields[0]) : undefined;
23
+ exports.keyValueType = keyValueType;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.keyValueType=exports.fieldType=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.find.js");const fieldType=(e,t)=>e?.definition?.find((e=>e.name===t))?.type;exports.fieldType=fieldType;const keyValueType=(e,t)=>1===t.fields.length?fieldType(e,t.fields[0]):void 0;exports.keyValueType=keyValueType;
@@ -28,7 +28,8 @@ const getConditionIndexedList = async (parsed, recordData, dataSet) => {
28
28
  const matchedRecords = (0, _where.where)(indexed[entity][property], {
29
29
  property: 'value',
30
30
  comparator: condition.comparator,
31
- value: condition.value
31
+ value: condition.value,
32
+ type: condition.type
32
33
  });
33
34
  for (const matchedRecord of matchedRecords) {
34
35
  for (const file of matchedRecord.record) {
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.getConditionIndexedList=void 0;var _isEntityProperty=require("./parsers/isEntityProperty"),_splitEntityProperty=require("./parsers/splitEntityProperty"),_retrieveRecord=require("./retrieveRecord"),_where=require("../queries/where"),_retrieveFile=require("./retrieveFile"),_getMatchingIndexes=require("./getMatchingIndexes");const getConditionIndexedList=async(e,t,r)=>{const i=[];for(const o of e.conditions){let n=e.entity,s=o.property;if((0,_isEntityProperty.isEntityProperty)(s)){const e=(0,_splitEntityProperty.splitEntityProperty)(s);n=e.entity,s=e.property}Object.prototype.hasOwnProperty.call(t,n)||(t[n]=await(0,_retrieveRecord.retrieveRecord)(n));const p={},c=async(e,t,r,i,o,n)=>{const s=(0,_where.where)(n[e][t],{property:"value",comparator:i.comparator,value:i.value});for(const t of s)for(const r of t.record)o[e].push(await(0,_retrieveFile.retrieveFile)(`${e}/${r}`))};await(0,_getMatchingIndexes.getMatchingIndexes)(n,s,t,o,r,p,c)||i.push(o)}return e.conditions=i,e};exports.getConditionIndexedList=getConditionIndexedList;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.getConditionIndexedList=void 0;var _isEntityProperty=require("./parsers/isEntityProperty"),_splitEntityProperty=require("./parsers/splitEntityProperty"),_retrieveRecord=require("./retrieveRecord"),_where=require("../queries/where"),_retrieveFile=require("./retrieveFile"),_getMatchingIndexes=require("./getMatchingIndexes");const getConditionIndexedList=async(e,t,r)=>{const i=[];for(const o of e.conditions){let n=e.entity,s=o.property;if((0,_isEntityProperty.isEntityProperty)(s)){const e=(0,_splitEntityProperty.splitEntityProperty)(s);n=e.entity,s=e.property}Object.prototype.hasOwnProperty.call(t,n)||(t[n]=await(0,_retrieveRecord.retrieveRecord)(n));const p={},y=async(e,t,r,i,o,n)=>{const s=(0,_where.where)(n[e][t],{property:"value",comparator:i.comparator,value:i.value,type:i.type});for(const t of s)for(const r of t.record)o[e].push(await(0,_retrieveFile.retrieveFile)(`${e}/${r}`))};await(0,_getMatchingIndexes.getMatchingIndexes)(n,s,t,o,r,p,y)||i.push(o)}return e.conditions=i,e};exports.getConditionIndexedList=getConditionIndexedList;