json-fs-query 1.1.0 → 2.0.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 (113) hide show
  1. package/LICENSE +674 -674
  2. package/README.md +295 -98
  3. package/browser/jsonFsQuery.js +12733 -10934
  4. package/browser/jsonFsQuery.min.js +1 -1
  5. package/dist/data/introspect/create.d.ts +1 -1
  6. package/dist/data/introspect/create.js +35 -4
  7. package/dist/data/introspect/create.min.js +1 -1
  8. package/dist/data/introspect/definitions/field.d.ts +6 -2
  9. package/dist/data/introspect/definitions/field.js +7 -1
  10. package/dist/data/introspect/definitions/field.min.js +1 -1
  11. package/dist/data/introspect/index.d.ts +6 -3
  12. package/dist/data/introspect/index.js +10 -19
  13. package/dist/data/introspect/index.min.js +1 -1
  14. package/dist/data/introspect/policies/foreignKeyExists.js +28 -28
  15. package/dist/data/introspect/policies/hasDependents.js +53 -53
  16. package/dist/data/introspect/policies/keyUnique.js +34 -34
  17. package/dist/data/introspect/policies/typeCheck.d.ts +9 -1
  18. package/dist/data/introspect/policies/typeCheck.js +16 -2
  19. package/dist/data/introspect/policies/typeCheck.min.js +1 -1
  20. package/dist/data/queries/createRecord.d.ts +11 -0
  21. package/dist/data/queries/createRecord.js +58 -0
  22. package/dist/data/queries/createRecord.min.js +1 -0
  23. package/dist/data/queries/deleteEntity.js +100 -100
  24. package/dist/data/queries/describeRecord.d.ts +9 -0
  25. package/dist/data/queries/describeRecord.js +29 -0
  26. package/dist/data/queries/describeRecord.min.js +1 -0
  27. package/dist/data/queries/dropRecord.d.ts +9 -0
  28. package/dist/data/queries/dropRecord.js +61 -0
  29. package/dist/data/queries/dropRecord.min.js +1 -0
  30. package/dist/data/queries/insertEntity.js +122 -117
  31. package/dist/data/queries/insertEntity.min.js +1 -1
  32. package/dist/data/queries/parser.d.ts +1 -1
  33. package/dist/data/queries/parser.js +7 -15
  34. package/dist/data/queries/parser.min.js +1 -1
  35. package/dist/data/queries/query.d.ts +6 -0
  36. package/dist/data/queries/query.js +15 -6
  37. package/dist/data/queries/query.min.js +1 -1
  38. package/dist/data/queries/queryStatus.d.ts +15 -0
  39. package/dist/data/queries/queryStatus.js +52 -0
  40. package/dist/data/queries/queryStatus.min.js +1 -0
  41. package/dist/data/queries/quote.d.ts +11 -0
  42. package/dist/data/queries/quote.js +17 -0
  43. package/dist/data/queries/quote.min.js +1 -0
  44. package/dist/data/queries/showRecords.d.ts +6 -0
  45. package/dist/data/queries/showRecords.js +21 -0
  46. package/dist/data/queries/showRecords.min.js +1 -0
  47. package/dist/data/queries/sortBy.js +27 -27
  48. package/dist/data/queries/updateEntity.js +245 -193
  49. package/dist/data/queries/updateEntity.min.js +1 -1
  50. package/dist/data/queries/where.d.ts +7 -7
  51. package/dist/data/queries/where.js +67 -67
  52. package/dist/data/utilities/compareAs.d.ts +19 -19
  53. package/dist/data/utilities/compareAs.js +57 -57
  54. package/dist/data/utilities/config.d.ts +15 -0
  55. package/dist/data/utilities/config.js +31 -1
  56. package/dist/data/utilities/config.min.js +1 -1
  57. package/dist/data/utilities/databaseLock.d.ts +16 -0
  58. package/dist/data/utilities/databaseLock.js +63 -0
  59. package/dist/data/utilities/databaseLock.min.js +1 -0
  60. package/dist/data/utilities/fieldType.d.ts +15 -15
  61. package/dist/data/utilities/fieldType.js +22 -22
  62. package/dist/data/utilities/getConditionIndexedList.js +47 -47
  63. package/dist/data/utilities/matchIndexedJoins.js +62 -62
  64. package/dist/data/utilities/mergeJoin.js +47 -47
  65. package/dist/data/utilities/parsers/findConditions.d.ts +18 -15
  66. package/dist/data/utilities/parsers/findConditions.js +15 -6
  67. package/dist/data/utilities/parsers/findConditions.min.js +1 -1
  68. package/dist/data/utilities/parsers/findInsertValues.js +3 -2
  69. package/dist/data/utilities/parsers/findInsertValues.min.js +1 -1
  70. package/dist/data/utilities/parsers/findSelects.js +6 -3
  71. package/dist/data/utilities/parsers/findSelects.min.js +1 -1
  72. package/dist/data/utilities/parsers/findSortClauses.js +5 -2
  73. package/dist/data/utilities/parsers/findSortClauses.min.js +1 -1
  74. package/dist/data/utilities/parsers/findUpdateValues.js +3 -2
  75. package/dist/data/utilities/parsers/findUpdateValues.min.js +1 -1
  76. package/dist/data/utilities/parsers/maskStrings.d.ts +39 -0
  77. package/dist/data/utilities/parsers/maskStrings.js +123 -0
  78. package/dist/data/utilities/parsers/maskStrings.min.js +1 -0
  79. package/dist/data/utilities/parsers/parseCreate.d.ts +20 -0
  80. package/dist/data/utilities/parsers/parseCreate.js +330 -0
  81. package/dist/data/utilities/parsers/parseCreate.min.js +1 -0
  82. package/dist/data/utilities/parsers/parseLiteralValue.d.ts +2 -1
  83. package/dist/data/utilities/parsers/parseLiteralValue.js +6 -3
  84. package/dist/data/utilities/parsers/parseLiteralValue.min.js +1 -1
  85. package/dist/data/utilities/parsers/parseQuery.d.ts +3 -0
  86. package/dist/data/utilities/parsers/parseQuery.js +28 -2
  87. package/dist/data/utilities/parsers/parseQuery.min.js +1 -1
  88. package/dist/data/utilities/parsers/parseSchemaStatement.d.ts +13 -0
  89. package/dist/data/utilities/parsers/parseSchemaStatement.js +82 -0
  90. package/dist/data/utilities/parsers/parseSchemaStatement.min.js +1 -0
  91. package/dist/data/utilities/parsers/scanQuery.d.ts +52 -0
  92. package/dist/data/utilities/parsers/scanQuery.js +158 -0
  93. package/dist/data/utilities/parsers/scanQuery.min.js +1 -0
  94. package/dist/data/utilities/parsers/splitQueries.d.ts +6 -0
  95. package/dist/data/utilities/parsers/splitQueries.js +20 -2
  96. package/dist/data/utilities/parsers/splitQueries.min.js +1 -1
  97. package/dist/data/utilities/parsers/startsQuery.d.ts +5 -0
  98. package/dist/data/utilities/parsers/startsQuery.js +10 -0
  99. package/dist/data/utilities/parsers/startsQuery.min.js +1 -0
  100. package/dist/data/utilities/recordExists.d.ts +6 -0
  101. package/dist/data/utilities/recordExists.js +18 -0
  102. package/dist/data/utilities/recordExists.min.js +1 -0
  103. package/dist/data/utilities/removeFromIndex.d.ts +14 -14
  104. package/dist/data/utilities/removeFromIndex.js +45 -45
  105. package/dist/data/utilities/runQuery.js +135 -112
  106. package/dist/data/utilities/runQuery.min.js +1 -1
  107. package/dist/data/utilities/updateIndex.d.ts +17 -17
  108. package/dist/data/utilities/updateIndex.js +57 -57
  109. package/dist/data/utilities/useJoinClause.js +56 -56
  110. package/dist/index.d.ts +2 -0
  111. package/dist/index.js +14 -0
  112. package/dist/index.min.js +1 -1
  113. package/package.json +68 -60
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.scanQuery = exports.assertClosed = void 0;
7
+ const escapes = {
8
+ n: '\n',
9
+ t: '\t'
10
+ };
11
+ const closers = {
12
+ ']': '[',
13
+ ')': '('
14
+ };
15
+ /**
16
+ * Walk a query once, left to right, finding its strings, comments and the `;` between statements.
17
+ *
18
+ * Strings use `'` or `"` and close only with the quote they opened with. Inside a string a backslash escapes the
19
+ * next character: `\n` and `\t` are a newline and a tab, any other `\x` is `x` (so `\'`, `\"` and `\\` are a quote
20
+ * and a backslash). Outside strings a backslash has no meaning. Comments run from `--` to the end of the line, or
21
+ * from `/*` to `*\/`; anything inside a comment is ignored, and comment markers inside a string are just text. A `--`
22
+ * starts a comment only at the start of the text or after whitespace or a `;`, since names can contain `-`
23
+ * (`my--table` is a name). A `;` inside brackets does not end a query.
24
+ *
25
+ * Never throws: whatever is left open is reported in `end`, for a prompt which asks for more input. Use
26
+ * assertClosed to turn it into an error.
27
+ * @param text
28
+ */
29
+ const scanQuery = (text = '') => {
30
+ const strings = [];
31
+ const comments = [];
32
+ const semicolons = [];
33
+ const brackets = [];
34
+ let strayCloser;
35
+ let openQuote;
36
+ let escape = false;
37
+ let blockComment = false;
38
+ let lastCode = -1;
39
+ let index = 0;
40
+ while (index < text.length) {
41
+ const char = text[index];
42
+ const next = text[index + 1];
43
+ if (char === '\'' || char === '"') {
44
+ const start = index;
45
+ let value = '';
46
+ index++;
47
+ while (index < text.length && text[index] !== char) {
48
+ if (text[index] === '\\') {
49
+ if (index + 1 === text.length) {
50
+ escape = true;
51
+ index++;
52
+ break;
53
+ }
54
+ value += escapes[text[index + 1]] ?? text[index + 1];
55
+ index += 2;
56
+ continue;
57
+ }
58
+ value += text[index];
59
+ index++;
60
+ }
61
+ if (index < text.length) {
62
+ index++;
63
+ } else {
64
+ openQuote = char;
65
+ }
66
+ strings.push({
67
+ start,
68
+ end: index,
69
+ quote: char,
70
+ value
71
+ });
72
+ lastCode = start;
73
+ continue;
74
+ }
75
+ if (char === '-' && next === '-' && (index === 0 || /[\s;]/.test(text[index - 1]))) {
76
+ const newline = text.indexOf('\n', index + 2);
77
+ const end = newline === -1 ? text.length : newline + 1;
78
+ comments.push({
79
+ start: index,
80
+ end,
81
+ kind: 'line'
82
+ });
83
+ index = end;
84
+ continue;
85
+ }
86
+ if (char === '/' && next === '*') {
87
+ const close = text.indexOf('*/', index + 2);
88
+ const end = close === -1 ? text.length : close + 2;
89
+ blockComment = close === -1;
90
+ comments.push({
91
+ start: index,
92
+ end,
93
+ kind: 'block'
94
+ });
95
+ index = end;
96
+ continue;
97
+ }
98
+ if (char === '[' || char === '(') {
99
+ brackets.push(char);
100
+ } else if (closers[char]) {
101
+ if (brackets[brackets.length - 1] === closers[char]) {
102
+ brackets.pop();
103
+ } else if (!strayCloser) {
104
+ strayCloser = {
105
+ char,
106
+ index
107
+ };
108
+ }
109
+ } else if (char === ';' && brackets.length === 0) {
110
+ semicolons.push(index);
111
+ }
112
+ if (!/\s/.test(char)) {
113
+ lastCode = index;
114
+ }
115
+ index++;
116
+ }
117
+ const end = {
118
+ quote: openQuote,
119
+ escape,
120
+ blockComment,
121
+ brackets,
122
+ strayCloser
123
+ };
124
+ const closed = !end.quote && !end.blockComment && brackets.length === 0;
125
+ return {
126
+ strings,
127
+ comments,
128
+ semicolons,
129
+ end,
130
+ closed,
131
+ terminated: closed && semicolons.length > 0 && semicolons[semicolons.length - 1] === lastCode
132
+ };
133
+ };
134
+ /**
135
+ * Throw a clear error for anything scanQuery found left open or unmatched: a string, a block comment or a bracket.
136
+ * @param scanned
137
+ */
138
+ exports.scanQuery = scanQuery;
139
+ const assertClosed = scanned => {
140
+ const {
141
+ end
142
+ } = scanned;
143
+ if (end.quote) {
144
+ const open = scanned.strings[scanned.strings.length - 1];
145
+ throw new Error(`Unclosed string: the ${end.quote} at position ${open.start} is never closed`);
146
+ }
147
+ if (end.blockComment) {
148
+ throw new Error(`Unclosed comment: the /* at position ${scanned.comments[scanned.comments.length - 1].start} is never closed`);
149
+ }
150
+ if (end.strayCloser) {
151
+ throw new Error(`Unexpected ${end.strayCloser.char} at position ${end.strayCloser.index}: there is nothing to close`);
152
+ }
153
+ if (end.brackets.length > 0) {
154
+ throw new Error(`Unclosed bracket: ${end.brackets.join(' ')} never closed`);
155
+ }
156
+ return scanned;
157
+ };
158
+ exports.assertClosed = assertClosed;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.scanQuery=exports.assertClosed=void 0;const escapes={n:"\n",t:"\t"},closers={"]":"[",")":"("},scanQuery=(e="")=>{const s=[],t=[],n=[],o=[];let r,l,c=!1,i=!1,a=-1,h=0;for(;h<e.length;){const d=e[h],p=e[h+1];if("'"!==d&&'"'!==d)if("-"!==d||"-"!==p||0!==h&&!/[\s;]/.test(e[h-1]))if("/"!==d||"*"!==p)"["===d||"("===d?o.push(d):closers[d]?o[o.length-1]===closers[d]?o.pop():r||(r={char:d,index:h}):";"===d&&0===o.length&&n.push(h),/\s/.test(d)||(a=h),h++;else{const s=e.indexOf("*/",h+2),n=-1===s?e.length:s+2;i=-1===s,t.push({start:h,end:n,kind:"block"}),h=n}else{const s=e.indexOf("\n",h+2),n=-1===s?e.length:s+1;t.push({start:h,end:n,kind:"line"}),h=n}else{const t=h;let n="";for(h++;h<e.length&&e[h]!==d;)if("\\"!==e[h])n+=e[h],h++;else{if(h+1===e.length){c=!0,h++;break}n+=escapes[e[h+1]]??e[h+1],h+=2}h<e.length?h++:l=d,s.push({start:t,end:h,quote:d,value:n}),a=t}}const d={quote:l,escape:c,blockComment:i,brackets:o,strayCloser:r},p=!d.quote&&!d.blockComment&&0===o.length;return{strings:s,comments:t,semicolons:n,end:d,closed:p,terminated:p&&n.length>0&&n[n.length-1]===a}};exports.scanQuery=scanQuery;const assertClosed=e=>{const{end:s}=e;if(s.quote){const t=e.strings[e.strings.length-1];throw new Error(`Unclosed string: the ${s.quote} at position ${t.start} is never closed`)}if(s.blockComment)throw new Error(`Unclosed comment: the /* at position ${e.comments[e.comments.length-1].start} is never closed`);if(s.strayCloser)throw new Error(`Unexpected ${s.strayCloser.char} at position ${s.strayCloser.index}: there is nothing to close`);if(s.brackets.length>0)throw new Error(`Unclosed bracket: ${s.brackets.join(" ")} never closed`);return e};exports.assertClosed=assertClosed;
@@ -1,2 +1,8 @@
1
+ /**
2
+ * Split a string of queries into one query each, on the `;` between them. A `;` inside a string or a comment does
3
+ * not count, comments are removed, and the `;` after the last query is optional.
4
+ * @param queries
5
+ * @throws {Error} For an unclosed string, block comment or bracket.
6
+ */
1
7
  export declare const splitQueries: (queries?: string) => string[];
