json-fs-query 1.1.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -674
- package/README.md +326 -98
- package/browser/jsonFsQuery.js +12819 -10934
- package/browser/jsonFsQuery.min.js +1 -1
- package/dist/data/introspect/create.d.ts +1 -1
- package/dist/data/introspect/create.js +35 -4
- package/dist/data/introspect/create.min.js +1 -1
- package/dist/data/introspect/definitions/field.d.ts +6 -2
- package/dist/data/introspect/definitions/field.js +7 -1
- package/dist/data/introspect/definitions/field.min.js +1 -1
- package/dist/data/introspect/index.d.ts +6 -3
- package/dist/data/introspect/index.js +10 -19
- package/dist/data/introspect/index.min.js +1 -1
- package/dist/data/introspect/policies/foreignKeyExists.js +28 -28
- package/dist/data/introspect/policies/hasDependents.js +53 -53
- package/dist/data/introspect/policies/keyUnique.js +34 -34
- package/dist/data/introspect/policies/typeCheck.d.ts +9 -1
- package/dist/data/introspect/policies/typeCheck.js +20 -2
- package/dist/data/introspect/policies/typeCheck.min.js +1 -1
- package/dist/data/queries/createRecord.d.ts +11 -0
- package/dist/data/queries/createRecord.js +58 -0
- package/dist/data/queries/createRecord.min.js +1 -0
- package/dist/data/queries/deleteEntity.js +100 -100
- package/dist/data/queries/describeRecord.d.ts +9 -0
- package/dist/data/queries/describeRecord.js +29 -0
- package/dist/data/queries/describeRecord.min.js +1 -0
- package/dist/data/queries/dropRecord.d.ts +9 -0
- package/dist/data/queries/dropRecord.js +61 -0
- package/dist/data/queries/dropRecord.min.js +1 -0
- package/dist/data/queries/insertEntity.js +122 -117
- package/dist/data/queries/insertEntity.min.js +1 -1
- package/dist/data/queries/parser.d.ts +1 -1
- package/dist/data/queries/parser.js +7 -15
- package/dist/data/queries/parser.min.js +1 -1
- package/dist/data/queries/query.d.ts +6 -0
- package/dist/data/queries/query.js +15 -6
- package/dist/data/queries/query.min.js +1 -1
- package/dist/data/queries/queryStatus.d.ts +15 -0
- package/dist/data/queries/queryStatus.js +52 -0
- package/dist/data/queries/queryStatus.min.js +1 -0
- package/dist/data/queries/quote.d.ts +11 -0
- package/dist/data/queries/quote.js +17 -0
- package/dist/data/queries/quote.min.js +1 -0
- package/dist/data/queries/showRecords.d.ts +6 -0
- package/dist/data/queries/showRecords.js +21 -0
- package/dist/data/queries/showRecords.min.js +1 -0
- package/dist/data/queries/sortBy.js +40 -27
- package/dist/data/queries/sortBy.min.js +1 -1
- package/dist/data/queries/updateEntity.js +245 -193
- package/dist/data/queries/updateEntity.min.js +1 -1
- package/dist/data/queries/where.d.ts +7 -7
- package/dist/data/queries/where.js +85 -67
- package/dist/data/queries/where.min.js +1 -1
- package/dist/data/utilities/compareAs.d.ts +19 -19
- package/dist/data/utilities/compareAs.js +57 -57
- package/dist/data/utilities/config.d.ts +15 -0
- package/dist/data/utilities/config.js +31 -1
- package/dist/data/utilities/config.min.js +1 -1
- package/dist/data/utilities/databaseLock.d.ts +16 -0
- package/dist/data/utilities/databaseLock.js +63 -0
- package/dist/data/utilities/databaseLock.min.js +1 -0
- package/dist/data/utilities/fieldType.d.ts +15 -15
- package/dist/data/utilities/fieldType.js +22 -22
- package/dist/data/utilities/getConditionIndexedList.js +47 -47
- package/dist/data/utilities/matchIndexedJoins.js +62 -62
- package/dist/data/utilities/mergeJoin.js +47 -47
- package/dist/data/utilities/parsers/findConditions.d.ts +19 -15
- package/dist/data/utilities/parsers/findConditions.js +34 -8
- package/dist/data/utilities/parsers/findConditions.min.js +1 -1
- package/dist/data/utilities/parsers/findInsertValues.js +3 -2
- package/dist/data/utilities/parsers/findInsertValues.min.js +1 -1
- package/dist/data/utilities/parsers/findJoinEntity.js +3 -1
- package/dist/data/utilities/parsers/findJoinEntity.min.js +1 -1
- package/dist/data/utilities/parsers/findSelects.js +6 -3
- package/dist/data/utilities/parsers/findSelects.min.js +1 -1
- package/dist/data/utilities/parsers/findSortClauses.js +5 -2
- package/dist/data/utilities/parsers/findSortClauses.min.js +1 -1
- package/dist/data/utilities/parsers/findUpdateValues.js +3 -2
- package/dist/data/utilities/parsers/findUpdateValues.min.js +1 -1
- package/dist/data/utilities/parsers/maskStrings.d.ts +39 -0
- package/dist/data/utilities/parsers/maskStrings.js +127 -0
- package/dist/data/utilities/parsers/maskStrings.min.js +1 -0
- package/dist/data/utilities/parsers/parseCreate.d.ts +20 -0
- package/dist/data/utilities/parsers/parseCreate.js +332 -0
- package/dist/data/utilities/parsers/parseCreate.min.js +1 -0
- package/dist/data/utilities/parsers/parseLiteralValue.d.ts +18 -1
- package/dist/data/utilities/parsers/parseLiteralValue.js +34 -5
- package/dist/data/utilities/parsers/parseLiteralValue.min.js +1 -1
- package/dist/data/utilities/parsers/parseQuery.d.ts +3 -0
- package/dist/data/utilities/parsers/parseQuery.js +28 -2
- package/dist/data/utilities/parsers/parseQuery.min.js +1 -1
- package/dist/data/utilities/parsers/parseSchemaStatement.d.ts +13 -0
- package/dist/data/utilities/parsers/parseSchemaStatement.js +82 -0
- package/dist/data/utilities/parsers/parseSchemaStatement.min.js +1 -0
- package/dist/data/utilities/parsers/scanQuery.d.ts +52 -0
- package/dist/data/utilities/parsers/scanQuery.js +158 -0
- package/dist/data/utilities/parsers/scanQuery.min.js +1 -0
- package/dist/data/utilities/parsers/splitQueries.d.ts +6 -0
- package/dist/data/utilities/parsers/splitQueries.js +20 -2
- package/dist/data/utilities/parsers/splitQueries.min.js +1 -1
- package/dist/data/utilities/parsers/startsQuery.d.ts +5 -0
- package/dist/data/utilities/parsers/startsQuery.js +10 -0
- package/dist/data/utilities/parsers/startsQuery.min.js +1 -0
- package/dist/data/utilities/recordExists.d.ts +6 -0
- package/dist/data/utilities/recordExists.js +18 -0
- package/dist/data/utilities/recordExists.min.js +1 -0
- package/dist/data/utilities/removeFromIndex.d.ts +14 -14
- package/dist/data/utilities/removeFromIndex.js +45 -45
- package/dist/data/utilities/runQuery.js +135 -112
- package/dist/data/utilities/runQuery.min.js +1 -1
- package/dist/data/utilities/updateIndex.d.ts +17 -17
- package/dist/data/utilities/updateIndex.js +57 -57
- package/dist/data/utilities/useJoinClause.js +56 -56
- package/dist/index.d.ts +2 -0
- package/dist/index.js +14 -0
- package/dist/index.min.js +1 -1
- package/package.json +68 -60
|
@@ -2,7 +2,7 @@ import { recordDefinition } from './definitions/record';
|
|
|
2
2
|
import { keyProperties } from './definitions/key';
|
|
3
3
|
import { fieldProperties } from './definitions/field';
|
|
4
4
|
/**
|
|
5
|
-
* Create a new record.
|
|
5
|
+
* Create a new record. Throws if the definition is invalid (see assertValidDefinition).
|
|
6
6
|
* @param recordName
|
|
7
7
|
* @param definition
|
|
8
8
|
* @param keys
|
|
@@ -5,11 +5,41 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.create = void 0;
|
|
7
7
|
require("core-js/modules/es.json.stringify.js");
|
|
8
|
+
require("core-js/modules/esnext.iterator.constructor.js");
|
|
9
|
+
require("core-js/modules/esnext.iterator.find.js");
|
|
10
|
+
require("core-js/modules/esnext.iterator.some.js");
|
|
8
11
|
var _record = require("./definitions/record");
|
|
9
12
|
var _registerRecord = require("../utilities/registerRecord");
|
|
10
13
|
var _config = require("../utilities/config");
|
|
14
|
+
var _typeCheck = require("./policies/typeCheck");
|
|
11
15
|
/**
|
|
12
|
-
*
|
|
16
|
+
* Reject a definition that could never be written correctly, before anything is created: a
|
|
17
|
+
* default that fails its field's type check (otherwise every insert leaving that field out would
|
|
18
|
+
* fail instead), including a null default on a field that isn't nullable, and a nullable field in
|
|
19
|
+
* the primary key (an entry's file name comes from its primary key value).
|
|
20
|
+
* @param recordName
|
|
21
|
+
* @param recordContent
|
|
22
|
+
*/
|
|
23
|
+
const assertValidDefinition = (recordName, recordContent) => {
|
|
24
|
+
for (const field of recordContent.definition) {
|
|
25
|
+
if (!Object.prototype.hasOwnProperty.call(field, 'default')) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
(0, _typeCheck.typeCheck)(field.type, field['default'], field.nullable);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
throw new Error(`Invalid default for field "${field.name}" of ${recordName}: ${err.message}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const primaryKey = recordContent.keys.find(key => key.type === 'primary');
|
|
35
|
+
for (const fieldName of primaryKey ? primaryKey.fields : []) {
|
|
36
|
+
if (recordContent.definition.some(field => field.name === fieldName && field.nullable)) {
|
|
37
|
+
throw new Error(`Primary key field "${fieldName}" of ${recordName} can't be nullable`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Create a new record. Throws if the definition is invalid (see assertValidDefinition).
|
|
13
43
|
* @param recordName
|
|
14
44
|
* @param definition
|
|
15
45
|
* @param keys
|
|
@@ -29,14 +59,15 @@ const create = async (recordName, definition = [], keys = []) => {
|
|
|
29
59
|
if (existsSync(`${databasePath}${recordName}.json`)) {
|
|
30
60
|
return null;
|
|
31
61
|
}
|
|
32
|
-
await mkdir(databasePath, {
|
|
33
|
-
recursive: true
|
|
34
|
-
});
|
|
35
62
|
const recordContent = (0, _record.record)({
|
|
36
63
|
path: recordName,
|
|
37
64
|
definition,
|
|
38
65
|
keys
|
|
39
66
|
});
|
|
67
|
+
assertValidDefinition(recordName, recordContent);
|
|
68
|
+
await mkdir(databasePath, {
|
|
69
|
+
recursive: true
|
|
70
|
+
});
|
|
40
71
|
await writeFile(`${databasePath}${recordName}.json`, JSON.stringify(recordContent, null, 2));
|
|
41
72
|
await mkdir(`${databasePath}${recordName}`, {
|
|
42
73
|
recursive: true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.create=void 0,require("core-js/modules/es.json.stringify.js");var _record=require("./definitions/record"),_registerRecord=require("../utilities/registerRecord"),_config=require("../utilities/config");const create=async(e,r=[],
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.create=void 0,require("core-js/modules/es.json.stringify.js"),require("core-js/modules/esnext.iterator.constructor.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"),_config=require("../utilities/config"),_typeCheck=require("./policies/typeCheck");const assertValidDefinition=(e,r)=>{for(const t of r.definition)if(Object.prototype.hasOwnProperty.call(t,"default"))try{(0,_typeCheck.typeCheck)(t.type,t.default,t.nullable)}catch(r){throw new Error(`Invalid default for field "${t.name}" of ${e}: ${r.message}`)}const t=r.keys.find((e=>"primary"===e.type));for(const i of t?t.fields:[])if(r.definition.some((e=>e.name===i&&e.nullable)))throw new Error(`Primary key field "${i}" of ${e} can't be nullable`)},create=async(e,r=[],t=[])=>{const{writeFile:i,mkdir:s}=require("fs/promises"),{existsSync:o}=require("fs"),n=(0,_config.getSetting)("databasePath","database/");if("__RECORDS"===e)return null;if(o(`${n}${e}.json`))return null;const a=(0,_record.record)({path:e,definition:r,keys:t});return assertValidDefinition(e,a),await s(n,{recursive:!0}),await i(`${n}${e}.json`,JSON.stringify(a,null,2)),await s(`${n}${e}`,{recursive:!0}),await(0,_registerRecord.registerRecord)(e),a};exports.create=create;
|
|
@@ -3,6 +3,7 @@ export type fieldDefinition = {
|
|
|
3
3
|
name: fieldName;
|
|
4
4
|
type: string;
|
|
5
5
|
optional: boolean;
|
|
6
|
+
nullable?: boolean;
|
|
6
7
|
default?: any;
|
|
7
8
|
autoGenerate: boolean;
|
|
8
9
|
};
|
|
@@ -10,19 +11,22 @@ export type fieldProperties = {
|
|
|
10
11
|
name?: string;
|
|
11
12
|
type?: string;
|
|
12
13
|
optional?: boolean;
|
|
14
|
+
nullable?: boolean;
|
|
13
15
|
useDefault?: boolean;
|
|
14
16
|
defaultValue?: any;
|
|
15
17
|
autoGenerate?: boolean;
|
|
16
18
|
};
|
|
17
19
|
/**
|
|
18
|
-
* Generate a field for a record.
|
|
20
|
+
* Generate a field for a record. `nullable` is only stored when true (like `default`), so fields
|
|
21
|
+
* that never mention it, and schemas written before it existed, stay exactly as they were.
|
|
19
22
|
* @param properties
|
|
20
23
|
* @param properties.name
|
|
21
24
|
* @param properties.type
|
|
22
25
|
* @param properties.optional
|
|
26
|
+
* @param properties.nullable
|
|
23
27
|
* @param properties.useDefault
|
|
24
28
|
* @param properties.defaultValue
|
|
25
29
|
* @param properties.autoGenerate
|
|
26
30
|
*/
|
|
27
|
-
export declare const field: ({ name, type, optional, useDefault, defaultValue, autoGenerate }?: fieldProperties) => fieldDefinition;
|
|
31
|
+
export declare const field: ({ name, type, optional, nullable, useDefault, defaultValue, autoGenerate }?: fieldProperties) => fieldDefinition;
|
|
28
32
|
//# sourceMappingURL=field.d.ts.map
|
|
@@ -5,11 +5,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.field = void 0;
|
|
7
7
|
/**
|
|
8
|
-
* Generate a field for a record.
|
|
8
|
+
* Generate a field for a record. `nullable` is only stored when true (like `default`), so fields
|
|
9
|
+
* that never mention it, and schemas written before it existed, stay exactly as they were.
|
|
9
10
|
* @param properties
|
|
10
11
|
* @param properties.name
|
|
11
12
|
* @param properties.type
|
|
12
13
|
* @param properties.optional
|
|
14
|
+
* @param properties.nullable
|
|
13
15
|
* @param properties.useDefault
|
|
14
16
|
* @param properties.defaultValue
|
|
15
17
|
* @param properties.autoGenerate
|
|
@@ -18,6 +20,7 @@ const field = ({
|
|
|
18
20
|
name = '',
|
|
19
21
|
type = 'string',
|
|
20
22
|
optional = false,
|
|
23
|
+
nullable = false,
|
|
21
24
|
useDefault = false,
|
|
22
25
|
defaultValue = '',
|
|
23
26
|
autoGenerate = false
|
|
@@ -28,6 +31,9 @@ const field = ({
|
|
|
28
31
|
optional,
|
|
29
32
|
autoGenerate
|
|
30
33
|
};
|
|
34
|
+
if (nullable) {
|
|
35
|
+
returnField['nullable'] = true;
|
|
36
|
+
}
|
|
31
37
|
if (useDefault) {
|
|
32
38
|
returnField['default'] = defaultValue;
|
|
33
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.field=void 0;const field=({name:e="",type:t="string",optional:
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.field=void 0;const field=({name:e="",type:t="string",optional:l=!1,nullable:a=!1,useDefault:o=!1,defaultValue:n="",autoGenerate:u=!1}={})=>{const r={name:e,type:t,optional:l,autoGenerate:u};return a&&(r.nullable=!0),o&&(r.default=n),r};exports.field=field;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { create as createRecord } from './create';
|
|
2
|
+
import { drop as dropRecord } from './drop';
|
|
3
|
+
import { describe as describeRecord } from './describe';
|
|
4
|
+
export declare const create: (...args: Parameters<typeof createRecord>) => ReturnType<typeof createRecord>;
|
|
5
|
+
export declare const drop: (...args: Parameters<typeof dropRecord>) => ReturnType<typeof dropRecord>;
|
|
6
|
+
export declare const describe: (...args: Parameters<typeof describeRecord>) => ReturnType<typeof describeRecord>;
|
|
4
7
|
export { fieldProperties, fieldDefinition, fieldName } from './definitions/field';
|
|
5
8
|
export { keyProperties, keyDefinition, indexType, indexLocation } from './definitions/key';
|
|
6
9
|
export { referenceProperties, reference } from './definitions/keyReference';
|
|
@@ -7,24 +7,15 @@ require("core-js/modules/esnext.iterator.drop.js");
|
|
|
7
7
|
Object.defineProperty(exports, "__esModule", {
|
|
8
8
|
value: true
|
|
9
9
|
});
|
|
10
|
-
|
|
11
|
-
enumerable: true,
|
|
12
|
-
get: function () {
|
|
13
|
-
return _create.create;
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
Object.defineProperty(exports, "describe", {
|
|
17
|
-
enumerable: true,
|
|
18
|
-
get: function () {
|
|
19
|
-
return _describe.describe;
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
Object.defineProperty(exports, "drop", {
|
|
23
|
-
enumerable: true,
|
|
24
|
-
get: function () {
|
|
25
|
-
return _drop.drop;
|
|
26
|
-
}
|
|
27
|
-
});
|
|
10
|
+
exports.drop = exports.describe = exports.create = void 0;
|
|
28
11
|
var _create = require("./create");
|
|
29
12
|
var _drop = require("./drop");
|
|
30
|
-
var _describe = require("./describe");
|
|
13
|
+
var _describe = require("./describe");
|
|
14
|
+
var _databaseLock = require("../utilities/databaseLock");
|
|
15
|
+
// The public versions take the database lock (see withDatabaseLock); code inside the package imports the files directly
|
|
16
|
+
const create = (...args) => (0, _databaseLock.withDatabaseLock)(() => (0, _create.create)(...args));
|
|
17
|
+
exports.create = create;
|
|
18
|
+
const drop = (...args) => (0, _databaseLock.withDatabaseLock)(() => (0, _drop.drop)(...args));
|
|
19
|
+
exports.drop = drop;
|
|
20
|
+
const describe = (...args) => (0, _databaseLock.withDatabaseLock)(() => (0, _describe.describe)(...args));
|
|
21
|
+
exports.describe = describe;
|
|
@@ -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}),
|
|
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=exports.describe=exports.create=void 0;var _create=require("./create"),_drop=require("./drop"),_describe=require("./describe"),_databaseLock=require("../utilities/databaseLock");const create=(...e)=>(0,_databaseLock.withDatabaseLock)((()=>(0,_create.create)(...e)));exports.create=create;const drop=(...e)=>(0,_databaseLock.withDatabaseLock)((()=>(0,_drop.drop)(...e)));exports.drop=drop;const describe=(...e)=>(0,_databaseLock.withDatabaseLock)((()=>(0,_describe.describe)(...e)));exports.describe=describe;
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.foreignKeyExists = void 0;
|
|
7
|
-
var _retrieveRecords = require("../../utilities/retrieveRecords");
|
|
8
|
-
var _where = require("../../queries/where");
|
|
9
|
-
var _retrieveRecord = require("../../utilities/retrieveRecord");
|
|
10
|
-
var _fieldType = require("../../utilities/fieldType");
|
|
11
|
-
/**
|
|
12
|
-
* Check whether any record in the referenced entity has the given property set to the given
|
|
13
|
-
* value - the mirror image of keyUnique(), which checks that no record already has a value.
|
|
14
|
-
* @param entity
|
|
15
|
-
* @param property
|
|
16
|
-
* @param value
|
|
17
|
-
*/
|
|
18
|
-
const foreignKeyExists = async (entity, property, value) => {
|
|
19
|
-
const records = await (0, _retrieveRecords.retrieveRecords)(entity);
|
|
20
|
-
const type = (0, _fieldType.fieldType)(await (0, _retrieveRecord.retrieveRecord)(entity), property);
|
|
21
|
-
const found = (0, _where.where)(records, {
|
|
22
|
-
property,
|
|
23
|
-
comparator: '=',
|
|
24
|
-
value,
|
|
25
|
-
type
|
|
26
|
-
});
|
|
27
|
-
return found.length > 0;
|
|
28
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.foreignKeyExists = void 0;
|
|
7
|
+
var _retrieveRecords = require("../../utilities/retrieveRecords");
|
|
8
|
+
var _where = require("../../queries/where");
|
|
9
|
+
var _retrieveRecord = require("../../utilities/retrieveRecord");
|
|
10
|
+
var _fieldType = require("../../utilities/fieldType");
|
|
11
|
+
/**
|
|
12
|
+
* Check whether any record in the referenced entity has the given property set to the given
|
|
13
|
+
* value - the mirror image of keyUnique(), which checks that no record already has a value.
|
|
14
|
+
* @param entity
|
|
15
|
+
* @param property
|
|
16
|
+
* @param value
|
|
17
|
+
*/
|
|
18
|
+
const foreignKeyExists = async (entity, property, value) => {
|
|
19
|
+
const records = await (0, _retrieveRecords.retrieveRecords)(entity);
|
|
20
|
+
const type = (0, _fieldType.fieldType)(await (0, _retrieveRecord.retrieveRecord)(entity), property);
|
|
21
|
+
const found = (0, _where.where)(records, {
|
|
22
|
+
property,
|
|
23
|
+
comparator: '=',
|
|
24
|
+
value,
|
|
25
|
+
type
|
|
26
|
+
});
|
|
27
|
+
return found.length > 0;
|
|
28
|
+
};
|
|
29
29
|
exports.foreignKeyExists = foreignKeyExists;
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.hasDependents = void 0;
|
|
7
|
-
var _describe = require("../describe");
|
|
8
|
-
var _retrieveRecord = require("../../utilities/retrieveRecord");
|
|
9
|
-
var _retrieveRecords = require("../../utilities/retrieveRecords");
|
|
10
|
-
var _where = require("../../queries/where");
|
|
11
|
-
var _fieldType = require("../../utilities/fieldType");
|
|
12
|
-
var _splitEntityProperty = require("../../utilities/parsers/splitEntityProperty");
|
|
13
|
-
/**
|
|
14
|
-
* Check whether any other record, in any entity, still has a single-field foreign key pointing
|
|
15
|
-
* at entity.property = value - the mirror image of foreignKeyExists(), which checks the opposite
|
|
16
|
-
* 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. Scans every record in
|
|
18
|
-
* the database via the __RECORDS registry, the same "no index needed, just look" approach as
|
|
19
|
-
* keyUnique()/foreignKeyExists() - correctness over speed, matching this project's overall scale.
|
|
20
|
-
* @param entity
|
|
21
|
-
* @param property
|
|
22
|
-
* @param value
|
|
23
|
-
*/
|
|
24
|
-
const hasDependents = async (entity, property, value) => {
|
|
25
|
-
const entityFiles = await (0, _describe.describe)();
|
|
26
|
-
for (const entityFile of entityFiles) {
|
|
27
|
-
const otherEntity = entityFile.replace(/\.json$/, '');
|
|
28
|
-
const otherRecord = await (0, _retrieveRecord.retrieveRecord)(otherEntity);
|
|
29
|
-
for (const key of otherRecord.keys) {
|
|
30
|
-
if (key.type !== 'foreign' || key.fields.length !== 1 || !key.references || key.references.length !== 1) {
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
const {
|
|
34
|
-
entity: refEntity,
|
|
35
|
-
property: refProperty
|
|
36
|
-
} = (0, _splitEntityProperty.splitEntityProperty)(key.references[0].fields[0]);
|
|
37
|
-
if (refEntity !== entity || refProperty !== property) {
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
const records = await (0, _retrieveRecords.retrieveRecords)(otherEntity);
|
|
41
|
-
const found = (0, _where.where)(records, {
|
|
42
|
-
property: key.fields[0],
|
|
43
|
-
comparator: '=',
|
|
44
|
-
value,
|
|
45
|
-
type: (0, _fieldType.fieldType)(otherRecord, key.fields[0])
|
|
46
|
-
});
|
|
47
|
-
if (found.length) {
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return false;
|
|
53
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.hasDependents = void 0;
|
|
7
|
+
var _describe = require("../describe");
|
|
8
|
+
var _retrieveRecord = require("../../utilities/retrieveRecord");
|
|
9
|
+
var _retrieveRecords = require("../../utilities/retrieveRecords");
|
|
10
|
+
var _where = require("../../queries/where");
|
|
11
|
+
var _fieldType = require("../../utilities/fieldType");
|
|
12
|
+
var _splitEntityProperty = require("../../utilities/parsers/splitEntityProperty");
|
|
13
|
+
/**
|
|
14
|
+
* Check whether any other record, in any entity, still has a single-field foreign key pointing
|
|
15
|
+
* at entity.property = value - the mirror image of foreignKeyExists(), which checks the opposite
|
|
16
|
+
* 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. Scans every record in
|
|
18
|
+
* the database via the __RECORDS registry, the same "no index needed, just look" approach as
|
|
19
|
+
* keyUnique()/foreignKeyExists() - correctness over speed, matching this project's overall scale.
|
|
20
|
+
* @param entity
|
|
21
|
+
* @param property
|
|
22
|
+
* @param value
|
|
23
|
+
*/
|
|
24
|
+
const hasDependents = async (entity, property, value) => {
|
|
25
|
+
const entityFiles = await (0, _describe.describe)();
|
|
26
|
+
for (const entityFile of entityFiles) {
|
|
27
|
+
const otherEntity = entityFile.replace(/\.json$/, '');
|
|
28
|
+
const otherRecord = await (0, _retrieveRecord.retrieveRecord)(otherEntity);
|
|
29
|
+
for (const key of otherRecord.keys) {
|
|
30
|
+
if (key.type !== 'foreign' || key.fields.length !== 1 || !key.references || key.references.length !== 1) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const {
|
|
34
|
+
entity: refEntity,
|
|
35
|
+
property: refProperty
|
|
36
|
+
} = (0, _splitEntityProperty.splitEntityProperty)(key.references[0].fields[0]);
|
|
37
|
+
if (refEntity !== entity || refProperty !== property) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const records = await (0, _retrieveRecords.retrieveRecords)(otherEntity);
|
|
41
|
+
const found = (0, _where.where)(records, {
|
|
42
|
+
property: key.fields[0],
|
|
43
|
+
comparator: '=',
|
|
44
|
+
value,
|
|
45
|
+
type: (0, _fieldType.fieldType)(otherRecord, key.fields[0])
|
|
46
|
+
});
|
|
47
|
+
if (found.length) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
};
|
|
54
54
|
exports.hasDependents = hasDependents;
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.keyUnique = void 0;
|
|
7
|
-
var _retrieveRecords = require("../../utilities/retrieveRecords");
|
|
8
|
-
var _where = require("../../queries/where");
|
|
9
|
-
var _retrieveRecord = require("../../utilities/retrieveRecord");
|
|
10
|
-
var _fieldType = require("../../utilities/fieldType");
|
|
11
|
-
/**
|
|
12
|
-
* Check that no existing record already has this combination of values across all of the given
|
|
13
|
-
* fields - a single field for a normal unique/primary key, or several for a composite one.
|
|
14
|
-
* references and checkKeys are parallel arrays: references[i]'s value must equal checkKeys[i].
|
|
15
|
-
* @param entity
|
|
16
|
-
* @param references
|
|
17
|
-
* @param checkKeys
|
|
18
|
-
*/
|
|
19
|
-
const keyUnique = async (entity, references = [], checkKeys = []) => {
|
|
20
|
-
if (!references.length || references.length !== checkKeys.length) {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
let records = await (0, _retrieveRecords.retrieveRecords)(entity);
|
|
24
|
-
const record = await (0, _retrieveRecord.retrieveRecord)(entity);
|
|
25
|
-
for (let i = 0; i < references.length; i++) {
|
|
26
|
-
records = (0, _where.where)(records, {
|
|
27
|
-
property: references[i],
|
|
28
|
-
comparator: '=',
|
|
29
|
-
value: checkKeys[i],
|
|
30
|
-
type: (0, _fieldType.fieldType)(record, references[i])
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
return !records.length;
|
|
34
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.keyUnique = void 0;
|
|
7
|
+
var _retrieveRecords = require("../../utilities/retrieveRecords");
|
|
8
|
+
var _where = require("../../queries/where");
|
|
9
|
+
var _retrieveRecord = require("../../utilities/retrieveRecord");
|
|
10
|
+
var _fieldType = require("../../utilities/fieldType");
|
|
11
|
+
/**
|
|
12
|
+
* Check that no existing record already has this combination of values across all of the given
|
|
13
|
+
* fields - a single field for a normal unique/primary key, or several for a composite one.
|
|
14
|
+
* references and checkKeys are parallel arrays: references[i]'s value must equal checkKeys[i].
|
|
15
|
+
* @param entity
|
|
16
|
+
* @param references
|
|
17
|
+
* @param checkKeys
|
|
18
|
+
*/
|
|
19
|
+
const keyUnique = async (entity, references = [], checkKeys = []) => {
|
|
20
|
+
if (!references.length || references.length !== checkKeys.length) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
let records = await (0, _retrieveRecords.retrieveRecords)(entity);
|
|
24
|
+
const record = await (0, _retrieveRecord.retrieveRecord)(entity);
|
|
25
|
+
for (let i = 0; i < references.length; i++) {
|
|
26
|
+
records = (0, _where.where)(records, {
|
|
27
|
+
property: references[i],
|
|
28
|
+
comparator: '=',
|
|
29
|
+
value: checkKeys[i],
|
|
30
|
+
type: (0, _fieldType.fieldType)(record, references[i])
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return !records.length;
|
|
34
|
+
};
|
|
35
35
|
exports.keyUnique = keyUnique;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The type names typeCheck knows. The create statement accepts only these; create() accepts any name (see below).
|
|
3
|
+
*/
|
|
4
|
+
export declare const fieldTypes: string[];
|
|
1
5
|
/**
|
|
2
6
|
* Validate (and where sensible, coerce) a value against a field's declared type. Runs only
|
|
3
7
|
* against values being written by insertEntity/updateEntity - it never re-validates data already
|
|
@@ -5,8 +9,12 @@
|
|
|
5
9
|
* happen, since nothing enforced this before) is left alone until something actually updates it.
|
|
6
10
|
* An unrecognized type name is treated as unconstrained rather than rejected, so a typo in a
|
|
7
11
|
* schema's field type can't silently block every write to that field.
|
|
12
|
+
*
|
|
13
|
+
* A null is a real JSON null, kept as it is for a nullable field and rejected for any other, of
|
|
14
|
+
* any type: it is never coerced, so a string field can't store the text "null" or an int field 0.
|
|
8
15
|
* @param type
|
|
9
16
|
* @param value
|
|
17
|
+
* @param nullable - Whether the field may hold null (the field definition's `nullable`).
|
|
10
18
|
*/
|
|
11
|
-
export declare const typeCheck: (type?: string, value?: any) => any;
|
|
19
|
+
export declare const typeCheck: (type?: string, value?: any, nullable?: boolean) => any;
|
|
12
20
|
//# sourceMappingURL=typeCheck.d.ts.map
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.typeCheck = void 0;
|
|
6
|
+
exports.typeCheck = exports.fieldTypes = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* The type names typeCheck knows. The create statement accepts only these; create() accepts any name (see below).
|
|
9
|
+
*/
|
|
10
|
+
const fieldTypes = exports.fieldTypes = ['string', 'int', 'boolean', 'object', 'array'];
|
|
7
11
|
/**
|
|
8
12
|
* Validate (and where sensible, coerce) a value against a field's declared type. Runs only
|
|
9
13
|
* against values being written by insertEntity/updateEntity - it never re-validates data already
|
|
@@ -11,13 +15,23 @@ exports.typeCheck = void 0;
|
|
|
11
15
|
* happen, since nothing enforced this before) is left alone until something actually updates it.
|
|
12
16
|
* An unrecognized type name is treated as unconstrained rather than rejected, so a typo in a
|
|
13
17
|
* schema's field type can't silently block every write to that field.
|
|
18
|
+
*
|
|
19
|
+
* A null is a real JSON null, kept as it is for a nullable field and rejected for any other, of
|
|
20
|
+
* any type: it is never coerced, so a string field can't store the text "null" or an int field 0.
|
|
14
21
|
* @param type
|
|
15
22
|
* @param value
|
|
23
|
+
* @param nullable - Whether the field may hold null (the field definition's `nullable`).
|
|
16
24
|
*/
|
|
17
|
-
const typeCheck = (type = 'string', value = undefined) => {
|
|
25
|
+
const typeCheck = (type = 'string', value = undefined, nullable = false) => {
|
|
18
26
|
if (typeof value === 'undefined') {
|
|
19
27
|
return value;
|
|
20
28
|
}
|
|
29
|
+
if (value === null) {
|
|
30
|
+
if (nullable) {
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
throw new Error('Value "null" is not allowed: the field is not nullable');
|
|
34
|
+
}
|
|
21
35
|
switch (type) {
|
|
22
36
|
case 'string':
|
|
23
37
|
return typeof value === 'string' ? value : String(value);
|
|
@@ -27,6 +41,10 @@ const typeCheck = (type = 'string', value = undefined) => {
|
|
|
27
41
|
if (Number.isNaN(coerced) || !Number.isInteger(coerced)) {
|
|
28
42
|
throw new Error(`Value "${value}" is not a valid int`);
|
|
29
43
|
}
|
|
44
|
+
// Past Number.MAX_SAFE_INTEGER an int can't be held exactly: '9007199254740993' would be stored as ...992
|
|
45
|
+
if (!Number.isSafeInteger(coerced)) {
|
|
46
|
+
throw new Error(`Value "${value}" is too large for an int (the largest is ${Number.MAX_SAFE_INTEGER})`);
|
|
47
|
+
}
|
|
30
48
|
return coerced;
|
|
31
49
|
}
|
|
32
50
|
case 'boolean':
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.typeCheck=void 0;const typeCheck=(
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.typeCheck=exports.fieldTypes=void 0;const fieldTypes=exports.fieldTypes=["string","int","boolean","object","array"],typeCheck=(e="string",r=void 0,t=!1)=>{if(void 0===r)return r;if(null===r){if(t)return r;throw new Error('Value "null" is not allowed: the field is not nullable')}switch(e){case"string":return"string"==typeof r?r:String(r);case"int":{const e=Number(r);if(Number.isNaN(e)||!Number.isInteger(e))throw new Error(`Value "${r}" is not a valid int`);if(!Number.isSafeInteger(e))throw new Error(`Value "${r}" is too large for an int (the largest is ${Number.MAX_SAFE_INTEGER})`);return e}case"boolean":if("boolean"==typeof r)return r;if("true"===r)return!0;if("false"===r)return!1;throw new Error(`Value "${r}" is not a valid boolean`);case"object":if("object"!=typeof r||null===r||Array.isArray(r))throw new Error(`Value "${r}" is not a valid object`);return r;case"array":if(!Array.isArray(r))throw new Error(`Value "${r}" is not a valid array`);return r;default:return r}};exports.typeCheck=typeCheck;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { recordDefinition } from '../introspect/definitions/record';
|
|
2
|
+
import { ParsedCreate } from '../utilities/parsers/parseCreate';
|
|
3
|
+
/**
|
|
4
|
+
* Run a parsed create statement: an error if the record already exists, unless the statement says
|
|
5
|
+
* `if not exists` (then nothing happens and the result is null). Otherwise create() it and resolve to its
|
|
6
|
+
* definition, as create() does.
|
|
7
|
+
* @param entity
|
|
8
|
+
* @param parsed
|
|
9
|
+
*/
|
|
10
|
+
export declare const createRecord: (entity: string, parsed: ParsedCreate) => Promise<recordDefinition | null>;
|
|
11
|
+
//# sourceMappingURL=createRecord.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createRecord = void 0;
|
|
7
|
+
require("core-js/modules/es.array.includes.js");
|
|
8
|
+
require("core-js/modules/esnext.iterator.constructor.js");
|
|
9
|
+
require("core-js/modules/esnext.iterator.map.js");
|
|
10
|
+
var _create = require("../introspect/create");
|
|
11
|
+
var _retrieveRecord = require("../utilities/retrieveRecord");
|
|
12
|
+
var _splitEntityProperty = require("../utilities/parsers/splitEntityProperty");
|
|
13
|
+
var _recordExists = require("../utilities/recordExists");
|
|
14
|
+
/**
|
|
15
|
+
* Reject a foreign key whose referenced record, or field on it, doesn't exist. A key referencing the record being
|
|
16
|
+
* created is checked against its own fields.
|
|
17
|
+
* @param entity
|
|
18
|
+
* @param parsed
|
|
19
|
+
*/
|
|
20
|
+
const assertReferencesExist = async (entity, parsed) => {
|
|
21
|
+
for (const key of parsed.keys) {
|
|
22
|
+
if (key.type !== 'foreign') {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const {
|
|
26
|
+
entity: refEntity,
|
|
27
|
+
property: refProperty
|
|
28
|
+
} = (0, _splitEntityProperty.splitEntityProperty)(key.references[0].fields[0]);
|
|
29
|
+
let fields = parsed.definition.map(field => field.name);
|
|
30
|
+
if (refEntity !== entity) {
|
|
31
|
+
if (!(0, _recordExists.recordExists)(refEntity)) {
|
|
32
|
+
throw new Error(`Foreign key "${key.fields[0]}" references "${refEntity}", which doesn't exist`);
|
|
33
|
+
}
|
|
34
|
+
fields = (await (0, _retrieveRecord.retrieveRecord)(refEntity)).definition.map(field => field.name);
|
|
35
|
+
}
|
|
36
|
+
if (!fields.includes(refProperty)) {
|
|
37
|
+
throw new Error(`Foreign key "${key.fields[0]}" references "${refEntity}.${refProperty}", which is not a field`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Run a parsed create statement: an error if the record already exists, unless the statement says
|
|
43
|
+
* `if not exists` (then nothing happens and the result is null). Otherwise create() it and resolve to its
|
|
44
|
+
* definition, as create() does.
|
|
45
|
+
* @param entity
|
|
46
|
+
* @param parsed
|
|
47
|
+
*/
|
|
48
|
+
const createRecord = async (entity, parsed) => {
|
|
49
|
+
if ((0, _recordExists.recordExists)(entity)) {
|
|
50
|
+
if (parsed.ifNotExists) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
throw new Error(`Record "${entity}" already exists`);
|
|
54
|
+
}
|
|
55
|
+
await assertReferencesExist(entity, parsed);
|
|
56
|
+
return (0, _create.create)(entity, parsed.definition, parsed.keys);
|
|
57
|
+
};
|
|
58
|
+
exports.createRecord = createRecord;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.createRecord=void 0,require("core-js/modules/es.array.includes.js"),require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.map.js");var _create=require("../introspect/create"),_retrieveRecord=require("../utilities/retrieveRecord"),_splitEntityProperty=require("../utilities/parsers/splitEntityProperty"),_recordExists=require("../utilities/recordExists");const assertReferencesExist=async(e,r)=>{for(const t of r.keys){if("foreign"!==t.type)continue;const{entity:i,property:s}=(0,_splitEntityProperty.splitEntityProperty)(t.references[0].fields[0]);let o=r.definition.map((e=>e.name));if(i!==e){if(!(0,_recordExists.recordExists)(i))throw new Error(`Foreign key "${t.fields[0]}" references "${i}", which doesn't exist`);o=(await(0,_retrieveRecord.retrieveRecord)(i)).definition.map((e=>e.name))}if(!o.includes(s))throw new Error(`Foreign key "${t.fields[0]}" references "${i}.${s}", which is not a field`)}},createRecord=async(e,r)=>{if((0,_recordExists.recordExists)(e)){if(r.ifNotExists)return null;throw new Error(`Record "${e}" already exists`)}return await assertReferencesExist(e,r),(0,_create.create)(e,r.definition,r.keys)};exports.createRecord=createRecord;
|