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.
Files changed (117) hide show
  1. package/LICENSE +674 -674
  2. package/README.md +326 -98
  3. package/browser/jsonFsQuery.js +12819 -10934
  4. package/browser/jsonFsQuery.min.js +1 -1
  5. package/dist/data/introspect/create.d.ts +1 -1
  6. package/dist/data/introspect/create.js +35 -4
  7. package/dist/data/introspect/create.min.js +1 -1
  8. package/dist/data/introspect/definitions/field.d.ts +6 -2
  9. package/dist/data/introspect/definitions/field.js +7 -1
  10. package/dist/data/introspect/definitions/field.min.js +1 -1
  11. package/dist/data/introspect/index.d.ts +6 -3
  12. package/dist/data/introspect/index.js +10 -19
  13. package/dist/data/introspect/index.min.js +1 -1
  14. package/dist/data/introspect/policies/foreignKeyExists.js +28 -28
  15. package/dist/data/introspect/policies/hasDependents.js +53 -53
  16. package/dist/data/introspect/policies/keyUnique.js +34 -34
  17. package/dist/data/introspect/policies/typeCheck.d.ts +9 -1
  18. package/dist/data/introspect/policies/typeCheck.js +20 -2
  19. package/dist/data/introspect/policies/typeCheck.min.js +1 -1
  20. package/dist/data/queries/createRecord.d.ts +11 -0
  21. package/dist/data/queries/createRecord.js +58 -0
  22. package/dist/data/queries/createRecord.min.js +1 -0
  23. package/dist/data/queries/deleteEntity.js +100 -100
  24. package/dist/data/queries/describeRecord.d.ts +9 -0
  25. package/dist/data/queries/describeRecord.js +29 -0
  26. package/dist/data/queries/describeRecord.min.js +1 -0
  27. package/dist/data/queries/dropRecord.d.ts +9 -0
  28. package/dist/data/queries/dropRecord.js +61 -0
  29. package/dist/data/queries/dropRecord.min.js +1 -0
  30. package/dist/data/queries/insertEntity.js +122 -117
  31. package/dist/data/queries/insertEntity.min.js +1 -1
  32. package/dist/data/queries/parser.d.ts +1 -1
  33. package/dist/data/queries/parser.js +7 -15
  34. package/dist/data/queries/parser.min.js +1 -1
  35. package/dist/data/queries/query.d.ts +6 -0
  36. package/dist/data/queries/query.js +15 -6
  37. package/dist/data/queries/query.min.js +1 -1
  38. package/dist/data/queries/queryStatus.d.ts +15 -0
  39. package/dist/data/queries/queryStatus.js +52 -0
  40. package/dist/data/queries/queryStatus.min.js +1 -0
  41. package/dist/data/queries/quote.d.ts +11 -0
  42. package/dist/data/queries/quote.js +17 -0
  43. package/dist/data/queries/quote.min.js +1 -0
  44. package/dist/data/queries/showRecords.d.ts +6 -0
  45. package/dist/data/queries/showRecords.js +21 -0
  46. package/dist/data/queries/showRecords.min.js +1 -0
  47. package/dist/data/queries/sortBy.js +40 -27
  48. package/dist/data/queries/sortBy.min.js +1 -1
  49. package/dist/data/queries/updateEntity.js +245 -193
  50. package/dist/data/queries/updateEntity.min.js +1 -1
  51. package/dist/data/queries/where.d.ts +7 -7
  52. package/dist/data/queries/where.js +85 -67
  53. package/dist/data/queries/where.min.js +1 -1
  54. package/dist/data/utilities/compareAs.d.ts +19 -19
  55. package/dist/data/utilities/compareAs.js +57 -57
  56. package/dist/data/utilities/config.d.ts +15 -0
  57. package/dist/data/utilities/config.js +31 -1
  58. package/dist/data/utilities/config.min.js +1 -1
  59. package/dist/data/utilities/databaseLock.d.ts +16 -0
  60. package/dist/data/utilities/databaseLock.js +63 -0
  61. package/dist/data/utilities/databaseLock.min.js +1 -0
  62. package/dist/data/utilities/fieldType.d.ts +15 -15
  63. package/dist/data/utilities/fieldType.js +22 -22
  64. package/dist/data/utilities/getConditionIndexedList.js +47 -47
  65. package/dist/data/utilities/matchIndexedJoins.js +62 -62
  66. package/dist/data/utilities/mergeJoin.js +47 -47
  67. package/dist/data/utilities/parsers/findConditions.d.ts +19 -15
  68. package/dist/data/utilities/parsers/findConditions.js +34 -8
  69. package/dist/data/utilities/parsers/findConditions.min.js +1 -1
  70. package/dist/data/utilities/parsers/findInsertValues.js +3 -2
  71. package/dist/data/utilities/parsers/findInsertValues.min.js +1 -1
  72. package/dist/data/utilities/parsers/findJoinEntity.js +3 -1
  73. package/dist/data/utilities/parsers/findJoinEntity.min.js +1 -1
  74. package/dist/data/utilities/parsers/findSelects.js +6 -3
  75. package/dist/data/utilities/parsers/findSelects.min.js +1 -1
  76. package/dist/data/utilities/parsers/findSortClauses.js +5 -2
  77. package/dist/data/utilities/parsers/findSortClauses.min.js +1 -1
  78. package/dist/data/utilities/parsers/findUpdateValues.js +3 -2
  79. package/dist/data/utilities/parsers/findUpdateValues.min.js +1 -1
  80. package/dist/data/utilities/parsers/maskStrings.d.ts +39 -0
  81. package/dist/data/utilities/parsers/maskStrings.js +127 -0
  82. package/dist/data/utilities/parsers/maskStrings.min.js +1 -0
  83. package/dist/data/utilities/parsers/parseCreate.d.ts +20 -0
  84. package/dist/data/utilities/parsers/parseCreate.js +332 -0
  85. package/dist/data/utilities/parsers/parseCreate.min.js +1 -0
  86. package/dist/data/utilities/parsers/parseLiteralValue.d.ts +18 -1
  87. package/dist/data/utilities/parsers/parseLiteralValue.js +34 -5
  88. package/dist/data/utilities/parsers/parseLiteralValue.min.js +1 -1
  89. package/dist/data/utilities/parsers/parseQuery.d.ts +3 -0
  90. package/dist/data/utilities/parsers/parseQuery.js +28 -2
  91. package/dist/data/utilities/parsers/parseQuery.min.js +1 -1
  92. package/dist/data/utilities/parsers/parseSchemaStatement.d.ts +13 -0
  93. package/dist/data/utilities/parsers/parseSchemaStatement.js +82 -0
  94. package/dist/data/utilities/parsers/parseSchemaStatement.min.js +1 -0
  95. package/dist/data/utilities/parsers/scanQuery.d.ts +52 -0
  96. package/dist/data/utilities/parsers/scanQuery.js +158 -0
  97. package/dist/data/utilities/parsers/scanQuery.min.js +1 -0
  98. package/dist/data/utilities/parsers/splitQueries.d.ts +6 -0
  99. package/dist/data/utilities/parsers/splitQueries.js +20 -2
  100. package/dist/data/utilities/parsers/splitQueries.min.js +1 -1
  101. package/dist/data/utilities/parsers/startsQuery.d.ts +5 -0
  102. package/dist/data/utilities/parsers/startsQuery.js +10 -0
  103. package/dist/data/utilities/parsers/startsQuery.min.js +1 -0
  104. package/dist/data/utilities/recordExists.d.ts +6 -0
  105. package/dist/data/utilities/recordExists.js +18 -0
  106. package/dist/data/utilities/recordExists.min.js +1 -0
  107. package/dist/data/utilities/removeFromIndex.d.ts +14 -14
  108. package/dist/data/utilities/removeFromIndex.js +45 -45
  109. package/dist/data/utilities/runQuery.js +135 -112
  110. package/dist/data/utilities/runQuery.min.js +1 -1
  111. package/dist/data/utilities/updateIndex.d.ts +17 -17
  112. package/dist/data/utilities/updateIndex.js +57 -57
  113. package/dist/data/utilities/useJoinClause.js +56 -56
  114. package/dist/index.d.ts +2 -0
  115. package/dist/index.js +14 -0
  116. package/dist/index.min.js +1 -1
  117. package/package.json +68 -60
