json-fs-query 3.1.4 → 3.3.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 (187) hide show
  1. package/README.md +257 -15
  2. package/browser/jsonFsQuery.js +3884 -5057
  3. package/browser/jsonFsQuery.min.js +1 -1
  4. package/dist/data/introspect/alter.d.ts +12 -0
  5. package/dist/data/introspect/alter.js +304 -0
  6. package/dist/data/introspect/alter.min.js +1 -0
  7. package/dist/data/introspect/create.d.ts +10 -0
  8. package/dist/data/introspect/create.js +9 -23
  9. package/dist/data/introspect/create.min.js +1 -1
  10. package/dist/data/introspect/drop.js +7 -15
  11. package/dist/data/introspect/drop.min.js +1 -1
  12. package/dist/data/introspect/formatDatabase.d.ts +17 -0
  13. package/dist/data/introspect/formatDatabase.js +56 -0
  14. package/dist/data/introspect/formatDatabase.min.js +1 -0
  15. package/dist/data/introspect/index.d.ts +9 -0
  16. package/dist/data/introspect/index.js +18 -5
  17. package/dist/data/introspect/index.min.js +1 -1
  18. package/dist/data/introspect/packDatabase.d.ts +27 -0
  19. package/dist/data/introspect/packDatabase.js +113 -0
  20. package/dist/data/introspect/packDatabase.min.js +1 -0
  21. package/dist/data/introspect/policies/foreignKeyExists.d.ts +2 -0
  22. package/dist/data/introspect/policies/foreignKeyExists.js +9 -3
  23. package/dist/data/introspect/policies/foreignKeyExists.min.js +1 -1
  24. package/dist/data/introspect/policies/hasDependents.d.ts +3 -3
  25. package/dist/data/introspect/policies/hasDependents.js +11 -3
  26. package/dist/data/introspect/policies/hasDependents.min.js +1 -1
  27. package/dist/data/introspect/policies/keyUnique.d.ts +3 -0
  28. package/dist/data/introspect/policies/keyUnique.js +10 -0
  29. package/dist/data/introspect/policies/keyUnique.min.js +1 -1
  30. package/dist/data/queries/databaseStatements.d.ts +31 -0
  31. package/dist/data/queries/databaseStatements.js +97 -0
  32. package/dist/data/queries/databaseStatements.min.js +1 -0
  33. package/dist/data/queries/deleteEntity.js +35 -19
  34. package/dist/data/queries/deleteEntity.min.js +1 -1
  35. package/dist/data/queries/insertEntity.d.ts +8 -0
  36. package/dist/data/queries/insertEntity.js +340 -43
  37. package/dist/data/queries/insertEntity.min.js +1 -1
  38. package/dist/data/queries/joinEntity.d.ts +15 -0
  39. package/dist/data/queries/joinEntity.js +91 -15
  40. package/dist/data/queries/joinEntity.min.js +1 -1
  41. package/dist/data/queries/query.d.ts +2 -1
  42. package/dist/data/queries/query.js +5 -2
  43. package/dist/data/queries/query.min.js +1 -1
  44. package/dist/data/queries/selectFields.d.ts +5 -4
  45. package/dist/data/queries/selectFields.js +25 -11
  46. package/dist/data/queries/selectFields.min.js +1 -1
  47. package/dist/data/queries/updateEntity.js +54 -15
  48. package/dist/data/queries/updateEntity.min.js +1 -1
  49. package/dist/data/storage/databases.d.ts +32 -0
  50. package/dist/data/storage/databases.js +93 -0
  51. package/dist/data/storage/databases.min.js +1 -0
  52. package/dist/data/storage/fileExists.d.ts +7 -0
  53. package/dist/data/storage/fileExists.js +25 -0
  54. package/dist/data/storage/fileExists.min.js +1 -0
  55. package/dist/data/storage/index.d.ts +19 -0
  56. package/dist/data/storage/index.js +124 -0
  57. package/dist/data/storage/index.min.js +1 -0
  58. package/dist/data/storage/listFiles.d.ts +8 -0
  59. package/dist/data/storage/listFiles.js +52 -0
  60. package/dist/data/storage/listFiles.min.js +1 -0
  61. package/dist/data/storage/makeDirectory.d.ts +7 -0
  62. package/dist/data/storage/makeDirectory.js +24 -0
  63. package/dist/data/storage/makeDirectory.min.js +1 -0
  64. package/dist/data/storage/nodeFiles.d.ts +6 -0
  65. package/dist/data/storage/nodeFiles.js +12 -0
  66. package/dist/data/storage/nodeFiles.min.js +1 -0
  67. package/dist/data/storage/readCache.d.ts +37 -0
  68. package/dist/data/storage/readCache.js +117 -0
  69. package/dist/data/storage/readCache.min.js +1 -0
  70. package/dist/data/storage/readJson.d.ts +16 -0
  71. package/dist/data/storage/readJson.js +38 -0
  72. package/dist/data/storage/readJson.min.js +1 -0
  73. package/dist/data/storage/removeDirectory.d.ts +8 -0
  74. package/dist/data/storage/removeDirectory.js +30 -0
  75. package/dist/data/storage/removeDirectory.min.js +1 -0
  76. package/dist/data/storage/removeFile.d.ts +8 -0
  77. package/dist/data/storage/removeFile.js +31 -0
  78. package/dist/data/storage/removeFile.min.js +1 -0
  79. package/dist/data/storage/storagePath.d.ts +11 -0
  80. package/dist/data/storage/storagePath.js +25 -0
  81. package/dist/data/storage/storagePath.min.js +1 -0
  82. package/dist/data/storage/writeJson.d.ts +17 -0
  83. package/dist/data/storage/writeJson.js +37 -0
  84. package/dist/data/storage/writeJson.min.js +1 -0
  85. package/dist/data/storage/writeSet.d.ts +64 -0
  86. package/dist/data/storage/writeSet.js +306 -0
  87. package/dist/data/storage/writeSet.min.js +1 -0
  88. package/dist/data/utilities/compareAs.d.ts +1 -0
  89. package/dist/data/utilities/compareAs.js +2 -2
  90. package/dist/data/utilities/compareAs.min.js +1 -1
  91. package/dist/data/utilities/config.d.ts +37 -0
  92. package/dist/data/utilities/config.js +77 -5
  93. package/dist/data/utilities/config.min.js +1 -1
  94. package/dist/data/utilities/databaseLock.d.ts +7 -0
  95. package/dist/data/utilities/databaseLock.js +19 -4
  96. package/dist/data/utilities/databaseLock.min.js +1 -1
  97. package/dist/data/utilities/deregisterRecord.js +4 -10
  98. package/dist/data/utilities/deregisterRecord.min.js +1 -1
  99. package/dist/data/utilities/getConditionIndexedList.js +3 -4
  100. package/dist/data/utilities/getConditionIndexedList.min.js +1 -1
  101. package/dist/data/utilities/indexBuffer.d.ts +35 -0
  102. package/dist/data/utilities/indexBuffer.js +139 -0
  103. package/dist/data/utilities/indexBuffer.min.js +1 -0
  104. package/dist/data/utilities/indexHas.d.ts +13 -0
  105. package/dist/data/utilities/indexHas.js +48 -0
  106. package/dist/data/utilities/indexHas.min.js +1 -0
  107. package/dist/data/utilities/joinBases.d.ts +29 -0
  108. package/dist/data/utilities/joinBases.js +128 -0
  109. package/dist/data/utilities/joinBases.min.js +1 -0
  110. package/dist/data/utilities/joinKey.d.ts +17 -0
  111. package/dist/data/utilities/joinKey.js +31 -0
  112. package/dist/data/utilities/joinKey.min.js +1 -0
  113. package/dist/data/utilities/keyIndexFiles.d.ts +16 -0
  114. package/dist/data/utilities/keyIndexFiles.js +60 -0
  115. package/dist/data/utilities/keyIndexFiles.min.js +1 -0
  116. package/dist/data/utilities/knownFields.d.ts +26 -0
  117. package/dist/data/utilities/knownFields.js +128 -0
  118. package/dist/data/utilities/knownFields.min.js +1 -0
  119. package/dist/data/utilities/packedTable.d.ts +34 -0
  120. package/dist/data/utilities/packedTable.js +60 -0
  121. package/dist/data/utilities/packedTable.min.js +1 -0
  122. package/dist/data/utilities/parsers/findInsertValues.d.ts +3 -3
  123. package/dist/data/utilities/parsers/findInsertValues.js +28 -12
  124. package/dist/data/utilities/parsers/findInsertValues.min.js +1 -1
  125. package/dist/data/utilities/parsers/maskStrings.js +11 -2
  126. package/dist/data/utilities/parsers/maskStrings.min.js +1 -1
  127. package/dist/data/utilities/parsers/parseAlter.d.ts +33 -0
  128. package/dist/data/utilities/parsers/parseAlter.js +84 -0
  129. package/dist/data/utilities/parsers/parseAlter.min.js +1 -0
  130. package/dist/data/utilities/parsers/parseCreate.d.ts +14 -0
  131. package/dist/data/utilities/parsers/parseCreate.js +13 -5
  132. package/dist/data/utilities/parsers/parseCreate.min.js +1 -1
  133. package/dist/data/utilities/parsers/parseDatabaseStatement.d.ts +17 -0
  134. package/dist/data/utilities/parsers/parseDatabaseStatement.js +82 -0
  135. package/dist/data/utilities/parsers/parseDatabaseStatement.min.js +1 -0
  136. package/dist/data/utilities/parsers/parseQuery.d.ts +3 -0
  137. package/dist/data/utilities/parsers/parseQuery.js +24 -0
  138. package/dist/data/utilities/parsers/parseQuery.min.js +1 -1
  139. package/dist/data/utilities/parsers/startsQuery.js +1 -1
  140. package/dist/data/utilities/parsers/startsQuery.min.js +1 -1
  141. package/dist/data/utilities/recordExists.js +2 -7
  142. package/dist/data/utilities/recordExists.min.js +1 -1
  143. package/dist/data/utilities/registerRecord.js +4 -10
  144. package/dist/data/utilities/registerRecord.min.js +1 -1
  145. package/dist/data/utilities/removeFromIndex.js +4 -10
  146. package/dist/data/utilities/removeFromIndex.min.js +1 -1
  147. package/dist/data/utilities/retrieveFile.d.ts +5 -0
  148. package/dist/data/utilities/retrieveFile.js +7 -16
  149. package/dist/data/utilities/retrieveFile.min.js +1 -1
  150. package/dist/data/utilities/retrieveFiles.d.ts +15 -0
  151. package/dist/data/utilities/retrieveFiles.js +48 -0
  152. package/dist/data/utilities/retrieveFiles.min.js +1 -0
  153. package/dist/data/utilities/retrieveRecord.d.ts +6 -0
  154. package/dist/data/utilities/retrieveRecord.js +24 -1
  155. package/dist/data/utilities/retrieveRecord.min.js +1 -1
  156. package/dist/data/utilities/retrieveRecords.d.ts +22 -0
  157. package/dist/data/utilities/retrieveRecords.js +60 -10
  158. package/dist/data/utilities/retrieveRecords.min.js +1 -1
  159. package/dist/data/utilities/rowLookup.d.ts +38 -0
  160. package/dist/data/utilities/rowLookup.js +99 -0
  161. package/dist/data/utilities/rowLookup.min.js +1 -0
  162. package/dist/data/utilities/runQuery.js +28 -4
  163. package/dist/data/utilities/runQuery.min.js +1 -1
  164. package/dist/data/utilities/semiJoin.d.ts +27 -0
  165. package/dist/data/utilities/semiJoin.js +97 -0
  166. package/dist/data/utilities/semiJoin.min.js +1 -0
  167. package/dist/data/utilities/updateIndex.js +5 -14
  168. package/dist/data/utilities/updateIndex.min.js +1 -1
  169. package/dist/index.d.ts +1 -1
  170. package/dist/index.js +24 -0
  171. package/dist/index.min.js +1 -1
  172. package/package.json +10 -4
  173. package/dist/data/utilities/getJoinIndexedList.d.ts +0 -3
  174. package/dist/data/utilities/getJoinIndexedList.js +0 -76
  175. package/dist/data/utilities/getJoinIndexedList.min.js +0 -1
  176. package/dist/data/utilities/getMatchingIndexes.d.ts +0 -2
  177. package/dist/data/utilities/getMatchingIndexes.js +0 -28
  178. package/dist/data/utilities/getMatchingIndexes.min.js +0 -1
  179. package/dist/data/utilities/matchIndexedJoins.d.ts +0 -2
  180. package/dist/data/utilities/matchIndexedJoins.js +0 -63
  181. package/dist/data/utilities/matchIndexedJoins.min.js +0 -1
  182. package/dist/data/utilities/restrictIndexedList.d.ts +0 -2
  183. package/dist/data/utilities/restrictIndexedList.js +0 -45
  184. package/dist/data/utilities/restrictIndexedList.min.js +0 -1
  185. package/dist/data/utilities/useJoinClause.d.ts +0 -6
  186. package/dist/data/utilities/useJoinClause.js +0 -57
  187. package/dist/data/utilities/useJoinClause.min.js +0 -1
