json-fs-query 1.0.6 → 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 (126) hide show
  1. package/LICENSE +674 -674
  2. package/README.md +295 -98
  3. package/browser/jsonFsQuery.js +12733 -10777
  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 +5 -1
  15. package/dist/data/introspect/policies/foreignKeyExists.min.js +1 -1
  16. package/dist/data/introspect/policies/hasDependents.js +3 -1
  17. package/dist/data/introspect/policies/hasDependents.min.js +1 -1
  18. package/dist/data/introspect/policies/keyUnique.js +5 -1
  19. package/dist/data/introspect/policies/keyUnique.min.js +1 -1
  20. package/dist/data/introspect/policies/typeCheck.d.ts +9 -1
  21. package/dist/data/introspect/policies/typeCheck.js +16 -2
  22. package/dist/data/introspect/policies/typeCheck.min.js +1 -1
  23. package/dist/data/queries/createRecord.d.ts +11 -0
  24. package/dist/data/queries/createRecord.js +58 -0
  25. package/dist/data/queries/createRecord.min.js +1 -0
  26. package/dist/data/queries/deleteEntity.js +2 -1
  27. package/dist/data/queries/deleteEntity.min.js +1 -1
  28. package/dist/data/queries/describeRecord.d.ts +9 -0
  29. package/dist/data/queries/describeRecord.js +29 -0
  30. package/dist/data/queries/describeRecord.min.js +1 -0
  31. package/dist/data/queries/dropRecord.d.ts +9 -0
  32. package/dist/data/queries/dropRecord.js +61 -0
  33. package/dist/data/queries/dropRecord.min.js +1 -0
  34. package/dist/data/queries/insertEntity.js +11 -5
  35. package/dist/data/queries/insertEntity.min.js +1 -1
  36. package/dist/data/queries/parser.d.ts +1 -1
  37. package/dist/data/queries/parser.js +7 -15
  38. package/dist/data/queries/parser.min.js +1 -1
  39. package/dist/data/queries/query.d.ts +6 -0
  40. package/dist/data/queries/query.js +15 -6
  41. package/dist/data/queries/query.min.js +1 -1
  42. package/dist/data/queries/queryStatus.d.ts +15 -0
  43. package/dist/data/queries/queryStatus.js +52 -0
  44. package/dist/data/queries/queryStatus.min.js +1 -0
  45. package/dist/data/queries/quote.d.ts +11 -0
  46. package/dist/data/queries/quote.js +17 -0
  47. package/dist/data/queries/quote.min.js +1 -0
  48. package/dist/data/queries/showRecords.d.ts +6 -0
  49. package/dist/data/queries/showRecords.js +21 -0
  50. package/dist/data/queries/showRecords.min.js +1 -0
  51. package/dist/data/queries/sortBy.js +3 -0
  52. package/dist/data/queries/updateEntity.js +74 -18
  53. package/dist/data/queries/updateEntity.min.js +1 -1
  54. package/dist/data/queries/where.d.ts +2 -1
  55. package/dist/data/queries/where.js +18 -6
  56. package/dist/data/queries/where.min.js +1 -1
  57. package/dist/data/utilities/compareAs.d.ts +20 -0
  58. package/dist/data/utilities/compareAs.js +58 -0
  59. package/dist/data/utilities/compareAs.min.js +1 -0
  60. package/dist/data/utilities/config.d.ts +15 -0
  61. package/dist/data/utilities/config.js +31 -1
  62. package/dist/data/utilities/config.min.js +1 -1
  63. package/dist/data/utilities/databaseLock.d.ts +16 -0
  64. package/dist/data/utilities/databaseLock.js +63 -0
  65. package/dist/data/utilities/databaseLock.min.js +1 -0
  66. package/dist/data/utilities/fieldType.d.ts +16 -0
  67. package/dist/data/utilities/fieldType.js +23 -0
  68. package/dist/data/utilities/fieldType.min.js +1 -0
  69. package/dist/data/utilities/getConditionIndexedList.js +2 -1
  70. package/dist/data/utilities/getConditionIndexedList.min.js +1 -1
  71. package/dist/data/utilities/matchIndexedJoins.js +3 -1
  72. package/dist/data/utilities/matchIndexedJoins.min.js +1 -1
  73. package/dist/data/utilities/mergeJoin.js +5 -1
  74. package/dist/data/utilities/mergeJoin.min.js +1 -1
  75. package/dist/data/utilities/parsers/findConditions.d.ts +5 -1
  76. package/dist/data/utilities/parsers/findConditions.js +15 -6
  77. package/dist/data/utilities/parsers/findConditions.min.js +1 -1
  78. package/dist/data/utilities/parsers/findInsertValues.js +3 -2
  79. package/dist/data/utilities/parsers/findInsertValues.min.js +1 -1
  80. package/dist/data/utilities/parsers/findSelects.js +6 -3
  81. package/dist/data/utilities/parsers/findSelects.min.js +1 -1
  82. package/dist/data/utilities/parsers/findSortClauses.js +5 -2
  83. package/dist/data/utilities/parsers/findSortClauses.min.js +1 -1
  84. package/dist/data/utilities/parsers/findUpdateValues.js +3 -2
  85. package/dist/data/utilities/parsers/findUpdateValues.min.js +1 -1
  86. package/dist/data/utilities/parsers/maskStrings.d.ts +39 -0
  87. package/dist/data/utilities/parsers/maskStrings.js +123 -0
  88. package/dist/data/utilities/parsers/maskStrings.min.js +1 -0
  89. package/dist/data/utilities/parsers/parseCreate.d.ts +20 -0
  90. package/dist/data/utilities/parsers/parseCreate.js +330 -0
  91. package/dist/data/utilities/parsers/parseCreate.min.js +1 -0
  92. package/dist/data/utilities/parsers/parseLiteralValue.d.ts +2 -1
  93. package/dist/data/utilities/parsers/parseLiteralValue.js +6 -3
  94. package/dist/data/utilities/parsers/parseLiteralValue.min.js +1 -1
  95. package/dist/data/utilities/parsers/parseQuery.d.ts +3 -0
  96. package/dist/data/utilities/parsers/parseQuery.js +28 -2
  97. package/dist/data/utilities/parsers/parseQuery.min.js +1 -1
  98. package/dist/data/utilities/parsers/parseSchemaStatement.d.ts +13 -0
  99. package/dist/data/utilities/parsers/parseSchemaStatement.js +82 -0
  100. package/dist/data/utilities/parsers/parseSchemaStatement.min.js +1 -0
  101. package/dist/data/utilities/parsers/scanQuery.d.ts +52 -0
  102. package/dist/data/utilities/parsers/scanQuery.js +158 -0
  103. package/dist/data/utilities/parsers/scanQuery.min.js +1 -0
  104. package/dist/data/utilities/parsers/splitQueries.d.ts +6 -0
  105. package/dist/data/utilities/parsers/splitQueries.js +20 -2
  106. package/dist/data/utilities/parsers/splitQueries.min.js +1 -1
  107. package/dist/data/utilities/parsers/startsQuery.d.ts +5 -0
  108. package/dist/data/utilities/parsers/startsQuery.js +10 -0
  109. package/dist/data/utilities/parsers/startsQuery.min.js +1 -0
  110. package/dist/data/utilities/recordExists.d.ts +6 -0
  111. package/dist/data/utilities/recordExists.js +18 -0
  112. package/dist/data/utilities/recordExists.min.js +1 -0
  113. package/dist/data/utilities/removeFromIndex.d.ts +2 -1
  114. package/dist/data/utilities/removeFromIndex.js +4 -2
  115. package/dist/data/utilities/removeFromIndex.min.js +1 -1
  116. package/dist/data/utilities/runQuery.js +49 -0
  117. package/dist/data/utilities/runQuery.min.js +1 -1
  118. package/dist/data/utilities/updateIndex.d.ts +2 -1
  119. package/dist/data/utilities/updateIndex.js +4 -2
  120. package/dist/data/utilities/updateIndex.min.js +1 -1
  121. package/dist/data/utilities/useJoinClause.js +8 -2
  122. package/dist/data/utilities/useJoinClause.min.js +1 -1
  123. package/dist/index.d.ts +2 -0
  124. package/dist/index.js +14 -0
  125. package/dist/index.min.js +1 -1
  126. package/package.json +68 -55
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Normalize a value to a field's declared type for an equality comparison - never written back,
3
+ * only compared. Writes are coerced to the declared type (typeCheck), but values already stored
4
+ * may not match it (ids declared string, so they can hold an integer or a UUID, are often stored
5
+ * as numbers), and query literals carry their own type. A declared type is what says '3' and 3
6
+ * are the same value. A missing or unrecognized type returns the value unchanged.
7
+ * @param type
8
+ * @param value
9
+ */
10
+ export declare const compareAs: (type: string | undefined, value: any) => any;
11
+ /**
12
+ * Whether two values are equal for a field of the given declared type: both are normalized to
13
+ * that type (see compareAs) and compared strictly. A field with no declared type, or one that
14
+ * can't be normalized (object, array, or an unrecognized type), keeps loose equality.
15
+ * @param type
16
+ * @param a
17
+ * @param b
18
+ */
19
+ export declare const sameValue: (type: string | undefined, a: any, b: any) => boolean;
20
+ //# sourceMappingURL=compareAs.d.ts.map
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.sameValue = exports.compareAs = void 0;
7
+ require("core-js/modules/es.array.includes.js");
8
+ /**
9
+ * Normalize a value to a field's declared type for an equality comparison - never written back,
10
+ * only compared. Writes are coerced to the declared type (typeCheck), but values already stored
11
+ * may not match it (ids declared string, so they can hold an integer or a UUID, are often stored
12
+ * as numbers), and query literals carry their own type. A declared type is what says '3' and 3
13
+ * are the same value. A missing or unrecognized type returns the value unchanged.
14
+ * @param type
15
+ * @param value
16
+ */
17
+ const compareAs = (type, value) => {
18
+ if (value === null || typeof value === 'undefined') {
19
+ return value;
20
+ }
21
+ switch (type) {
22
+ case 'string':
23
+ return typeof value === 'object' ? value : String(value);
24
+ case 'int':
25
+ {
26
+ const coerced = Number(value);
27
+ return Number.isNaN(coerced) ? value : coerced;
28
+ }
29
+ case 'boolean':
30
+ if (value === 'true') {
31
+ return true;
32
+ }
33
+ if (value === 'false') {
34
+ return false;
35
+ }
36
+ return value;
37
+ default:
38
+ return value;
39
+ }
40
+ };
41
+ exports.compareAs = compareAs;
42
+ const comparableTypes = ['string', 'int', 'boolean'];
43
+ /**
44
+ * Whether two values are equal for a field of the given declared type: both are normalized to
45
+ * that type (see compareAs) and compared strictly. A field with no declared type, or one that
46
+ * can't be normalized (object, array, or an unrecognized type), keeps loose equality.
47
+ * @param type
48
+ * @param a
49
+ * @param b
50
+ */
51
+ const sameValue = (type, a, b) => {
52
+ if (!comparableTypes.includes(type)) {
53
+ // eslint-disable-next-line eqeqeq
54
+ return a == b;
55
+ }
56
+ return compareAs(type, a) === compareAs(type, b);
57
+ };
58
+ exports.sameValue = sameValue;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.sameValue=exports.compareAs=void 0,require("core-js/modules/es.array.includes.js");const compareAs=(e,r)=>{if(null==r)return r;switch(e){case"string":return"object"==typeof r?r:String(r);case"int":{const e=Number(r);return Number.isNaN(e)?r:e}case"boolean":return"true"===r||"false"!==r&&r;default:return r}};exports.compareAs=compareAs;const comparableTypes=["string","int","boolean"],sameValue=(e,r,s)=>comparableTypes.includes(e)?compareAs(e,r)===compareAs(e,s):r==s;exports.sameValue=sameValue;
@@ -3,6 +3,18 @@ export type RuntimeSettings = {
3
3
  relativePath: string;
4
4
  enforceForeignKeys: boolean;
5
5
  };