@@ -1,68 +1,86 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.where = 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.filter.js");
10
- require("core-js/modules/esnext.iterator.some.js");
11
- var _compareAs = require("../utilities/compareAs");
12
- const likeMatch = (dataValue, pattern) => {
13
- if (typeof dataValue !== 'string' || typeof pattern !== 'string') {
14
- return false;
15
- }
16
- const regexPattern = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/%/g, '.*').replace(/_/g, '.');
17
- return new RegExp(`^${regexPattern}$`, 'i').test(dataValue);
18
- };
19
- /**
20
- * Equality (=, !=, <>, in) compares by the field's declared type when given one (see sameValue), so
21
- * '3' and 3 match in a string or int field. Ordering (>, <, between, like) compares the raw values.
22
- * @param data
23
- * @param property
24
- * @param comparator
25
- * @param value
26
- * @param type
27
- */
28
- const makeCondition = (data, property, comparator, value, type = undefined) => {
29
- if (!Object.prototype.hasOwnProperty.call(data, property)) {
30
- return false;
31
- }
32
- const dataValue = data[property];
33
- switch (comparator) {
34
- case '=':
35
- return (0, _compareAs.sameValue)(type, dataValue, value);
36
- case '!=':
37
- case '<>':
38
- return !(0, _compareAs.sameValue)(type, dataValue, value);
39
- case '>':
40
- return dataValue > value;
41
- case '>=':
42
- return dataValue >= value;
43
- case '<':
44
- return dataValue < value;
45
- case '<=':
46
- return dataValue <= value;
47
- case 'in':
48
- return Array.isArray(value) && (type ? value.some(item => (0, _compareAs.sameValue)(type, dataValue, item)) : value.includes(dataValue));
49
- case 'between':
50
- return Array.isArray(value) && value.length === 2 && dataValue >= value[0] && dataValue <= value[1];
51
- case 'like':
52
- return likeMatch(dataValue, value);
53
- }
54
- return false;
55
- };
56
- const where = (dataSet = [], {
57
- property = '',
58
- joinEntity = undefined,
59
- comparator = '=',
60
- value = null,
61
- type = undefined
62
- } = {}) => {
63
- return dataSet.filter(data => {
64
- const testProperty = joinEntity ? `${joinEntity}.${property}` : property;
65
- return makeCondition(data, testProperty, comparator, value, type);
66
- });
67
- };
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.where = 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.filter.js");
10
+ require("core-js/modules/esnext.iterator.some.js");
11
+ var _compareAs = require("../utilities/compareAs");
12
+ const likeMatch = (dataValue, pattern) => {
13
+ if (typeof dataValue !== 'string' || typeof pattern !== 'string') {
14
+ return false;
15
+ }
16
+ const regexPattern = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/%/g, '.*').replace(/_/g, '.');
17
+ return new RegExp(`^${regexPattern}$`, 'i').test(dataValue);
18
+ };
19
+ /**
20
+ * Equality (=, !=, <>, in) compares by the field's declared type when given one (see sameValue), so
21
+ * '3' and 3 match in a string or int field. Ordering (>, <, between, like) compares the raw values.
22
+ *
23
+ * Null and missing are their own cases, as in SQL: a field that is null or missing matches no comparison (not even
24
+ * `!=`), and a null never equals anything, not even another null. Only these test for them:
25
+ * - `is null`: the field is there and holds null
26
+ * - `is not null`: the field is there and holds a value (so a missing field doesn't match either)
27
+ * - `exists` / `does not exist`: the field is there (null counts) / is missing
28
+ * @param data
29
+ * @param property
30
+ * @param comparator
31
+ * @param value
32
+ * @param type
33
+ */
34
+ const makeCondition = (data, property, comparator, value, type = undefined) => {
35
+ const exists = Object.prototype.hasOwnProperty.call(data, property);
36
+ switch (comparator) {
37
+ case 'exists':
38
+ return exists;
39
+ case 'does not exist':
40
+ return !exists;
41
+ case 'is null':
42
+ return exists && data[property] === null;
43
+ case 'is not null':
44
+ return exists && data[property] !== null;
45
+ }
46
+ if (!exists || data[property] === null || value === null) {
47
+ return false;
48
+ }
49
+ const dataValue = data[property];
50
+ switch (comparator) {
51
+ case '=':
52
+ return (0, _compareAs.sameValue)(type, dataValue, value);
53
+ case '!=':
54
+ case '<>':
55
+ return !(0, _compareAs.sameValue)(type, dataValue, value);
56
+ case '>':
57
+ return dataValue > value;
58
+ case '>=':
59
+ return dataValue >= value;
60
+ case '<':
61
+ return dataValue < value;
62
+ case '<=':
63
+ return dataValue <= value;
64
+ case 'in':
65
+ return Array.isArray(value) && (type ? value.some(item => (0, _compareAs.sameValue)(type, dataValue, item)) : value.includes(dataValue));
66
+ case 'between':
67
+ // A null bound would act as 0 in >= / <=: it bounds nothing, so nothing matches (the parser refuses it)
68
+ return Array.isArray(value) && value.length === 2 && !value.includes(null) && dataValue >= value[0] && dataValue <= value[1];
69
+ case 'like':
70
+ return likeMatch(dataValue, value);
71
+ }
72
+ return false;
73
+ };
74
+ const where = (dataSet = [], {
75
+ property = '',
76
+ joinEntity = undefined,
77
+ comparator = '=',
78
+ value = null,
79
+ type = undefined
80
+ } = {}) => {
81
+ return dataSet.filter(data => {
82
+ const testProperty = joinEntity ? `${joinEntity}.${property}` : property;
83
+ return makeCondition(data, testProperty, comparator, value, type);
84
+ });
85
+ };
68
86
  exports.where = where;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.where=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.some.js");var _compareAs=require("../utilities/compareAs");const likeMatch=(e,r)=>{if("string"!=typeof e||"string"!=typeof r)return!1;const t=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/%/g,".*").replace(/_/g,".");return new RegExp(`^${t}$`,"i").test(e)},makeCondition=(e,r,t,s,a=void 0)=>{if(!Object.prototype.hasOwnProperty.call(e,r))return!1;const o=e[r];switch(t){case"=":return(0,_compareAs.sameValue)(a,o,s);case"!=":case"<>":return!(0,_compareAs.sameValue)(a,o,s);case">":return o>s;case">=":return o>=s;case"<":return o<s;case"<=":return o<=s;case"in":return Array.isArray(s)&&(a?s.some((e=>(0,_compareAs.sameValue)(a,o,e))):s.includes(o));case"between":return Array.isArray(s)&&2===s.length&&o>=s[0]&&o<=s[1];case"like":return likeMatch(o,s)}return!1},where=(e=[],{property:r="",joinEntity:t,comparator:s="=",value:a=null,type:o}={})=>e.filter((e=>makeCondition(e,t?`${t}.${r}`:r,s,a,o)));exports.where=where;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.where=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.some.js");var _compareAs=require("../utilities/compareAs");const likeMatch=(e,r)=>{if("string"!=typeof e||"string"!=typeof r)return!1;const t=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/%/g,".*").replace(/_/g,".");return new RegExp(`^${t}$`,"i").test(e)},makeCondition=(e,r,t,s,n=void 0)=>{const a=Object.prototype.hasOwnProperty.call(e,r);switch(t){case"exists":return a;case"does not exist":return!a;case"is null":return a&&null===e[r];case"is not null":return a&&null!==e[r]}if(!a||null===e[r]||null===s)return!1;const o=e[r];switch(t){case"=":return(0,_compareAs.sameValue)(n,o,s);case"!=":case"<>":return!(0,_compareAs.sameValue)(n,o,s);case">":return o>s;case">=":return o>=s;case"<":return o<s;case"<=":return o<=s;case"in":return Array.isArray(s)&&(n?s.some((e=>(0,_compareAs.sameValue)(n,o,e))):s.includes(o));case"between":return Array.isArray(s)&&2===s.length&&!s.includes(null)&&o>=s[0]&&o<=s[1];case"like":return likeMatch(o,s)}return!1},where=(e=[],{property:r="",joinEntity:t,comparator:s="=",value:n=null,type:a}={})=>e.filter((e=>makeCondition(e,t?`${t}.${r}`:r,s,n,a)));exports.where=where;