@@ -7,10 +7,12 @@ exports.query = void 0;
7
7
  var _parser = require("./parser");
8
8
  var _runQuery = require("../utilities/runQuery");
9
9
  var _databaseLock = require("../utilities/databaseLock");
10
+ var _storage = require("../storage");
10
11
  /**
11
12
  * Parse a query string (one query, or several separated by `;`) and run each query in turn, resolving to one result
12
13
  * per query. The queries of one call run together, under the database lock: no other call's queries run between
13
- * them (see withDatabaseLock).
14
+ * them (see withDatabaseLock). Each query is all or nothing: one that fails changes nothing, and the queries before it
15
+ * keep their changes (see withWriteSet).
14
16
  * @param queryString
15
17
  */
16
18
  const query = async (queryString = '') => {
@@ -18,7 +20,8 @@ const query = async (queryString = '') => {
18
20
  return (0, _databaseLock.withDatabaseLock)(async () => {
19
21
  const queryResults = [];
20
22
  for (const parsed of parsedQueries) {
21
- const dataSet = await (0, _runQuery.runQuery)(parsed);
23
+ // Each query's changes reach storage together, or not at all if it fails (see withWriteSet)
24
+ const dataSet = await (0, _storage.withWriteSet)(() => (0, _runQuery.runQuery)(parsed));
22
25
  queryResults.push(dataSet[parsed.entity]);
23
26
  }
24
27
  return queryResults;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.query=void 0;var _parser=require("./parser"),_runQuery=require("../utilities/runQuery"),_databaseLock=require("../utilities/databaseLock");const query=async(e="")=>{const r=(0,_parser.parser)(e);return(0,_databaseLock.withDatabaseLock)((async()=>{const e=[];for(const t of r){const r=await(0,_runQuery.runQuery)(t);e.push(r[t.entity])}return e}))};exports.query=query;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.query=void 0;var _parser=require("./parser"),_runQuery=require("../utilities/runQuery"),_databaseLock=require("../utilities/databaseLock"),_storage=require("../storage");const query=async(e="")=>{const r=(0,_parser.parser)(e);return(0,_databaseLock.withDatabaseLock)((async()=>{const e=[];for(const t of r){const r=await(0,_storage.withWriteSet)((()=>(0,_runQuery.runQuery)(t)));e.push(r[t.entity])}return e}))};exports.query=query;
@@ -1,12 +1,13 @@
1
1
  import { ParsedSelect } from '../utilities/parsers/findSelects';
2
2
  import { Group } from './groupBy';
3
3
  /**
4
- * Shape each row down to only the selected properties (aliased, when given). dataSet is either a list of rows, or
5
- * (once groupBy has run) a list of groups, whose rows are shaped the same way at any depth; the groups keep their
6
- * field and value, selected or not.
4
+ * Shape each row down to only the selected properties (aliased, when given, otherwise named as written). dataSet is
5
+ * either a list of rows, or (once groupBy has run) a list of groups, whose rows are shaped the same way at any depth;
6
+ * the groups keep their field and value, selected or not.
7
7
  * @param dataSet
8
8
  * @param selectClauses
9
9
  * @param grouped Whether dataSet is a list of groups (see groupBy)
10
+ * @param entity The queried record's name, so `<record>.<field>` picks the row's own field
10
11
  */
11
- export declare const selectFields: (dataSet?: Object[] | Group[], selectClauses?: ParsedSelect[], grouped?: boolean) => Object[] | Group[];
12
+ export declare const selectFields: (dataSet?: Object[] | Group[], selectClauses?: ParsedSelect[], grouped?: boolean, entity?: string) => Object[] | Group[];
12
13
  //# sourceMappingURL=selectFields.d.ts.map
@@ -7,35 +7,49 @@ exports.selectFields = void 0;
7
7
  require("core-js/modules/esnext.iterator.constructor.js");
8
8
  require("core-js/modules/esnext.iterator.map.js");
9
9
  require("core-js/modules/esnext.iterator.reduce.js");
10
- const shapeRow = (row, selectClauses) => selectClauses.reduce((shaped, {
10
+ /**
11
+ * The value a select name picks from a row: the row's own key (a field, a merged record's `<record>.<field>`, or a
12
+ * joined record's rows), or for `<queried record>.<field>`, the row's own field.
13
+ * @param row
14
+ * @param property
15
+ * @param entity - The queried record's name.
16
+ */
17
+ const pick = (row, property, entity) => {
18
+ if (Object.prototype.hasOwnProperty.call(row, property) || typeof entity === 'undefined' || !property.startsWith(`${entity}.`)) {
19
+ return row[property];
20
+ }
21
+ return row[property.slice(entity.length + 1)];
22
+ };
23
+ const shapeRow = (row, selectClauses, entity) => selectClauses.reduce((shaped, {
11
24
  property,
12
25
  alias
13
26
  }) => {
14
- shaped[alias || property] = row[property];
27
+ shaped[alias || property] = pick(row, property, entity);
15
28
  return shaped;
16
29
  }, {});
17
- const shapeGroup = (group, selectClauses) => group.groups ? {
30
+ const shapeGroup = (group, selectClauses, entity) => group.groups ? {
18
31
  ...group,
19
- groups: group.groups.map(inner => shapeGroup(inner, selectClauses))
32
+ groups: group.groups.map(inner => shapeGroup(inner, selectClauses, entity))
20
33
  } : {
21
34
  ...group,
22
- rows: group.rows.map(row => shapeRow(row, selectClauses))
35
+ rows: group.rows.map(row => shapeRow(row, selectClauses, entity))
23
36
  };
24
37
  /**
25
- * Shape each row down to only the selected properties (aliased, when given). dataSet is either a list of rows, or
26
- * (once groupBy has run) a list of groups, whose rows are shaped the same way at any depth; the groups keep their
27
- * field and value, selected or not.
38
+ * Shape each row down to only the selected properties (aliased, when given, otherwise named as written). dataSet is
39
+ * either a list of rows, or (once groupBy has run) a list of groups, whose rows are shaped the same way at any depth;
40
+ * the groups keep their field and value, selected or not.
28
41
  * @param dataSet
29
42
  * @param selectClauses
30
43
  * @param grouped Whether dataSet is a list of groups (see groupBy)
44
+ * @param entity The queried record's name, so `<record>.<field>` picks the row's own field
31
45
  */
32
- const selectFields = (dataSet = [], selectClauses = [], grouped = false) => {
46
+ const selectFields = (dataSet = [], selectClauses = [], grouped = false, entity) => {
33
47
  if (!selectClauses.length) {
34
48
  return dataSet;
35
49
  }
36
50
  if (grouped) {
37
- return dataSet.map(group => shapeGroup(group, selectClauses));
51
+ return dataSet.map(group => shapeGroup(group, selectClauses, entity));
38
52
  }
39
- return dataSet.map(row => shapeRow(row, selectClauses));
53
+ return dataSet.map(row => shapeRow(row, selectClauses, entity));
40
54
  };
41
55
  exports.selectFields = selectFields;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.selectFields=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.iterator.reduce.js");const shapeRow=(e,s)=>s.reduce(((s,{property:r,alias:o})=>(s[o||r]=e[r],s)),{}),shapeGroup=(e,s)=>e.groups?{...e,groups:e.groups.map((e=>shapeGroup(e,s)))}:{...e,rows:e.rows.map((e=>shapeRow(e,s)))},selectFields=(e=[],s=[],r=!1)=>s.length?r?e.map((e=>shapeGroup(e,s))):e.map((e=>shapeRow(e,s))):e;exports.selectFields=selectFields;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.selectFields=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.iterator.reduce.js");const pick=(e,s,r)=>Object.prototype.hasOwnProperty.call(e,s)||void 0===r||!s.startsWith(`${r}.`)?e[s]:e[s.slice(r.length+1)],shapeRow=(e,s,r)=>s.reduce(((s,{property:o,alias:t})=>(s[t||o]=pick(e,o,r),s)),{}),shapeGroup=(e,s,r)=>e.groups?{...e,groups:e.groups.map((e=>shapeGroup(e,s,r)))}:{...e,rows:e.rows.map((e=>shapeRow(e,s,r)))},selectFields=(e=[],s=[],r=!1,o)=>s.length?r?e.map((e=>shapeGroup(e,s,o))):e.map((e=>shapeRow(e,s,o))):e;exports.selectFields=selectFields;
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.updateEntity = void 0;
7
- require("core-js/modules/es.json.stringify.js");
8
7
  require("core-js/modules/esnext.iterator.constructor.js");
9
8
  require("core-js/modules/esnext.iterator.find.js");
10
9
  require("core-js/modules/esnext.iterator.map.js");
@@ -22,21 +21,30 @@ var _foreignKeyExists = require("../introspect/policies/foreignKeyExists");
22
21
  var _hasDependents = require("../introspect/policies/hasDependents");
23
22
  var _splitEntityProperty = require("../utilities/parsers/splitEntityProperty");
24
23
  var _config = require("../utilities/config");
25
- const {
26
- writeFile
27
- } = require('fs/promises');
24
+ var _keyIndexFiles = require("../utilities/keyIndexFiles");
25
+ var _storage = require("../storage");
26
+ var _packedTable = require("../utilities/packedTable");
27
+ var _knownFields = require("../utilities/knownFields");
28
28
  /**
29
29
  * Same reasoning as deleteEntity: a record object carries no memory of which entry file it came
30
- * from, so re-scan entries[] and match by the record's own primary key value(s) - a single field,
31
- * or a composite of several for a multi-field primary key.
30
+ * from, so find the file whose primary key value(s) match - a single field, or a composite of
31
+ * several for a multi-field primary key. The primary key's index says which file that is; the file
32
+ * is read to confirm it, and without an index (or when it leads nowhere) every entry is looked at
33
+ * in turn, as before.
32
34
  * @param record
33
35
  * @param primaryKey
34
36
  * @param primaryValue
35
37
  */
36
38
  const findEntryFile = async (record, primaryKey, primaryValue) => {
39
+ const type = (0, _fieldType.keyValueType)(record, primaryKey);
40
+ const isMatch = async fileName => (0, _compareAs.sameValue)(type, (0, _computeKeyValue.computeKeyValue)(primaryKey.fields, await (0, _retrieveFile.retrieveFile)(`${record.path}/${fileName}`)), primaryValue);
41
+ for (const fileName of (await (0, _keyIndexFiles.keyIndexFiles)(record, primaryKey, value => (0, _compareAs.sameValue)(type, value, primaryValue))) ?? []) {
42
+ if (await isMatch(fileName)) {
43
+ return fileName;
44
+ }
45
+ }
37
46
  for (const fileName of record.entries) {
38
- const data = await (0, _retrieveFile.retrieveFile)(`${record.path}/${fileName}`);
39
- if ((0, _compareAs.sameValue)((0, _fieldType.keyValueType)(record, primaryKey), (0, _computeKeyValue.computeKeyValue)(primaryKey.fields, data), primaryValue)) {
47
+ if (await isMatch(fileName)) {
40
48
  return fileName;
41
49
  }
42
50
  }
@@ -68,7 +76,8 @@ const assertUniqueForUpdate = async (entity, record, oldData, newData, newValues
68
76
  continue;
69
77
  }
70
78
  const checkKeys = key.fields.map(field => newData[field]);
71
- if (checkKeys.some(value => value === null)) {
79
+ // A null, or a field the row doesn't have (left out, or removed by this update), is never a duplicate
80
+ if (checkKeys.some(value => value === null || typeof value === 'undefined')) {
72
81
  continue;
73
82
  }
74
83
  const isUnique = await (0, _keyUnique.keyUnique)(entity, key.fields, checkKeys);
@@ -93,7 +102,8 @@ const assertForeignKeysForUpdate = async (entity, record, oldData, newValues) =>
93
102
  continue;
94
103
  }
95
104
  const field = key.fields[0];
96
- if (!Object.prototype.hasOwnProperty.call(newValues, field) || newValues[field] === null || (0, _compareAs.sameValue)((0, _fieldType.fieldType)(record, field), newValues[field], oldData[field])) {
105
+ // A null, or a field the update removes (undefined), references nothing
106
+ if (!Object.prototype.hasOwnProperty.call(newValues, field) || newValues[field] === null || typeof newValues[field] === 'undefined' || (0, _compareAs.sameValue)((0, _fieldType.fieldType)(record, field), newValues[field], oldData[field])) {
97
107
  continue;
98
108
  }
99
109
  const {
@@ -163,7 +173,7 @@ const assertUniqueWithinUpdate = (entity, record, planned, newValues) => {
163
173
  oldData,
164
174
  newData
165
175
  } of planned) {
166
- if (!keyFieldsChanged(record, key, oldData, newValues) || key.fields.some(field => newData[field] === null)) {
176
+ if (!keyFieldsChanged(record, key, oldData, newValues) || key.fields.some(field => newData[field] === null || typeof newData[field] === 'undefined')) {
167
177
  continue;
168
178
  }
169
179
  const value = (0, _computeKeyValue.computeKeyValue)(key.fields, newData);
@@ -186,6 +196,11 @@ const assertRequiredFields = (entity, record, newData) => {
186
196
  * of the merged record - a field whose already-stored value doesn't match its declared type
187
197
  * (nothing enforced this before typeCheck() existed) must not block an update that never touches
188
198
  * that field.
199
+ *
200
+ * A null for an optional field that isn't nullable means the field is removed from the row (the
201
+ * field can't hold null, so this is the only thing it can mean, and the only way to clear one):
202
+ * it's kept as undefined here, so the key checks and indexes see the field change, and removed from
203
+ * the row that's written (see withoutRemoved).
189
204
  * @param record
190
205
  * @param values
191
206
  */
@@ -193,19 +208,40 @@ const applyFieldTypes = (record, values) => {
193
208
  const typedValues = Object.assign({}, values);
194
209
  for (const field of record.definition) {
195
210
  if (Object.prototype.hasOwnProperty.call(typedValues, field.name)) {
196
- typedValues[field.name] = (0, _typeCheck.typeCheck)(field.type, typedValues[field.name], field.nullable);
211
+ typedValues[field.name] = typedValues[field.name] === null && field.optional && !field.nullable ? undefined : (0, _typeCheck.typeCheck)(field.type, typedValues[field.name], field.nullable);
197
212
  }
198
213
  }
199
214
  return typedValues;
200
215
  };
216
+ /**
217
+ * A row without the fields an update removes (those it set to undefined, see applyFieldTypes).
218
+ * @param row
219
+ * @param typedValues
220
+ */
221
+ const withoutRemoved = (row, typedValues) => {
222
+ const kept = Object.assign({}, row);
223
+ for (const field of Object.keys(typedValues)) {
224
+ if (typeof typedValues[field] === 'undefined') {
225
+ delete kept[field];
226
+ }
227
+ }
228
+ return kept;
229
+ };
201
230
  const updateEntity = async (entity = '', values = {}, dataSet = {}) => {
202
- const databasePath = (0, _config.getSetting)('databasePath', 'database/');
203
231
  const record = await (0, _retrieveRecord.retrieveRecord)(entity);
204
232
  const primaryKey = record.keys.find(key => key.type === 'primary');
205
233
  if (!primaryKey) {
206
234
  throw new Error(`Cannot update "${entity}" without a primary key`);
207
235
  }
236
+ // A field the record doesn't define would otherwise be stored outside its definition
237
+ (0, _knownFields.assertFieldsDefined)(entity, record, Object.keys(values || {}), 'set');
208
238
  const typedValues = applyFieldTypes(record, values);
239
+ // A row is found by its primary key, so none of its fields can be cleared (an optional one could be, by null)
240
+ for (const field of primaryKey.fields) {
241
+ if (Object.prototype.hasOwnProperty.call(typedValues, field) && typeof typedValues[field] === 'undefined') {
242
+ throw new Error(`Cannot clear "${field}" on ${entity}: it's part of the primary key`);
243
+ }
244
+ }
209
245
  // Check every row first and write only once all of them pass, so a row that fails leaves the others unchanged too
210
246
  const planned = [];
211
247
  for (const row of dataSet[entity] || []) {
@@ -218,7 +254,7 @@ const updateEntity = async (entity = '', values = {}, dataSet = {}) => {
218
254
  continue;
219
255
  }
220
256
  const oldData = await (0, _retrieveFile.retrieveFile)(`${record.path}/${fileName}`);
221
- const newData = Object.assign({}, oldData, typedValues);
257
+ const newData = withoutRemoved(Object.assign({}, oldData, typedValues), typedValues);
222
258
  await assertUniqueForUpdate(entity, record, oldData, newData, typedValues);
223
259
  await assertForeignKeysForUpdate(entity, record, oldData, typedValues);
224
260
  await assertNoDependentsForUpdate(entity, record, primaryKey, oldData, typedValues);
@@ -230,13 +266,16 @@ const updateEntity = async (entity = '', values = {}, dataSet = {}) => {
230
266
  });
231
267
  }
232
268
  assertUniqueWithinUpdate(entity, record, planned, typedValues);
269
+ if (planned.length) {
270
+ await (0, _packedTable.discardPacked)(record.path);
271
+ }
233
272
  for (const {
234
273
  fileName,
235
274
  oldData,
236
275
  newData
237
276
  } of planned) {
238
277
  await reconcileIndexes(record, oldData, newData, typedValues, fileName);
239
- await writeFile(`${databasePath}${record.path}/${fileName}`, JSON.stringify(newData, null, 2));
278
+ await (0, _storage.writeJson)(`${record.path}/${fileName}`, newData);
240
279
  }
241
280
  dataSet[entity] = planned.map(({
242
281
  newData
@@ -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"),_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 o=await(0,_retrieveFile.retrieveFile)(`${e.path}/${r}`);if((0,_compareAs.sameValue)((0,_fieldType.keyValueType)(e,t),(0,_computeKeyValue.computeKeyValue)(t.fields,o),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,o)=>{for(const s of t.keys){if("primary"!==s.type&&"unique"!==s.type||!keyFieldsChanged(t,s,i,o))continue;const n=s.fields.map((e=>r[e]));if(n.some((e=>null===e)))continue;if(!await(0,_keyUnique.keyUnique)(e,s.fields,n))throw new Error(`Duplicate value for ${s.type} key "${s.fields.join(", ")}" on ${e}`)}},assertForeignKeysForUpdate=async(e,t,i,r)=>{for(const o of t.keys){if("foreign"!==o.type||1!==o.fields.length||!o.references||1!==o.references.length)continue;const s=o.fields[0];if(!Object.prototype.hasOwnProperty.call(r,s)||null===r[s]||(0,_compareAs.sameValue)((0,_fieldType.fieldType)(t,s),r[s],i[s]))continue;const{entity:n,property:a}=(0,_splitEntityProperty.splitEntityProperty)(o.references[0].fields[0]);if(!await(0,_foreignKeyExists.foreignKeyExists)(n,a,r[s]))throw new Error(`Foreign key "${s}" on ${e} references a nonexistent ${n}.${a} = ${r[s]}`)}},assertNoDependentsForUpdate=async(e,t,i,r,o)=>{if(!(0,_config.getSetting)("enforceForeignKeys",!0)||1!==i.fields.length||!keyFieldsChanged(t,i,r,o))return;const s=i.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,i,r,o)=>{for(const s of e.keys)keyFieldsChanged(e,s,t,r)&&(await(0,_removeFromIndex.removeFromIndex)(e.path,s,(0,_computeKeyValue.computeKeyValue)(s.fields,t),o,(0,_fieldType.keyValueType)(e,s)),await(0,_updateIndex.updateIndex)(e.path,s,(0,_computeKeyValue.computeKeyValue)(s.fields,i),o,(0,_fieldType.keyValueType)(e,s)))},assertUniqueWithinUpdate=(e,t,i,r)=>{for(const o of t.keys){if("primary"!==o.type&&"unique"!==o.type)continue;const s=[];for(const{oldData:n,newData:a}of i){if(!keyFieldsChanged(t,o,n,r)||o.fields.some((e=>null===a[e])))continue;const i=(0,_computeKeyValue.computeKeyValue)(o.fields,a);if(s.some((e=>(0,_compareAs.sameValue)((0,_fieldType.keyValueType)(t,o),e,i))))throw new Error(`Duplicate value for ${o.type} key "${o.fields.join(", ")}" on ${e}`);s.push(i)}}},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],t.nullable));return i},updateEntity=async(e="",t={},i={})=>{const r=(0,_config.getSetting)("databasePath","database/"),o=await(0,_retrieveRecord.retrieveRecord)(e),s=o.keys.find((e=>"primary"===e.type));if(!s)throw new Error(`Cannot update "${e}" without a primary key`);const n=applyFieldTypes(o,t),a=[];for(const t of i[e]||[]){const i=await findEntryFile(o,s,(0,_computeKeyValue.computeKeyValue)(s.fields,t));if(!i)throw new Error(`Could not find entry for ${e} where "${s.fields.join(", ")}" = ${(0,_computeKeyValue.computeKeyValue)(s.fields,t)}`);if(a.some((e=>e.fileName===i)))continue;const r=await(0,_retrieveFile.retrieveFile)(`${o.path}/${i}`),l=Object.assign({},r,n);await assertUniqueForUpdate(e,o,r,l,n),await assertForeignKeysForUpdate(e,o,r,n),await assertNoDependentsForUpdate(e,o,s,r,n),assertRequiredFields(e,o,l),a.push({fileName:i,oldData:r,newData:l})}assertUniqueWithinUpdate(e,o,a,n);for(const{fileName:e,oldData:t,newData:i}of a)await reconcileIndexes(o,t,i,n,e),await writeFile(`${r}${o.path}/${e}`,JSON.stringify(i,null,2));return i[e]=a.map((({newData:e})=>e)),i};exports.updateEntity=updateEntity;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.updateEntity=void 0,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"),_keyIndexFiles=require("../utilities/keyIndexFiles"),_storage=require("../storage"),_packedTable=require("../utilities/packedTable"),_knownFields=require("../utilities/knownFields");const findEntryFile=async(e,t,i)=>{const r=(0,_fieldType.keyValueType)(e,t),o=async o=>(0,_compareAs.sameValue)(r,(0,_computeKeyValue.computeKeyValue)(t.fields,await(0,_retrieveFile.retrieveFile)(`${e.path}/${o}`)),i);for(const s of await(0,_keyIndexFiles.keyIndexFiles)(e,t,(e=>(0,_compareAs.sameValue)(r,e,i)))??[])if(await o(s))return s;for(const t of e.entries)if(await o(t))return t;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,o)=>{for(const s of t.keys){if("primary"!==s.type&&"unique"!==s.type||!keyFieldsChanged(t,s,i,o))continue;const n=s.fields.map((e=>r[e]));if(n.some((e=>null==e)))continue;if(!await(0,_keyUnique.keyUnique)(e,s.fields,n))throw new Error(`Duplicate value for ${s.type} key "${s.fields.join(", ")}" on ${e}`)}},assertForeignKeysForUpdate=async(e,t,i,r)=>{for(const o of t.keys){if("foreign"!==o.type||1!==o.fields.length||!o.references||1!==o.references.length)continue;const s=o.fields[0];if(!Object.prototype.hasOwnProperty.call(r,s)||null===r[s]||void 0===r[s]||(0,_compareAs.sameValue)((0,_fieldType.fieldType)(t,s),r[s],i[s]))continue;const{entity:n,property:a}=(0,_splitEntityProperty.splitEntityProperty)(o.references[0].fields[0]);if(!await(0,_foreignKeyExists.foreignKeyExists)(n,a,r[s]))throw new Error(`Foreign key "${s}" on ${e} references a nonexistent ${n}.${a} = ${r[s]}`)}},assertNoDependentsForUpdate=async(e,t,i,r,o)=>{if(!(0,_config.getSetting)("enforceForeignKeys",!0)||1!==i.fields.length||!keyFieldsChanged(t,i,r,o))return;const s=i.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,i,r,o)=>{for(const s of e.keys)keyFieldsChanged(e,s,t,r)&&(await(0,_removeFromIndex.removeFromIndex)(e.path,s,(0,_computeKeyValue.computeKeyValue)(s.fields,t),o,(0,_fieldType.keyValueType)(e,s)),await(0,_updateIndex.updateIndex)(e.path,s,(0,_computeKeyValue.computeKeyValue)(s.fields,i),o,(0,_fieldType.keyValueType)(e,s)))},assertUniqueWithinUpdate=(e,t,i,r)=>{for(const o of t.keys){if("primary"!==o.type&&"unique"!==o.type)continue;const s=[];for(const{oldData:n,newData:a}of i){if(!keyFieldsChanged(t,o,n,r)||o.fields.some((e=>null===a[e]||void 0===a[e])))continue;const i=(0,_computeKeyValue.computeKeyValue)(o.fields,a);if(s.some((e=>(0,_compareAs.sameValue)((0,_fieldType.keyValueType)(t,o),e,i))))throw new Error(`Duplicate value for ${o.type} key "${o.fields.join(", ")}" on ${e}`);s.push(i)}}},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]=null===i[t.name]&&t.optional&&!t.nullable?void 0:(0,_typeCheck.typeCheck)(t.type,i[t.name],t.nullable));return i},withoutRemoved=(e,t)=>{const i=Object.assign({},e);for(const e of Object.keys(t))void 0===t[e]&&delete i[e];return i},updateEntity=async(e="",t={},i={})=>{const r=await(0,_retrieveRecord.retrieveRecord)(e),o=r.keys.find((e=>"primary"===e.type));if(!o)throw new Error(`Cannot update "${e}" without a primary key`);(0,_knownFields.assertFieldsDefined)(e,r,Object.keys(t||{}),"set");const s=applyFieldTypes(r,t);for(const t of o.fields)if(Object.prototype.hasOwnProperty.call(s,t)&&void 0===s[t])throw new Error(`Cannot clear "${t}" on ${e}: it's part of the primary key`);const n=[];for(const t of i[e]||[]){const i=await findEntryFile(r,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)}`);if(n.some((e=>e.fileName===i)))continue;const a=await(0,_retrieveFile.retrieveFile)(`${r.path}/${i}`),l=withoutRemoved(Object.assign({},a,s),s);await assertUniqueForUpdate(e,r,a,l,s),await assertForeignKeysForUpdate(e,r,a,s),await assertNoDependentsForUpdate(e,r,o,a,s),assertRequiredFields(e,r,l),n.push({fileName:i,oldData:a,newData:l})}assertUniqueWithinUpdate(e,r,n,s),n.length&&await(0,_packedTable.discardPacked)(r.path);for(const{fileName:e,oldData:t,newData:i}of n)await reconcileIndexes(r,t,i,s,e),await(0,_storage.writeJson)(`${r.path}/${e}`,i);return i[e]=n.map((({newData:e})=>e)),i};exports.updateEntity=updateEntity;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Where something in the folder holding the databases is (see databasesFolder), as storagePath gives it for a database:
3
+ * on disk in Node, behind relativePath over fetch() in a browser.
4
+ * @param path - A path inside that folder, such as `__DATABASES.json` or a database's name.
5
+ */
6
+ export declare const databasesLocation: (path?: string) => string;
7
+ /**
8
+ * The databases' names, in the order they were created, from `__DATABASES.json` in the folder holding them (a list, so
9
+ * a browser can read it too: it can't list a folder). No list yet means no databases.
10
+ */
11
+ export declare const readDatabaseList: () => Promise<string[]>;
12
+ /**
13
+ * Replace the list of databases. Node only.
14
+ * @param names
15
+ */
16
+ export declare const writeDatabaseList: (names: string[]) => Promise<void>;
17
+ /**
18
+ * Whether a database's folder exists. Node only.
19
+ * @param name
20
+ */
21
+ export declare const databaseFolderExists: (name: string) => boolean;
22
+ /**
23
+ * Create a database's (empty) folder. Node only.
24
+ * @param name
25
+ */
26
+ export declare const makeDatabaseFolder: (name: string) => Promise<void>;
27
+ /**
28
+ * Delete a database's folder and everything in it, and forget anything read from it. Node only.
29
+ * @param name
30
+ */
31
+ export declare const removeDatabaseFolder: (name: string) => Promise<void>;
32
+ //# sourceMappingURL=databases.d.ts.map
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+
3
+ require("core-js/modules/esnext.weak-map.delete-all.js");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.writeDatabaseList = exports.removeDatabaseFolder = exports.readDatabaseList = exports.makeDatabaseFolder = exports.databasesLocation = exports.databaseFolderExists = void 0;
8
+ require("core-js/modules/es.json.stringify.js");
9
+ var jsEnv = _interopRequireWildcard(require("browser-or-node"));
10
+ var _config = require("../utilities/config");
11
+ var _nodeFiles = require("./nodeFiles");
12
+ var _readCache = require("./readCache");
13
+ var _writeSet = require("./writeSet");
14
+ var e;
15
+ function _interopRequireWildcard(t, r) { if (!r && t && t.__esModule) return t; var n, a, o = Object.defineProperty, f = { __proto__: null, default: t }; if (Object(t) !== t) return f; if (e || "function" != typeof WeakMap || (e = new WeakMap()), e) { if (e.has(t)) return e.get(t); e.set(t, f); } for (a in t) "default" !== a && {}.hasOwnProperty.call(t, a) && ((n = o && Object.getOwnPropertyDescriptor(t, a)) && (n.get || n.set) ? o(f, a, n) : f[a] = t[a]); return f; }
16
+ /**
17
+ * Where something in the folder holding the databases is (see databasesFolder), as storagePath gives it for a database:
18
+ * on disk in Node, behind relativePath over fetch() in a browser.
19
+ * @param path - A path inside that folder, such as `__DATABASES.json` or a database's name.
20
+ */
21
+ const databasesLocation = (path = '') => {
22
+ const relativePath = jsEnv.isBrowser ? (0, _config.getSetting)('relativePath', '') : '';
23
+ return `${relativePath}${(0, _config.databasesFolder)()}${path}`;
24
+ };
25
+ exports.databasesLocation = databasesLocation;
26
+ const listLocation = () => databasesLocation('__DATABASES.json');
27
+ /**
28
+ * The databases' names, in the order they were created, from `__DATABASES.json` in the folder holding them (a list, so
29
+ * a browser can read it too: it can't list a folder). No list yet means no databases.
30
+ */
31
+ const readDatabaseList = async () => {
32
+ let text;
33
+ try {
34
+ text = jsEnv.isNode ? await (0, _nodeFiles.nodeFiles)().readFile(listLocation(), 'utf8') : await fetch(listLocation()).then(response => response.ok === false ? '[]' : response.text());
35
+ } catch (error) {
36
+ if (jsEnv.isNode && error?.code !== 'ENOENT') {
37
+ throw error;
38
+ }
39
+ return [];
40
+ }
41
+ try {
42
+ const names = JSON.parse(text);
43
+ return Array.isArray(names) ? names : [];
44
+ } catch (error) {
45
+ // A static host answers a missing file with a page that isn't JSON
46
+ if (!jsEnv.isNode) {
47
+ return [];
48
+ }
49
+ throw new Error(`Could not read ${listLocation()}: ${error.message}`);
50
+ }
51
+ };
52
+ /**
53
+ * Replace the list of databases. Node only.
54
+ * @param names
55
+ */
56
+ exports.readDatabaseList = readDatabaseList;
57
+ const writeDatabaseList = async names => {
58
+ await (0, _nodeFiles.nodeFiles)().mkdir(databasesLocation(), {
59
+ recursive: true
60
+ });
61
+ await (0, _writeSet.writeAtomically)(listLocation(), JSON.stringify(names));
62
+ };
63
+ /**
64
+ * Whether a database's folder exists. Node only.
65
+ * @param name
66
+ */
67
+ exports.writeDatabaseList = writeDatabaseList;
68
+ const databaseFolderExists = name => require('fs').existsSync(databasesLocation(name));
69
+ /**
70
+ * Create a database's (empty) folder. Node only.
71
+ * @param name
72
+ */
73
+ exports.databaseFolderExists = databaseFolderExists;
74
+ const makeDatabaseFolder = async name => {
75
+ await (0, _nodeFiles.nodeFiles)().mkdir(databasesLocation(name), {
76
+ recursive: true
77
+ });
78
+ };
79
+ /**
80
+ * Delete a database's folder and everything in it, and forget anything read from it. Node only.
81
+ * @param name
82
+ */
83
+ exports.makeDatabaseFolder = makeDatabaseFolder;
84
+ const removeDatabaseFolder = async name => {
85
+ const location = databasesLocation(name);
86
+ (0, _readCache.cacheRemove)(location, true);
87
+ await (0, _nodeFiles.nodeFiles)().rm(location, {
88
+ recursive: true,
89
+ force: true
90
+ });
91
+ (0, _readCache.cacheRemove)(location, true);
92
+ };
93
+ exports.removeDatabaseFolder = removeDatabaseFolder;
@@ -0,0 +1 @@
1
+ "use strict";require("core-js/modules/esnext.weak-map.delete-all.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.writeDatabaseList=exports.removeDatabaseFolder=exports.readDatabaseList=exports.makeDatabaseFolder=exports.databasesLocation=exports.databaseFolderExists=void 0,require("core-js/modules/es.json.stringify.js");var e,jsEnv=_interopRequireWildcard(require("browser-or-node")),_config=require("../utilities/config"),_nodeFiles=require("./nodeFiles"),_readCache=require("./readCache"),_writeSet=require("./writeSet");function _interopRequireWildcard(a,t){if(!t&&a&&a.__esModule)return a;var s,r,o=Object.defineProperty,i={__proto__:null,default:a};if(Object(a)!==a)return i;if(e||"function"!=typeof WeakMap||(e=new WeakMap),e){if(e.has(a))return e.get(a);e.set(a,i)}for(r in a)"default"!==r&&{}.hasOwnProperty.call(a,r)&&((s=o&&Object.getOwnPropertyDescriptor(a,r))&&(s.get||s.set)?o(i,r,s):i[r]=a[r]);return i}const databasesLocation=(e="")=>`${jsEnv.isBrowser?(0,_config.getSetting)("relativePath",""):""}${(0,_config.databasesFolder)()}${e}`;exports.databasesLocation=databasesLocation;const listLocation=()=>databasesLocation("__DATABASES.json"),readDatabaseList=async()=>{let e;try{e=jsEnv.isNode?await(0,_nodeFiles.nodeFiles)().readFile(listLocation(),"utf8"):await fetch(listLocation()).then((e=>!1===e.ok?"[]":e.text()))}catch(e){if(jsEnv.isNode&&"ENOENT"!==e?.code)throw e;return[]}try{const a=JSON.parse(e);return Array.isArray(a)?a:[]}catch(e){if(!jsEnv.isNode)return[];throw new Error(`Could not read ${listLocation()}: ${e.message}`)}};exports.readDatabaseList=readDatabaseList;const writeDatabaseList=async e=>{await(0,_nodeFiles.nodeFiles)().mkdir(databasesLocation(),{recursive:!0}),await(0,_writeSet.writeAtomically)(listLocation(),JSON.stringify(e))};exports.writeDatabaseList=writeDatabaseList;const databaseFolderExists=e=>require("fs").existsSync(databasesLocation(e));exports.databaseFolderExists=databaseFolderExists;const makeDatabaseFolder=async e=>{await(0,_nodeFiles.nodeFiles)().mkdir(databasesLocation(e),{recursive:!0})};exports.makeDatabaseFolder=makeDatabaseFolder;const removeDatabaseFolder=async e=>{const a=databasesLocation(e);(0,_readCache.cacheRemove)(a,!0),await(0,_nodeFiles.nodeFiles)().rm(a,{recursive:!0,force:!0}),(0,_readCache.cacheRemove)(a,!0)};exports.removeDatabaseFolder=removeDatabaseFolder;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Whether a file (or folder) of the database exists, counting what the running statement has written or deleted so
3
+ * far (see withWriteSet). Node only, like the schema statements that use it.
4
+ * @param path - A path inside the database, such as `users.json`.
5
+ */
6
+ export declare const fileExists: (path: string) => boolean;
7
+ //# sourceMappingURL=fileExists.d.ts.map
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.fileExists = void 0;
7
+ var _storagePath = require("./storagePath");
8
+ var _writeSet = require("./writeSet");
9
+ /**
10
+ * Whether a file (or folder) of the database exists, counting what the running statement has written or deleted so
11
+ * far (see withWriteSet). Node only, like the schema statements that use it.
12
+ * @param path - A path inside the database, such as `users.json`.
13
+ */
14
+ const fileExists = path => {
15
+ const location = (0, _storagePath.storagePath)(path);
16
+ const pending = (0, _writeSet.pendingExists)(location);
17
+ if (pending !== undefined) {
18
+ return pending;
19
+ }
20
+ const {
21
+ existsSync
22
+ } = require('fs');
23
+ return existsSync(location);
24
+ };
25
+ exports.fileExists = fileExists;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.fileExists=void 0;var _storagePath=require("./storagePath"),_writeSet=require("./writeSet");const fileExists=e=>{const t=(0,_storagePath.storagePath)(e),s=(0,_writeSet.pendingExists)(t);if(void 0!==s)return s;const{existsSync:r}=require("fs");return r(t)};exports.fileExists=fileExists;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The storage layer: every file json-fs-query reads, writes or deletes goes through these functions, and nothing else
3
+ * touches `fs` or `fetch()`. Paths given to them are inside the database (see storagePath).
4
+ *
5
+ * Today there is one backend, JSON files (on disk in Node, over fetch() in a browser). Keeping it behind these few
6
+ * functions is what lets a read cache, batched writes and other storage backends come later without touching queries.
7
+ */
8
+ export { storagePath } from './storagePath';
9
+ export { readJson, readText } from './readJson';
10
+ export { writeJson, jsonText } from './writeJson';
11
+ export { makeDirectory } from './makeDirectory';
12
+ export { removeFile } from './removeFile';
13
+ export { removeDirectory } from './removeDirectory';
14
+ export { fileExists } from './fileExists';
15
+ export { listFiles } from './listFiles';
16
+ export { databasesLocation, readDatabaseList, writeDatabaseList, databaseFolderExists, makeDatabaseFolder, removeDatabaseFolder } from './databases';
17
+ export { withReadCache } from './readCache';
18
+ export { withWriteSet } from './writeSet';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "databaseFolderExists", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _databases.databaseFolderExists;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "databasesLocation", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _databases.databasesLocation;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "fileExists", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _fileExists.fileExists;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "jsonText", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _writeJson.jsonText;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "listFiles", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _listFiles.listFiles;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "makeDatabaseFolder", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _databases.makeDatabaseFolder;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "makeDirectory", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _makeDirectory.makeDirectory;
46
+ }
47
+ });
48
+ Object.defineProperty(exports, "readDatabaseList", {
49
+ enumerable: true,
50
+ get: function () {
51
+ return _databases.readDatabaseList;
52
+ }
53
+ });
54
+ Object.defineProperty(exports, "readJson", {
55
+ enumerable: true,
56
+ get: function () {
57
+ return _readJson.readJson;
58
+ }
59
+ });
60
+ Object.defineProperty(exports, "readText", {
61
+ enumerable: true,
62
+ get: function () {
63
+ return _readJson.readText;
64
+ }
65
+ });
66
+ Object.defineProperty(exports, "removeDatabaseFolder", {
67
+ enumerable: true,
68
+ get: function () {
69
+ return _databases.removeDatabaseFolder;
70
+ }
71
+ });
72
+ Object.defineProperty(exports, "removeDirectory", {
73
+ enumerable: true,
74
+ get: function () {
75
+ return _removeDirectory.removeDirectory;
76
+ }
77
+ });
78
+ Object.defineProperty(exports, "removeFile", {
79
+ enumerable: true,
80
+ get: function () {
81
+ return _removeFile.removeFile;
82
+ }
83
+ });
84
+ Object.defineProperty(exports, "storagePath", {
85
+ enumerable: true,
86
+ get: function () {
87
+ return _storagePath.storagePath;
88
+ }
89
+ });
90
+ Object.defineProperty(exports, "withReadCache", {
91
+ enumerable: true,
92
+ get: function () {
93
+ return _readCache.withReadCache;
94
+ }
95
+ });
96
+ Object.defineProperty(exports, "withWriteSet", {
97
+ enumerable: true,
98
+ get: function () {
99
+ return _writeSet.withWriteSet;
100
+ }
101
+ });
102
+ Object.defineProperty(exports, "writeDatabaseList", {
103
+ enumerable: true,
104
+ get: function () {
105
+ return _databases.writeDatabaseList;
106
+ }
107
+ });
108
+ Object.defineProperty(exports, "writeJson", {
109
+ enumerable: true,
110
+ get: function () {
111
+ return _writeJson.writeJson;
112
+ }
113
+ });
114
+ var _storagePath = require("./storagePath");
115
+ var _readJson = require("./readJson");
116
+ var _writeJson = require("./writeJson");
117
+ var _makeDirectory = require("./makeDirectory");
118
+ var _removeFile = require("./removeFile");
119
+ var _removeDirectory = require("./removeDirectory");
120
+ var _fileExists = require("./fileExists");
121
+ var _listFiles = require("./listFiles");
122
+ var _databases = require("./databases");
123
+ var _readCache = require("./readCache");
124
+ var _writeSet = require("./writeSet");
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"databaseFolderExists",{enumerable:!0,get:function(){return _databases.databaseFolderExists}}),Object.defineProperty(exports,"databasesLocation",{enumerable:!0,get:function(){return _databases.databasesLocation}}),Object.defineProperty(exports,"fileExists",{enumerable:!0,get:function(){return _fileExists.fileExists}}),Object.defineProperty(exports,"jsonText",{enumerable:!0,get:function(){return _writeJson.jsonText}}),Object.defineProperty(exports,"listFiles",{enumerable:!0,get:function(){return _listFiles.listFiles}}),Object.defineProperty(exports,"makeDatabaseFolder",{enumerable:!0,get:function(){return _databases.makeDatabaseFolder}}),Object.defineProperty(exports,"makeDirectory",{enumerable:!0,get:function(){return _makeDirectory.makeDirectory}}),Object.defineProperty(exports,"readDatabaseList",{enumerable:!0,get:function(){return _databases.readDatabaseList}}),Object.defineProperty(exports,"readJson",{enumerable:!0,get:function(){return _readJson.readJson}}),Object.defineProperty(exports,"readText",{enumerable:!0,get:function(){return _readJson.readText}}),Object.defineProperty(exports,"removeDatabaseFolder",{enumerable:!0,get:function(){return _databases.removeDatabaseFolder}}),Object.defineProperty(exports,"removeDirectory",{enumerable:!0,get:function(){return _removeDirectory.removeDirectory}}),Object.defineProperty(exports,"removeFile",{enumerable:!0,get:function(){return _removeFile.removeFile}}),Object.defineProperty(exports,"storagePath",{enumerable:!0,get:function(){return _storagePath.storagePath}}),Object.defineProperty(exports,"withReadCache",{enumerable:!0,get:function(){return _readCache.withReadCache}}),Object.defineProperty(exports,"withWriteSet",{enumerable:!0,get:function(){return _writeSet.withWriteSet}}),Object.defineProperty(exports,"writeDatabaseList",{enumerable:!0,get:function(){return _databases.writeDatabaseList}}),Object.defineProperty(exports,"writeJson",{enumerable:!0,get:function(){return _writeJson.writeJson}});var _storagePath=require("./storagePath"),_readJson=require("./readJson"),_writeJson=require("./writeJson"),_makeDirectory=require("./makeDirectory"),_removeFile=require("./removeFile"),_removeDirectory=require("./removeDirectory"),_fileExists=require("./fileExists"),_listFiles=require("./listFiles"),_databases=require("./databases"),_readCache=require("./readCache"),_writeSet=require("./writeSet");
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Every file in a folder of the database and the folders inside it, as paths inside the database (such as
3
+ * `users/1.json`), sorted. During a statement it counts what the statement has written or deleted (see withWriteSet).
4
+ * A folder that doesn't exist has no files. Node only.
5
+ * @param path - A path inside the database, such as `users`. Empty for the whole database.
6
+ */
7
+ export declare const listFiles: (path?: string) => Promise<string[]>;
8
+ //# sourceMappingURL=listFiles.d.ts.map