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.
- package/LICENSE +674 -674
- package/README.md +295 -98
- package/browser/jsonFsQuery.js +12733 -10777
- package/browser/jsonFsQuery.min.js +1 -1
- package/dist/data/introspect/create.d.ts +1 -1
- package/dist/data/introspect/create.js +35 -4
- package/dist/data/introspect/create.min.js +1 -1
- package/dist/data/introspect/definitions/field.d.ts +6 -2
- package/dist/data/introspect/definitions/field.js +7 -1
- package/dist/data/introspect/definitions/field.min.js +1 -1
- package/dist/data/introspect/index.d.ts +6 -3
- package/dist/data/introspect/index.js +10 -19
- package/dist/data/introspect/index.min.js +1 -1
- package/dist/data/introspect/policies/foreignKeyExists.js +5 -1
- package/dist/data/introspect/policies/foreignKeyExists.min.js +1 -1
- package/dist/data/introspect/policies/hasDependents.js +3 -1
- package/dist/data/introspect/policies/hasDependents.min.js +1 -1
- package/dist/data/introspect/policies/keyUnique.js +5 -1
- package/dist/data/introspect/policies/keyUnique.min.js +1 -1
- package/dist/data/introspect/policies/typeCheck.d.ts +9 -1
- package/dist/data/introspect/policies/typeCheck.js +16 -2
- package/dist/data/introspect/policies/typeCheck.min.js +1 -1
- package/dist/data/queries/createRecord.d.ts +11 -0
- package/dist/data/queries/createRecord.js +58 -0
- package/dist/data/queries/createRecord.min.js +1 -0
- package/dist/data/queries/deleteEntity.js +2 -1
- package/dist/data/queries/deleteEntity.min.js +1 -1
- package/dist/data/queries/describeRecord.d.ts +9 -0
- package/dist/data/queries/describeRecord.js +29 -0
- package/dist/data/queries/describeRecord.min.js +1 -0
- package/dist/data/queries/dropRecord.d.ts +9 -0
- package/dist/data/queries/dropRecord.js +61 -0
- package/dist/data/queries/dropRecord.min.js +1 -0
- package/dist/data/queries/insertEntity.js +11 -5
- package/dist/data/queries/insertEntity.min.js +1 -1
- package/dist/data/queries/parser.d.ts +1 -1
- package/dist/data/queries/parser.js +7 -15
- package/dist/data/queries/parser.min.js +1 -1
- package/dist/data/queries/query.d.ts +6 -0
- package/dist/data/queries/query.js +15 -6
- package/dist/data/queries/query.min.js +1 -1
- package/dist/data/queries/queryStatus.d.ts +15 -0
- package/dist/data/queries/queryStatus.js +52 -0
- package/dist/data/queries/queryStatus.min.js +1 -0
- package/dist/data/queries/quote.d.ts +11 -0
- package/dist/data/queries/quote.js +17 -0
- package/dist/data/queries/quote.min.js +1 -0
- package/dist/data/queries/showRecords.d.ts +6 -0
- package/dist/data/queries/showRecords.js +21 -0
- package/dist/data/queries/showRecords.min.js +1 -0
- package/dist/data/queries/sortBy.js +3 -0
- package/dist/data/queries/updateEntity.js +74 -18
- package/dist/data/queries/updateEntity.min.js +1 -1
- package/dist/data/queries/where.d.ts +2 -1
- package/dist/data/queries/where.js +18 -6
- package/dist/data/queries/where.min.js +1 -1
- package/dist/data/utilities/compareAs.d.ts +20 -0
- package/dist/data/utilities/compareAs.js +58 -0
- package/dist/data/utilities/compareAs.min.js +1 -0
- package/dist/data/utilities/config.d.ts +15 -0
- package/dist/data/utilities/config.js +31 -1
- package/dist/data/utilities/config.min.js +1 -1
- package/dist/data/utilities/databaseLock.d.ts +16 -0
- package/dist/data/utilities/databaseLock.js +63 -0
- package/dist/data/utilities/databaseLock.min.js +1 -0
- package/dist/data/utilities/fieldType.d.ts +16 -0
- package/dist/data/utilities/fieldType.js +23 -0
- package/dist/data/utilities/fieldType.min.js +1 -0
- package/dist/data/utilities/getConditionIndexedList.js +2 -1
- package/dist/data/utilities/getConditionIndexedList.min.js +1 -1
- package/dist/data/utilities/matchIndexedJoins.js +3 -1
- package/dist/data/utilities/matchIndexedJoins.min.js +1 -1
- package/dist/data/utilities/mergeJoin.js +5 -1
- package/dist/data/utilities/mergeJoin.min.js +1 -1
- package/dist/data/utilities/parsers/findConditions.d.ts +5 -1
- package/dist/data/utilities/parsers/findConditions.js +15 -6
- package/dist/data/utilities/parsers/findConditions.min.js +1 -1
- package/dist/data/utilities/parsers/findInsertValues.js +3 -2
- package/dist/data/utilities/parsers/findInsertValues.min.js +1 -1
- package/dist/data/utilities/parsers/findSelects.js +6 -3
- package/dist/data/utilities/parsers/findSelects.min.js +1 -1
- package/dist/data/utilities/parsers/findSortClauses.js +5 -2
- package/dist/data/utilities/parsers/findSortClauses.min.js +1 -1
- package/dist/data/utilities/parsers/findUpdateValues.js +3 -2
- package/dist/data/utilities/parsers/findUpdateValues.min.js +1 -1
- package/dist/data/utilities/parsers/maskStrings.d.ts +39 -0
- package/dist/data/utilities/parsers/maskStrings.js +123 -0
- package/dist/data/utilities/parsers/maskStrings.min.js +1 -0
- package/dist/data/utilities/parsers/parseCreate.d.ts +20 -0
- package/dist/data/utilities/parsers/parseCreate.js +330 -0
- package/dist/data/utilities/parsers/parseCreate.min.js +1 -0
- package/dist/data/utilities/parsers/parseLiteralValue.d.ts +2 -1
- package/dist/data/utilities/parsers/parseLiteralValue.js +6 -3
- package/dist/data/utilities/parsers/parseLiteralValue.min.js +1 -1
- package/dist/data/utilities/parsers/parseQuery.d.ts +3 -0
- package/dist/data/utilities/parsers/parseQuery.js +28 -2
- package/dist/data/utilities/parsers/parseQuery.min.js +1 -1
- package/dist/data/utilities/parsers/parseSchemaStatement.d.ts +13 -0
- package/dist/data/utilities/parsers/parseSchemaStatement.js +82 -0
- package/dist/data/utilities/parsers/parseSchemaStatement.min.js +1 -0
- package/dist/data/utilities/parsers/scanQuery.d.ts +52 -0
- package/dist/data/utilities/parsers/scanQuery.js +158 -0
- package/dist/data/utilities/parsers/scanQuery.min.js +1 -0
- package/dist/data/utilities/parsers/splitQueries.d.ts +6 -0
- package/dist/data/utilities/parsers/splitQueries.js +20 -2
- package/dist/data/utilities/parsers/splitQueries.min.js +1 -1
- package/dist/data/utilities/parsers/startsQuery.d.ts +5 -0
- package/dist/data/utilities/parsers/startsQuery.js +10 -0
- package/dist/data/utilities/parsers/startsQuery.min.js +1 -0
- package/dist/data/utilities/recordExists.d.ts +6 -0
- package/dist/data/utilities/recordExists.js +18 -0
- package/dist/data/utilities/recordExists.min.js +1 -0
- package/dist/data/utilities/removeFromIndex.d.ts +2 -1
- package/dist/data/utilities/removeFromIndex.js +4 -2
- package/dist/data/utilities/removeFromIndex.min.js +1 -1
- package/dist/data/utilities/runQuery.js +49 -0
- package/dist/data/utilities/runQuery.min.js +1 -1
- package/dist/data/utilities/updateIndex.d.ts +2 -1
- package/dist/data/utilities/updateIndex.js +4 -2
- package/dist/data/utilities/updateIndex.min.js +1 -1
- package/dist/data/utilities/useJoinClause.js +8 -2
- package/dist/data/utilities/useJoinClause.min.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +14 -0
- package/dist/index.min.js +1 -1
- 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,
|
|
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={},
|
|
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}))),[]),
|
|
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);
|
|
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
|
-
|
|
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[
|
|
21
|
-
comparator: condition[
|
|
22
|
-
value: (0, _parseLiteralValue.parseLiteralValue)(condition,
|
|
28
|
+
property: condition[4],
|
|
29
|
+
comparator: condition[5],
|
|
30
|
+
value: (0, _parseLiteralValue.parseLiteralValue)(condition, 7)
|
|
23
31
|
});
|
|
24
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
9
|
-
|
|
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[
|
|
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
|
|
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
|
-
|
|
9
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|