6
+ /**
7
+ * The folder a databasePath points to, so that `database/`, `./database` and its absolute path count as one database.
8
+ * Node only (only Node calls are counted, see trackDatabaseCall).
9
+ * @param databasePath
10
+ */
11
+ export declare const resolveDatabasePath: (databasePath: string) => string;
12
+ /**
13
+ * Count a database call (taken by withDatabaseLock as soon as a call is queued) until the returned function is called.
14
+ * While any call is counted, configure() refuses to point databasePath somewhere else: every step of a call reads
15
+ * databasePath again, so a change halfway would write part of the call to one folder and the rest to another.
16
+ */
17
+ export declare const trackDatabaseCall: () => (() => void);
6
18
  /**
7
19
  * Set where this package's data lives: databasePath (a filesystem path, used in Node) and/or
8
20
  * relativePath (a URL prefix prepended to databasePath, used when reading over fetch() in a
@@ -13,7 +25,10 @@ export type RuntimeSettings = {
13
25
  * that would leave another record's foreign key pointing at a value that no longer exists -
14
26
  * mirroring MySQL's own foreign_key_checks setting, which is also toggleable rather than always
15
27
  * on, since strict enforcement isn't always what every consumer wants.
28
+ *
29
+ * Changing databasePath while calls are still running or queued throws (see trackDatabaseCall): await them first.
16
30
  * @param newSettings
31
+ * @throws {Error} When databasePath would point to another folder while database calls are in progress.
17
32
  */
18
33
  export declare const configure: (newSettings: Partial<RuntimeSettings>) => void;