@@ -1,20 +1,20 @@
1
- /**
2
- * Normalize a value to a field's declared type for an equality comparison - never written back,
3
- * only compared. Writes are coerced to the declared type (typeCheck), but values already stored
4
- * may not match it (ids declared string, so they can hold an integer or a UUID, are often stored
5
- * as numbers), and query literals carry their own type. A declared type is what says '3' and 3
6
- * are the same value. A missing or unrecognized type returns the value unchanged.
7
- * @param type
8
- * @param value
9
- */
10
- export declare const compareAs: (type: string | undefined, value: any) => any;
11
- /**
12
- * Whether two values are equal for a field of the given declared type: both are normalized to
13
- * that type (see compareAs) and compared strictly. A field with no declared type, or one that
14
- * can't be normalized (object, array, or an unrecognized type), keeps loose equality.
15
- * @param type
16
- * @param a
17
- * @param b
18
- */
19
- export declare const sameValue: (type: string | undefined, a: any, b: any) => boolean;
1
+ /**
2
+ * Normalize a value to a field's declared type for an equality comparison - never written back,
3
+ * only compared. Writes are coerced to the declared type (typeCheck), but values already stored
4
+ * may not match it (ids declared string, so they can hold an integer or a UUID, are often stored
5
+ * as numbers), and query literals carry their own type. A declared type is what says '3' and 3
6
+ * are the same value. A missing or unrecognized type returns the value unchanged.
7
+ * @param type
8
+ * @param value
9
+ */
10
+ export declare const compareAs: (type: string | undefined, value: any) => any;
11
+ /**
12
+ * Whether two values are equal for a field of the given declared type: both are normalized to
13
+ * that type (see compareAs) and compared strictly. A field with no declared type, or one that
14
+ * can't be normalized (object, array, or an unrecognized type), keeps loose equality.
15
+ * @param type
16
+ * @param a
17
+ * @param b
18
+ */
19
+ export declare const sameValue: (type: string | undefined, a: any, b: any) => boolean;
20
20
  //# sourceMappingURL=compareAs.d.ts.map