2
8
  //# sourceMappingURL=splitQueries.d.ts.map
@@ -6,6 +6,24 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.splitQueries = void 0;
7
7
  require("core-js/modules/esnext.iterator.constructor.js");
8
8
  require("core-js/modules/esnext.iterator.filter.js");
9
- const queryMatch = /\s*(?=(?:delete|insert|read|update)\s+[a-z0-9._-]+)\s*/i;
10
- const splitQueries = (queries = '') => queries.split(queryMatch).filter(query => query.length > 0);
9
+ require("core-js/modules/esnext.iterator.reduce.js");
10
+ var _scanQuery = require("./scanQuery");
11
+ /**
12
+ * Split a string of queries into one query each, on the `;` between them. A `;` inside a string or a comment does
13
+ * not count, comments are removed, and the `;` after the last query is optional.
14
+ * @param queries
15
+ * @throws {Error} For an unclosed string, block comment or bracket.
16
+ */
17
+ const splitQueries = (queries = '') => {
18
+ const {
19
+ comments,
20
+ semicolons
21
+ } = (0, _scanQuery.assertClosed)((0, _scanQuery.scanQuery)(queries));
22
+ // Blank each comment out with spaces, so the positions of the ; stay the same and the words either side stay apart
23
+ const uncommented = comments.reduce((text, {
24
+ start,
25
+ end
26
+ }) => `${text.slice(0, start)}${' '.repeat(end - start)}${text.slice(end)}`, queries);
27
+ return [...semicolons, uncommented.length].map((end, index) => uncommented.slice(index === 0 ? 0 : semicolons[index - 1] + 1, end).trim()).filter(query => query.length > 0);
28
+ };
11
29
  exports.splitQueries = splitQueries;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.splitQueries=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.filter.js");const queryMatch=/\s*(?=(?:delete|insert|read|update)\s+[a-z0-9._-]+)\s*/i,splitQueries=(e="")=>e.split(queryMatch).filter((e=>e.length>0));exports.splitQueries=splitQueries;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.splitQueries=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.filter.js"),require("core-js/modules/esnext.iterator.reduce.js");var _scanQuery=require("./scanQuery");const splitQueries=(e="")=>{const{comments:r,semicolons:s}=(0,_scanQuery.assertClosed)((0,_scanQuery.scanQuery)(e)),t=r.reduce(((e,{start:r,end:s})=>`${e.slice(0,r)}${" ".repeat(s-r)}${e.slice(s)}`),e);return[...s,t.length].map(((e,r)=>t.slice(0===r?0:s[r-1]+1,e).trim())).filter((e=>e.length>0))};exports.splitQueries=splitQueries;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Matches text that starts with a command word, for the "Missing ; before" error when a query runs on into the next.
