json-fs-query 3.1.4 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +257 -15
- package/browser/jsonFsQuery.js +3884 -5057
- package/browser/jsonFsQuery.min.js +1 -1
- package/dist/data/introspect/alter.d.ts +12 -0
- package/dist/data/introspect/alter.js +304 -0
- package/dist/data/introspect/alter.min.js +1 -0
- package/dist/data/introspect/create.d.ts +10 -0
- package/dist/data/introspect/create.js +9 -23
- package/dist/data/introspect/create.min.js +1 -1
- package/dist/data/introspect/drop.js +7 -15
- package/dist/data/introspect/drop.min.js +1 -1
- package/dist/data/introspect/formatDatabase.d.ts +17 -0
- package/dist/data/introspect/formatDatabase.js +56 -0
- package/dist/data/introspect/formatDatabase.min.js +1 -0
- package/dist/data/introspect/index.d.ts +9 -0
- package/dist/data/introspect/index.js +18 -5
- package/dist/data/introspect/index.min.js +1 -1
- package/dist/data/introspect/packDatabase.d.ts +27 -0
- package/dist/data/introspect/packDatabase.js +113 -0
- package/dist/data/introspect/packDatabase.min.js +1 -0
- package/dist/data/introspect/policies/foreignKeyExists.d.ts +2 -0
- package/dist/data/introspect/policies/foreignKeyExists.js +9 -3
- package/dist/data/introspect/policies/foreignKeyExists.min.js +1 -1
- package/dist/data/introspect/policies/hasDependents.d.ts +3 -3
- package/dist/data/introspect/policies/hasDependents.js +11 -3
- package/dist/data/introspect/policies/hasDependents.min.js +1 -1
- package/dist/data/introspect/policies/keyUnique.d.ts +3 -0
- package/dist/data/introspect/policies/keyUnique.js +10 -0
- package/dist/data/introspect/policies/keyUnique.min.js +1 -1
- package/dist/data/queries/databaseStatements.d.ts +31 -0
- package/dist/data/queries/databaseStatements.js +97 -0
- package/dist/data/queries/databaseStatements.min.js +1 -0
- package/dist/data/queries/deleteEntity.js +35 -19
- package/dist/data/queries/deleteEntity.min.js +1 -1
- package/dist/data/queries/insertEntity.d.ts +8 -0
- package/dist/data/queries/insertEntity.js +340 -43
- package/dist/data/queries/insertEntity.min.js +1 -1
- package/dist/data/queries/joinEntity.d.ts +15 -0
- package/dist/data/queries/joinEntity.js +91 -15
- package/dist/data/queries/joinEntity.min.js +1 -1
- package/dist/data/queries/query.d.ts +2 -1
- package/dist/data/queries/query.js +5 -2
- package/dist/data/queries/query.min.js +1 -1
- package/dist/data/queries/selectFields.d.ts +5 -4
- package/dist/data/queries/selectFields.js +25 -11
- package/dist/data/queries/selectFields.min.js +1 -1
- package/dist/data/queries/updateEntity.js +54 -15
- package/dist/data/queries/updateEntity.min.js +1 -1
- package/dist/data/storage/databases.d.ts +32 -0
- package/dist/data/storage/databases.js +93 -0
- package/dist/data/storage/databases.min.js +1 -0
- package/dist/data/storage/fileExists.d.ts +7 -0
- package/dist/data/storage/fileExists.js +25 -0
- package/dist/data/storage/fileExists.min.js +1 -0
- package/dist/data/storage/index.d.ts +19 -0
- package/dist/data/storage/index.js +124 -0
- package/dist/data/storage/index.min.js +1 -0
- package/dist/data/storage/listFiles.d.ts +8 -0
- package/dist/data/storage/listFiles.js +52 -0
- package/dist/data/storage/listFiles.min.js +1 -0
- package/dist/data/storage/makeDirectory.d.ts +7 -0
- package/dist/data/storage/makeDirectory.js +24 -0
- package/dist/data/storage/makeDirectory.min.js +1 -0
- package/dist/data/storage/nodeFiles.d.ts +6 -0
- package/dist/data/storage/nodeFiles.js +12 -0
- package/dist/data/storage/nodeFiles.min.js +1 -0
- package/dist/data/storage/readCache.d.ts +37 -0
- package/dist/data/storage/readCache.js +117 -0
- package/dist/data/storage/readCache.min.js +1 -0
- package/dist/data/storage/readJson.d.ts +16 -0
- package/dist/data/storage/readJson.js +38 -0
- package/dist/data/storage/readJson.min.js +1 -0
- package/dist/data/storage/removeDirectory.d.ts +8 -0
- package/dist/data/storage/removeDirectory.js +30 -0
- package/dist/data/storage/removeDirectory.min.js +1 -0
- package/dist/data/storage/removeFile.d.ts +8 -0
- package/dist/data/storage/removeFile.js +31 -0
- package/dist/data/storage/removeFile.min.js +1 -0
- package/dist/data/storage/storagePath.d.ts +11 -0
- package/dist/data/storage/storagePath.js +25 -0
- package/dist/data/storage/storagePath.min.js +1 -0
- package/dist/data/storage/writeJson.d.ts +17 -0
- package/dist/data/storage/writeJson.js +37 -0
- package/dist/data/storage/writeJson.min.js +1 -0
- package/dist/data/storage/writeSet.d.ts +64 -0
- package/dist/data/storage/writeSet.js +306 -0
- package/dist/data/storage/writeSet.min.js +1 -0
- package/dist/data/utilities/compareAs.d.ts +1 -0
- package/dist/data/utilities/compareAs.js +2 -2
- package/dist/data/utilities/compareAs.min.js +1 -1
- package/dist/data/utilities/config.d.ts +37 -0
- package/dist/data/utilities/config.js +77 -5
- package/dist/data/utilities/config.min.js +1 -1
- package/dist/data/utilities/databaseLock.d.ts +7 -0
- package/dist/data/utilities/databaseLock.js +19 -4
- package/dist/data/utilities/databaseLock.min.js +1 -1
- package/dist/data/utilities/deregisterRecord.js +4 -10
- package/dist/data/utilities/deregisterRecord.min.js +1 -1
- package/dist/data/utilities/getConditionIndexedList.js +3 -4
- package/dist/data/utilities/getConditionIndexedList.min.js +1 -1
- package/dist/data/utilities/indexBuffer.d.ts +35 -0
- package/dist/data/utilities/indexBuffer.js +139 -0
- package/dist/data/utilities/indexBuffer.min.js +1 -0
- package/dist/data/utilities/indexHas.d.ts +13 -0
- package/dist/data/utilities/indexHas.js +48 -0
- package/dist/data/utilities/indexHas.min.js +1 -0
- package/dist/data/utilities/joinBases.d.ts +29 -0
- package/dist/data/utilities/joinBases.js +128 -0
- package/dist/data/utilities/joinBases.min.js +1 -0
- package/dist/data/utilities/joinKey.d.ts +17 -0
- package/dist/data/utilities/joinKey.js +31 -0
- package/dist/data/utilities/joinKey.min.js +1 -0
- package/dist/data/utilities/keyIndexFiles.d.ts +16 -0
- package/dist/data/utilities/keyIndexFiles.js +60 -0
- package/dist/data/utilities/keyIndexFiles.min.js +1 -0
- package/dist/data/utilities/knownFields.d.ts +26 -0
- package/dist/data/utilities/knownFields.js +128 -0
- package/dist/data/utilities/knownFields.min.js +1 -0
- package/dist/data/utilities/packedTable.d.ts +34 -0
- package/dist/data/utilities/packedTable.js +60 -0
- package/dist/data/utilities/packedTable.min.js +1 -0
- package/dist/data/utilities/parsers/findInsertValues.d.ts +3 -3
- package/dist/data/utilities/parsers/findInsertValues.js +28 -12
- package/dist/data/utilities/parsers/findInsertValues.min.js +1 -1
- package/dist/data/utilities/parsers/maskStrings.js +11 -2
- package/dist/data/utilities/parsers/maskStrings.min.js +1 -1
- package/dist/data/utilities/parsers/parseAlter.d.ts +33 -0
- package/dist/data/utilities/parsers/parseAlter.js +84 -0
- package/dist/data/utilities/parsers/parseAlter.min.js +1 -0
- package/dist/data/utilities/parsers/parseCreate.d.ts +14 -0
- package/dist/data/utilities/parsers/parseCreate.js +13 -5
- package/dist/data/utilities/parsers/parseCreate.min.js +1 -1
- package/dist/data/utilities/parsers/parseDatabaseStatement.d.ts +17 -0
- package/dist/data/utilities/parsers/parseDatabaseStatement.js +82 -0
- package/dist/data/utilities/parsers/parseDatabaseStatement.min.js +1 -0
- package/dist/data/utilities/parsers/parseQuery.d.ts +3 -0
- package/dist/data/utilities/parsers/parseQuery.js +24 -0
- package/dist/data/utilities/parsers/parseQuery.min.js +1 -1
- package/dist/data/utilities/parsers/startsQuery.js +1 -1
- package/dist/data/utilities/parsers/startsQuery.min.js +1 -1
- package/dist/data/utilities/recordExists.js +2 -7
- package/dist/data/utilities/recordExists.min.js +1 -1
- package/dist/data/utilities/registerRecord.js +4 -10
- package/dist/data/utilities/registerRecord.min.js +1 -1
- package/dist/data/utilities/removeFromIndex.js +4 -10
- package/dist/data/utilities/removeFromIndex.min.js +1 -1
- package/dist/data/utilities/retrieveFile.d.ts +5 -0
- package/dist/data/utilities/retrieveFile.js +7 -16
- package/dist/data/utilities/retrieveFile.min.js +1 -1
- package/dist/data/utilities/retrieveFiles.d.ts +15 -0
- package/dist/data/utilities/retrieveFiles.js +48 -0
- package/dist/data/utilities/retrieveFiles.min.js +1 -0
- package/dist/data/utilities/retrieveRecord.d.ts +6 -0
- package/dist/data/utilities/retrieveRecord.js +24 -1
- package/dist/data/utilities/retrieveRecord.min.js +1 -1
- package/dist/data/utilities/retrieveRecords.d.ts +22 -0
- package/dist/data/utilities/retrieveRecords.js +60 -10
- package/dist/data/utilities/retrieveRecords.min.js +1 -1
- package/dist/data/utilities/rowLookup.d.ts +38 -0
- package/dist/data/utilities/rowLookup.js +99 -0
- package/dist/data/utilities/rowLookup.min.js +1 -0
- package/dist/data/utilities/runQuery.js +28 -4
- package/dist/data/utilities/runQuery.min.js +1 -1
- package/dist/data/utilities/semiJoin.d.ts +27 -0
- package/dist/data/utilities/semiJoin.js +97 -0
- package/dist/data/utilities/semiJoin.min.js +1 -0
- package/dist/data/utilities/updateIndex.js +5 -14
- package/dist/data/utilities/updateIndex.min.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +24 -0
- package/dist/index.min.js +1 -1
- package/package.json +10 -4
- package/dist/data/utilities/getJoinIndexedList.d.ts +0 -3
- package/dist/data/utilities/getJoinIndexedList.js +0 -76
- package/dist/data/utilities/getJoinIndexedList.min.js +0 -1
- package/dist/data/utilities/getMatchingIndexes.d.ts +0 -2
- package/dist/data/utilities/getMatchingIndexes.js +0 -28
- package/dist/data/utilities/getMatchingIndexes.min.js +0 -1
- package/dist/data/utilities/matchIndexedJoins.d.ts +0 -2
- package/dist/data/utilities/matchIndexedJoins.js +0 -63
- package/dist/data/utilities/matchIndexedJoins.min.js +0 -1
- package/dist/data/utilities/restrictIndexedList.d.ts +0 -2
- package/dist/data/utilities/restrictIndexedList.js +0 -45
- package/dist/data/utilities/restrictIndexedList.min.js +0 -1
- package/dist/data/utilities/useJoinClause.d.ts +0 -6
- package/dist/data/utilities/useJoinClause.js +0 -57
- package/dist/data/utilities/useJoinClause.min.js +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { recordDefinition } from '../introspect/definitions/record';
|
|
2
|
+
/**
|
|
3
|
+
* Throw unless `record` defines every one of `fields`, naming the first that it doesn't and the fields it has: a
|
|
4
|
+
* misspelled field would otherwise be dropped from an insert, stored by an update, or match nothing in a read.
|
|
5
|
+
* @param entity - The record's name, for the message.
|
|
6
|
+
* @param record
|
|
7
|
+
* @param fields
|
|
8
|
+
* @param where - Where the fields were given (`insert`, `set`, `where`...), for the message.
|
|
9
|
+
* @throws {Error} `Unknown field "<field>" in <where>: <entity> has <fields>`.
|
|
10
|
+
*/
|
|
11
|
+
export declare const assertFieldsDefined: (entity: string, record: recordDefinition, fields: string[], where: string) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Throw unless every field a query names (in `where`, `sort`, `group by`, `select`, `on`, `merge`, and an insert's or
|
|
14
|
+
* update's values) is defined by its record, before anything is read: the queried record for a plain name, the named
|
|
15
|
+
* one for `<record>.<field>` (any record, as a join through another one names it). In `select`, the joined record's
|
|
16
|
+
* name stands for its rows, and `<record>.<field>` names the queried record's own field or a merged record's (a joined
|
|
17
|
+
* record's rows are a list, with no one value to pick).
|
|
18
|
+
* @param parsed - The parsed query.
|
|
19
|
+
* @param recordData - Records already read, by name (more are read as they're named, and kept here).
|
|
20
|
+
* @throws {Error} `Unknown field ...` (see assertFieldsDefined), or `Record "<name>" doesn't exist` for a record that
|
|
21
|
+
* doesn't.
|
|
22
|
+
*/
|
|
23
|
+
export declare const assertKnownFields: (parsed: any, recordData: {
|
|
24
|
+
[entity: string]: recordDefinition;
|
|
25
|
+
}) => Promise<void>;
|
|
26
|
+
//# sourceMappingURL=knownFields.d.ts.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.assertKnownFields = exports.assertFieldsDefined = void 0;
|
|
7
|
+
require("core-js/modules/esnext.iterator.constructor.js");
|
|
8
|
+
require("core-js/modules/esnext.iterator.filter.js");
|
|
9
|
+
require("core-js/modules/esnext.iterator.find.js");
|
|
10
|
+
require("core-js/modules/esnext.iterator.flat-map.js");
|
|
11
|
+
require("core-js/modules/esnext.iterator.map.js");
|
|
12
|
+
require("core-js/modules/esnext.set.add-all.js");
|
|
13
|
+
require("core-js/modules/esnext.set.delete-all.js");
|
|
14
|
+
require("core-js/modules/esnext.set.difference.js");
|
|
15
|
+
require("core-js/modules/esnext.set.every.js");
|
|
16
|
+
require("core-js/modules/esnext.set.filter.js");
|
|
17
|
+
require("core-js/modules/esnext.set.find.js");
|
|
18
|
+
require("core-js/modules/esnext.set.intersection.js");
|
|
19
|
+
require("core-js/modules/esnext.set.is-disjoint-from.js");
|
|
20
|
+
require("core-js/modules/esnext.set.is-subset-of.js");
|
|
21
|
+
require("core-js/modules/esnext.set.is-superset-of.js");
|
|
22
|
+
require("core-js/modules/esnext.set.join.js");
|
|
23
|
+
require("core-js/modules/esnext.set.map.js");
|
|
24
|
+
require("core-js/modules/esnext.set.reduce.js");
|
|
25
|
+
require("core-js/modules/esnext.set.some.js");
|
|
26
|
+
require("core-js/modules/esnext.set.symmetric-difference.js");
|
|
27
|
+
require("core-js/modules/esnext.set.union.js");
|
|
28
|
+
var _retrieveRecord = require("./retrieveRecord");
|
|
29
|
+
var _isEntityProperty = require("./parsers/isEntityProperty");
|
|
30
|
+
var _splitEntityProperty = require("./parsers/splitEntityProperty");
|
|
31
|
+
var _conditionTree = require("./conditionTree");
|
|
32
|
+
/**
|
|
33
|
+
* The fields a record defines, for an error message.
|
|
34
|
+
* @param record
|
|
35
|
+
*/
|
|
36
|
+
const fieldList = record => record.definition.map(field => field.name).join(', ');
|
|
37
|
+
/**
|
|
38
|
+
* Throw unless `record` defines every one of `fields`, naming the first that it doesn't and the fields it has: a
|
|
39
|
+
* misspelled field would otherwise be dropped from an insert, stored by an update, or match nothing in a read.
|
|
40
|
+
* @param entity - The record's name, for the message.
|
|
41
|
+
* @param record
|
|
42
|
+
* @param fields
|
|
43
|
+
* @param where - Where the fields were given (`insert`, `set`, `where`...), for the message.
|
|
44
|
+
* @throws {Error} `Unknown field "<field>" in <where>: <entity> has <fields>`.
|
|
45
|
+
*/
|
|
46
|
+
const assertFieldsDefined = (entity, record, fields, where) => {
|
|
47
|
+
const defined = new Set(record.definition.map(field => field.name));
|
|
48
|
+
const unknown = fields.find(field => !defined.has(field));
|
|
49
|
+
if (typeof unknown !== 'undefined') {
|
|
50
|
+
throw new Error(`Unknown field "${unknown}" in ${where}: ${entity} has ${fieldList(record)}`);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Throw unless every field a query names (in `where`, `sort`, `group by`, `select`, `on`, `merge`, and an insert's or
|
|
55
|
+
* update's values) is defined by its record, before anything is read: the queried record for a plain name, the named
|
|
56
|
+
* one for `<record>.<field>` (any record, as a join through another one names it). In `select`, the joined record's
|
|
57
|
+
* name stands for its rows, and `<record>.<field>` names the queried record's own field or a merged record's (a joined
|
|
58
|
+
* record's rows are a list, with no one value to pick).
|
|
59
|
+
* @param parsed - The parsed query.
|
|
60
|
+
* @param recordData - Records already read, by name (more are read as they're named, and kept here).
|
|
61
|
+
* @throws {Error} `Unknown field ...` (see assertFieldsDefined), or `Record "<name>" doesn't exist` for a record that
|
|
62
|
+
* doesn't.
|
|
63
|
+
*/
|
|
64
|
+
exports.assertFieldsDefined = assertFieldsDefined;
|
|
65
|
+
const assertKnownFields = async (parsed, recordData) => {
|
|
66
|
+
// A merged record's fields are on each row as `<record>.<field>`, so select can name them; a joined one's rows are a
|
|
67
|
+
// list, with no one value to pick
|
|
68
|
+
const merged = new Set((parsed.mergeJoins || []).map(merge => (0, _splitEntityProperty.splitEntityProperty)(merge.propertyB).entity));
|
|
69
|
+
const named = [...(0, _conditionTree.conditionsOf)(parsed.where).map(condition => ({
|
|
70
|
+
property: condition.property,
|
|
71
|
+
clause: 'where'
|
|
72
|
+
})), ...(parsed.sortClauses || []).map(sort => ({
|
|
73
|
+
property: sort.property,
|
|
74
|
+
clause: 'sort'
|
|
75
|
+
})), ...(parsed.groupBy || []).map(property => ({
|
|
76
|
+
property,
|
|
77
|
+
clause: 'group by'
|
|
78
|
+
})), ...(parsed.selectClauses || []).filter(select => select.property !== parsed.joinEntity).map(select => ({
|
|
79
|
+
property: select.property,
|
|
80
|
+
clause: 'select'
|
|
81
|
+
})), ...(parsed.insertValues || []).flatMap(row => Object.keys(row || {}).map(property => ({
|
|
82
|
+
property,
|
|
83
|
+
clause: 'insert',
|
|
84
|
+
own: true
|
|
85
|
+
}))), ...Object.keys(parsed.updateValues || {}).map(property => ({
|
|
86
|
+
property,
|
|
87
|
+
clause: 'set',
|
|
88
|
+
own: true
|
|
89
|
+
})), ...(parsed.joinClauses || []).flatMap(join => [{
|
|
90
|
+
property: join.propertyA,
|
|
91
|
+
clause: 'on'
|
|
92
|
+
}, {
|
|
93
|
+
property: join.propertyB,
|
|
94
|
+
clause: 'on'
|
|
95
|
+
}]), ...(parsed.mergeJoins || []).flatMap(merge => [{
|
|
96
|
+
property: merge.propertyA,
|
|
97
|
+
clause: 'merge'
|
|
98
|
+
}, {
|
|
99
|
+
property: merge.propertyB,
|
|
100
|
+
clause: 'merge'
|
|
101
|
+
}])];
|
|
102
|
+
for (const {
|
|
103
|
+
property,
|
|
104
|
+
clause,
|
|
105
|
+
own
|
|
106
|
+
} of named) {
|
|
107
|
+
if (typeof property !== 'string') {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
let entity = parsed.entity;
|
|
111
|
+
let field = property;
|
|
112
|
+
// Insert and set values are always the queried record's own fields, whatever their name
|
|
113
|
+
if (!own && (0, _isEntityProperty.isEntityProperty)(property)) {
|
|
114
|
+
({
|
|
115
|
+
entity,
|
|
116
|
+
property: field
|
|
117
|
+
} = (0, _splitEntityProperty.splitEntityProperty)(property));
|
|
118
|
+
}
|
|
119
|
+
if (clause === 'select' && entity !== parsed.entity && !merged.has(entity)) {
|
|
120
|
+
throw new Error(`Can't select "${property}": a joined record's rows are a list under its name (select ${entity}), ` + `and its fields are on each row only when merged (merge ... with ${entity}.<field>)`);
|
|
121
|
+
}
|
|
122
|
+
if (!Object.prototype.hasOwnProperty.call(recordData, entity)) {
|
|
123
|
+
recordData[entity] = await (0, _retrieveRecord.retrieveRecord)(entity);
|
|
124
|
+
}
|
|
125
|
+
assertFieldsDefined(entity, recordData[entity], [field], clause);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
exports.assertKnownFields = assertKnownFields;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.assertKnownFields=exports.assertFieldsDefined=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.filter.js"),require("core-js/modules/esnext.iterator.find.js"),require("core-js/modules/esnext.iterator.flat-map.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.set.add-all.js"),require("core-js/modules/esnext.set.delete-all.js"),require("core-js/modules/esnext.set.difference.js"),require("core-js/modules/esnext.set.every.js"),require("core-js/modules/esnext.set.filter.js"),require("core-js/modules/esnext.set.find.js"),require("core-js/modules/esnext.set.intersection.js"),require("core-js/modules/esnext.set.is-disjoint-from.js"),require("core-js/modules/esnext.set.is-subset-of.js"),require("core-js/modules/esnext.set.is-superset-of.js"),require("core-js/modules/esnext.set.join.js"),require("core-js/modules/esnext.set.map.js"),require("core-js/modules/esnext.set.reduce.js"),require("core-js/modules/esnext.set.some.js"),require("core-js/modules/esnext.set.symmetric-difference.js"),require("core-js/modules/esnext.set.union.js");var _retrieveRecord=require("./retrieveRecord"),_isEntityProperty=require("./parsers/isEntityProperty"),_splitEntityProperty=require("./parsers/splitEntityProperty"),_conditionTree=require("./conditionTree");const fieldList=e=>e.definition.map((e=>e.name)).join(", "),assertFieldsDefined=(e,r,s,t)=>{const o=new Set(r.definition.map((e=>e.name))),i=s.find((e=>!o.has(e)));if(void 0!==i)throw new Error(`Unknown field "${i}" in ${t}: ${e} has ${fieldList(r)}`)};exports.assertFieldsDefined=assertFieldsDefined;const assertKnownFields=async(e,r)=>{const s=new Set((e.mergeJoins||[]).map((e=>(0,_splitEntityProperty.splitEntityProperty)(e.propertyB).entity))),t=[...(0,_conditionTree.conditionsOf)(e.where).map((e=>({property:e.property,clause:"where"}))),...(e.sortClauses||[]).map((e=>({property:e.property,clause:"sort"}))),...(e.groupBy||[]).map((e=>({property:e,clause:"group by"}))),...(e.selectClauses||[]).filter((r=>r.property!==e.joinEntity)).map((e=>({property:e.property,clause:"select"}))),...(e.insertValues||[]).flatMap((e=>Object.keys(e||{}).map((e=>({property:e,clause:"insert",own:!0}))))),...Object.keys(e.updateValues||{}).map((e=>({property:e,clause:"set",own:!0}))),...(e.joinClauses||[]).flatMap((e=>[{property:e.propertyA,clause:"on"},{property:e.propertyB,clause:"on"}])),...(e.mergeJoins||[]).flatMap((e=>[{property:e.propertyA,clause:"merge"},{property:e.propertyB,clause:"merge"}]))];for(const{property:o,clause:i,own:n}of t){if("string"!=typeof o)continue;let t=e.entity,p=o;if(!n&&(0,_isEntityProperty.isEntityProperty)(o)&&({entity:t,property:p}=(0,_splitEntityProperty.splitEntityProperty)(o)),"select"===i&&t!==e.entity&&!s.has(t))throw new Error(`Can't select "${o}": a joined record's rows are a list under its name (select ${t}), and its fields are on each row only when merged (merge ... with ${t}.<field>)`);Object.prototype.hasOwnProperty.call(r,t)||(r[t]=await(0,_retrieveRecord.retrieveRecord)(t)),assertFieldsDefined(t,r[t],[p],i)}};exports.assertKnownFields=assertKnownFields;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { recordDefinition } from '../introspect/definitions/record';
|
|
2
|
+
/**
|
|
3
|
+
* One record packed into one file by packDatabase: its entry files' names and rows, in the record's order, so a browser
|
|
4
|
+
* reads a whole record in one request instead of one per row. Indexes stay in their own (small) files: a lookup that
|
|
5
|
+
* needs a few rows reads the index and those rows, not the whole record.
|
|
6
|
+
*/
|
|
7
|
+
export type packedTable = {
|
|
8
|
+
entries: string[];
|
|
9
|
+
rows: any[];
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Where a record's packed file lives, inside the database.
|
|
13
|
+
* @param recordPath
|
|
14
|
+
*/
|
|
15
|
+
export declare const packedPath: (recordPath: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* Whether reads may use packed files: by default in a browser (where every file is a request) and not in Node (which
|
|
18
|
+
* reads the entry files, the copy that's edited, so a packed file can never hide a change there). See configure.
|
|
19
|
+
*/
|
|
20
|
+
export declare const usesPackedReads: () => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* A record's packed file, when reads may use packed files (see usesPackedReads) and the record has one that matches it:
|
|
23
|
+
* the same entries in the same order as the record file. Anything else (no packed file, one that can't be read, or one
|
|
24
|
+
* packed before entries were added or removed) gives undefined, and the caller reads the entry files as before.
|
|
25
|
+
* @param record
|
|
26
|
+
*/
|
|
27
|
+
export declare const retrievePacked: (record: recordDefinition) => Promise<packedTable | undefined>;
|
|
28
|
+
/**
|
|
29
|
+
* Remove a record's packed file, if it has one, as part of a statement that changes the record's rows: a packed file
|
|
30
|
+
* is a copy of them, and one left behind after a change would be read in a browser in place of the change.
|
|
31
|
+
* @param recordPath
|
|
32
|
+
*/
|
|
33
|
+
export declare const discardPacked: (recordPath: string) => Promise<void>;
|
|
34
|
+
//# sourceMappingURL=packedTable.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
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.usesPackedReads = exports.retrievePacked = exports.packedPath = exports.discardPacked = void 0;
|
|
8
|
+
require("core-js/modules/esnext.iterator.constructor.js");
|
|
9
|
+
require("core-js/modules/esnext.iterator.some.js");
|
|
10
|
+
var jsEnv = _interopRequireWildcard(require("browser-or-node"));
|
|
11
|
+
var _storage = require("../storage");
|
|
12
|
+
var _config = require("./config");
|
|
13
|
+
var e;
|
|
14
|
+
function _interopRequireWildcard(t, r) { if (!r && t && t.__esModule) return t; var n, a, o = Object.defineProperty, f = { __proto__: null, default: t }; if (Object(t) !== t) return f; if (e || "function" != typeof WeakMap || (e = new WeakMap()), e) { if (e.has(t)) return e.get(t); e.set(t, f); } for (a in t) "default" !== a && {}.hasOwnProperty.call(t, a) && ((n = o && Object.getOwnPropertyDescriptor(t, a)) && (n.get || n.set) ? o(f, a, n) : f[a] = t[a]); return f; }
|
|
15
|
+
/**
|
|
16
|
+
* Where a record's packed file lives, inside the database.
|
|
17
|
+
* @param recordPath
|
|
18
|
+
*/
|
|
19
|
+
const packedPath = recordPath => `__packed/${recordPath}.json`;
|
|
20
|
+
/**
|
|
21
|
+
* Whether reads may use packed files: by default in a browser (where every file is a request) and not in Node (which
|
|
22
|
+
* reads the entry files, the copy that's edited, so a packed file can never hide a change there). See configure.
|
|
23
|
+
*/
|
|
24
|
+
exports.packedPath = packedPath;
|
|
25
|
+
const usesPackedReads = () => (0, _config.getSetting)('packedReads', !jsEnv.isNode);
|
|
26
|
+
/**
|
|
27
|
+
* A record's packed file, when reads may use packed files (see usesPackedReads) and the record has one that matches it:
|
|
28
|
+
* the same entries in the same order as the record file. Anything else (no packed file, one that can't be read, or one
|
|
29
|
+
* packed before entries were added or removed) gives undefined, and the caller reads the entry files as before.
|
|
30
|
+
* @param record
|
|
31
|
+
*/
|
|
32
|
+
exports.usesPackedReads = usesPackedReads;
|
|
33
|
+
const retrievePacked = async record => {
|
|
34
|
+
if (!usesPackedReads()) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
let packed;
|
|
38
|
+
try {
|
|
39
|
+
packed = await (0, _storage.readJson)(packedPath(record.path));
|
|
40
|
+
} catch (error) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const entries = record.entries || [];
|
|
44
|
+
if (!packed || !Array.isArray(packed.entries) || !Array.isArray(packed.rows) || packed.entries.length !== entries.length || packed.rows.length !== entries.length || packed.entries.some((entry, position) => entry !== entries[position])) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
return packed;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Remove a record's packed file, if it has one, as part of a statement that changes the record's rows: a packed file
|
|
51
|
+
* is a copy of them, and one left behind after a change would be read in a browser in place of the change.
|
|
52
|
+
* @param recordPath
|
|
53
|
+
*/
|
|
54
|
+
exports.retrievePacked = retrievePacked;
|
|
55
|
+
const discardPacked = async recordPath => {
|
|
56
|
+
if ((0, _storage.fileExists)(packedPath(recordPath))) {
|
|
57
|
+
await (0, _storage.removeFile)(packedPath(recordPath));
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
exports.discardPacked = discardPacked;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";require("core-js/modules/esnext.weak-map.delete-all.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.usesPackedReads=exports.retrievePacked=exports.packedPath=exports.discardPacked=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.some.js");var e,jsEnv=_interopRequireWildcard(require("browser-or-node")),_storage=require("../storage"),_config=require("./config");function _interopRequireWildcard(r,t){if(!t&&r&&r.__esModule)return r;var s,a,o=Object.defineProperty,d={__proto__:null,default:r};if(Object(r)!==r)return d;if(e||"function"!=typeof WeakMap||(e=new WeakMap),e){if(e.has(r))return e.get(r);e.set(r,d)}for(a in r)"default"!==a&&{}.hasOwnProperty.call(r,a)&&((s=o&&Object.getOwnPropertyDescriptor(r,a))&&(s.get||s.set)?o(d,a,s):d[a]=r[a]);return d}const packedPath=e=>`__packed/${e}.json`;exports.packedPath=packedPath;const usesPackedReads=()=>(0,_config.getSetting)("packedReads",!jsEnv.isNode);exports.usesPackedReads=usesPackedReads;const retrievePacked=async e=>{if(!usesPackedReads())return;let r;try{r=await(0,_storage.readJson)(packedPath(e.path))}catch(e){return}const t=e.entries||[];return r&&Array.isArray(r.entries)&&Array.isArray(r.rows)&&r.entries.length===t.length&&r.rows.length===t.length&&!r.entries.some(((e,r)=>e!==t[r]))?r:void 0};exports.retrievePacked=retrievePacked;const discardPacked=async e=>{(0,_storage.fileExists)(packedPath(e))&&await(0,_storage.removeFile)(packedPath(e))};exports.discardPacked=discardPacked;
|
|
@@ -3,9 +3,9 @@ export type ParsedInsertRow = {
|
|
|
3
3
|
[field: string]: any;
|
|
4
4
|
};
|
|
5
5
|
/**
|
|
6
|
-
* Read an insert's values clause body (
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Read an insert's values clause body (see splitClauses), the same way findUpdateValues() does for "set": one row
|
|
7
|
+
* (`field = value, field2 = value2`), or several, each in brackets and separated by commas
|
|
8
|
+
* (`(field = value, field2 = value2), (field = value3, field2 = value4)`), inserted together in one statement.
|
|
9
9
|
* @param parsed
|
|
10
10
|
* @param body
|
|
11
11
|
* @returns The rest of the body, after the last assignment.
|
|
@@ -7,29 +7,45 @@ exports.findInsertValues = void 0;
|
|
|
7
7
|
var _parseLiteralValue = require("./parseLiteralValue");
|
|
8
8
|
var _maskStrings = require("./maskStrings");
|
|
9
9
|
const literal = `(?:${_maskStrings.placeholderSource.replace('(', '(?:')}|${_parseLiteralValue.numberSource}|${_maskStrings.arraySource.replace('(', '(?:')}|null|true|false)`;
|
|
10
|
-
const
|
|
10
|
+
const assignments = `[a-z0-9_-]+\\s*=\\s*${literal}(?:\\s*,\\s*[a-z0-9_-]+\\s*=\\s*${literal})*`;
|
|
11
|
+
const valuesMatch = new RegExp(`^(${assignments})`, 'i');
|
|
12
|
+
const rowSource = `\\(\\s*(${assignments})\\s*\\)`;
|
|
13
|
+
const rowsMatch = new RegExp(`^${rowSource}(?:\\s*,\\s*${rowSource.replace('(' + assignments, '(?:' + assignments)})*`, 'i');
|
|
14
|
+
const rowMatch = new RegExp(rowSource, 'ig');
|
|
11
15
|
const assignmentMatch = new RegExp(`([a-z0-9_-]+)\\s*=\\s*(${_maskStrings.placeholderSource}|(${_parseLiteralValue.numberSource})|${_maskStrings.arraySource}|(null)|(true)|(false))`, 'ig');
|
|
12
16
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
|
|
17
|
+
* One row's values from its assignments (`field = value, field2 = value2`).
|
|
18
|
+
* @param assignments
|
|
19
|
+
*/
|
|
20
|
+
const parseRow = assignments => {
|
|
21
|
+
const row = {};
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
for (const assignment of assignments.matchAll(assignmentMatch)) {
|
|
24
|
+
row[assignment[1]] = (0, _parseLiteralValue.parseLiteralValue)(assignment, 3);
|
|
25
|
+
}
|
|
26
|
+
return row;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Read an insert's values clause body (see splitClauses), the same way findUpdateValues() does for "set": one row
|
|
30
|
+
* (`field = value, field2 = value2`), or several, each in brackets and separated by commas
|
|
31
|
+
* (`(field = value, field2 = value2), (field = value3, field2 = value4)`), inserted together in one statement.
|
|
16
32
|
* @param parsed
|
|
17
33
|
* @param body
|
|
18
34
|
* @returns The rest of the body, after the last assignment.
|
|
19
35
|
*/
|
|
20
36
|
const findInsertValues = (parsed, body) => {
|
|
21
|
-
const clauseFound = body.match(valuesMatch);
|
|
22
37
|
parsed['insertValues'] = [];
|
|
38
|
+
const rowsFound = body.match(rowsMatch);
|
|
39
|
+
if (rowsFound) {
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
parsed['insertValues'] = [...rowsFound[0].matchAll(rowMatch)].map(row => parseRow(row[1]));
|
|
42
|
+
return body.slice(rowsFound[0].length).trim();
|
|
43
|
+
}
|
|
44
|
+
const clauseFound = body.match(valuesMatch);
|
|
23
45
|
if (!clauseFound) {
|
|
24
46
|
return body;
|
|
25
47
|
}
|
|
26
|
-
|
|
27
|
-
const assignmentsFound = clauseFound[1].matchAll(assignmentMatch);
|
|
28
|
-
// @ts-ignore
|
|
29
|
-
for (const assignment of assignmentsFound) {
|
|
30
|
-
row[assignment[1]] = (0, _parseLiteralValue.parseLiteralValue)(assignment, 3);
|
|
31
|
-
}
|
|
32
|
-
parsed['insertValues'] = [row];
|
|
48
|
+
parsed['insertValues'] = [parseRow(clauseFound[1])];
|
|
33
49
|
return body.slice(clauseFound[0].length).trim();
|
|
34
50
|
};
|
|
35
51
|
exports.findInsertValues = findInsertValues;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findInsertValues=void 0;var _parseLiteralValue=require("./parseLiteralValue"),_maskStrings=require("./maskStrings");const literal=`(?:${_maskStrings.placeholderSource.replace("(","(?:")}|${_parseLiteralValue.numberSource}|${_maskStrings.arraySource.replace("(","(?:")}|null|true|false)`,
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.findInsertValues=void 0;var _parseLiteralValue=require("./parseLiteralValue"),_maskStrings=require("./maskStrings");const literal=`(?:${_maskStrings.placeholderSource.replace("(","(?:")}|${_parseLiteralValue.numberSource}|${_maskStrings.arraySource.replace("(","(?:")}|null|true|false)`,assignments=`[a-z0-9_-]+\\s*=\\s*${literal}(?:\\s*,\\s*[a-z0-9_-]+\\s*=\\s*${literal})*`,valuesMatch=new RegExp(`^(${assignments})`,"i"),rowSource=`\\(\\s*(${assignments})\\s*\\)`,rowsMatch=new RegExp(`^${rowSource}(?:\\s*,\\s*${rowSource.replace("("+assignments,"(?:"+assignments)})*`,"i"),rowMatch=new RegExp(rowSource,"ig"),assignmentMatch=new RegExp(`([a-z0-9_-]+)\\s*=\\s*(${_maskStrings.placeholderSource}|(${_parseLiteralValue.numberSource})|${_maskStrings.arraySource}|(null)|(true)|(false))`,"ig"),parseRow=e=>{const s={};for(const r of e.matchAll(assignmentMatch))s[r[1]]=(0,_parseLiteralValue.parseLiteralValue)(r,3);return s},findInsertValues=(e,s)=>{e.insertValues=[];const r=s.match(rowsMatch);if(r)return e.insertValues=[...r[0].matchAll(rowMatch)].map((e=>parseRow(e[1]))),s.slice(r[0].length).trim();const a=s.match(valuesMatch);return a?(e.insertValues=[parseRow(a[1])],s.slice(a[0].length).trim()):s};exports.findInsertValues=findInsertValues;
|
|
@@ -54,11 +54,20 @@ const maskStrings = query => {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
// One pass from the left (the strings come in order, without overlapping): rebuilding the whole query for each string
|
|
58
|
+
// made a long query (an insert of thousands of rows) take time growing with the square of its length
|
|
59
|
+
const parts = [];
|
|
60
|
+
let copied = 0;
|
|
61
|
+
for (const {
|
|
58
62
|
start,
|
|
59
63
|
end,
|
|
60
64
|
value
|
|
61
|
-
}
|
|
65
|
+
} of strings) {
|
|
66
|
+
parts.push(query.slice(copied, start), `\u0000${toHex(value)}\u0000`);
|
|
67
|
+
copied = end;
|
|
68
|
+
}
|
|
69
|
+
parts.push(query.slice(copied));
|
|
70
|
+
return parts.join('');
|
|
62
71
|
};
|
|
63
72
|
/**
|
|
64
73
|
* Put every placeholder back the way it would be written in a query: strings quoted, arrays as JSON. For error
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.unmaskStrings=exports.placeholderSource=exports.maskStrings=exports.maskArrays=exports.fromPlaceholder=exports.arraySource=void 0,require("core-js/modules/es.json.stringify.js"),require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.iterator.some.js");var _scanQuery=require("./scanQuery");const placeholderSource=exports.placeholderSource="\\u0000([0-9a-f]*)\\u0000",placeholderMatch=new RegExp(placeholderSource,"g"),arraySource=exports.arraySource="\\u0001([0-9a-f]*)\\u0001",arrayMatch=new RegExp(arraySource,"g"),toHex=r=>r.split("").map((r=>r.charCodeAt(0).toString(16).padStart(4,"0"))).join(""),fromPlaceholder=r=>(r.match(/.{4}/g)||[]).map((r=>String.fromCharCode(parseInt(r,16)))).join("");exports.fromPlaceholder=fromPlaceholder;const maskStrings=r=>{const{strings:e}=(0,_scanQuery.assertClosed)((0,_scanQuery.scanQuery)(r));for(const[s,t]of[["\0","NUL"],["","SOH"]])for(let o=r.indexOf(s);-1!==o;o=r.indexOf(s,o+1))if(!e.some((({start:r,end:e})=>r<o&&o<e)))throw new Error(`Unexpected ${t} character at position ${o}`);
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.unmaskStrings=exports.placeholderSource=exports.maskStrings=exports.maskArrays=exports.fromPlaceholder=exports.arraySource=void 0,require("core-js/modules/es.json.stringify.js"),require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.iterator.some.js");var _scanQuery=require("./scanQuery");const placeholderSource=exports.placeholderSource="\\u0000([0-9a-f]*)\\u0000",placeholderMatch=new RegExp(placeholderSource,"g"),arraySource=exports.arraySource="\\u0001([0-9a-f]*)\\u0001",arrayMatch=new RegExp(arraySource,"g"),toHex=r=>r.split("").map((r=>r.charCodeAt(0).toString(16).padStart(4,"0"))).join(""),fromPlaceholder=r=>(r.match(/.{4}/g)||[]).map((r=>String.fromCharCode(parseInt(r,16)))).join("");exports.fromPlaceholder=fromPlaceholder;const maskStrings=r=>{const{strings:e}=(0,_scanQuery.assertClosed)((0,_scanQuery.scanQuery)(r));for(const[s,t]of[["\0","NUL"],["","SOH"]])for(let o=r.indexOf(s);-1!==o;o=r.indexOf(s,o+1))if(!e.some((({start:r,end:e})=>r<o&&o<e)))throw new Error(`Unexpected ${t} character at position ${o}`);const s=[];let t=0;for(const{start:o,end:a,value:n}of e)s.push(r.slice(t,o),`\0${toHex(n)}\0`),t=a;return s.push(r.slice(t)),s.join("")};exports.maskStrings=maskStrings;const unmaskStrings=(r,e="json")=>r.replace(placeholderMatch,((r,s)=>{const t=fromPlaceholder(s);return"json"===e?JSON.stringify(t):`'${t.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}'`})).replace(arrayMatch,((r,e)=>fromPlaceholder(e)));exports.unmaskStrings=unmaskStrings;const arrayJson=r=>{try{return JSON.stringify(JSON.parse(unmaskStrings(r),((r,e)=>{if("number"==typeof e&&!Number.isFinite(e))throw new Error(`${e} is too large`);if(Number.isInteger(e)&&!Number.isSafeInteger(e))throw new Error(`${e} is too large to store exactly (the largest whole number is ${Number.MAX_SAFE_INTEGER}): quote it to keep it as text`);return e})))}catch(e){throw new Error(`Invalid array ${unmaskStrings(r,"'")}: ${e.message}`)}},maskArrays=r=>{let e="",s=0,t=0;for(let o=0;o<r.length;o++){const a=r[o];if("["===a)0===s&&(t=o),s++;else if("]"===a&&s>0&&(s--,0===s)){e+=`${toHex(arrayJson(r.slice(t,o+1)))}`;continue}0===s&&(e+=a)}return s>0?e+r.slice(t):e};exports.maskArrays=maskArrays;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { fieldProperties } from '../../introspect/definitions/field';
|
|
2
|
+
/**
|
|
3
|
+
* One change to a record's fields (see alter):
|
|
4
|
+
* - `add`: a new field, as create defines one
|
|
5
|
+
* - `drop`: remove a field
|
|
6
|
+
* - `rename`: give a field a new name
|
|
7
|
+
* - `modify`: a field's new definition (the same name and type; optional, null and default can change)
|
|
8
|
+
*/
|
|
9
|
+
export type ParsedAlter = {
|
|
10
|
+
action: 'add';
|
|
11
|
+
field: fieldProperties;
|
|
12
|
+
} | {
|
|
13
|
+
action: 'drop';
|
|
14
|
+
name: string;
|
|
15
|
+
} | {
|
|
16
|
+
action: 'rename';
|
|
17
|
+
name: string;
|
|
18
|
+
to: string;
|
|
19
|
+
} | {
|
|
20
|
+
action: 'modify';
|
|
21
|
+
field: fieldProperties;
|
|
22
|
+
};
|
|
23
|
+
export type ParsedAlterQuery = {
|
|
24
|
+
entity: string;
|
|
25
|
+
alter: ParsedAlter;
|
|
26
|
+
};
|
|
27
|
+
export declare const alterMatch: RegExp;
|
|
28
|
+
/**
|
|
29
|
+
* Read an alter statement (one change per statement; several statements in one query run in turn).
|
|
30
|
+
* @param query - The statement, with its strings and arrays masked (see maskStrings).
|
|
31
|
+
*/
|
|
32
|
+
export declare const parseAlter: (query: string) => ParsedAlterQuery;
|
|
33
|
+
//# sourceMappingURL=parseAlter.d.ts.map
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.parseAlter = exports.alterMatch = void 0;
|
|
7
|
+
var _parseCreate = require("./parseCreate");
|
|
8
|
+
var _maskStrings = require("./maskStrings");
|
|
9
|
+
var _startsQuery = require("./startsQuery");
|
|
10
|
+
const alterMatch = exports.alterMatch = /^\s*alter(?![a-z0-9_-])/i;
|
|
11
|
+
const headMatch = new RegExp(`^\\s*alter\\s+(${_parseCreate.nameSource})\\s+(add|drop|rename|modify)(?![a-z0-9_-])([\\s\\S]*)$`, 'i');
|
|
12
|
+
const renameMatch = new RegExp(`^\\s*(${_parseCreate.nameSource})\\s+to\\s+(${_parseCreate.nameSource})\\s*$`, 'i');
|
|
13
|
+
const expected = 'Expected: alter <record> add <field> <type> ..., drop <field>, rename <field> to <name>, or modify <field> <type> ...';
|
|
14
|
+
const shown = text => (0, _maskStrings.unmaskStrings)(text.trim(), '\'');
|
|
15
|
+
/**
|
|
16
|
+
* A field as create's field list writes one (`<name> <type> [optional] [null | not null] [default <value>] [auto]`).
|
|
17
|
+
* @param text
|
|
18
|
+
*/
|
|
19
|
+
const fieldSpec = text => {
|
|
20
|
+
const found = text.trim().match(_parseCreate.fieldMatch);
|
|
21
|
+
if (!found) {
|
|
22
|
+
throw new Error(`Expected a field (<name> <type> ...) in: ${shown(text)}`);
|
|
23
|
+
}
|
|
24
|
+
return (0, _parseCreate.parseField)(found);
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Read an alter statement (one change per statement; several statements in one query run in turn).
|
|
28
|
+
* @param query - The statement, with its strings and arrays masked (see maskStrings).
|
|
29
|
+
*/
|
|
30
|
+
const parseAlter = query => {
|
|
31
|
+
const head = query.match(headMatch);
|
|
32
|
+
if (!head) {
|
|
33
|
+
throw new Error(expected);
|
|
34
|
+
}
|
|
35
|
+
const [, entity, actionWord, rest] = head;
|
|
36
|
+
if (entity === '__RECORDS') {
|
|
37
|
+
throw new Error('__RECORDS is reserved for the list of records');
|
|
38
|
+
}
|
|
39
|
+
const action = actionWord.toLowerCase();
|
|
40
|
+
if (_startsQuery.startsQueryMatch.test(rest.trim()) && !/^\s*(add|drop|rename|modify)\b/i.test(rest)) {
|
|
41
|
+
throw new Error(`Missing ; before: ${shown(rest)}`);
|
|
42
|
+
}
|
|
43
|
+
switch (action) {
|
|
44
|
+
case 'add':
|
|
45
|
+
case 'modify':
|
|
46
|
+
return {
|
|
47
|
+
entity,
|
|
48
|
+
alter: {
|
|
49
|
+
action,
|
|
50
|
+
field: fieldSpec(rest)
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
case 'drop':
|
|
54
|
+
{
|
|
55
|
+
const name = rest.trim();
|
|
56
|
+
if (!_parseCreate.nameMatch.test(name)) {
|
|
57
|
+
throw new Error(`Expected: alter ${entity} drop <field>${name ? ` (got: ${shown(name)})` : ''}`);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
entity,
|
|
61
|
+
alter: {
|
|
62
|
+
action,
|
|
63
|
+
name
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
default:
|
|
68
|
+
{
|
|
69
|
+
const found = rest.match(renameMatch);
|
|
70
|
+
if (!found) {
|
|
71
|
+
throw new Error(`Expected: alter ${entity} rename <field> to <name>${rest.trim() ? ` (got: ${shown(rest)})` : ''}`);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
entity,
|
|
75
|
+
alter: {
|
|
76
|
+
action: 'rename',
|
|
77
|
+
name: found[1],
|
|
78
|
+
to: found[2]
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
exports.parseAlter = parseAlter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.parseAlter=exports.alterMatch=void 0;var _parseCreate=require("./parseCreate"),_maskStrings=require("./maskStrings"),_startsQuery=require("./startsQuery");const alterMatch=exports.alterMatch=/^\s*alter(?![a-z0-9_-])/i,headMatch=new RegExp(`^\\s*alter\\s+(${_parseCreate.nameSource})\\s+(add|drop|rename|modify)(?![a-z0-9_-])([\\s\\S]*)$`,"i"),renameMatch=new RegExp(`^\\s*(${_parseCreate.nameSource})\\s+to\\s+(${_parseCreate.nameSource})\\s*$`,"i"),expected="Expected: alter <record> add <field> <type> ..., drop <field>, rename <field> to <name>, or modify <field> <type> ...",shown=e=>(0,_maskStrings.unmaskStrings)(e.trim(),"'"),fieldSpec=e=>{const r=e.trim().match(_parseCreate.fieldMatch);if(!r)throw new Error(`Expected a field (<name> <type> ...) in: ${shown(e)}`);return(0,_parseCreate.parseField)(r)},parseAlter=e=>{const r=e.match(headMatch);if(!r)throw new Error(expected);const[,t,a,s]=r;if("__RECORDS"===t)throw new Error("__RECORDS is reserved for the list of records");const o=a.toLowerCase();if(_startsQuery.startsQueryMatch.test(s.trim())&&!/^\s*(add|drop|rename|modify)\b/i.test(s))throw new Error(`Missing ; before: ${shown(s)}`);switch(o){case"add":case"modify":return{entity:t,alter:{action:o,field:fieldSpec(s)}};case"drop":{const e=s.trim();if(!_parseCreate.nameMatch.test(e))throw new Error(`Expected: alter ${t} drop <field>${e?` (got: ${shown(e)})`:""}`);return{entity:t,alter:{action:o,name:e}}}default:{const e=s.match(renameMatch);if(!e)throw new Error(`Expected: alter ${t} rename <field> to <name>${s.trim()?` (got: ${shown(s)})`:""}`);return{entity:t,alter:{action:"rename",name:e[1],to:e[2]}}}}};exports.parseAlter=parseAlter;
|
|
@@ -10,6 +10,20 @@ export type ParsedCreateQuery = {
|
|
|
10
10
|
create: ParsedCreate;
|
|
11
11
|
};
|
|
12
12
|
export declare const createMatch: RegExp;
|
|
13
|
+
export declare const nameSource = "[a-z0-9_-]+";
|
|
14
|
+
export declare const nameMatch: RegExp;
|
|
15
|
+
export declare const fieldMatch: RegExp;
|
|
16
|
+
/**
|
|
17
|
+
* The index file name a key's index lives in, from its type and fields (as create names it).
|
|
18
|
+
* @param type
|
|
19
|
+
* @param fields
|
|
20
|
+
*/
|
|
21
|
+
export declare const keyLookup: (type: string, fields: string[]) => string;
|
|
22
|
+
/**
|
|
23
|
+
* One field: `<name> <type> [optional] [null | not null] [auto] [default <value>]`, the modifiers in any order.
|
|
24
|
+
* @param found - The field's fieldMatch match.
|
|
25
|
+
*/
|
|
26
|
+
export declare const parseField: (found: RegExpMatchArray) => fieldProperties;
|
|
13
27
|
/**
|
|
14
28
|
* Parse a create statement (strings and arrays already masked):
|
|
15
29
|
* `create [if not exists] <name> (<field>, ..., <key>, ...)`. See the README's "Creating a record". Only checks
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.parseCreate = exports.createMatch = void 0;
|
|
6
|
+
exports.parseField = exports.parseCreate = exports.nameSource = exports.nameMatch = exports.keyLookup = exports.fieldMatch = exports.createMatch = void 0;
|
|
7
7
|
require("core-js/modules/es.array.includes.js");
|
|
8
8
|
require("core-js/modules/esnext.iterator.constructor.js");
|
|
9
9
|
require("core-js/modules/esnext.iterator.filter.js");
|
|
@@ -32,10 +32,10 @@ var _parseLiteralValue = require("./parseLiteralValue");
|
|
|
32
32
|
var _startsQuery = require("./startsQuery");
|
|
33
33
|
const createMatch = exports.createMatch = /^\s*create(?![a-z0-9_-])/i;
|
|
34
34
|
const headMatch = /^\s*create\s+(if\s+not\s+exists\s+)?([a-z0-9_-]+)\s*\(/i;
|
|
35
|
-
const nameSource = '[a-z0-9_-]+';
|
|
36
|
-
const nameMatch = new RegExp(`^${nameSource}$`, 'i');
|
|
35
|
+
const nameSource = exports.nameSource = '[a-z0-9_-]+';
|
|
36
|
+
const nameMatch = exports.nameMatch = new RegExp(`^${nameSource}$`, 'i');
|
|
37
37
|
const numberMatch = new RegExp(`^${_parseLiteralValue.numberSource}$`, 'i');
|
|
38
|
-
const fieldMatch = new RegExp(`^(${nameSource})\\s+(${nameSource})((?:\\s[\\s\\S]*)?)$`, 'i');
|
|
38
|
+
const fieldMatch = exports.fieldMatch = new RegExp(`^(${nameSource})\\s+(${nameSource})((?:\\s[\\s\\S]*)?)$`, 'i');
|
|
39
39
|
const primaryMatch = /^primary\s+key\s*\(([^()]*)\)$/i;
|
|
40
40
|
const uniqueMatch = /^unique\s*\(([^()]*)\)$/i;
|
|
41
41
|
const indexMatch = /^index\s*\(([^()]*)\)$/i;
|
|
@@ -48,10 +48,17 @@ const lookupPrefix = {
|
|
|
48
48
|
index: 'index',
|
|
49
49
|
foreign: 'fk'
|
|
50
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* The index file name a key's index lives in, from its type and fields (as create names it).
|
|
53
|
+
* @param type
|
|
54
|
+
* @param fields
|
|
55
|
+
*/
|
|
56
|
+
const keyLookup = (type, fields) => `${lookupPrefix[type]}_${fields.join('_')}.json`;
|
|
51
57
|
/**
|
|
52
58
|
* Show a piece of the (masked) query the way it was written, for an error message.
|
|
53
59
|
* @param text
|
|
54
60
|
*/
|
|
61
|
+
exports.keyLookup = keyLookup;
|
|
55
62
|
const shown = text => (0, _maskStrings.unmaskStrings)(text.trim(), '\'');
|
|
56
63
|
/**
|
|
57
64
|
* The position of the `)` closing the `(` at `open`, or -1. Strings and arrays are placeholders by now, so round
|
|
@@ -197,6 +204,7 @@ const parseField = found => {
|
|
|
197
204
|
* One key, or null when the item isn't written as a key (so it's a field).
|
|
198
205
|
* @param item
|
|
199
206
|
*/
|
|
207
|
+
exports.parseField = parseField;
|
|
200
208
|
const parseKey = item => {
|
|
201
209
|
let found = item.match(primaryMatch);
|
|
202
210
|
if (found) {
|
|
@@ -254,7 +262,7 @@ const finishKeys = (definition, keys) => {
|
|
|
254
262
|
if (missing) {
|
|
255
263
|
throw new Error(`The ${key.type} key (${key.fields.join(', ')}) names "${missing}", which is not a field`);
|
|
256
264
|
}
|
|
257
|
-
const lookup =
|
|
265
|
+
const lookup = keyLookup(key.type, key.fields);
|
|
258
266
|
if (lookups.has(lookup)) {
|
|
259
267
|
throw new Error(`The same ${key.type} key on "${key.fields.join(', ')}" is given twice`);
|
|
260
268
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.parseCreate=exports.createMatch=void 0,require("core-js/modules/es.array.includes.js"),require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.filter.js"),require("core-js/modules/esnext.iterator.find.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.iterator.some.js"),require("core-js/modules/esnext.set.add-all.js"),require("core-js/modules/esnext.set.delete-all.js"),require("core-js/modules/esnext.set.difference.js"),require("core-js/modules/esnext.set.every.js"),require("core-js/modules/esnext.set.filter.js"),require("core-js/modules/esnext.set.find.js"),require("core-js/modules/esnext.set.intersection.js"),require("core-js/modules/esnext.set.is-disjoint-from.js"),require("core-js/modules/esnext.set.is-subset-of.js"),require("core-js/modules/esnext.set.is-superset-of.js"),require("core-js/modules/esnext.set.join.js"),require("core-js/modules/esnext.set.map.js"),require("core-js/modules/esnext.set.reduce.js"),require("core-js/modules/esnext.set.some.js"),require("core-js/modules/esnext.set.symmetric-difference.js"),require("core-js/modules/esnext.set.union.js");var _typeCheck=require("../../introspect/policies/typeCheck"),_maskStrings=require("./maskStrings"),_parseLiteralValue=require("./parseLiteralValue"),_startsQuery=require("./startsQuery");const createMatch=exports.createMatch=/^\s*create(?![a-z0-9_-])/i,headMatch=/^\s*create\s+(if\s+not\s+exists\s+)?([a-z0-9_-]+)\s*\(/i,nameSource="[a-z0-9_-]+",nameMatch=new RegExp(`^${nameSource}$`,"i"),numberMatch=new RegExp(`^${_parseLiteralValue.numberSource}$`,"i"),fieldMatch=new RegExp(`^(${nameSource})\\s+(${nameSource})((?:\\s[\\s\\S]*)?)$`,"i"),primaryMatch=/^primary\s+key\s*\(([^()]*)\)$/i,uniqueMatch=/^unique\s*\(([^()]*)\)$/i,indexMatch=/^index\s*\(([^()]*)\)$/i,foreignMatch=new RegExp(`^foreign\\s+key\\s*\\(([^()]*)\\)\\s*references\\s+(${nameSource})\\s*\\(([^()]*)\\)$`,"i"),stringLiteral=new RegExp(`^${_maskStrings.placeholderSource}$`),arrayLiteral=new RegExp(`^${_maskStrings.arraySource}$`),lookupPrefix={primary:"pk",unique:"unique",index:"index",foreign:"fk"},shown=e=>(0,_maskStrings.unmaskStrings)(e.trim(),"'"),findClose=(e,r)=>{let s=0;for(let t=r;t<e.length;t++)if("("===e[t])s++;else if(")"===e[t]&&(s--,0===s))return t;return-1},splitItems=e=>{const r=[];let s=0,t=0;for(let i=0;i<e.length;i++)"("===e[i]?s++:")"===e[i]?s--:","===e[i]&&0===s&&(r.push(e.slice(t,i)),t=i+1);return r.push(e.slice(t)),r.map((e=>e.trim()))},parseNames=(e,r)=>{const s=e.split(",").map((e=>e.trim()));if(s.some((e=>!nameMatch.test(e))))throw new Error(`Expected field names separated by commas in: ${shown(r)}`);if(new Set(s).size!==s.length)throw new Error(`The same field is named twice in: ${shown(r)}`);return s},parseDefault=e=>{if(void 0===e)throw new Error("Missing a value after default");const r=e.match(stringLiteral);if(r)return(0,_maskStrings.fromPlaceholder)(r[1]);const s=e.match(arrayLiteral);if(s)return JSON.parse((0,_maskStrings.fromPlaceholder)(s[1]));if(numberMatch.test(e))return(0,_parseLiteralValue.parseNumber)(e);switch(e.toLowerCase()){case"null":return null;case"true":return!0;case"false":return!1}throw new Error(`Unrecognized default value: ${shown(e)}`)},parseField=e=>{const[r,s,t,i]=e,
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.parseField=exports.parseCreate=exports.nameSource=exports.nameMatch=exports.keyLookup=exports.fieldMatch=exports.createMatch=void 0,require("core-js/modules/es.array.includes.js"),require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.filter.js"),require("core-js/modules/esnext.iterator.find.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.iterator.some.js"),require("core-js/modules/esnext.set.add-all.js"),require("core-js/modules/esnext.set.delete-all.js"),require("core-js/modules/esnext.set.difference.js"),require("core-js/modules/esnext.set.every.js"),require("core-js/modules/esnext.set.filter.js"),require("core-js/modules/esnext.set.find.js"),require("core-js/modules/esnext.set.intersection.js"),require("core-js/modules/esnext.set.is-disjoint-from.js"),require("core-js/modules/esnext.set.is-subset-of.js"),require("core-js/modules/esnext.set.is-superset-of.js"),require("core-js/modules/esnext.set.join.js"),require("core-js/modules/esnext.set.map.js"),require("core-js/modules/esnext.set.reduce.js"),require("core-js/modules/esnext.set.some.js"),require("core-js/modules/esnext.set.symmetric-difference.js"),require("core-js/modules/esnext.set.union.js");var _typeCheck=require("../../introspect/policies/typeCheck"),_maskStrings=require("./maskStrings"),_parseLiteralValue=require("./parseLiteralValue"),_startsQuery=require("./startsQuery");const createMatch=exports.createMatch=/^\s*create(?![a-z0-9_-])/i,headMatch=/^\s*create\s+(if\s+not\s+exists\s+)?([a-z0-9_-]+)\s*\(/i,nameSource=exports.nameSource="[a-z0-9_-]+",nameMatch=exports.nameMatch=new RegExp(`^${nameSource}$`,"i"),numberMatch=new RegExp(`^${_parseLiteralValue.numberSource}$`,"i"),fieldMatch=exports.fieldMatch=new RegExp(`^(${nameSource})\\s+(${nameSource})((?:\\s[\\s\\S]*)?)$`,"i"),primaryMatch=/^primary\s+key\s*\(([^()]*)\)$/i,uniqueMatch=/^unique\s*\(([^()]*)\)$/i,indexMatch=/^index\s*\(([^()]*)\)$/i,foreignMatch=new RegExp(`^foreign\\s+key\\s*\\(([^()]*)\\)\\s*references\\s+(${nameSource})\\s*\\(([^()]*)\\)$`,"i"),stringLiteral=new RegExp(`^${_maskStrings.placeholderSource}$`),arrayLiteral=new RegExp(`^${_maskStrings.arraySource}$`),lookupPrefix={primary:"pk",unique:"unique",index:"index",foreign:"fk"},keyLookup=(e,r)=>`${lookupPrefix[e]}_${r.join("_")}.json`;exports.keyLookup=keyLookup;const shown=e=>(0,_maskStrings.unmaskStrings)(e.trim(),"'"),findClose=(e,r)=>{let s=0;for(let t=r;t<e.length;t++)if("("===e[t])s++;else if(")"===e[t]&&(s--,0===s))return t;return-1},splitItems=e=>{const r=[];let s=0,t=0;for(let i=0;i<e.length;i++)"("===e[i]?s++:")"===e[i]?s--:","===e[i]&&0===s&&(r.push(e.slice(t,i)),t=i+1);return r.push(e.slice(t)),r.map((e=>e.trim()))},parseNames=(e,r)=>{const s=e.split(",").map((e=>e.trim()));if(s.some((e=>!nameMatch.test(e))))throw new Error(`Expected field names separated by commas in: ${shown(r)}`);if(new Set(s).size!==s.length)throw new Error(`The same field is named twice in: ${shown(r)}`);return s},parseDefault=e=>{if(void 0===e)throw new Error("Missing a value after default");const r=e.match(stringLiteral);if(r)return(0,_maskStrings.fromPlaceholder)(r[1]);const s=e.match(arrayLiteral);if(s)return JSON.parse((0,_maskStrings.fromPlaceholder)(s[1]));if(numberMatch.test(e))return(0,_parseLiteralValue.parseNumber)(e);switch(e.toLowerCase()){case"null":return null;case"true":return!0;case"false":return!1}throw new Error(`Unrecognized default value: ${shown(e)}`)},parseField=e=>{const[r,s,t,i]=e,o=t.toLowerCase();if(!_typeCheck.fieldTypes.includes(o))throw new Error(`Unknown type "${t}" for field "${s}" (expected ${_typeCheck.fieldTypes.join(", ")})`);const n={name:s,type:o,optional:!1,autoGenerate:!1},a=new Set,l=e=>{if(a.has(e))throw new Error(`"${e}" is given twice for field "${s}"`);a.add(e)},u=""===i.trim()?[]:i.trim().split(/\s+/);for(let e=0;e<u.length;e++){const t=u[e].toLowerCase();if("optional"===t)l("optional"),n.optional=!0;else if("auto"===t)l("auto"),n.autoGenerate=!0;else if("null"===t)l("null"),n.nullable=!0;else if("not"===t&&"null"===(u[e+1]||"").toLowerCase())l("null"),n.nullable=!1,e++;else{if("default"!==t)throw new Error(`Unrecognized "${shown(u[e])}" for field "${s}" in: ${shown(r)}`);l("default"),n.useDefault=!0,n.defaultValue=parseDefault(u[++e])}}if(n.autoGenerate&&n.useDefault)throw new Error(`Field "${s}" can't be both auto and have a default`);if(n.autoGenerate&&"string"!==o)throw new Error(`Field "${s}" is auto, which generates a UUID, so its type must be string`);return n};exports.parseField=parseField;const parseKey=e=>{let r=e.match(primaryMatch);if(r)return{type:"primary",fields:parseNames(r[1],e)};if(r=e.match(uniqueMatch),r)return{type:"unique",fields:parseNames(r[1],e)};if(r=e.match(indexMatch),r)return{type:"index",fields:parseNames(r[1],e)};if(r=e.match(foreignMatch),r){const s=parseNames(r[1],e),t=parseNames(r[3],e);if(1!==s.length||1!==t.length)throw new Error(`Only single-field foreign keys are supported so far: ${shown(e)}`);return{type:"foreign",fields:s,references:[{fields:[`${r[2]}.${t[0]}`],lookup:`${r[2]}.json`}]}}return null},finishKeys=(e,r)=>{const s=e.map((e=>e.name));if(r.filter((e=>"primary"===e.type)).length>1)throw new Error("Only one primary key is allowed");const t=new Set;return r.map((e=>{const r=e.fields.find((e=>!s.includes(e)));if(r)throw new Error(`The ${e.type} key (${e.fields.join(", ")}) names "${r}", which is not a field`);const i=keyLookup(e.type,e.fields);if(t.has(i))throw new Error(`The same ${e.type} key on "${e.fields.join(", ")}" is given twice`);return t.add(i),Object.assign({type:e.type,fields:e.fields,lookup:i},e.references?{references:e.references}:{})}))},parseCreate=e=>{const r=e.match(headMatch);if(!r)throw new Error("Expected: create [if not exists] <name> (<fields and keys>)");const s=r[2];if("__RECORDS"===s)throw new Error("__RECORDS is reserved for the list of records");const t=r[0].length-1,i=findClose(e,t);if(-1===i)throw new Error("Missing ) at the end of the field list");const o=e.slice(i+1).trim();if(o){if(_startsQuery.startsQueryMatch.test(o))throw new Error(`Missing ; before: ${shown(o)}`);throw new Error(`Unrecognized query value: ${shown(o)}`)}const n=e.slice(t+1,i),a=[],l=[];if(n.trim())for(const e of splitItems(n)){if(!e)throw new Error("Empty item in the field list (an extra comma?)");const r=parseKey(e);if(r){l.push(r);continue}const s=e.match(fieldMatch);if(!s)throw new Error(`Expected a field (<name> <type> ...) or a key in: ${shown(e)}`);const t=parseField(s);if(a.some((e=>e.name===t.name)))throw new Error(`Field "${t.name}" is given twice`);a.push(t)}return{entity:s,create:{ifNotExists:Boolean(r[1]),definition:a,keys:finishKeys(a,l)}}};exports.parseCreate=parseCreate;
|