@@ -1,58 +1,58 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.sameValue = exports.compareAs = void 0;
7
- require("core-js/modules/es.array.includes.js");
8
- /**
9
- * Normalize a value to a field's declared type for an equality comparison - never written back,
10
- * only compared. Writes are coerced to the declared type (typeCheck), but values already stored
11
- * may not match it (ids declared string, so they can hold an integer or a UUID, are often stored
12
- * as numbers), and query literals carry their own type. A declared type is what says '3' and 3
13
- * are the same value. A missing or unrecognized type returns the value unchanged.
14
- * @param type
15
- * @param value
16
- */
17
- const compareAs = (type, value) => {
18
- if (value === null || typeof value === 'undefined') {
19
- return value;
20
- }
21
- switch (type) {
22
- case 'string':
23
- return typeof value === 'object' ? value : String(value);
24
- case 'int':
25
- {
26
- const coerced = Number(value);
27
- return Number.isNaN(coerced) ? value : coerced;
28
- }
29
- case 'boolean':
30
- if (value === 'true') {
31
- return true;
32
- }
33
- if (value === 'false') {
34
- return false;
35
- }
36
- return value;
37
- default:
38
- return value;
39
- }
40
- };
41
- exports.compareAs = compareAs;
42
- const comparableTypes = ['string', 'int', 'boolean'];
43
- /**
44
- * Whether two values are equal for a field of the given declared type: both are normalized to
45
- * that type (see compareAs) and compared strictly. A field with no declared type, or one that
46
- * can't be normalized (object, array, or an unrecognized type), keeps loose equality.
47
- * @param type
48
- * @param a
49
- * @param b
50
- */
51
- const sameValue = (type, a, b) => {
52
- if (!comparableTypes.includes(type)) {
53
- // eslint-disable-next-line eqeqeq
54
- return a == b;
55
- }
56
- return compareAs(type, a) === compareAs(type, b);
57
- };
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.sameValue = exports.compareAs = void 0;
7
+ require("core-js/modules/es.array.includes.js");
8
+ /**
9
+ * Normalize a value to a field's declared type for an equality comparison - never written back,
10
+ * only compared. Writes are coerced to the declared type (typeCheck), but values already stored
11
+ * may not match it (ids declared string, so they can hold an integer or a UUID, are often stored
12
+ * as numbers), and query literals carry their own type. A declared type is what says '3' and 3
13
+ * are the same value. A missing or unrecognized type returns the value unchanged.
14
+ * @param type
15
+ * @param value
16
+ */
17
+ const compareAs = (type, value) => {
18
+ if (value === null || typeof value === 'undefined') {
19
+ return value;
20
+ }
21
+ switch (type) {
22
+ case 'string':
23
+ return typeof value === 'object' ? value : String(value);
24
+ case 'int':
25
+ {
26
+ const coerced = Number(value);
27
+ return Number.isNaN(coerced) ? value : coerced;
28
+ }
29
+ case 'boolean':
30
+ if (value === 'true') {
31
+ return true;
32
+ }
33
+ if (value === 'false') {
34
+ return false;
35
+ }
36
+ return value;
37
+ default:
38
+ return value;
39
+ }
40
+ };
41
+ exports.compareAs = compareAs;
42
+ const comparableTypes = ['string', 'int', 'boolean'];
43
+ /**
44
+ * Whether two values are equal for a field of the given declared type: both are normalized to
45
+ * that type (see compareAs) and compared strictly. A field with no declared type, or one that
46
+ * can't be normalized (object, array, or an unrecognized type), keeps loose equality.
47
+ * @param type
48
+ * @param a
49
+ * @param b
50
+ */
51
+ const sameValue = (type, a, b) => {
52
+ if (!comparableTypes.includes(type)) {
53
+ // eslint-disable-next-line eqeqeq
54
+ return a == b;
55
+ }
56
+ return compareAs(type, a) === compareAs(type, b);
57
+ };
58
58
  exports.sameValue = sameValue;