3
+ */
4
+ export declare const startsQueryMatch: RegExp;
5
+ //# sourceMappingURL=startsQuery.d.ts.map
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.startsQueryMatch = void 0;
7
+ /**
8
+ * Matches text that starts with a command word, for the "Missing ; before" error when a query runs on into the next.
9
+ */
10
+ const startsQueryMatch = exports.startsQueryMatch = /^\s*(create|delete|describe|drop|insert|read|show|update)(?![a-z0-9_-])/i;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.startsQueryMatch=void 0;const startsQueryMatch=exports.startsQueryMatch=/^\s*(create|delete|describe|drop|insert|read|show|update)(?![a-z0-9_-])/i;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Whether a record (its `<name>.json` file) exists in the database. Node only, like the schema statements that use it.
3
+ * @param entity
4
+ */
5
+ export declare const recordExists: (entity: string) => boolean;
6
+ //# sourceMappingURL=recordExists.d.ts.map
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.recordExists = void 0;
7
+ var _config = require("./config");
8
+ /**
9
+ * Whether a record (its `<name>.json` file) exists in the database. Node only, like the schema statements that use it.
10
+ * @param entity
11
+ */
12
+ const recordExists = entity => {
13
+ const {
14
+ existsSync
15
+ } = require('fs');
16
+ return existsSync(`${(0, _config.getSetting)('databasePath', 'database/')}${entity}.json`);
17
+ };
18
+ exports.recordExists = recordExists;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.recordExists=void 0;var _config=require("./config");const recordExists=e=>{const{existsSync:s}=require("fs");return s(`${(0,_config.getSetting)("databasePath","database/")}${e}.json`)};exports.recordExists=recordExists;
@@ -1,15 +1,15 @@
1
- import { keyDefinition } from '../introspect/definitions/key';
2
- import { recordPath } from '../introspect/definitions/record';
3
- import { indexEntry } from './updateIndex';
4
- /**
5
- * Remove a single entry file from the index that backs one of a record's keys, dropping a value
6
- * entirely once its last file is removed. A key with no lookup, or an index file that doesn't
7
- * exist yet, is left untouched.
8
- * @param path
9
- * @param key
10
- * @param value
11
- * @param fileName
12
- * @param type - The declared type of the indexed value (see keyValueType), so '3' and 3 are one entry.
13
- */
14
- export declare const removeFromIndex: (path?: recordPath, key?: keyDefinition, value?: any, fileName?: string, type?: string) => Promise<indexEntry[] | null>;
1
+ import { keyDefinition } from '../introspect/definitions/key';
2
+ import { recordPath } from '../introspect/definitions/record';
3
+ import { indexEntry } from './updateIndex';
4
+ /**
5
+ * Remove a single entry file from the index that backs one of a record's keys, dropping a value
6
+ * entirely once its last file is removed. A key with no lookup, or an index file that doesn't
7
+ * exist yet, is left untouched.
8
+ * @param path
9
+ * @param key
10
+ * @param value
11
+ * @param fileName
12
+ * @param type - The declared type of the indexed value (see keyValueType), so '3' and 3 are one entry.
13
+ */
14
+ export declare const removeFromIndex: (path?: recordPath, key?: keyDefinition, value?: any, fileName?: string, type?: string) => Promise<indexEntry[] | null>;
15
15
  //# sourceMappingURL=removeFromIndex.d.ts.map