19
34
  /**
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.getSetting = exports.configure = void 0;
6
+ exports.trackDatabaseCall = exports.resolveDatabasePath = exports.getSetting = exports.configure = void 0;
7
7
  const defaults = {
8
8
  databasePath: 'database/',
9
9
  relativePath: '',
@@ -12,6 +12,29 @@ const defaults = {
12
12
  let settings = {
13
13
  ...defaults
14
14
  };
15
+ let activeCalls = 0;
16
+ /**
17
+ * The folder a databasePath points to, so that `database/`, `./database` and its absolute path count as one database.
18
+ * Node only (only Node calls are counted, see trackDatabaseCall).
19
+ * @param databasePath
20
+ */
21
+ const resolveDatabasePath = databasePath => require('path').resolve(databasePath);
22
+ /**
23
+ * Count a database call (taken by withDatabaseLock as soon as a call is queued) until the returned function is called.
24
+ * While any call is counted, configure() refuses to point databasePath somewhere else: every step of a call reads
25
+ * databasePath again, so a change halfway would write part of the call to one folder and the rest to another.
26
+ */
27
+ exports.resolveDatabasePath = resolveDatabasePath;
28
+ const trackDatabaseCall = () => {
29
+ activeCalls++;
30
+ let ended = false;
31
+ return () => {
32
+ if (!ended) {
33
+ ended = true;
34
+ activeCalls--;
35
+ }
36
+ };
37
+ };
15
38
  /**
16
39
  * Set where this package's data lives: databasePath (a filesystem path, used in Node) and/or
17
40
  * relativePath (a URL prefix prepended to databasePath, used when reading over fetch() in a
@@ -22,9 +45,16 @@ let settings = {
22
45
  * that would leave another record's foreign key pointing at a value that no longer exists -
23
46
  * mirroring MySQL's own foreign_key_checks setting, which is also toggleable rather than always
24
47
  * on, since strict enforcement isn't always what every consumer wants.
48
+ *
49
+ * Changing databasePath while calls are still running or queued throws (see trackDatabaseCall): await them first.
25
50
  * @param newSettings
51
+ * @throws {Error} When databasePath would point to another folder while database calls are in progress.
26
52
  */