@@ -3,6 +3,18 @@ export type RuntimeSettings = {
3
3
  relativePath: string;
4
4
  enforceForeignKeys: boolean;
5
5
  };
6
+ /**
7
+ * The folder a databasePath points to, so that `database/`, `./database` and its absolute path count as one database.
8
+ * Node only (only Node calls are counted, see trackDatabaseCall).
9
+ * @param databasePath
10
+ */
11
+ export declare const resolveDatabasePath: (databasePath: string) => string;
12
+ /**
13
+ * Count a database call (taken by withDatabaseLock as soon as a call is queued) until the returned function is called.
14
+ * While any call is counted, configure() refuses to point databasePath somewhere else: every step of a call reads
15
+ * databasePath again, so a change halfway would write part of the call to one folder and the rest to another.
16
+ */
17
+ export declare const trackDatabaseCall: () => (() => void);
6
18
  /**
7
19
  * Set where this package's data lives: databasePath (a filesystem path, used in Node) and/or
8
20
  * relativePath (a URL prefix prepended to databasePath, used when reading over fetch() in a
@@ -13,7 +25,10 @@ export type RuntimeSettings = {
13
25
  * that would leave another record's foreign key pointing at a value that no longer exists -
14
26
  * mirroring MySQL's own foreign_key_checks setting, which is also toggleable rather than always
15
27
  * on, since strict enforcement isn't always what every consumer wants.
28
+ *
29
+ * Changing databasePath while calls are still running or queued throws (see trackDatabaseCall): await them first.
16
30
  * @param newSettings
31
+ * @throws {Error} When databasePath would point to another folder while database calls are in progress.
17
32
  */