@@ -1,46 +1,46 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.removeFromIndex = 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
- require("core-js/modules/esnext.iterator.map.js");
11
- var _config = require("./config");
12
- var _compareAs = require("./compareAs");
13
- const {
14
- readFile,
15
- writeFile
16
- } = require('fs/promises');
17
- /**
18
- * Remove a single entry file from the index that backs one of a record's keys, dropping a value
19
- * entirely once its last file is removed. A key with no lookup, or an index file that doesn't
20
- * exist yet, is left untouched.
21
- * @param path
22
- * @param key
23
- * @param value
24
- * @param fileName
25
- * @param type - The declared type of the indexed value (see keyValueType), so '3' and 3 are one entry.
26
- */
27
- const removeFromIndex = async (path = '', key = null, value = undefined, fileName = '', type = undefined) => {
28
- if (!key || !key.lookup) {
29
- return null;
30
- }
31
- const databasePath = (0, _config.getSetting)('databasePath', 'database/');
32
- const indexPath = `${databasePath}__indexes/${path}/${key.lookup}`;
33
- let index = [];
34
- try {
35
- index = JSON.parse(await readFile(indexPath, 'utf8'));
36
- } catch (err) {
37
- return null;
38
- }
39
- index = index.map(entry => (0, _compareAs.sameValue)(type, entry.value, value) ? {
40
- value: entry.value,
41
- record: entry.record.filter(record => record !== fileName)
42
- } : entry).filter(entry => entry.record.length);
43
- await writeFile(indexPath, JSON.stringify(index, null, 2));
44
- return index;
45
- };
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.removeFromIndex = 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
+ require("core-js/modules/esnext.iterator.map.js");
11
+ var _config = require("./config");
12
+ var _compareAs = require("./compareAs");
13
+ const {
14
+ readFile,
15
+ writeFile
16
+ } = require('fs/promises');
17
+ /**
18
+ * Remove a single entry file from the index that backs one of a record's keys, dropping a value
19
+ * entirely once its last file is removed. A key with no lookup, or an index file that doesn't
20
+ * exist yet, is left untouched.
21
+ * @param path
22
+ * @param key
23
+ * @param value
24
+ * @param fileName
25
+ * @param type - The declared type of the indexed value (see keyValueType), so '3' and 3 are one entry.
26
+ */
27
+ const removeFromIndex = async (path = '', key = null, value = undefined, fileName = '', type = undefined) => {
28
+ if (!key || !key.lookup) {
29
+ return null;
30
+ }
31
+ const databasePath = (0, _config.getSetting)('databasePath', 'database/');
32
+ const indexPath = `${databasePath}__indexes/${path}/${key.lookup}`;
33
+ let index = [];
34
+ try {
35
+ index = JSON.parse(await readFile(indexPath, 'utf8'));
36
+ } catch (err) {
37
+ return null;
38
+ }
39
+ index = index.map(entry => (0, _compareAs.sameValue)(type, entry.value, value) ? {
40
+ value: entry.value,
41
+ record: entry.record.filter(record => record !== fileName)
42
+ } : entry).filter(entry => entry.record.length);
43
+ await writeFile(indexPath, JSON.stringify(index, null, 2));
44
+ return index;
45
+ };
46
46
  exports.removeFromIndex = removeFromIndex;