53
+ exports.trackDatabaseCall = trackDatabaseCall;
27
54
  const configure = newSettings => {
55
+ if (activeCalls > 0 && typeof newSettings.databasePath !== 'undefined' && resolveDatabasePath(newSettings.databasePath) !== resolveDatabasePath(settings.databasePath)) {
56
+ throw new Error(`Can't change databasePath while ${activeCalls} database call(s) are still running or queued: await them first`);
57
+ }
28
58
  settings = {
29
59
  ...settings,
30
60
  ...newSettings
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.getSetting=exports.configure=void 0;const defaults={databasePath:"database/",relativePath:"",enforceForeignKeys:!0};let settings={...defaults};const configure=t=>{settings={...settings,...t}};exports.configure=configure;const getSetting=(t,e)=>void 0!==settings[t]?settings[t]:e;exports.getSetting=getSetting;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.trackDatabaseCall=exports.resolveDatabasePath=exports.getSetting=exports.configure=void 0;const defaults={databasePath:"database/",relativePath:"",enforceForeignKeys:!0};let settings={...defaults},activeCalls=0;const resolveDatabasePath=t=>require("path").resolve(t);exports.resolveDatabasePath=resolveDatabasePath;const trackDatabaseCall=()=>{activeCalls++;let t=!1;return()=>{t||(t=!0,activeCalls--)}};exports.trackDatabaseCall=trackDatabaseCall;const configure=t=>{if(activeCalls>0&&void 0!==t.databasePath&&resolveDatabasePath(t.databasePath)!==resolveDatabasePath(settings.databasePath))throw new Error(`Can't change databasePath while ${activeCalls} database call(s) are still running or queued: await them first`);settings={...settings,...t}};exports.configure=configure;const getSetting=(t,a)=>void 0!==settings[t]?settings[t]:a;exports.getSetting=getSetting;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Run `task` once every earlier task on the same database (the configured databasePath) has finished, so that calls
3
+ * never interleave. Every write is several files in turn (an entry, the record's entry list, each index), each read and
4
+ * rewritten whole, so two writes running at once overwrite each other's changes: ten parallel inserts used to leave
5
+ * nine of the rows unreadable, and two parallel inserts of one unique value both succeeded. Reads take their turn too,
6
+ * so a read never sees a write half done. A task that throws still lets the next one run.
7
+ *
8
+ * Only the public functions (query, create, drop, describe) take the lock; what they call inside doesn't take it
9
+ * again, so it can't deadlock. In the browser nothing can be written, so tasks just run.
10
+ *
11
+ * The queue is per folder (`database/` and `./database` share one). Every step of a task reads databasePath when it
12
+ * runs, so configure() refuses to change it while tasks are queued or running (see trackDatabaseCall).
13
+ * @param task
14
+ */
15
+ export declare const withDatabaseLock: <T>(task: () => Promise<T>) => Promise<T>;
16
+ //# sourceMappingURL=databaseLock.d.ts.map
@@ -0,0 +1,63 @@
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.withDatabaseLock = void 0;
8
+ require("core-js/modules/esnext.map.delete-all.js");
9
+ require("core-js/modules/esnext.map.every.js");
10
+ require("core-js/modules/esnext.map.filter.js");
11
+ require("core-js/modules/esnext.map.find.js");
12
+ require("core-js/modules/esnext.map.find-key.js");
13
+ require("core-js/modules/esnext.map.includes.js");
14
+ require("core-js/modules/esnext.map.key-of.js");
15
+ require("core-js/modules/esnext.map.map-keys.js");
16
+ require("core-js/modules/esnext.map.map-values.js");
17
+ require("core-js/modules/esnext.map.merge.js");
18
+ require("core-js/modules/esnext.map.reduce.js");
19
+ require("core-js/modules/esnext.map.some.js");
20
+ require("core-js/modules/esnext.map.update.js");
21
+ var jsEnv = _interopRequireWildcard(require("browser-or-node"));
22
+ var _config = require("./config");
23
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
24
+ const queues = new Map();
25
+ /**
26
+ * Run `task` once every earlier task on the same database (the configured databasePath) has finished, so that calls
27
+ * never interleave. Every write is several files in turn (an entry, the record's entry list, each index), each read and
28
+ * rewritten whole, so two writes running at once overwrite each other's changes: ten parallel inserts used to leave
29
+ * nine of the rows unreadable, and two parallel inserts of one unique value both succeeded. Reads take their turn too,
30
+ * so a read never sees a write half done. A task that throws still lets the next one run.
31
+ *
32
+ * Only the public functions (query, create, drop, describe) take the lock; what they call inside doesn't take it
33
+ * again, so it can't deadlock. In the browser nothing can be written, so tasks just run.
34
+ *
35
+ * The queue is per folder (`database/` and `./database` share one). Every step of a task reads databasePath when it
36
+ * runs, so configure() refuses to change it while tasks are queued or running (see trackDatabaseCall).
37
+ * @param task
38
+ */
39
+ const withDatabaseLock = async task => {
40
+ if (!jsEnv.isNode) {
41
+ return task();
42
+ }
43
+ const database = (0, _config.resolveDatabasePath)((0, _config.getSetting)('databasePath', 'database/'));
44
+ const ended = (0, _config.trackDatabaseCall)();
45
+ const previous = queues.get(database) || Promise.resolve();
46
+ let release;
47
+ const turn = new Promise(resolve => {
48
+ release = resolve;
49
+ });
50
+ const queued = previous.then(() => turn);
51
+ queues.set(database, queued);
52
+ await previous;
53
+ try {
54
+ return await task();
55
+ } finally {
56
+ ended();
57
+ release();
58
+ if (queues.get(database) === queued) {
59
+ queues.delete(database);
60
+ }
61
+ }
62
+ };
63
+ exports.withDatabaseLock = withDatabaseLock;
@@ -0,0 +1 @@
1
+ "use strict";require("core-js/modules/esnext.weak-map.delete-all.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.withDatabaseLock=void 0,require("core-js/modules/esnext.map.delete-all.js"),require("core-js/modules/esnext.map.every.js"),require("core-js/modules/esnext.map.filter.js"),require("core-js/modules/esnext.map.find.js"),require("core-js/modules/esnext.map.find-key.js"),require("core-js/modules/esnext.map.includes.js"),require("core-js/modules/esnext.map.key-of.js"),require("core-js/modules/esnext.map.map-keys.js"),require("core-js/modules/esnext.map.map-values.js"),require("core-js/modules/esnext.map.merge.js"),require("core-js/modules/esnext.map.reduce.js"),require("core-js/modules/esnext.map.some.js"),require("core-js/modules/esnext.map.update.js");var jsEnv=_interopRequireWildcard(require("browser-or-node")),_config=require("./config");function _interopRequireWildcard(e,r){if("function"==typeof WeakMap)var s=new WeakMap,t=new WeakMap;return(_interopRequireWildcard=function(e,r){if(!r&&e&&e.__esModule)return e;var o,a,u={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return u;if(o=r?t:s){if(o.has(e))return o.get(e);o.set(e,u)}for(const r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((a=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,r))&&(a.get||a.set)?o(u,r,a):u[r]=e[r]);return u})(e,r)}const queues=new Map,withDatabaseLock=async e=>{if(!jsEnv.isNode)return e();const r=(0,_config.resolveDatabasePath)((0,_config.getSetting)("databasePath","database/")),s=(0,_config.trackDatabaseCall)(),t=queues.get(r)||Promise.resolve();let o;const a=new Promise((e=>{o=e})),u=t.then((()=>a));queues.set(r,u),await t;try{return await e()}finally{s(),o(),queues.get(r)===u&&queues.delete(r)}};exports.withDatabaseLock=withDatabaseLock;
@@ -0,0 +1,16 @@
1
+ import { recordDefinition } from '../introspect/definitions/record';
2
+ import { keyDefinition } from '../introspect/definitions/key';
3
+ /**
4
+ * The declared type of one of a record's fields, or undefined when the record or field is unknown.
5
+ * @param record
6
+ * @param property
7
+ */
8
+ export declare const fieldType: (record: recordDefinition | undefined, property: string) => string | undefined;
9
+ /**
10
+ * The declared type of the value a key indexes: its field's type for a single-field key. A
11
+ * multi-field key's value is a composite (see computeKeyValue), so it has no single declared type.
12
+ * @param record
13
+ * @param key
14
+ */
15
+ export declare const keyValueType: (record: recordDefinition | undefined, key: keyDefinition) => string | undefined;
16
+ //# sourceMappingURL=fieldType.d.ts.map
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.keyValueType = exports.fieldType = void 0;
7
+ require("core-js/modules/esnext.iterator.constructor.js");
8
+ require("core-js/modules/esnext.iterator.find.js");
9
+ /**
10
+ * The declared type of one of a record's fields, or undefined when the record or field is unknown.
11
+ * @param record
12
+ * @param property
13
+ */
14
+ const fieldType = (record, property) => record?.definition?.find(field => field.name === property)?.type;
15
+ /**
16
+ * The declared type of the value a key indexes: its field's type for a single-field key. A
17
+ * multi-field key's value is a composite (see computeKeyValue), so it has no single declared type.
18
+ * @param record
19
+ * @param key
20
+ */
21
+ exports.fieldType = fieldType;
22
+ const keyValueType = (record, key) => key.fields.length === 1 ? fieldType(record, key.fields[0]) : undefined;
23
+ exports.keyValueType = keyValueType;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.keyValueType=exports.fieldType=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.find.js");const fieldType=(e,t)=>e?.definition?.find((e=>e.name===t))?.type;exports.fieldType=fieldType;const keyValueType=(e,t)=>1===t.fields.length?fieldType(e,t.fields[0]):void 0;exports.keyValueType=keyValueType;
@@ -28,7 +28,8 @@ const getConditionIndexedList = async (parsed, recordData, dataSet) => {
28
28
  const matchedRecords = (0, _where.where)(indexed[entity][property], {
29
29
  property: 'value',
30
30
  comparator: condition.comparator,
31
- value: condition.value
31
+ value: condition.value,
32
+ type: condition.type
32
33
  });
33
34
  for (const matchedRecord of matchedRecords) {
34
35
  for (const file of matchedRecord.record) {
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.getConditionIndexedList=void 0;var _isEntityProperty=require("./parsers/isEntityProperty"),_splitEntityProperty=require("./parsers/splitEntityProperty"),_retrieveRecord=require("./retrieveRecord"),_where=require("../queries/where"),_retrieveFile=require("./retrieveFile"),_getMatchingIndexes=require("./getMatchingIndexes");const getConditionIndexedList=async(e,t,r)=>{const i=[];for(const o of e.conditions){let n=e.entity,s=o.property;if((0,_isEntityProperty.isEntityProperty)(s)){const e=(0,_splitEntityProperty.splitEntityProperty)(s);n=e.entity,s=e.property}Object.prototype.hasOwnProperty.call(t,n)||(t[n]=await(0,_retrieveRecord.retrieveRecord)(n));const p={},c=async(e,t,r,i,o,n)=>{const s=(0,_where.where)(n[e][t],{property:"value",comparator:i.comparator,value:i.value});for(const t of s)for(const r of t.record)o[e].push(await(0,_retrieveFile.retrieveFile)(`${e}/${r}`))};await(0,_getMatchingIndexes.getMatchingIndexes)(n,s,t,o,r,p,c)||i.push(o)}return e.conditions=i,e};exports.getConditionIndexedList=getConditionIndexedList;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.getConditionIndexedList=void 0;var _isEntityProperty=require("./parsers/isEntityProperty"),_splitEntityProperty=require("./parsers/splitEntityProperty"),_retrieveRecord=require("./retrieveRecord"),_where=require("../queries/where"),_retrieveFile=require("./retrieveFile"),_getMatchingIndexes=require("./getMatchingIndexes");const getConditionIndexedList=async(e,t,r)=>{const i=[];for(const o of e.conditions){let n=e.entity,s=o.property;if((0,_isEntityProperty.isEntityProperty)(s)){const e=(0,_splitEntityProperty.splitEntityProperty)(s);n=e.entity,s=e.property}Object.prototype.hasOwnProperty.call(t,n)||(t[n]=await(0,_retrieveRecord.retrieveRecord)(n));const p={},y=async(e,t,r,i,o,n)=>{const s=(0,_where.where)(n[e][t],{property:"value",comparator:i.comparator,value:i.value,type:i.type});for(const t of s)for(const r of t.record)o[e].push(await(0,_retrieveFile.retrieveFile)(`${e}/${r}`))};await(0,_getMatchingIndexes.getMatchingIndexes)(n,s,t,o,r,p,y)||i.push(o)}return e.conditions=i,e};exports.getConditionIndexedList=getConditionIndexedList;
@@ -10,6 +10,7 @@ var _siFunciona = _interopRequireDefault(require("si-funciona"));
10
10
  var _where = require("../queries/where");
11
11
  var _retrieveFile = require("./retrieveFile");
12
12
  var _splitEntityProperty = require("./parsers/splitEntityProperty");
13
+ var _fieldType = require("./fieldType");
13
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
15
  const matchIndexedJoins = (entity, indexedClone, dataSets) => async (focusEntity, property, recordData, joinClause, filterJoins, indexed) => {
15
16
  const {
@@ -38,7 +39,8 @@ const matchIndexedJoins = (entity, indexedClone, dataSets) => async (focusEntity
38
39
  const matchedRecords = indexedClone[checkProp.entitySecond][checkProp.propertySecond].reduce((dataA, dataB) => _siFunciona.default.mergeArrays(dataA, (0, _where.where)(indexedClone[checkProp.entityFirst][checkProp.propertyFirst], {
39
40
  property: 'value',
40
41
  comparator: joinClause.comparator,
41
- value: dataB.value
42
+ value: dataB.value,
43
+ type: (0, _fieldType.fieldType)(recordData[checkProp.entityFirst], checkProp.propertyFirst)
42
44
  })), []);
43
45
  const skipPush = checkProp.entityFirst === entity;
44
46
  if (!Object.prototype.hasOwnProperty.call(dataSets, checkProp.entityFirst)) {
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.matchIndexedJoins=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.reduce.js");var _siFunciona=_interopRequireDefault(require("si-funciona")),_where=require("../queries/where"),_retrieveFile=require("./retrieveFile"),_splitEntityProperty=require("./parsers/splitEntityProperty");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const matchIndexedJoins=(e,t,r)=>async(i,o,n,s,p,y)=>{const{entity:c,property:u}=(0,_splitEntityProperty.splitEntityProperty)(s.propertyA),{entity:a,property:d}=(0,_splitEntityProperty.splitEntityProperty)(s.propertyB),l=[{entityFirst:c,propertyFirst:u,entitySecond:a,propertySecond:d},{entityFirst:a,propertyFirst:d,entitySecond:c,propertySecond:u}];for(const i of l){Object.prototype.hasOwnProperty.call(t,i.entitySecond)||(t[i.entitySecond]=_siFunciona.default.cloneObject(y[i.entitySecond]));const o=t[i.entitySecond][i.propertySecond].reduce(((e,r)=>_siFunciona.default.mergeArrays(e,(0,_where.where)(t[i.entityFirst][i.propertyFirst],{property:"value",comparator:s.comparator,value:r.value}))),[]),n=i.entityFirst===e;Object.prototype.hasOwnProperty.call(r,i.entityFirst)||(r[i.entityFirst]=[]);for(const e of o)for(const t of e.record){let e=t;"string"==typeof t&&(e=await(0,_retrieveFile.retrieveFile)(`${i.entityFirst}/${t}`)),n||r[i.entityFirst].push(e),p[i.entityFirst].push(e)}}};exports.matchIndexedJoins=matchIndexedJoins;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.matchIndexedJoins=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.reduce.js");var _siFunciona=_interopRequireDefault(require("si-funciona")),_where=require("../queries/where"),_retrieveFile=require("./retrieveFile"),_splitEntityProperty=require("./parsers/splitEntityProperty"),_fieldType=require("./fieldType");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const matchIndexedJoins=(e,t,r)=>async(i,o,n,s,p,y)=>{const{entity:c,property:u}=(0,_splitEntityProperty.splitEntityProperty)(s.propertyA),{entity:a,property:d}=(0,_splitEntityProperty.splitEntityProperty)(s.propertyB),l=[{entityFirst:c,propertyFirst:u,entitySecond:a,propertySecond:d},{entityFirst:a,propertyFirst:d,entitySecond:c,propertySecond:u}];for(const i of l){Object.prototype.hasOwnProperty.call(t,i.entitySecond)||(t[i.entitySecond]=_siFunciona.default.cloneObject(y[i.entitySecond]));const o=t[i.entitySecond][i.propertySecond].reduce(((e,r)=>_siFunciona.default.mergeArrays(e,(0,_where.where)(t[i.entityFirst][i.propertyFirst],{property:"value",comparator:s.comparator,value:r.value,type:(0,_fieldType.fieldType)(n[i.entityFirst],i.propertyFirst)}))),[]),c=i.entityFirst===e;Object.prototype.hasOwnProperty.call(r,i.entityFirst)||(r[i.entityFirst]=[]);for(const e of o)for(const t of e.record){let e=t;"string"==typeof t&&(e=await(0,_retrieveFile.retrieveFile)(`${i.entityFirst}/${t}`)),c||r[i.entityFirst].push(e),p[i.entityFirst].push(e)}}};exports.matchIndexedJoins=matchIndexedJoins;
@@ -9,6 +9,8 @@ require("core-js/modules/esnext.iterator.map.js");
9
9
  var _readEntity = require("../queries/readEntity");
10
10
  var _splitEntityProperty = require("./parsers/splitEntityProperty");
11
11
  var _where = require("../queries/where");
12
+ var _retrieveRecord = require("./retrieveRecord");
13
+ var _fieldType = require("./fieldType");
12
14
  const mergeJoin = async (propertyA = '', propertyB = '', dataSets = {}) => {
13
15
  const {
14
16
  entity: entityA,
@@ -20,11 +22,13 @@ const mergeJoin = async (propertyA = '', propertyB = '', dataSets = {}) => {
20
22
  } = (0, _splitEntityProperty.splitEntityProperty)(propertyB);
21
23
  dataSets = await (0, _readEntity.readEntity)(entityA, dataSets);
22
24
  dataSets = await (0, _readEntity.readEntity)(entityB, dataSets);
25
+ const typeB = (0, _fieldType.fieldType)(await (0, _retrieveRecord.retrieveRecord)(entityB), propB);
23
26
  dataSets[entityA] = dataSets[entityA].map(dataA => {
24
27
  const matches = (0, _where.where)(dataSets[entityB], {
25
28
  property: propB,
26
29
  comparator: '=',
27
- value: dataA[propA]
30
+ value: dataA[propA],
31
+ type: typeB
28
32
  });
29
33
  if (!matches.length) {
30
34
  return dataA;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.mergeJoin=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.map.js");var _readEntity=require("../queries/readEntity"),_splitEntityProperty=require("./parsers/splitEntityProperty"),_where=require("../queries/where");const mergeJoin=async(e="",r="",t={})=>{const{entity:i,property:o}=(0,_splitEntityProperty.splitEntityProperty)(e),{entity:n,property:s}=(0,_splitEntityProperty.splitEntityProperty)(r);return t=await(0,_readEntity.readEntity)(i,t),(t=await(0,_readEntity.readEntity)(n,t))[i]=t[i].map((e=>{const r=(0,_where.where)(t[n],{property:s,comparator:"=",value:e[o]});if(!r.length)return e;const i=r[0];for(const r in i)r!==s&&(e[`${n}.${r}`]=i[r]);return e})),t};exports.mergeJoin=mergeJoin;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.mergeJoin=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.map.js");var _readEntity=require("../queries/readEntity"),_splitEntityProperty=require("./parsers/splitEntityProperty"),_where=require("../queries/where"),_retrieveRecord=require("./retrieveRecord"),_fieldType=require("./fieldType");const mergeJoin=async(e="",r="",t={})=>{const{entity:i,property:o}=(0,_splitEntityProperty.splitEntityProperty)(e),{entity:n,property:s}=(0,_splitEntityProperty.splitEntityProperty)(r);t=await(0,_readEntity.readEntity)(i,t),t=await(0,_readEntity.readEntity)(n,t);const p=(0,_fieldType.fieldType)(await(0,_retrieveRecord.retrieveRecord)(n),s);return t[i]=t[i].map((e=>{const r=(0,_where.where)(t[n],{property:s,comparator:"=",value:e[o],type:p});if(!r.length)return e;const i=r[0];for(const r in i)r!==s&&(e[`${n}.${r}`]=i[r]);return e})),t};exports.mergeJoin=mergeJoin;
@@ -5,11 +5,15 @@ export type ParsedCondition = {
5
5
  property: string;
6
6
  comparator: string;
7
7
  value: ConditionValue;
8
+ type?: string;
8
9
  };
9
10
  /**
10
- * Extract condition clauses from the query.
11
+ * Extract condition clauses from the query: `where <field> <comparator> <value>`, each further one joined with
12
+ * `and where`. `or where` is refused until or is built (TASKS: the where-clauses epic): it used to be read the same as
13
+ * `and where`, which silently returned the wrong rows.
11
14
  * @param parsed
12
15
  * @param query
16
+ * @throws {Error} For `or where`.
13
17
  */
14
18
  export declare const findConditions: (parsed: ParsedQuery, query: string) => string;
15
19
  //# sourceMappingURL=findConditions.d.ts.map
@@ -6,22 +6,31 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.findConditions = void 0;
7
7
  var _removeFromQuery = require("./removeFromQuery");
8
8
  var _parseLiteralValue = require("./parseLiteralValue");
9
- const conditionMatch = /(and|or)?\s*(where)\s+([a-z0-9_-]+\.?[a-z0-9_-]*)\s+(=|!=|>|<|>=|<=|in|between|like)\s+(["'](.*)['"]|([0-9]+)|(\[.*])|(null)|(true)|(false))/ig;
9
+ var _maskStrings = require("./maskStrings");
10
+ // `and`/`or`/`where` count only as whole words: in `on t.x = u.color where ...` the `or` is part of the name `color`
11
+ const conditionMatch = new RegExp(`(^|[^a-z0-9._-])(?:(and|or)\\s+)?(where)\\s+([a-z0-9_-]+\\.?[a-z0-9_-]*)\\s+(=|!=|>|<|>=|<=|in|between|like)\\s+(${_maskStrings.placeholderSource}|([0-9]+)|${_maskStrings.arraySource}|(null)|(true)|(false))`, 'ig');
10
12
  /**
11
- * Extract condition clauses from the query.
13
+ * Extract condition clauses from the query: `where <field> <comparator> <value>`, each further one joined with
14
+ * `and where`. `or where` is refused until or is built (TASKS: the where-clauses epic): it used to be read the same as
15
+ * `and where`, which silently returned the wrong rows.
12
16
  * @param parsed
13
17
  * @param query
18
+ * @throws {Error} For `or where`.
14
19
  */
15
20
  const findConditions = (parsed, query) => {
16
21
  const conditionsFound = query.matchAll(conditionMatch);
17
22
  // @ts-ignore
18
23
  for (const condition of conditionsFound) {
24
+ if (typeof condition[2] !== 'undefined' && condition[2].toLowerCase() === 'or') {
25
+ throw new Error('`or where` is not supported yet: use `and where`, or run one query per alternative');
26
+ }
19
27
  parsed['conditions'].push({
20
- property: condition[3],
21
- comparator: condition[4],
22
- value: (0, _parseLiteralValue.parseLiteralValue)(condition, 6)
28
+ property: condition[4],
29
+ comparator: condition[5],
30
+ value: (0, _parseLiteralValue.parseLiteralValue)(condition, 7)
23
31
  });
24
- query = (0, _removeFromQuery.removeFromQuery)(condition[0], query);
32
+ // Leave out the character before the condition (group 1): it isn't part of it, and an earlier removal may have trimmed it
33
+ query = (0, _removeFromQuery.removeFromQuery)(condition[0].slice(condition[1].length), query);
25
34
  }
26
35
  return query;
27
36
  };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findConditions=void 0;var _removeFromQuery=require("./removeFromQuery"),_parseLiteralValue=require("./parseLiteralValue");const conditionMatch=/(and|or)?\s*(where)\s+([a-z0-9_-]+\.?[a-z0-9_-]*)\s+(=|!=|>|<|>=|<=|in|between|like)\s+(["'](.*)['"]|([0-9]+)|(\[.*])|(null)|(true)|(false))/gi,findConditions=(e,r)=>{const o=r.matchAll(conditionMatch);for(const i of o)e.conditions.push({property:i[3],comparator:i[4],value:(0,_parseLiteralValue.parseLiteralValue)(i,6)}),r=(0,_removeFromQuery.removeFromQuery)(i[0],r);return r};exports.findConditions=findConditions;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findConditions=void 0;var _removeFromQuery=require("./removeFromQuery"),_parseLiteralValue=require("./parseLiteralValue"),_maskStrings=require("./maskStrings");const conditionMatch=new RegExp(`(^|[^a-z0-9._-])(?:(and|or)\\s+)?(where)\\s+([a-z0-9_-]+\\.?[a-z0-9_-]*)\\s+(=|!=|>|<|>=|<=|in|between|like)\\s+(${_maskStrings.placeholderSource}|([0-9]+)|${_maskStrings.arraySource}|(null)|(true)|(false))`,"ig"),findConditions=(e,r)=>{const o=r.matchAll(conditionMatch);for(const t of o){if(void 0!==t[2]&&"or"===t[2].toLowerCase())throw new Error("`or where` is not supported yet: use `and where`, or run one query per alternative");e.conditions.push({property:t[4],comparator:t[5],value:(0,_parseLiteralValue.parseLiteralValue)(t,7)}),r=(0,_removeFromQuery.removeFromQuery)(t[0].slice(t[1].length),r)}return r};exports.findConditions=findConditions;
@@ -6,9 +6,10 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.findInsertValues = void 0;
7
7
  var _removeFromQuery = require("./removeFromQuery");
8
8
  var _parseLiteralValue = require("./parseLiteralValue");
9
- const literal = '(?:["\'][^"\']*[\'"]|[0-9]+|\\[.*?]|null|true|false)';
9
+ var _maskStrings = require("./maskStrings");
10
+ const literal = `(?:${_maskStrings.placeholderSource.replace('(', '(?:')}|[0-9]+|${_maskStrings.arraySource.replace('(', '(?:')}|null|true|false)`;
10
11
  const valuesClauseMatch = new RegExp(`(values)\\s+([a-z0-9_-]+\\s*=\\s*${literal}(?:\\s*,\\s*[a-z0-9_-]+\\s*=\\s*${literal})*)`, 'i');
11
- const assignmentMatch = /([a-z0-9_-]+)\s*=\s*(["'](.*?)['"]|([0-9]+)|(\[.*?])|(null)|(true)|(false))/ig;
12
+ const assignmentMatch = new RegExp(`([a-z0-9_-]+)\\s*=\\s*(${_maskStrings.placeholderSource}|([0-9]+)|${_maskStrings.arraySource}|(null)|(true)|(false))`, 'ig');
12
13
  /**
13
14
  * Extract an insert's "values field = value, field2 = value2" clause from the query, the same way
14
15
  * findUpdateValues() does for "set". insertEntity() accepts an array of rows for bulk inserts, but
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findInsertValues=void 0;var _removeFromQuery=require("./removeFromQuery"),_parseLiteralValue=require("./parseLiteralValue");const literal="(?:[\"'][^\"']*['\"]|[0-9]+|\\[.*?]|null|true|false)",valuesClauseMatch=new RegExp(`(values)\\s+([a-z0-9_-]+\\s*=\\s*${literal}(?:\\s*,\\s*[a-z0-9_-]+\\s*=\\s*${literal})*)`,"i"),assignmentMatch=/([a-z0-9_-]+)\s*=\s*(["'](.*?)['"]|([0-9]+)|(\[.*?])|(null)|(true)|(false))/gi,findInsertValues=(e,r)=>{const s=r.match(valuesClauseMatch);if(e.insertValues=[],!s)return r;const a={},t=s[2].matchAll(assignmentMatch);for(const e of t)a[e[1]]=(0,_parseLiteralValue.parseLiteralValue)(e,3);return e.insertValues=[a],(0,_removeFromQuery.removeFromQuery)(s[0],r)};exports.findInsertValues=findInsertValues;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findInsertValues=void 0;var _removeFromQuery=require("./removeFromQuery"),_parseLiteralValue=require("./parseLiteralValue"),_maskStrings=require("./maskStrings");const literal=`(?:${_maskStrings.placeholderSource.replace("(","(?:")}|[0-9]+|${_maskStrings.arraySource.replace("(","(?:")}|null|true|false)`,valuesClauseMatch=new RegExp(`(values)\\s+([a-z0-9_-]+\\s*=\\s*${literal}(?:\\s*,\\s*[a-z0-9_-]+\\s*=\\s*${literal})*)`,"i"),assignmentMatch=new RegExp(`([a-z0-9_-]+)\\s*=\\s*(${_maskStrings.placeholderSource}|([0-9]+)|${_maskStrings.arraySource}|(null)|(true)|(false))`,"ig"),findInsertValues=(e,r)=>{const s=r.match(valuesClauseMatch);if(e.insertValues=[],!s)return r;const a={},t=s[2].matchAll(assignmentMatch);for(const e of t)a[e[1]]=(0,_parseLiteralValue.parseLiteralValue)(e,3);return e.insertValues=[a],(0,_removeFromQuery.removeFromQuery)(s[0],r)};exports.findInsertValues=findInsertValues;
@@ -5,8 +5,11 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.findSelects = void 0;
7
7
  var _removeFromQuery = require("./removeFromQuery");
8
- const selectClausesMatch = /select\s+([a-z0-9=._-]+\s*(as\s+)?([a-z0-9_-]+)?)+\s*(,\s*[a-z0-9=._-]+\s*(as\s*[a-z0-9_-]+)?)*/i;
9
- const selectClauseMatch = /(select)?\s*,?\s*([a-z0-9=._-]+)\s*(as\s+)?([a-z0-9_-]+)?/ig;
8
+ // One field is a name, then optionally `as <alias>` (`as` as a whole word); fields are separated by commas. The first
9
+ // field used to accept an alias without `as`, so in `select name where a = 1` the word `where` became the alias.
10
+ const selectField = '[a-z0-9=._-]+(?:\\s+as\\s+[a-z0-9_-]+)?';
11
+ const selectClausesMatch = new RegExp(`select\\s+${selectField}(?:\\s*,\\s*${selectField})*`, 'i');
12
+ const selectClauseMatch = /(select)?\s*,?\s*([a-z0-9=._-]+)(?:\s+as\s+([a-z0-9_-]+))?/ig;
10
13
  /**
11
14
  * Extract select clauses from the query.
12
15
  * @param parsed
@@ -20,7 +23,7 @@ const findSelects = (parsed, query) => {
20
23
  for (const selectClause of selectClausesFound) {
21
24
  parsed['selectClauses'].push({
22
25
  property: selectClause[2],
23
- alias: selectClause[4]
26
+ alias: selectClause[3]
24
27
  });
25
28
  }
26
29
  return (0, _removeFromQuery.removeFromQuery)(selectsFound[0], query);
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findSelects=void 0;var _removeFromQuery=require("./removeFromQuery");const selectClausesMatch=/select\s+([a-z0-9=._-]+\s*(as\s+)?([a-z0-9_-]+)?)+\s*(,\s*[a-z0-9=._-]+\s*(as\s*[a-z0-9_-]+)?)*/i,selectClauseMatch=/(select)?\s*,?\s*([a-z0-9=._-]+)\s*(as\s+)?([a-z0-9_-]+)?/gi,findSelects=(e,s)=>{const t=s.match(selectClausesMatch);if(t){const r=t[0].matchAll(selectClauseMatch);for(const s of r)e.selectClauses.push({property:s[2],alias:s[4]});return(0,_removeFromQuery.removeFromQuery)(t[0],s)}return s};exports.findSelects=findSelects;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findSelects=void 0;var _removeFromQuery=require("./removeFromQuery");const selectField="[a-z0-9=._-]+(?:\\s+as\\s+[a-z0-9_-]+)?",selectClausesMatch=new RegExp(`select\\s+${selectField}(?:\\s*,\\s*${selectField})*`,"i"),selectClauseMatch=/(select)?\s*,?\s*([a-z0-9=._-]+)(?:\s+as\s+([a-z0-9_-]+))?/gi,findSelects=(e,s)=>{const t=s.match(selectClausesMatch);if(t){const r=t[0].matchAll(selectClauseMatch);for(const s of r)e.selectClauses.push({property:s[2],alias:s[3]});return(0,_removeFromQuery.removeFromQuery)(t[0],s)}return s};exports.findSelects=findSelects;
@@ -5,8 +5,11 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.findSortClauses = void 0;
7
7
  var _removeFromQuery = require("./removeFromQuery");
8
- const sortMatch = /sort\s+([a-z0-9._-]+\s*(asc|desc)?)+\s*(,\s*[a-z0-9._-]+\s*(asc|desc)?)*/i;
9
- const sortRuleMatch = /(sort)?\s*,?\s*([a-z0-9._-]+)\s*(asc|desc)?/ig;
8
+ // One rule is a field, then optionally asc or desc as a whole word. Rules are separated by commas, so the list ends
9
+ // at the first word that doesn't follow a comma: in `sort a limit 1`, `limit` starts the next clause.
10
+ const sortRule = '[a-z0-9._-]+(?:\\s+(?:asc|desc)(?![a-z0-9._-]))?';
11
+ const sortMatch = new RegExp(`sort\\s+${sortRule}(?:\\s*,\\s*${sortRule})*`, 'i');
12
+ const sortRuleMatch = /(sort)?\s*,?\s*([a-z0-9._-]+)(?:\s+(asc|desc)(?![a-z0-9._-]))?/ig;
10
13
  /**
11
14
  * Extract sort clauses from the query.
12
15
  * @param parsed
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findSortClauses=void 0;var _removeFromQuery=require("./removeFromQuery");const sortMatch=/sort\s+([a-z0-9._-]+\s*(asc|desc)?)+\s*(,\s*[a-z0-9._-]+\s*(asc|desc)?)*/i,sortRuleMatch=/(sort)?\s*,?\s*([a-z0-9._-]+)\s*(asc|desc)?/gi,findSortClauses=(s,r)=>{const e=r.match(sortMatch);if(e){const o=e[0].matchAll(sortRuleMatch);for(const r of o)s.sortClauses.push({property:r[2],direction:r[3]||"asc"});return(0,_removeFromQuery.removeFromQuery)(e[0],r)}return r};exports.findSortClauses=findSortClauses;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findSortClauses=void 0;var _removeFromQuery=require("./removeFromQuery");const sortRule="[a-z0-9._-]+(?:\\s+(?:asc|desc)(?![a-z0-9._-]))?",sortMatch=new RegExp(`sort\\s+${sortRule}(?:\\s*,\\s*${sortRule})*`,"i"),sortRuleMatch=/(sort)?\s*,?\s*([a-z0-9._-]+)(?:\s+(asc|desc)(?![a-z0-9._-]))?/gi,findSortClauses=(e,r)=>{const s=r.match(sortMatch);if(s){const o=s[0].matchAll(sortRuleMatch);for(const r of o)e.sortClauses.push({property:r[2],direction:r[3]||"asc"});return(0,_removeFromQuery.removeFromQuery)(s[0],r)}return r};exports.findSortClauses=findSortClauses;
@@ -6,9 +6,10 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.findUpdateValues = void 0;
7
7
  var _removeFromQuery = require("./removeFromQuery");
8
8
  var _parseLiteralValue = require("./parseLiteralValue");
9
- const literal = '(?:["\'][^"\']*[\'"]|[0-9]+|\\[.*?]|null|true|false)';
9
+ var _maskStrings = require("./maskStrings");
10
+ const literal = `(?:${_maskStrings.placeholderSource.replace('(', '(?:')}|[0-9]+|${_maskStrings.arraySource.replace('(', '(?:')}|null|true|false)`;
10
11
  const setClauseMatch = new RegExp(`(set)\\s+([a-z0-9_-]+\\s*=\\s*${literal}(?:\\s*,\\s*[a-z0-9_-]+\\s*=\\s*${literal})*)`, 'i');
11
- const assignmentMatch = /([a-z0-9_-]+)\s*=\s*(["'](.*?)['"]|([0-9]+)|(\[.*?])|(null)|(true)|(false))/ig;
12
+ const assignmentMatch = new RegExp(`([a-z0-9_-]+)\\s*=\\s*(${_maskStrings.placeholderSource}|([0-9]+)|${_maskStrings.arraySource}|(null)|(true)|(false))`, 'ig');
12
13
  /**
13
14
  * Extract an update's "set field = value, field2 = value2" clause from the query. Uses a two-pass
14
15
  * match, unlike the other parsers here: the set clause's own boundary is found first (so it can
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findUpdateValues=void 0;var _removeFromQuery=require("./removeFromQuery"),_parseLiteralValue=require("./parseLiteralValue");const literal="(?:[\"'][^\"']*['\"]|[0-9]+|\\[.*?]|null|true|false)",setClauseMatch=new RegExp(`(set)\\s+([a-z0-9_-]+\\s*=\\s*${literal}(?:\\s*,\\s*[a-z0-9_-]+\\s*=\\s*${literal})*)`,"i"),assignmentMatch=/([a-z0-9_-]+)\s*=\s*(["'](.*?)['"]|([0-9]+)|(\[.*?])|(null)|(true)|(false))/gi,findUpdateValues=(e,a)=>{const r=a.match(setClauseMatch);if(e.updateValues={},!r)return a;const s=r[2].matchAll(assignmentMatch);for(const a of s)e.updateValues[a[1]]=(0,_parseLiteralValue.parseLiteralValue)(a,3);return(0,_removeFromQuery.removeFromQuery)(r[0],a)};exports.findUpdateValues=findUpdateValues;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findUpdateValues=void 0;var _removeFromQuery=require("./removeFromQuery"),_parseLiteralValue=require("./parseLiteralValue"),_maskStrings=require("./maskStrings");const literal=`(?:${_maskStrings.placeholderSource.replace("(","(?:")}|[0-9]+|${_maskStrings.arraySource.replace("(","(?:")}|null|true|false)`,setClauseMatch=new RegExp(`(set)\\s+([a-z0-9_-]+\\s*=\\s*${literal}(?:\\s*,\\s*[a-z0-9_-]+\\s*=\\s*${literal})*)`,"i"),assignmentMatch=new RegExp(`([a-z0-9_-]+)\\s*=\\s*(${_maskStrings.placeholderSource}|([0-9]+)|${_maskStrings.arraySource}|(null)|(true)|(false))`,"ig"),findUpdateValues=(e,r)=>{const a=r.match(setClauseMatch);if(e.updateValues={},!a)return r;const s=a[2].matchAll(assignmentMatch);for(const r of s)e.updateValues[r[1]]=(0,_parseLiteralValue.parseLiteralValue)(r,3);return(0,_removeFromQuery.removeFromQuery)(a[0],r)};exports.findUpdateValues=findUpdateValues;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Regex source matching one placeholder from maskStrings, with the hex-encoded value as its only group. The
3
+ * find* parsers use it where they would otherwise match a quoted string.
4
+ */
5
+ export declare const placeholderSource = "\\u0000([0-9a-f]*)\\u0000";
6
+ /**
7
+ * Regex source matching one placeholder from maskArrays, with the hex-encoded JSON of the array as its only group.
8
+ * The find* parsers use it where they would otherwise match `[...]`.
9
+ */
10
+ export declare const arraySource = "\\u0001([0-9a-f]*)\\u0001";
11
+ /**
12
+ * Turn the hex of a placeholder back into the string's value.
13
+ * @param hex
14
+ */
15
+ export declare const fromPlaceholder: (hex: string) => string;
16
+ /**
17
+ * Replace every quoted string in a query with a placeholder holding its value (with the escapes applied), so that
18
+ * nothing inside a string (a keyword, a quote, `and`, a `]`) can be matched by the find* parsers.
19
+ * @param query
20
+ * @throws {Error} For an unclosed string, comment or bracket, or a NUL or SOH character outside a string (which
21
+ * could otherwise pass for a placeholder).
22
+ */
23
+ export declare const maskStrings: (query: string) => string;
24
+ /**
25
+ * Put every placeholder back the way it would be written in a query: strings quoted, arrays as JSON. For error
26
+ * messages, and for reading an array's text as JSON.
27
+ * @param text
28
+ * @param quote - wrap strings with JSON's double quotes (the default) or with single quotes
29
+ */
30
+ export declare const unmaskStrings: (text: string, quote?: "json" | "'") => string;
31
+ /**
32
+ * Replace every array (outermost brackets only, so a nested array stays inside its parent) with a placeholder holding
33
+ * its JSON, so that the find* parsers never have to find where an array ends, and nothing inside one (a `.`, a `]`,
34
+ * a keyword) can be matched by them. Run it on the output of maskStrings, where no `[` or `]` is inside a string.
35
+ * @param masked
36
+ * @throws {Error} For an array which is not valid JSON once its strings are put back.
37
+ */
38
+ export declare const maskArrays: (masked: string) => string;
39
+ //# sourceMappingURL=maskStrings.d.ts.map