18
33
  export declare const configure: (newSettings: Partial<RuntimeSettings>) => void;
19
34
  /**
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.getSetting = exports.configure = void 0;
6
+ exports.trackDatabaseCall = exports.resolveDatabasePath = exports.getSetting = exports.configure = void 0;
7
7
  const defaults = {
8
8
  databasePath: 'database/',
9
9
  relativePath: '',
@@ -12,6 +12,29 @@ const defaults = {
12
12
  let settings = {
13
13
  ...defaults
14
14
  };
15
+ let activeCalls = 0;
16
+ /**
17
+ * The folder a databasePath points to, so that `database/`, `./database` and its absolute path count as one database.
18
+ * Node only (only Node calls are counted, see trackDatabaseCall).
19
+ * @param databasePath
20
+ */
21
+ const resolveDatabasePath = databasePath => require('path').resolve(databasePath);
22
+ /**
23
+ * Count a database call (taken by withDatabaseLock as soon as a call is queued) until the returned function is called.
24
+ * While any call is counted, configure() refuses to point databasePath somewhere else: every step of a call reads
25
+ * databasePath again, so a change halfway would write part of the call to one folder and the rest to another.
26
+ */
27
+ exports.resolveDatabasePath = resolveDatabasePath;
28
+ const trackDatabaseCall = () => {
29
+ activeCalls++;
30
+ let ended = false;
31
+ return () => {
32
+ if (!ended) {
33
+ ended = true;
34
+ activeCalls--;
35
+ }
36
+ };
37
+ };
15
38
  /**
16
39
  * Set where this package's data lives: databasePath (a filesystem path, used in Node) and/or
17
40
  * relativePath (a URL prefix prepended to databasePath, used when reading over fetch() in a
@@ -22,9 +45,16 @@ let settings = {
22
45
  * that would leave another record's foreign key pointing at a value that no longer exists -
23
46
  * mirroring MySQL's own foreign_key_checks setting, which is also toggleable rather than always
24
47
  * on, since strict enforcement isn't always what every consumer wants.
48
+ *
49
+ * Changing databasePath while calls are still running or queued throws (see trackDatabaseCall): await them first.
25
50
  * @param newSettings
51
+ * @throws {Error} When databasePath would point to another folder while database calls are in progress.
26
52
  */