@@ -1,113 +1,136 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.runQuery = void 0;
7
- require("core-js/modules/esnext.iterator.constructor.js");
8
- require("core-js/modules/esnext.iterator.reduce.js");
9
- var _deleteEntity = require("../queries/deleteEntity");
10
- var _insertEntity = require("../queries/insertEntity");
11
- var _readEntity = require("../queries/readEntity");
12
- var _updateEntity = require("../queries/updateEntity");
13
- var _joinEntity = require("../queries/joinEntity");
14
- var _mergeJoins = require("../queries/mergeJoins");
15
- var _where = require("../queries/where");
16
- var _sortBy = require("../queries/sortBy");
17
- var _groupBy = require("../queries/groupBy");
18
- var _limitOffset = require("../queries/limitOffset");
19
- var _selectFields = require("../queries/selectFields");
20
- var _retrieveRecord = require("./retrieveRecord");
21
- var _getConditionIndexedList = require("./getConditionIndexedList");
22
- var _getJoinIndexedList = require("./getJoinIndexedList");
23
- var _isEntityProperty = require("./parsers/isEntityProperty");
24
- var _splitEntityProperty = require("./parsers/splitEntityProperty");
25
- var _fieldType = require("./fieldType");
26
- /**
27
- * Give each condition its field's declared type, so where compares by it (a joined entity's field
28
- * is looked up on that entity's record).
29
- * @param parsed
30
- * @param recordData
31
- */
32
- const typeConditions = async (parsed, recordData) => {
33
- for (const condition of parsed.conditions) {
34
- let entity = parsed.entity;
35
- let property = condition.property;
36
- if ((0, _isEntityProperty.isEntityProperty)(property)) {
37
- ({
38
- entity,
39
- property
40
- } = (0, _splitEntityProperty.splitEntityProperty)(property));
41
- }
42
- if (!Object.prototype.hasOwnProperty.call(recordData, entity)) {
43
- recordData[entity] = await (0, _retrieveRecord.retrieveRecord)(entity);
44
- }
45
- condition.type = (0, _fieldType.fieldType)(recordData[entity], property);
46
- }
47
- };
48
- const runQuery = async parsed => {
49
- const recordData = {
50
- [parsed.entity]: await (0, _retrieveRecord.retrieveRecord)(parsed.entity)
51
- };
52
- if (typeof parsed.joinEntity !== 'undefined') {
53
- recordData[parsed.joinEntity] = await (0, _retrieveRecord.retrieveRecord)(parsed.joinEntity);
54
- }
55
- await typeConditions(parsed, recordData);
56
- let dataSet = {
57
- [parsed.entity]: []
58
- };
59
- // A condition that's indexed but genuinely matches nothing leaves dataSet[entity] at [] - the
60
- // same state it starts in before anything has looked at it at all. readEntity() (below) can't
61
- // tell those two states apart on its own (it reloads whenever the array is empty, regardless of
62
- // why), so capture here, before that ambiguity can happen, whether every condition actually got
63
- // resolved this way - if so, dataSet[entity] is already correct and must not be reloaded.
64
- const hadConditions = parsed.conditions.length > 0;
65
- parsed = await (0, _getConditionIndexedList.getConditionIndexedList)(parsed, recordData, dataSet);
66
- const conditionsFullyIndexed = hadConditions && parsed.conditions.length === 0;
67
- parsed = await (0, _getJoinIndexedList.getJoinIndexedList)(parsed, recordData, dataSet);
68
- // delete/update act on whatever is already in dataSet[entity] - unlike read, which loads
69
- // everything and lets the where-reduce below narrow it down afterward, they never get a second
70
- // pass. So the matching rows have to be fully resolved (indexed conditions already are, via
71
- // getConditionIndexedList above; anything left in parsed.conditions is not) before either runs.
72
- if (parsed.command === 'delete' || parsed.command === 'update') {
73
- if (!conditionsFullyIndexed) {
74
- dataSet = await (0, _readEntity.readEntity)(parsed.entity, dataSet);
75
- }
76
- dataSet[parsed.entity] = parsed.conditions.reduce((remainingData, condition) => (0, _where.where)(remainingData, condition), dataSet[parsed.entity]);
77
- }
78
- switch (parsed.command) {
79
- case 'delete':
80
- dataSet = await (0, _deleteEntity.deleteEntity)(parsed.entity, dataSet);
81
- break;
82
- case 'insert':
83
- dataSet = await (0, _insertEntity.insertEntity)(parsed.entity, parsed.insertValues, dataSet);
84
- break;
85
- case 'read':
86
- if (!conditionsFullyIndexed) {
87
- dataSet = await (0, _readEntity.readEntity)(parsed.entity, dataSet);
88
- }
89
- break;
90
- case 'update':
91
- dataSet = await (0, _updateEntity.updateEntity)(parsed.entity, parsed.updateValues, dataSet);
92
- break;
93
- default:
94
- throw new Error(`Unknown command: ${parsed.command}`);
95
- }
96
- dataSet = await (0, _joinEntity.joinEntity)(parsed.entity, parsed.joinEntity, dataSet, parsed.joinClauses, conditionsFullyIndexed);
97
- dataSet = await (0, _mergeJoins.mergeJoins)(dataSet, parsed.mergeJoins);
98
- // delete/update already had parsed.conditions applied above, before they ran. Re-applying the
99
- // same conditions here would be wrong, not just redundant, for update specifically: if the
100
- // update just changed the very field a condition filters on, re-checking that condition against
101
- // the now-changed data would filter the just-updated rows back out.
102
- if (parsed.command !== 'delete' && parsed.command !== 'update') {
103
- dataSet[parsed.entity] = parsed.conditions.reduce((remainingData, condition) => {
104
- return (0, _where.where)(remainingData, condition);
105
- }, dataSet[parsed.entity]);
106
- }
107
- dataSet[parsed.entity] = (0, _sortBy.sortBy)(dataSet[parsed.entity], parsed.sortClauses);
108
- dataSet[parsed.entity] = (0, _limitOffset.limitOffset)(dataSet[parsed.entity], parsed.offset, parsed.limit);
109
- dataSet[parsed.entity] = (0, _groupBy.groupBy)(dataSet[parsed.entity], parsed.groupBy);
110
- dataSet[parsed.entity] = (0, _selectFields.selectFields)(dataSet[parsed.entity], parsed.selectClauses);
111
- return dataSet;
112
- };
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.runQuery = void 0;
7
+ require("core-js/modules/esnext.iterator.constructor.js");
8
+ require("core-js/modules/esnext.iterator.reduce.js");
9
+ var _deleteEntity = require("../queries/deleteEntity");
10
+ var _insertEntity = require("../queries/insertEntity");
11
+ var _readEntity = require("../queries/readEntity");
12
+ var _updateEntity = require("../queries/updateEntity");
13
+ var _createRecord = require("../queries/createRecord");
14
+ var _dropRecord = require("../queries/dropRecord");
15
+ var _describeRecord = require("../queries/describeRecord");
16
+ var _showRecords = require("../queries/showRecords");
17
+ var _joinEntity = require("../queries/joinEntity");
18
+ var _mergeJoins = require("../queries/mergeJoins");
19
+ var _where = require("../queries/where");
20
+ var _sortBy = require("../queries/sortBy");
21
+ var _groupBy = require("../queries/groupBy");
22
+ var _limitOffset = require("../queries/limitOffset");
23
+ var _selectFields = require("../queries/selectFields");
24
+ var _retrieveRecord = require("./retrieveRecord");
25
+ var _getConditionIndexedList = require("./getConditionIndexedList");
26
+ var _getJoinIndexedList = require("./getJoinIndexedList");
27
+ var _isEntityProperty = require("./parsers/isEntityProperty");
28
+ var _splitEntityProperty = require("./parsers/splitEntityProperty");
29
+ var _fieldType = require("./fieldType");
30
+ /**
31
+ * Give each condition its field's declared type, so where compares by it (a joined entity's field
32
+ * is looked up on that entity's record).
33
+ * @param parsed
34
+ * @param recordData
35
+ */
36
+ const typeConditions = async (parsed, recordData) => {
37
+ for (const condition of parsed.conditions) {
38
+ let entity = parsed.entity;
39
+ let property = condition.property;
40
+ if ((0, _isEntityProperty.isEntityProperty)(property)) {
41
+ ({
42
+ entity,
43
+ property
44
+ } = (0, _splitEntityProperty.splitEntityProperty)(property));
45
+ }
46
+ if (!Object.prototype.hasOwnProperty.call(recordData, entity)) {
47
+ recordData[entity] = await (0, _retrieveRecord.retrieveRecord)(entity);
48
+ }
49
+ condition.type = (0, _fieldType.fieldType)(recordData[entity], property);
50
+ }
51
+ };
52
+ const runQuery = async parsed => {
53
+ // Schema statements act on the database, not on entries (for create there is no record to read yet)
54
+ switch (parsed.command) {
55
+ case 'create':
56
+ return {
57
+ [parsed.entity]: await (0, _createRecord.createRecord)(parsed.entity, parsed.create)
58
+ };
59
+ case 'drop':
60
+ return {
61
+ [parsed.entity]: await (0, _dropRecord.dropRecord)(parsed.entity, parsed.ifExists)
62
+ };
63
+ case 'describe':
64
+ return {
65
+ [parsed.entity]: await (0, _describeRecord.describeRecord)(parsed.entity)
66
+ };
67
+ case 'show':
68
+ return {
69
+ [parsed.entity]: await (0, _showRecords.showRecords)()
70
+ };
71
+ }
72
+ const recordData = {
73
+ [parsed.entity]: await (0, _retrieveRecord.retrieveRecord)(parsed.entity)
74
+ };
75
+ if (typeof parsed.joinEntity !== 'undefined') {
76
+ recordData[parsed.joinEntity] = await (0, _retrieveRecord.retrieveRecord)(parsed.joinEntity);
77
+ }
78
+ await typeConditions(parsed, recordData);
79
+ let dataSet = {
80
+ [parsed.entity]: []
81
+ };
82
+ // A condition that's indexed but genuinely matches nothing leaves dataSet[entity] at [] - the
83
+ // same state it starts in before anything has looked at it at all. readEntity() (below) can't
84
+ // tell those two states apart on its own (it reloads whenever the array is empty, regardless of
85
+ // why), so capture here, before that ambiguity can happen, whether every condition actually got
86
+ // resolved this way - if so, dataSet[entity] is already correct and must not be reloaded.
87
+ const hadConditions = parsed.conditions.length > 0;
88
+ parsed = await (0, _getConditionIndexedList.getConditionIndexedList)(parsed, recordData, dataSet);
89
+ const conditionsFullyIndexed = hadConditions && parsed.conditions.length === 0;
90
+ parsed = await (0, _getJoinIndexedList.getJoinIndexedList)(parsed, recordData, dataSet);
91
+ // delete/update act on whatever is already in dataSet[entity] - unlike read, which loads
92
+ // everything and lets the where-reduce below narrow it down afterward, they never get a second
93
+ // pass. So the matching rows have to be fully resolved (indexed conditions already are, via
94
+ // getConditionIndexedList above; anything left in parsed.conditions is not) before either runs.
95
+ if (parsed.command === 'delete' || parsed.command === 'update') {
96
+ if (!conditionsFullyIndexed) {
97
+ dataSet = await (0, _readEntity.readEntity)(parsed.entity, dataSet);
98
+ }
99
+ dataSet[parsed.entity] = parsed.conditions.reduce((remainingData, condition) => (0, _where.where)(remainingData, condition), dataSet[parsed.entity]);
100
+ }
101
+ switch (parsed.command) {
102
+ case 'delete':
103
+ dataSet = await (0, _deleteEntity.deleteEntity)(parsed.entity, dataSet);
104
+ break;
105
+ case 'insert':
106
+ dataSet = await (0, _insertEntity.insertEntity)(parsed.entity, parsed.insertValues, dataSet);
107
+ break;
108
+ case 'read':
109
+ if (!conditionsFullyIndexed) {
110
+ dataSet = await (0, _readEntity.readEntity)(parsed.entity, dataSet);
111
+ }
112
+ break;
113
+ case 'update':
114
+ dataSet = await (0, _updateEntity.updateEntity)(parsed.entity, parsed.updateValues, dataSet);
115
+ break;
116
+ default:
117
+ throw new Error(`Unknown command: ${parsed.command}`);
118
+ }
119
+ dataSet = await (0, _joinEntity.joinEntity)(parsed.entity, parsed.joinEntity, dataSet, parsed.joinClauses, conditionsFullyIndexed);
120
+ dataSet = await (0, _mergeJoins.mergeJoins)(dataSet, parsed.mergeJoins);
121
+ // delete/update already had parsed.conditions applied above, before they ran. Re-applying the
122
+ // same conditions here would be wrong, not just redundant, for update specifically: if the
123
+ // update just changed the very field a condition filters on, re-checking that condition against
124
+ // the now-changed data would filter the just-updated rows back out.
125
+ if (parsed.command !== 'delete' && parsed.command !== 'update') {
126
+ dataSet[parsed.entity] = parsed.conditions.reduce((remainingData, condition) => {
127
+ return (0, _where.where)(remainingData, condition);
128
+ }, dataSet[parsed.entity]);
129
+ }
130
+ dataSet[parsed.entity] = (0, _sortBy.sortBy)(dataSet[parsed.entity], parsed.sortClauses);
131
+ dataSet[parsed.entity] = (0, _limitOffset.limitOffset)(dataSet[parsed.entity], parsed.offset, parsed.limit);
132
+ dataSet[parsed.entity] = (0, _groupBy.groupBy)(dataSet[parsed.entity], parsed.groupBy);
133
+ dataSet[parsed.entity] = (0, _selectFields.selectFields)(dataSet[parsed.entity], parsed.selectClauses);
134
+ return dataSet;
135
+ };
113
136
  exports.runQuery = runQuery;