json-fs-query 3.1.4 → 3.2.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/browser/jsonFsQuery.js +2172 -5305
- package/browser/jsonFsQuery.min.js +1 -1
- package/dist/data/introspect/create.js +7 -22
- package/dist/data/introspect/create.min.js +1 -1
- package/dist/data/introspect/drop.js +5 -15
- package/dist/data/introspect/drop.min.js +1 -1
- 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/deleteEntity.js +29 -18
- package/dist/data/queries/deleteEntity.min.js +1 -1
- package/dist/data/queries/insertEntity.js +4 -12
- 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/updateEntity.js +15 -10
- package/dist/data/queries/updateEntity.min.js +1 -1
- package/dist/data/storage/fileExists.d.ts +6 -0
- package/dist/data/storage/fileExists.js +18 -0
- package/dist/data/storage/fileExists.min.js +1 -0
- package/dist/data/storage/index.d.ts +16 -0
- package/dist/data/storage/index.js +61 -0
- package/dist/data/storage/index.min.js +1 -0
- package/dist/data/storage/makeDirectory.d.ts +6 -0
- package/dist/data/storage/makeDirectory.js +18 -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 +8 -0
- package/dist/data/storage/readJson.js +25 -0
- package/dist/data/storage/readJson.min.js +1 -0
- package/dist/data/storage/removeDirectory.d.ts +6 -0
- package/dist/data/storage/removeDirectory.js +24 -0
- package/dist/data/storage/removeDirectory.min.js +1 -0
- package/dist/data/storage/removeFile.d.ts +7 -0
- package/dist/data/storage/removeFile.js +22 -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 +8 -0
- package/dist/data/storage/writeJson.js +23 -0
- package/dist/data/storage/writeJson.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/databaseLock.d.ts +2 -0
- package/dist/data/utilities/databaseLock.js +5 -2
- 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/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 +136 -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/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/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 +1 -2
- 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/package.json +4 -2
- 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
|
@@ -5,14 +5,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.create = void 0;
|
|
7
7
|
require("core-js/modules/es.array.includes.js");
|
|
8
|
-
require("core-js/modules/es.json.stringify.js");
|
|
9
8
|
require("core-js/modules/esnext.iterator.constructor.js");
|
|
10
9
|
require("core-js/modules/esnext.iterator.filter.js");
|
|
11
10
|
require("core-js/modules/esnext.iterator.find.js");
|
|
12
11
|
require("core-js/modules/esnext.iterator.some.js");
|
|
13
12
|
var _record = require("./definitions/record");
|
|
14
13
|
var _registerRecord = require("../utilities/registerRecord");
|
|
15
|
-
var
|
|
14
|
+
var _storage = require("../storage");
|
|
16
15
|
var _requireNode = require("../utilities/requireNode");
|
|
17
16
|
var _typeCheck = require("./policies/typeCheck");
|
|
18
17
|
const knownKeyProperties = ['type', 'fields', 'lookup', 'references'];
|
|
@@ -76,18 +75,10 @@ const assertValidDefinition = (recordName, recordContent) => {
|
|
|
76
75
|
*/
|
|
77
76
|
const create = async (recordName, definition = [], keys = []) => {
|
|
78
77
|
(0, _requireNode.requireNode)('create()');
|
|
79
|
-
const {
|
|
80
|
-
writeFile,
|
|
81
|
-
mkdir
|
|
82
|
-
} = require('fs/promises');
|
|
83
|
-
const {
|
|
84
|
-
existsSync
|
|
85
|
-
} = require('fs');
|
|
86
|
-
const databasePath = (0, _config.getSetting)('databasePath', 'database/');
|
|
87
78
|
if (recordName === '__RECORDS') {
|
|
88
79
|
return null;
|
|
89
80
|
}
|
|
90
|
-
if (
|
|
81
|
+
if ((0, _storage.fileExists)(`${recordName}.json`)) {
|
|
91
82
|
return null;
|
|
92
83
|
}
|
|
93
84
|
assertKnownKeyProperties(recordName, keys);
|
|
@@ -97,22 +88,16 @@ const create = async (recordName, definition = [], keys = []) => {
|
|
|
97
88
|
keys
|
|
98
89
|
});
|
|
99
90
|
assertValidDefinition(recordName, recordContent);
|
|
100
|
-
await
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
await writeFile(`${databasePath}${recordName}.json`, JSON.stringify(recordContent, null, 2));
|
|
104
|
-
await mkdir(`${databasePath}${recordName}`, {
|
|
105
|
-
recursive: true
|
|
106
|
-
});
|
|
91
|
+
await (0, _storage.makeDirectory)();
|
|
92
|
+
await (0, _storage.writeJson)(`${recordName}.json`, recordContent);
|
|
93
|
+
await (0, _storage.makeDirectory)(recordName);
|
|
107
94
|
// Each indexed key starts with an empty index, so the new record reads like any other before its first insert
|
|
108
95
|
// (a where on a key used to fail with "Could not read __indexes/...", since the file only appeared with the first row)
|
|
109
96
|
const indexedKeys = recordContent.keys.filter(key => key.lookup);
|
|
110
97
|
if (indexedKeys.length) {
|
|
111
|
-
await
|
|
112
|
-
recursive: true
|
|
113
|
-
});
|
|
98
|
+
await (0, _storage.makeDirectory)(`__indexes/${recordName}`);
|
|
114
99
|
for (const key of indexedKeys) {
|
|
115
|
-
await
|
|
100
|
+
await (0, _storage.writeJson)(`__indexes/${recordName}/${key.lookup}`, []);
|
|
116
101
|
}
|
|
117
102
|
}
|
|
118
103
|
await (0, _registerRecord.registerRecord)(recordName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.create=void 0,require("core-js/modules/es.array.includes.js"),require("core-js/modules/
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.create=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.some.js");var _record=require("./definitions/record"),_registerRecord=require("../utilities/registerRecord"),_storage=require("../storage"),_requireNode=require("../utilities/requireNode"),_typeCheck=require("./policies/typeCheck");const knownKeyProperties=["type","fields","lookup","references"],assertKnownKeyProperties=(e,r)=>{for(const o of r)for(const r of Object.keys(o))if(!knownKeyProperties.includes(r))throw new Error(`Unknown property "${r}" on ${o.type??"index"} key of ${e}; must be ${knownKeyProperties.join(", ")}`)},assertValidDefinition=(e,r)=>{for(const o of r.definition)if(Object.prototype.hasOwnProperty.call(o,"default"))try{(0,_typeCheck.typeCheck)(o.type,o.default,o.nullable)}catch(r){throw new Error(`Invalid default for field "${o.name}" of ${e}: ${r.message}`)}for(const o of r.keys){if(o.fields.length<1)throw new Error(`The ${o.type} key of ${e} must have at least one field`);for(const t of o.fields)if(!r.definition.some((e=>e.name===t)))throw new Error(`The ${o.type} key of ${e} names field "${t}", which isn't in the definition`)}const o=r.keys.find((e=>"primary"===e.type));for(const t of o?o.fields:[])if(r.definition.some((e=>e.name===t&&e.nullable)))throw new Error(`Primary key field "${t}" of ${e} can't be nullable`)},create=async(e,r=[],o=[])=>{if((0,_requireNode.requireNode)("create()"),"__RECORDS"===e)return null;if((0,_storage.fileExists)(`${e}.json`))return null;assertKnownKeyProperties(e,o);const t=(0,_record.record)({path:e,definition:r,keys:o});assertValidDefinition(e,t),await(0,_storage.makeDirectory)(),await(0,_storage.writeJson)(`${e}.json`,t),await(0,_storage.makeDirectory)(e);const i=t.keys.filter((e=>e.lookup));if(i.length){await(0,_storage.makeDirectory)(`__indexes/${e}`);for(const r of i)await(0,_storage.writeJson)(`__indexes/${e}/${r.lookup}`,[])}return await(0,_registerRecord.registerRecord)(e),t};exports.create=create;
|
|
@@ -10,30 +10,20 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
10
10
|
exports.drop = void 0;
|
|
11
11
|
var _retrieveFile = require("../utilities/retrieveFile");
|
|
12
12
|
var _deregisterRecord = require("../utilities/deregisterRecord");
|
|
13
|
-
var _config = require("../utilities/config");
|
|
14
13
|
var _requireNode = require("../utilities/requireNode");
|
|
15
|
-
|
|
16
|
-
rm
|
|
17
|
-
} = require('fs/promises');
|
|
14
|
+
var _storage = require("../storage");
|
|
18
15
|
const drop = async record => {
|
|
19
16
|
(0, _requireNode.requireNode)('drop()');
|
|
20
|
-
const databasePath = (0, _config.getSetting)('databasePath', 'database/');
|
|
21
17
|
if (record === '__RECORDS') {
|
|
22
18
|
return null;
|
|
23
19
|
}
|
|
24
20
|
const recordFile = await (0, _retrieveFile.retrieveFile)(`${record}.json`);
|
|
25
21
|
for (const file of recordFile.entries) {
|
|
26
|
-
await
|
|
22
|
+
await (0, _storage.removeFile)(`${recordFile.path}/${file}`);
|
|
27
23
|
}
|
|
28
|
-
await
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
await rm(`${databasePath}__indexes/${recordFile.path}`, {
|
|
33
|
-
recursive: true,
|
|
34
|
-
force: true
|
|
35
|
-
});
|
|
36
|
-
await rm(`${databasePath}${record}.json`);
|
|
24
|
+
await (0, _storage.removeDirectory)(recordFile.path);
|
|
25
|
+
await (0, _storage.removeDirectory)(`__indexes/${recordFile.path}`);
|
|
26
|
+
await (0, _storage.removeFile)(`${record}.json`);
|
|
37
27
|
await (0, _deregisterRecord.deregisterRecord)(record);
|
|
38
28
|
};
|
|
39
29
|
exports.drop = drop;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";require("core-js/modules/esnext.async-iterator.constructor.js"),require("core-js/modules/esnext.async-iterator.drop.js"),require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.drop.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.drop=void 0;var _retrieveFile=require("../utilities/retrieveFile"),_deregisterRecord=require("../utilities/deregisterRecord"),
|
|
1
|
+
"use strict";require("core-js/modules/esnext.async-iterator.constructor.js"),require("core-js/modules/esnext.async-iterator.drop.js"),require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.drop.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.drop=void 0;var _retrieveFile=require("../utilities/retrieveFile"),_deregisterRecord=require("../utilities/deregisterRecord"),_requireNode=require("../utilities/requireNode"),_storage=require("../storage");const drop=async e=>{if((0,_requireNode.requireNode)("drop()"),"__RECORDS"===e)return null;const r=await(0,_retrieveFile.retrieveFile)(`${e}.json`);for(const e of r.entries)await(0,_storage.removeFile)(`${r.path}/${e}`);await(0,_storage.removeDirectory)(r.path),await(0,_storage.removeDirectory)(`__indexes/${r.path}`),await(0,_storage.removeFile)(`${e}.json`),await(0,_deregisterRecord.deregisterRecord)(e)};exports.drop=drop;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Check whether any record in the referenced entity has the given property set to the given
|
|
3
3
|
* value - the mirror image of keyUnique(), which checks that no record already has a value.
|
|
4
|
+
* A referenced field with an index (a foreign key usually references a primary key) is answered from it; otherwise
|
|
5
|
+
* every row is read.
|
|
4
6
|
* @param entity
|
|
5
7
|
* @param property
|
|
6
8
|
* @param value
|
|
@@ -8,22 +8,28 @@ var _retrieveRecords = require("../../utilities/retrieveRecords");
|
|
|
8
8
|
var _where = require("../../queries/where");
|
|
9
9
|
var _retrieveRecord = require("../../utilities/retrieveRecord");
|
|
10
10
|
var _fieldType = require("../../utilities/fieldType");
|
|
11
|
+
var _indexHas = require("../../utilities/indexHas");
|
|
11
12
|
/**
|
|
12
13
|
* Check whether any record in the referenced entity has the given property set to the given
|
|
13
14
|
* value - the mirror image of keyUnique(), which checks that no record already has a value.
|
|
15
|
+
* A referenced field with an index (a foreign key usually references a primary key) is answered from it; otherwise
|
|
16
|
+
* every row is read.
|
|
14
17
|
* @param entity
|
|
15
18
|
* @param property
|
|
16
19
|
* @param value
|
|
17
20
|
*/
|
|
18
21
|
const foreignKeyExists = async (entity, property, value) => {
|
|
22
|
+
const found = await (0, _indexHas.indexHas)(entity, property, value);
|
|
23
|
+
if (typeof found !== 'undefined') {
|
|
24
|
+
return found;
|
|
25
|
+
}
|
|
19
26
|
const records = await (0, _retrieveRecords.retrieveRecords)(entity);
|
|
20
27
|
const type = (0, _fieldType.fieldType)(await (0, _retrieveRecord.retrieveRecord)(entity), property);
|
|
21
|
-
|
|
28
|
+
return (0, _where.where)(records, {
|
|
22
29
|
property,
|
|
23
30
|
comparator: '=',
|
|
24
31
|
value,
|
|
25
32
|
type
|
|
26
|
-
});
|
|
27
|
-
return found.length > 0;
|
|
33
|
+
}).length > 0;
|
|
28
34
|
};
|
|
29
35
|
exports.foreignKeyExists = foreignKeyExists;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.foreignKeyExists=void 0;var _retrieveRecords=require("../../utilities/retrieveRecords"),_where=require("../../queries/where"),_retrieveRecord=require("../../utilities/retrieveRecord"),_fieldType=require("../../utilities/fieldType");const foreignKeyExists=async(e,r,i)=>{const t=await(0,_retrieveRecords.retrieveRecords)(e),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.foreignKeyExists=void 0;var _retrieveRecords=require("../../utilities/retrieveRecords"),_where=require("../../queries/where"),_retrieveRecord=require("../../utilities/retrieveRecord"),_fieldType=require("../../utilities/fieldType"),_indexHas=require("../../utilities/indexHas");const foreignKeyExists=async(e,r,i)=>{const t=await(0,_indexHas.indexHas)(e,r,i);if(void 0!==t)return t;const s=await(0,_retrieveRecords.retrieveRecords)(e),o=(0,_fieldType.fieldType)(await(0,_retrieveRecord.retrieveRecord)(e),r);return(0,_where.where)(s,{property:r,comparator:"=",value:i,type:o}).length>0};exports.foreignKeyExists=foreignKeyExists;
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Check whether any other record, in any entity, still has a single-field foreign key pointing
|
|
3
3
|
* at entity.property = value - the mirror image of foreignKeyExists(), which checks the opposite
|
|
4
4
|
* direction (that a new/updated foreign key value points at something real). Used to RESTRICT a
|
|
5
|
-
* delete or update that would otherwise leave a dangling reference behind.
|
|
6
|
-
* the database via the __RECORDS registry
|
|
7
|
-
*
|
|
5
|
+
* delete or update that would otherwise leave a dangling reference behind. Looks at every record in
|
|
6
|
+
* the database (via the __RECORDS registry) for a foreign key to entity.property. A foreign key field with an index
|
|
7
|
+
* (each one gets one) is answered from it; otherwise that record's rows are read.
|
|
8
8
|
* @param entity
|
|
9
9
|
* @param property
|
|
10
10
|
* @param value
|
|
@@ -10,13 +10,14 @@ var _retrieveRecords = require("../../utilities/retrieveRecords");
|
|
|
10
10
|
var _where = require("../../queries/where");
|
|
11
11
|
var _fieldType = require("../../utilities/fieldType");
|
|
12
12
|
var _splitEntityProperty = require("../../utilities/parsers/splitEntityProperty");
|
|
13
|
+
var _indexHas = require("../../utilities/indexHas");
|
|
13
14
|
/**
|
|
14
15
|
* Check whether any other record, in any entity, still has a single-field foreign key pointing
|
|
15
16
|
* at entity.property = value - the mirror image of foreignKeyExists(), which checks the opposite
|
|
16
17
|
* direction (that a new/updated foreign key value points at something real). Used to RESTRICT a
|
|
17
|
-
* delete or update that would otherwise leave a dangling reference behind.
|
|
18
|
-
* the database via the __RECORDS registry
|
|
19
|
-
*
|
|
18
|
+
* delete or update that would otherwise leave a dangling reference behind. Looks at every record in
|
|
19
|
+
* the database (via the __RECORDS registry) for a foreign key to entity.property. A foreign key field with an index
|
|
20
|
+
* (each one gets one) is answered from it; otherwise that record's rows are read.
|
|
20
21
|
* @param entity
|
|
21
22
|
* @param property
|
|
22
23
|
* @param value
|
|
@@ -37,6 +38,13 @@ const hasDependents = async (entity, property, value) => {
|
|
|
37
38
|
if (refEntity !== entity || refProperty !== property) {
|
|
38
39
|
continue;
|
|
39
40
|
}
|
|
41
|
+
const indexed = await (0, _indexHas.indexHas)(otherEntity, key.fields[0], value);
|
|
42
|
+
if (typeof indexed !== 'undefined') {
|
|
43
|
+
if (indexed) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
40
48
|
const records = await (0, _retrieveRecords.retrieveRecords)(otherEntity);
|
|
41
49
|
const found = (0, _where.where)(records, {
|
|
42
50
|
property: key.fields[0],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.hasDependents=void 0;var _describe=require("../describe"),_retrieveRecord=require("../../utilities/retrieveRecord"),_retrieveRecords=require("../../utilities/retrieveRecords"),_where=require("../../queries/where"),_fieldType=require("../../utilities/fieldType"),_splitEntityProperty=require("../../utilities/parsers/splitEntityProperty");const hasDependents=async(e,r,
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.hasDependents=void 0;var _describe=require("../describe"),_retrieveRecord=require("../../utilities/retrieveRecord"),_retrieveRecords=require("../../utilities/retrieveRecords"),_where=require("../../queries/where"),_fieldType=require("../../utilities/fieldType"),_splitEntityProperty=require("../../utilities/parsers/splitEntityProperty"),_indexHas=require("../../utilities/indexHas");const hasDependents=async(e,r,i)=>{const t=await(0,_describe.describe)();for(const s of t){const t=s.replace(/\.json$/,""),n=await(0,_retrieveRecord.retrieveRecord)(t);for(const s of n.keys){if("foreign"!==s.type||1!==s.fields.length||!s.references||1!==s.references.length)continue;const{entity:o,property:d}=(0,_splitEntityProperty.splitEntityProperty)(s.references[0].fields[0]);if(o!==e||d!==r)continue;const c=await(0,_indexHas.indexHas)(t,s.fields[0],i);if(void 0!==c){if(c)return!0;continue}const p=await(0,_retrieveRecords.retrieveRecords)(t);if((0,_where.where)(p,{property:s.fields[0],comparator:"=",value:i,type:(0,_fieldType.fieldType)(n,s.fields[0])}).length)return!0}}return!1};exports.hasDependents=hasDependents;
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* Check that no existing record already has this combination of values across all of the given
|
|
3
3
|
* fields - a single field for a normal unique/primary key, or several for a composite one.
|
|
4
4
|
* references and checkKeys are parallel arrays: references[i]'s value must equal checkKeys[i].
|
|
5
|
+
*
|
|
6
|
+
* One field with an index (every primary and unique key has one) is answered from the index; a composite key, or a
|
|
7
|
+
* field without one, reads every row.
|
|
5
8
|
* @param entity
|
|
6
9
|
* @param references
|
|
7
10
|
* @param checkKeys
|
|
@@ -8,10 +8,14 @@ var _retrieveRecords = require("../../utilities/retrieveRecords");
|
|
|
8
8
|
var _where = require("../../queries/where");
|
|
9
9
|
var _retrieveRecord = require("../../utilities/retrieveRecord");
|
|
10
10
|
var _fieldType = require("../../utilities/fieldType");
|
|
11
|
+
var _indexHas = require("../../utilities/indexHas");
|
|
11
12
|
/**
|
|
12
13
|
* Check that no existing record already has this combination of values across all of the given
|
|
13
14
|
* fields - a single field for a normal unique/primary key, or several for a composite one.
|
|
14
15
|
* references and checkKeys are parallel arrays: references[i]'s value must equal checkKeys[i].
|
|
16
|
+
*
|
|
17
|
+
* One field with an index (every primary and unique key has one) is answered from the index; a composite key, or a
|
|
18
|
+
* field without one, reads every row.
|
|
15
19
|
* @param entity
|
|
16
20
|
* @param references
|
|
17
21
|
* @param checkKeys
|
|
@@ -20,6 +24,12 @@ const keyUnique = async (entity, references = [], checkKeys = []) => {
|
|
|
20
24
|
if (!references.length || references.length !== checkKeys.length) {
|
|
21
25
|
return false;
|
|
22
26
|
}
|
|
27
|
+
if (references.length === 1) {
|
|
28
|
+
const found = await (0, _indexHas.indexHas)(entity, references[0], checkKeys[0]);
|
|
29
|
+
if (typeof found !== 'undefined') {
|
|
30
|
+
return !found;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
23
33
|
let records = await (0, _retrieveRecords.retrieveRecords)(entity);
|
|
24
34
|
const record = await (0, _retrieveRecord.retrieveRecord)(entity);
|
|
25
35
|
for (let i = 0; i < references.length; i++) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.keyUnique=void 0;var _retrieveRecords=require("../../utilities/retrieveRecords"),_where=require("../../queries/where"),_retrieveRecord=require("../../utilities/retrieveRecord"),_fieldType=require("../../utilities/fieldType");const keyUnique=async(e,r=[],
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.keyUnique=void 0;var _retrieveRecords=require("../../utilities/retrieveRecords"),_where=require("../../queries/where"),_retrieveRecord=require("../../utilities/retrieveRecord"),_fieldType=require("../../utilities/fieldType"),_indexHas=require("../../utilities/indexHas");const keyUnique=async(e,r=[],i=[])=>{if(!r.length||r.length!==i.length)return!1;if(1===r.length){const t=await(0,_indexHas.indexHas)(e,r[0],i[0]);if(void 0!==t)return!t}let t=await(0,_retrieveRecords.retrieveRecords)(e);const s=await(0,_retrieveRecord.retrieveRecord)(e);for(let e=0;e<r.length;e++)t=(0,_where.where)(t,{property:r[e],comparator:"=",value:i[e],type:(0,_fieldType.fieldType)(s,r[e])});return!t.length};exports.keyUnique=keyUnique;
|
|
@@ -4,8 +4,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.deleteEntity = void 0;
|
|
7
|
-
require("core-js/modules/es.json.stringify.js");
|
|
8
7
|
require("core-js/modules/esnext.iterator.constructor.js");
|
|
8
|
+
require("core-js/modules/esnext.iterator.filter.js");
|
|
9
9
|
require("core-js/modules/esnext.iterator.find.js");
|
|
10
10
|
require("core-js/modules/esnext.iterator.map.js");
|
|
11
11
|
require("core-js/modules/esnext.set.add-all.js");
|
|
@@ -31,10 +31,8 @@ var _computeKeyValue = require("../utilities/computeKeyValue");
|
|
|
31
31
|
var _fieldType = require("../utilities/fieldType");
|
|
32
32
|
var _hasDependents = require("../introspect/policies/hasDependents");
|
|
33
33
|
var _config = require("../utilities/config");
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
writeFile
|
|
37
|
-
} = require('fs/promises');
|
|
34
|
+
var _keyIndexFiles = require("../utilities/keyIndexFiles");
|
|
35
|
+
var _storage = require("../storage");
|
|
38
36
|
/**
|
|
39
37
|
* RESTRICT: reject the whole delete (before removing anything) if any row being deleted is still
|
|
40
38
|
* referenced by a single-field foreign key elsewhere. Only meaningful for a single-field primary
|
|
@@ -57,32 +55,45 @@ const assertNoDependents = async (entity, primaryKey, toDelete) => {
|
|
|
57
55
|
};
|
|
58
56
|
/**
|
|
59
57
|
* A record object carries no memory of which entry file it was read from, and files are not
|
|
60
|
-
* guaranteed to be named after any field's value, so
|
|
61
|
-
*
|
|
62
|
-
*
|
|
58
|
+
* guaranteed to be named after any field's value, so a deleted row's file is found by its primary
|
|
59
|
+
* key value(s) - a single field, or a composite of several for a multi-field primary key. The
|
|
60
|
+
* primary key's index says which files those are (each is read to confirm it); any deleted value
|
|
61
|
+
* the index didn't lead to, or a record without one, is found by looking at every entry, as before.
|
|
62
|
+
* Inserts and updates keep primary key values unique, so each value is one row: only a database
|
|
63
|
+
* edited by hand into two rows of one value, with an index listing just one, would keep the other
|
|
64
|
+
* (looking at every entry used to delete both).
|
|
63
65
|
* @param entity
|
|
64
66
|
* @param record
|
|
65
67
|
* @param primaryKey
|
|
66
68
|
* @param deletedValues
|
|
67
69
|
*/
|
|
68
70
|
const removeMatchingEntries = async (entity, record, primaryKey, deletedValues) => {
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
|
|
71
|
+
const removed = new Set();
|
|
72
|
+
const found = new Set();
|
|
73
|
+
const removeIfDeleted = async fileName => {
|
|
72
74
|
const data = await (0, _retrieveFile.retrieveFile)(`${record.path}/${fileName}`);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
const value = (0, _computeKeyValue.computeKeyValue)(primaryKey.fields, data);
|
|
76
|
+
if (!deletedValues.has(value)) {
|
|
77
|
+
return;
|
|
76
78
|
}
|
|
77
|
-
await
|
|
79
|
+
await (0, _storage.removeFile)(`${record.path}/${fileName}`);
|
|
78
80
|
for (const key of record.keys) {
|
|
79
81
|
await (0, _removeFromIndex.removeFromIndex)(record.path, key, (0, _computeKeyValue.computeKeyValue)(key.fields, data), fileName, (0, _fieldType.keyValueType)(record, key));
|
|
80
82
|
}
|
|
83
|
+
removed.add(fileName);
|
|
84
|
+
found.add(value);
|
|
85
|
+
};
|
|
86
|
+
for (const fileName of (await (0, _keyIndexFiles.keyIndexFiles)(record, primaryKey, value => deletedValues.has(value))) ?? []) {
|
|
87
|
+
await removeIfDeleted(fileName);
|
|
81
88
|
}
|
|
82
|
-
|
|
89
|
+
if (found.size < deletedValues.size) {
|
|
90
|
+
for (const fileName of record.entries.filter(entry => !removed.has(entry))) {
|
|
91
|
+
await removeIfDeleted(fileName);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return record.entries.filter(fileName => !removed.has(fileName));
|
|
83
95
|
};
|
|
84
96
|
const deleteEntity = async (entity = '', dataSet = {}) => {
|
|
85
|
-
const databasePath = (0, _config.getSetting)('databasePath', 'database/');
|
|
86
97
|
const record = await (0, _retrieveRecord.retrieveRecord)(entity);
|
|
87
98
|
const primaryKey = record.keys.find(key => key.type === 'primary');
|
|
88
99
|
if (!primaryKey) {
|
|
@@ -95,7 +106,7 @@ const deleteEntity = async (entity = '', dataSet = {}) => {
|
|
|
95
106
|
await assertNoDependents(entity, primaryKey, toDelete);
|
|
96
107
|
const deletedValues = new Set(toDelete.map(row => (0, _computeKeyValue.computeKeyValue)(primaryKey.fields, row)));
|
|
97
108
|
record.entries = await removeMatchingEntries(entity, record, primaryKey, deletedValues);
|
|
98
|
-
await
|
|
109
|
+
await (0, _storage.writeJson)(`${record.path}.json`, record);
|
|
99
110
|
return dataSet;
|
|
100
111
|
};
|
|
101
112
|
exports.deleteEntity = deleteEntity;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.deleteEntity=void 0,require("core-js/modules/
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.deleteEntity=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.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("../utilities/retrieveRecord"),_retrieveFile=require("../utilities/retrieveFile"),_removeFromIndex=require("../utilities/removeFromIndex"),_computeKeyValue=require("../utilities/computeKeyValue"),_fieldType=require("../utilities/fieldType"),_hasDependents=require("../introspect/policies/hasDependents"),_config=require("../utilities/config"),_keyIndexFiles=require("../utilities/keyIndexFiles"),_storage=require("../storage");const assertNoDependents=async(e,r,s)=>{if(!(0,_config.getSetting)("enforceForeignKeys",!0)||1!==r.fields.length)return;const t=r.fields[0];for(const r of s)if(await(0,_hasDependents.hasDependents)(e,t,r[t]))throw new Error(`Cannot delete from "${e}" where "${t}" = ${r[t]} - other records still reference it`)},removeMatchingEntries=async(e,r,s,t)=>{const i=new Set,o=new Set,n=async e=>{const n=await(0,_retrieveFile.retrieveFile)(`${r.path}/${e}`),u=(0,_computeKeyValue.computeKeyValue)(s.fields,n);if(t.has(u)){await(0,_storage.removeFile)(`${r.path}/${e}`);for(const s of r.keys)await(0,_removeFromIndex.removeFromIndex)(r.path,s,(0,_computeKeyValue.computeKeyValue)(s.fields,n),e,(0,_fieldType.keyValueType)(r,s));i.add(e),o.add(u)}};for(const e of await(0,_keyIndexFiles.keyIndexFiles)(r,s,(e=>t.has(e)))??[])await n(e);if(o.size<t.size)for(const e of r.entries.filter((e=>!i.has(e))))await n(e);return r.entries.filter((e=>!i.has(e)))},deleteEntity=async(e="",r={})=>{const s=await(0,_retrieveRecord.retrieveRecord)(e),t=s.keys.find((e=>"primary"===e.type));if(!t)throw new Error(`Cannot delete from "${e}" without a primary key`);const i=r[e]||[];if(!i.length)return r;await assertNoDependents(e,t,i);const o=new Set(i.map((e=>(0,_computeKeyValue.computeKeyValue)(t.fields,e))));return s.entries=await removeMatchingEntries(0,s,t,o),await(0,_storage.writeJson)(`${s.path}.json`,s),r};exports.deleteEntity=deleteEntity;
|
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.insertEntity = void 0;
|
|
7
|
-
require("core-js/modules/es.json.stringify.js");
|
|
8
7
|
require("core-js/modules/esnext.iterator.constructor.js");
|
|
9
8
|
require("core-js/modules/esnext.iterator.find.js");
|
|
10
9
|
require("core-js/modules/esnext.iterator.map.js");
|
|
@@ -19,11 +18,7 @@ var _foreignKeyExists = require("../introspect/policies/foreignKeyExists");
|
|
|
19
18
|
var _splitEntityProperty = require("../utilities/parsers/splitEntityProperty");
|
|
20
19
|
var _computeKeyValue = require("../utilities/computeKeyValue");
|
|
21
20
|
var _fieldType = require("../utilities/fieldType");
|
|
22
|
-
var
|
|
23
|
-
const {
|
|
24
|
-
writeFile,
|
|
25
|
-
mkdir
|
|
26
|
-
} = require('fs/promises');
|
|
21
|
+
var _storage = require("../storage");
|
|
27
22
|
/**
|
|
28
23
|
* Build one entity's stored values from the raw input values, generating any autoGenerate
|
|
29
24
|
* fields and applying field defaults, then throw if a required field still has no value.
|
|
@@ -100,7 +95,6 @@ const assertForeignKeys = async (entity, record, entityValues) => {
|
|
|
100
95
|
}
|
|
101
96
|
};
|
|
102
97
|
const insertEntity = async (entity = '', values = [], dataSet = {}) => {
|
|
103
|
-
const databasePath = (0, _config.getSetting)('databasePath', 'database/');
|
|
104
98
|
const record = await (0, _retrieveRecord.retrieveRecord)(entity);
|
|
105
99
|
const primaryKey = record.keys.find(key => key.type === 'primary' && key.fields.length === 1);
|
|
106
100
|
if (!Object.prototype.hasOwnProperty.call(dataSet, entity)) {
|
|
@@ -108,17 +102,15 @@ const insertEntity = async (entity = '', values = [], dataSet = {}) => {
|
|
|
108
102
|
}
|
|
109
103
|
// The record's folder can be missing even though the record exists: git doesn't keep empty folders, so a database
|
|
110
104
|
// committed before its first insert comes back from a fresh clone without it
|
|
111
|
-
await
|
|
112
|
-
recursive: true
|
|
113
|
-
});
|
|
105
|
+
await (0, _storage.makeDirectory)(record.path);
|
|
114
106
|
for (const rowValues of values) {
|
|
115
107
|
const entityValues = await buildEntityValues(entity, record, rowValues);
|
|
116
108
|
await assertUnique(entity, record, entityValues);
|
|
117
109
|
await assertForeignKeys(entity, record, entityValues);
|
|
118
110
|
const fileName = `${primaryKey ? entityValues[primaryKey.fields[0]] : crypto.randomUUID()}.json`;
|
|
119
|
-
await
|
|
111
|
+
await (0, _storage.writeJson)(`${record.path}/${fileName}`, entityValues);
|
|
120
112
|
record.entries.push(fileName);
|
|
121
|
-
await
|
|
113
|
+
await (0, _storage.writeJson)(`${record.path}.json`, record);
|
|
122
114
|
for (const key of record.keys) {
|
|
123
115
|
await (0, _updateIndex.updateIndex)(record.path, key, (0, _computeKeyValue.computeKeyValue)(key.fields, entityValues), fileName, (0, _fieldType.keyValueType)(record, key));
|
|
124
116
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.insertEntity=void 0,require("core-js/modules/
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.insertEntity=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.find.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.iterator.some.js");var _retrieveRecord=require("../utilities/retrieveRecord"),_updateIndex=require("../utilities/updateIndex"),_keyGenerate=require("../introspect/policies/keyGenerate"),_keyUnique=require("../introspect/policies/keyUnique"),_useDefault=require("../introspect/policies/useDefault"),_typeCheck=require("../introspect/policies/typeCheck"),_foreignKeyExists=require("../introspect/policies/foreignKeyExists"),_splitEntityProperty=require("../utilities/parsers/splitEntityProperty"),_computeKeyValue=require("../utilities/computeKeyValue"),_fieldType=require("../utilities/fieldType"),_storage=require("../storage");const buildEntityValues=async(e,t,r={})=>{const i={};for(const s of t.definition){let t=r[s.name];if(s.autoGenerate?t=await(0,_keyGenerate.keyGenerate)(e,[s.name]):Object.prototype.hasOwnProperty.call(s,"default")&&(t=(0,_useDefault.useDefault)(s.default,t)),void 0!==t)i[s.name]=(0,_typeCheck.typeCheck)(s.type,t,s.nullable);else if(!s.optional)throw new Error(`Missing required field "${s.name}" for ${e}`)}return i},assertUnique=async(e,t,r)=>{for(const i of t.keys){if("primary"!==i.type&&"unique"!==i.type)continue;const t=i.fields.map((e=>r[e]));if(t.some((e=>null===e)))continue;if(!await(0,_keyUnique.keyUnique)(e,i.fields,t))throw new Error(`Duplicate value for ${i.type} key "${i.fields.join(", ")}" on ${e}`)}},assertForeignKeys=async(e,t,r)=>{for(const i of t.keys){if("foreign"!==i.type||1!==i.fields.length||!i.references||1!==i.references.length)continue;const t=i.fields[0];if(!Object.prototype.hasOwnProperty.call(r,t)||null===r[t])continue;const{entity:s,property:o}=(0,_splitEntityProperty.splitEntityProperty)(i.references[0].fields[0]);if(!await(0,_foreignKeyExists.foreignKeyExists)(s,o,r[t]))throw new Error(`Foreign key "${t}" on ${e} references a nonexistent ${s}.${o} = ${r[t]}`)}},insertEntity=async(e="",t=[],r={})=>{const i=await(0,_retrieveRecord.retrieveRecord)(e),s=i.keys.find((e=>"primary"===e.type&&1===e.fields.length));Object.prototype.hasOwnProperty.call(r,e)||(r[e]=[]),await(0,_storage.makeDirectory)(i.path);for(const o of t){const t=await buildEntityValues(e,i,o);await assertUnique(e,i,t),await assertForeignKeys(e,i,t);const n=`${s?t[s.fields[0]]:crypto.randomUUID()}.json`;await(0,_storage.writeJson)(`${i.path}/${n}`,t),i.entries.push(n),await(0,_storage.writeJson)(`${i.path}.json`,i);for(const e of i.keys)await(0,_updateIndex.updateIndex)(i.path,e,(0,_computeKeyValue.computeKeyValue)(e.fields,t),n,(0,_fieldType.keyValueType)(i,e));r[e].push(t)}return r};exports.insertEntity=insertEntity;
|
|
@@ -1,2 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attach to each row of `entity` the rows of `joinEntity` its join reaches, through the `on` clauses in order.
|
|
3
|
+
*
|
|
4
|
+
* Each clause narrows both its records to the rows that match the other side: first the rows of the left one that
|
|
5
|
+
* match a right one, then the right ones that match those (see semiJoin for the order). A row's join starts from the
|
|
6
|
+
* row alone and from the rows read for every other record (see joinBases), so each record is read once for the whole
|
|
7
|
+
* join and each lookup is built once, rather than every loaded row being copied for each row joined.
|
|
8
|
+
* @param entity
|
|
9
|
+
* @param joinEntity
|
|
10
|
+
* @param dataSets
|
|
11
|
+
* @param joinClauses
|
|
12
|
+
* @param entityAlreadyResolved - Whether the where clause already narrowed entity's rows (then they aren't read again:
|
|
13
|
+
* an empty list reads as "not loaded yet", see readEntity).
|
|
14
|
+
* @param joinAlreadyResolved - The same for joinEntity.
|
|
15
|
+
*/
|
|
1
16
|
export declare const joinEntity: (entity: any, joinEntity: any, dataSets?: {}, joinClauses?: any[], entityAlreadyResolved?: boolean, joinAlreadyResolved?: boolean) => Promise<{}>;
|
|
2
17
|
//# sourceMappingURL=joinEntity.d.ts.map
|
|
@@ -4,31 +4,107 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.joinEntity = void 0;
|
|
7
|
-
|
|
7
|
+
require("core-js/modules/esnext.iterator.constructor.js");
|
|
8
|
+
require("core-js/modules/esnext.iterator.map.js");
|
|
9
|
+
require("core-js/modules/esnext.map.delete-all.js");
|
|
10
|
+
require("core-js/modules/esnext.map.every.js");
|
|
11
|
+
require("core-js/modules/esnext.map.filter.js");
|
|
12
|
+
require("core-js/modules/esnext.map.find.js");
|
|
13
|
+
require("core-js/modules/esnext.map.find-key.js");
|
|
14
|
+
require("core-js/modules/esnext.map.includes.js");
|
|
15
|
+
require("core-js/modules/esnext.map.key-of.js");
|
|
16
|
+
require("core-js/modules/esnext.map.map-keys.js");
|
|
17
|
+
require("core-js/modules/esnext.map.map-values.js");
|
|
18
|
+
require("core-js/modules/esnext.map.merge.js");
|
|
19
|
+
require("core-js/modules/esnext.map.reduce.js");
|
|
20
|
+
require("core-js/modules/esnext.map.some.js");
|
|
21
|
+
require("core-js/modules/esnext.map.update.js");
|
|
8
22
|
var _readEntity = require("./readEntity");
|
|
9
|
-
var
|
|
10
|
-
|
|
23
|
+
var _retrieveRecord = require("../utilities/retrieveRecord");
|
|
24
|
+
var _splitEntityProperty = require("../utilities/parsers/splitEntityProperty");
|
|
25
|
+
var _fieldType = require("../utilities/fieldType");
|
|
26
|
+
var _semiJoin = require("../utilities/semiJoin");
|
|
27
|
+
var _joinBases = require("../utilities/joinBases");
|
|
28
|
+
/**
|
|
29
|
+
* Each `on` clause with the types its two sides are compared by. Each record is read here, before its type is looked
|
|
30
|
+
* up, so a record that doesn't exist fails with "Could not read <record>.json", as it always has.
|
|
31
|
+
* @param joinClauses
|
|
32
|
+
*/
|
|
33
|
+
const joinSteps = async joinClauses => {
|
|
34
|
+
const steps = [];
|
|
35
|
+
for (const {
|
|
36
|
+
propertyA,
|
|
37
|
+
comparator,
|
|
38
|
+
propertyB
|
|
39
|
+
} of joinClauses) {
|
|
40
|
+
const {
|
|
41
|
+
entity: entityA,
|
|
42
|
+
property: a
|
|
43
|
+
} = (0, _splitEntityProperty.splitEntityProperty)(propertyA);
|
|
44
|
+
const {
|
|
45
|
+
entity: entityB,
|
|
46
|
+
property: b
|
|
47
|
+
} = (0, _splitEntityProperty.splitEntityProperty)(propertyB);
|
|
48
|
+
steps.push({
|
|
49
|
+
entityA,
|
|
50
|
+
propertyA: a,
|
|
51
|
+
typeA: (0, _fieldType.fieldType)(await (0, _retrieveRecord.retrieveRecord)(entityA), a),
|
|
52
|
+
comparator,
|
|
53
|
+
entityB,
|
|
54
|
+
propertyB: b,
|
|
55
|
+
typeB: (0, _fieldType.fieldType)(await (0, _retrieveRecord.retrieveRecord)(entityB), b)
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return steps;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* What a row gets for its joined rows. Today every row is kept with the list of rows its join found (none is an empty
|
|
62
|
+
* list), and a condition on the joined record's fields then drops rows with none (whereTree): an inner join. This is
|
|
63
|
+
* the one place a join type (left, right, outer) would decide differently.
|
|
64
|
+
* @param matches - The joined rows the row's join found, shared with other rows' joins until copied here.
|
|
65
|
+
*/
|
|
66
|
+
const joinedRows = matches => matches.map(match => structuredClone(match));
|
|
67
|
+
/**
|
|
68
|
+
* Attach to each row of `entity` the rows of `joinEntity` its join reaches, through the `on` clauses in order.
|
|
69
|
+
*
|
|
70
|
+
* Each clause narrows both its records to the rows that match the other side: first the rows of the left one that
|
|
71
|
+
* match a right one, then the right ones that match those (see semiJoin for the order). A row's join starts from the
|
|
72
|
+
* row alone and from the rows read for every other record (see joinBases), so each record is read once for the whole
|
|
73
|
+
* join and each lookup is built once, rather than every loaded row being copied for each row joined.
|
|
74
|
+
* @param entity
|
|
75
|
+
* @param joinEntity
|
|
76
|
+
* @param dataSets
|
|
77
|
+
* @param joinClauses
|
|
78
|
+
* @param entityAlreadyResolved - Whether the where clause already narrowed entity's rows (then they aren't read again:
|
|
79
|
+
* an empty list reads as "not loaded yet", see readEntity).
|
|
80
|
+
* @param joinAlreadyResolved - The same for joinEntity.
|
|
81
|
+
*/
|
|
11
82
|
const joinEntity = async (entity, joinEntity, dataSets = {}, joinClauses = [], entityAlreadyResolved = false, joinAlreadyResolved = false) => {
|
|
12
|
-
// Same ambiguity readEntity() always has (can't tell "never loaded" from "loaded, zero rows
|
|
13
|
-
// matched") - runQuery already resolved entity's rows via an indexed condition in that second
|
|
14
|
-
// case, so entityAlreadyResolved tells this call not to reload and silently discard that result.
|
|
15
83
|
if (!entityAlreadyResolved) {
|
|
16
84
|
dataSets = await (0, _readEntity.readEntity)(entity, dataSets);
|
|
17
85
|
}
|
|
18
86
|
if (!joinClauses.length) {
|
|
19
87
|
return dataSets;
|
|
20
88
|
}
|
|
21
|
-
|
|
22
|
-
if (!
|
|
23
|
-
|
|
89
|
+
const steps = await joinSteps(joinClauses);
|
|
90
|
+
if (!dataSets[entity].length) {
|
|
91
|
+
return dataSets;
|
|
24
92
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
93
|
+
const bases = await (0, _joinBases.joinBases)(entity, joinEntity, dataSets, steps, joinAlreadyResolved);
|
|
94
|
+
for (const row of dataSets[entity]) {
|
|
95
|
+
const sides = new Map(bases);
|
|
96
|
+
sides.set(entity, {
|
|
97
|
+
rows: [row]
|
|
98
|
+
});
|
|
99
|
+
for (const step of steps) {
|
|
100
|
+
sides.set(step.entityA, {
|
|
101
|
+
rows: (0, _semiJoin.semiJoin)(sides.get(step.entityA), sides.get(step.entityB), step.propertyA, step.propertyB, step.comparator, step.typeA)
|
|
102
|
+
});
|
|
103
|
+
sides.set(step.entityB, {
|
|
104
|
+
rows: (0, _semiJoin.semiJoin)(sides.get(step.entityB), sides.get(step.entityA), step.propertyB, step.propertyA, step.comparator, step.typeB)
|
|
105
|
+
});
|
|
30
106
|
}
|
|
31
|
-
|
|
107
|
+
row[joinEntity] = joinedRows(sides.get(joinEntity).rows);
|
|
32
108
|
}
|
|
33
109
|
return dataSets;
|
|
34
110
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.joinEntity=void 0
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.joinEntity=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.map.js"),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 _readEntity=require("./readEntity"),_retrieveRecord=require("../utilities/retrieveRecord"),_splitEntityProperty=require("../utilities/parsers/splitEntityProperty"),_fieldType=require("../utilities/fieldType"),_semiJoin=require("../utilities/semiJoin"),_joinBases=require("../utilities/joinBases");const joinSteps=async e=>{const t=[];for(const{propertyA:r,comparator:s,propertyB:i}of e){const{entity:e,property:o}=(0,_splitEntityProperty.splitEntityProperty)(r),{entity:n,property:p}=(0,_splitEntityProperty.splitEntityProperty)(i);t.push({entityA:e,propertyA:o,typeA:(0,_fieldType.fieldType)(await(0,_retrieveRecord.retrieveRecord)(e),o),comparator:s,entityB:n,propertyB:p,typeB:(0,_fieldType.fieldType)(await(0,_retrieveRecord.retrieveRecord)(n),p)})}return t},joinedRows=e=>e.map((e=>structuredClone(e))),joinEntity=async(e,t,r={},s=[],i=!1,o=!1)=>{if(i||(r=await(0,_readEntity.readEntity)(e,r)),!s.length)return r;const n=await joinSteps(s);if(!r[e].length)return r;const p=await(0,_joinBases.joinBases)(e,t,r,n,o);for(const s of r[e]){const r=new Map(p);r.set(e,{rows:[s]});for(const e of n)r.set(e.entityA,{rows:(0,_semiJoin.semiJoin)(r.get(e.entityA),r.get(e.entityB),e.propertyA,e.propertyB,e.comparator,e.typeA)}),r.set(e.entityB,{rows:(0,_semiJoin.semiJoin)(r.get(e.entityB),r.get(e.entityA),e.propertyB,e.propertyA,e.comparator,e.typeB)});s[t]=joinedRows(r.get(t).rows)}return r};exports.joinEntity=joinEntity;
|