53
+ exports.trackDatabaseCall = trackDatabaseCall;
27
54
  const configure = newSettings => {
55
+ if (activeCalls > 0 && typeof newSettings.databasePath !== 'undefined' && resolveDatabasePath(newSettings.databasePath) !== resolveDatabasePath(settings.databasePath)) {
56
+ throw new Error(`Can't change databasePath while ${activeCalls} database call(s) are still running or queued: await them first`);
57
+ }
28
58
  settings = {
29
59
  ...settings,
30
60
  ...newSettings
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.getSetting=exports.configure=void 0;const defaults={databasePath:"database/",relativePath:"",enforceForeignKeys:!0};let settings={...defaults};const configure=t=>{settings={...settings,...t}};exports.configure=configure;const getSetting=(t,e)=>void 0!==settings[t]?settings[t]:e;exports.getSetting=getSetting;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.trackDatabaseCall=exports.resolveDatabasePath=exports.getSetting=exports.configure=void 0;const defaults={databasePath:"database/",relativePath:"",enforceForeignKeys:!0};let settings={...defaults},activeCalls=0;const resolveDatabasePath=t=>require("path").resolve(t);exports.resolveDatabasePath=resolveDatabasePath;const trackDatabaseCall=()=>{activeCalls++;let t=!1;return()=>{t||(t=!0,activeCalls--)}};exports.trackDatabaseCall=trackDatabaseCall;const configure=t=>{if(activeCalls>0&&void 0!==t.databasePath&&resolveDatabasePath(t.databasePath)!==resolveDatabasePath(settings.databasePath))throw new Error(`Can't change databasePath while ${activeCalls} database call(s) are still running or queued: await them first`);settings={...settings,...t}};exports.configure=configure;const getSetting=(t,a)=>void 0!==settings[t]?settings[t]:a;exports.getSetting=getSetting;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Run `task` once every earlier task on the same database (the configured databasePath) has finished, so that calls
3
+ * never interleave. Every write is several files in turn (an entry, the record's entry list, each index), each read and
4
+ * rewritten whole, so two writes running at once overwrite each other's changes: ten parallel inserts used to leave
5
+ * nine of the rows unreadable, and two parallel inserts of one unique value both succeeded. Reads take their turn too,
6
+ * so a read never sees a write half done. A task that throws still lets the next one run.
7
+ *
8
+ * Only the public functions (query, create, drop, describe) take the lock; what they call inside doesn't take it
9
+ * again, so it can't deadlock. In the browser nothing can be written, so tasks just run.
10
+ *
11
+ * The queue is per folder (`database/` and `./database` share one). Every step of a task reads databasePath when it
12
+ * runs, so configure() refuses to change it while tasks are queued or running (see trackDatabaseCall).
13
+ * @param task
14
+ */
15
+ export declare const withDatabaseLock: <T>(task: () => Promise<T>) => Promise<T>;
16
+ //# sourceMappingURL=databaseLock.d.ts.map
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+
3
+ require("core-js/modules/esnext.weak-map.delete-all.js");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.withDatabaseLock = void 0;
8
+ require("core-js/modules/esnext.map.delete-all.js");
9
+ require("core-js/modules/esnext.map.every.js");
10
+ require("core-js/modules/esnext.map.filter.js");
11
+ require("core-js/modules/esnext.map.find.js");
12
+ require("core-js/modules/esnext.map.find-key.js");
13
+ require("core-js/modules/esnext.map.includes.js");
14
+ require("core-js/modules/esnext.map.key-of.js");
15
+ require("core-js/modules/esnext.map.map-keys.js");
16
+ require("core-js/modules/esnext.map.map-values.js");
17
+ require("core-js/modules/esnext.map.merge.js");
18
+ require("core-js/modules/esnext.map.reduce.js");
19
+ require("core-js/modules/esnext.map.some.js");
20
+ require("core-js/modules/esnext.map.update.js");
21
+ var jsEnv = _interopRequireWildcard(require("browser-or-node"));
22
+ var _config = require("./config");
23
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
24
+ const queues = new Map();
25
+ /**
26
+ * Run `task` once every earlier task on the same database (the configured databasePath) has finished, so that calls
27
+ * never interleave. Every write is several files in turn (an entry, the record's entry list, each index), each read and
28
+ * rewritten whole, so two writes running at once overwrite each other's changes: ten parallel inserts used to leave
29
+ * nine of the rows unreadable, and two parallel inserts of one unique value both succeeded. Reads take their turn too,
30
+ * so a read never sees a write half done. A task that throws still lets the next one run.
31
+ *
32
+ * Only the public functions (query, create, drop, describe) take the lock; what they call inside doesn't take it
33
+ * again, so it can't deadlock. In the browser nothing can be written, so tasks just run.
34
+ *
35
+ * The queue is per folder (`database/` and `./database` share one). Every step of a task reads databasePath when it
36
+ * runs, so configure() refuses to change it while tasks are queued or running (see trackDatabaseCall).
37
+ * @param task
38
+ */
39
+ const withDatabaseLock = async task => {
40
+ if (!jsEnv.isNode) {
41
+ return task();
42
+ }
43
+ const database = (0, _config.resolveDatabasePath)((0, _config.getSetting)('databasePath', 'database/'));
44
+ const ended = (0, _config.trackDatabaseCall)();
45
+ const previous = queues.get(database) || Promise.resolve();
46
+ let release;
47
+ const turn = new Promise(resolve => {
48
+ release = resolve;
49
+ });
50
+ const queued = previous.then(() => turn);
51
+ queues.set(database, queued);
52
+ await previous;
53
+ try {
54
+ return await task();
55
+ } finally {
56
+ ended();
57
+ release();
58
+ if (queues.get(database) === queued) {
59
+ queues.delete(database);
60
+ }
61
+ }
62
+ };
63
+ exports.withDatabaseLock = withDatabaseLock;
@@ -0,0 +1 @@
1
+ "use strict";require("core-js/modules/esnext.weak-map.delete-all.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.withDatabaseLock=void 0,require("core-js/modules/esnext.map.delete-all.js"),require("core-js/modules/esnext.map.every.js"),require("core-js/modules/esnext.map.filter.js"),require("core-js/modules/esnext.map.find.js"),require("core-js/modules/esnext.map.find-key.js"),require("core-js/modules/esnext.map.includes.js"),require("core-js/modules/esnext.map.key-of.js"),require("core-js/modules/esnext.map.map-keys.js"),require("core-js/modules/esnext.map.map-values.js"),require("core-js/modules/esnext.map.merge.js"),require("core-js/modules/esnext.map.reduce.js"),require("core-js/modules/esnext.map.some.js"),require("core-js/modules/esnext.map.update.js");var jsEnv=_interopRequireWildcard(require("browser-or-node")),_config=require("./config");function _interopRequireWildcard(e,r){if("function"==typeof WeakMap)var s=new WeakMap,t=new WeakMap;return(_interopRequireWildcard=function(e,r){if(!r&&e&&e.__esModule)return e;var o,a,u={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return u;if(o=r?t:s){if(o.has(e))return o.get(e);o.set(e,u)}for(const r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((a=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,r))&&(a.get||a.set)?o(u,r,a):u[r]=e[r]);return u})(e,r)}const queues=new Map,withDatabaseLock=async e=>{if(!jsEnv.isNode)return e();const r=(0,_config.resolveDatabasePath)((0,_config.getSetting)("databasePath","database/")),s=(0,_config.trackDatabaseCall)(),t=queues.get(r)||Promise.resolve();let o;const a=new Promise((e=>{o=e})),u=t.then((()=>a));queues.set(r,u),await t;try{return await e()}finally{s(),o(),queues.get(r)===u&&queues.delete(r)}};exports.withDatabaseLock=withDatabaseLock;
@@ -1,16 +1,16 @@
1
- import { recordDefinition } from '../introspect/definitions/record';
2
- import { keyDefinition } from '../introspect/definitions/key';
3
- /**
4
- * The declared type of one of a record's fields, or undefined when the record or field is unknown.
5
- * @param record
6
- * @param property
7
- */
8
- export declare const fieldType: (record: recordDefinition | undefined, property: string) => string | undefined;
9
- /**
10
- * The declared type of the value a key indexes: its field's type for a single-field key. A
11
- * multi-field key's value is a composite (see computeKeyValue), so it has no single declared type.
12
- * @param record
13
- * @param key
14
- */
15
- export declare const keyValueType: (record: recordDefinition | undefined, key: keyDefinition) => string | undefined;
1
+ import { recordDefinition } from '../introspect/definitions/record';
2
+ import { keyDefinition } from '../introspect/definitions/key';
3
+ /**
4
+ * The declared type of one of a record's fields, or undefined when the record or field is unknown.
5
+ * @param record
6
+ * @param property
7
+ */
8
+ export declare const fieldType: (record: recordDefinition | undefined, property: string) => string | undefined;
9
+ /**
10
+ * The declared type of the value a key indexes: its field's type for a single-field key. A
11
+ * multi-field key's value is a composite (see computeKeyValue), so it has no single declared type.
12
+ * @param record
13
+ * @param key
14
+ */
15
+ export declare const keyValueType: (record: recordDefinition | undefined, key: keyDefinition) => string | undefined;
16
16
  //# sourceMappingURL=fieldType.d.ts.map
@@ -1,23 +1,23 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.keyValueType = exports.fieldType = void 0;
7
- require("core-js/modules/esnext.iterator.constructor.js");
8
- require("core-js/modules/esnext.iterator.find.js");
9
- /**
10
- * The declared type of one of a record's fields, or undefined when the record or field is unknown.
11
- * @param record
12
- * @param property
13
- */
14
- const fieldType = (record, property) => record?.definition?.find(field => field.name === property)?.type;
15
- /**
16
- * The declared type of the value a key indexes: its field's type for a single-field key. A
17
- * multi-field key's value is a composite (see computeKeyValue), so it has no single declared type.
18
- * @param record
19
- * @param key
20
- */
21
- exports.fieldType = fieldType;
22
- const keyValueType = (record, key) => key.fields.length === 1 ? fieldType(record, key.fields[0]) : undefined;
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.keyValueType = exports.fieldType = void 0;
7
+ require("core-js/modules/esnext.iterator.constructor.js");
8
+ require("core-js/modules/esnext.iterator.find.js");
9
+ /**
10
+ * The declared type of one of a record's fields, or undefined when the record or field is unknown.
11
+ * @param record
12
+ * @param property
13
+ */
14
+ const fieldType = (record, property) => record?.definition?.find(field => field.name === property)?.type;
15
+ /**
16
+ * The declared type of the value a key indexes: its field's type for a single-field key. A
17
+ * multi-field key's value is a composite (see computeKeyValue), so it has no single declared type.
18
+ * @param record
19
+ * @param key
20
+ */
21
+ exports.fieldType = fieldType;
22
+ const keyValueType = (record, key) => key.fields.length === 1 ? fieldType(record, key.fields[0]) : undefined;
23
23
  exports.keyValueType = keyValueType;