@e22m4u/js-repository 0.0.31

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 (183) hide show
  1. package/.c8rc +9 -0
  2. package/.commitlintrc +5 -0
  3. package/.editorconfig +13 -0
  4. package/.eslintignore +1 -0
  5. package/.eslintrc.cjs +27 -0
  6. package/.husky/commit-msg +4 -0
  7. package/.husky/pre-commit +9 -0
  8. package/.mocharc.cjs +7 -0
  9. package/.prettierrc +7 -0
  10. package/LICENSE +21 -0
  11. package/README.md +523 -0
  12. package/mocha.setup.js +10 -0
  13. package/package.json +57 -0
  14. package/src/adapter/adapter-loader.d.ts +16 -0
  15. package/src/adapter/adapter-loader.js +63 -0
  16. package/src/adapter/adapter-loader.spec.js +31 -0
  17. package/src/adapter/adapter-registry.d.ts +14 -0
  18. package/src/adapter/adapter-registry.js +36 -0
  19. package/src/adapter/adapter-registry.spec.js +36 -0
  20. package/src/adapter/adapter.d.ts +118 -0
  21. package/src/adapter/adapter.js +181 -0
  22. package/src/adapter/adapter.spec.js +144 -0
  23. package/src/adapter/builtin/memory-adapter.d.ts +118 -0
  24. package/src/adapter/builtin/memory-adapter.js +342 -0
  25. package/src/adapter/builtin/memory-adapter.spec.js +2925 -0
  26. package/src/adapter/decorator/data-sanitizing-decorator.d.ts +13 -0
  27. package/src/adapter/decorator/data-sanitizing-decorator.js +44 -0
  28. package/src/adapter/decorator/data-sanitizing-decorator.spec.js +59 -0
  29. package/src/adapter/decorator/data-validation-decorator.d.ts +13 -0
  30. package/src/adapter/decorator/data-validation-decorator.js +41 -0
  31. package/src/adapter/decorator/data-validation-decorator.spec.js +59 -0
  32. package/src/adapter/decorator/default-values-decorator.d.ts +13 -0
  33. package/src/adapter/decorator/default-values-decorator.js +57 -0
  34. package/src/adapter/decorator/default-values-decorator.spec.js +141 -0
  35. package/src/adapter/decorator/fields-filtering-decorator.d.ts +13 -0
  36. package/src/adapter/decorator/fields-filtering-decorator.js +72 -0
  37. package/src/adapter/decorator/fields-filtering-decorator.spec.js +119 -0
  38. package/src/adapter/decorator/inclusion-decorator.d.ts +13 -0
  39. package/src/adapter/decorator/inclusion-decorator.js +78 -0
  40. package/src/adapter/decorator/inclusion-decorator.spec.js +117 -0
  41. package/src/adapter/decorator/index.d.ts +5 -0
  42. package/src/adapter/decorator/index.js +5 -0
  43. package/src/adapter/index.d.ts +3 -0
  44. package/src/adapter/index.js +3 -0
  45. package/src/definition/datasource/datasource-definition-validator.d.ts +14 -0
  46. package/src/definition/datasource/datasource-definition-validator.js +33 -0
  47. package/src/definition/datasource/datasource-definition-validator.spec.js +63 -0
  48. package/src/definition/datasource/datasource-definition.d.ts +7 -0
  49. package/src/definition/datasource/index.d.ts +2 -0
  50. package/src/definition/datasource/index.js +1 -0
  51. package/src/definition/definition-registry.d.ts +50 -0
  52. package/src/definition/definition-registry.js +98 -0
  53. package/src/definition/definition-registry.spec.js +78 -0
  54. package/src/definition/index.d.ts +3 -0
  55. package/src/definition/index.js +3 -0
  56. package/src/definition/model/index.d.ts +7 -0
  57. package/src/definition/model/index.js +6 -0
  58. package/src/definition/model/model-data-sanitizer.d.ts +15 -0
  59. package/src/definition/model/model-data-sanitizer.js +33 -0
  60. package/src/definition/model/model-data-validator.d.ts +32 -0
  61. package/src/definition/model/model-data-validator.js +144 -0
  62. package/src/definition/model/model-data-validator.spec.js +1889 -0
  63. package/src/definition/model/model-definition-utils.d.ts +161 -0
  64. package/src/definition/model/model-definition-utils.js +371 -0
  65. package/src/definition/model/model-definition-utils.spec.js +1474 -0
  66. package/src/definition/model/model-definition-validator.d.ts +14 -0
  67. package/src/definition/model/model-definition-validator.js +83 -0
  68. package/src/definition/model/model-definition-validator.spec.js +143 -0
  69. package/src/definition/model/model-definition.d.ts +28 -0
  70. package/src/definition/model/properties/data-type.d.ts +11 -0
  71. package/src/definition/model/properties/data-type.js +11 -0
  72. package/src/definition/model/properties/default-values-definition-validator.d.ts +15 -0
  73. package/src/definition/model/properties/default-values-definition-validator.js +53 -0
  74. package/src/definition/model/properties/default-values-definition-validator.spec.js +136 -0
  75. package/src/definition/model/properties/index.d.ts +5 -0
  76. package/src/definition/model/properties/index.js +4 -0
  77. package/src/definition/model/properties/primary-keys-definition-validator.d.ts +15 -0
  78. package/src/definition/model/properties/primary-keys-definition-validator.js +55 -0
  79. package/src/definition/model/properties/primary-keys-definition-validator.spec.js +145 -0
  80. package/src/definition/model/properties/properties-definition-validator.d.ts +15 -0
  81. package/src/definition/model/properties/properties-definition-validator.js +194 -0
  82. package/src/definition/model/properties/properties-definition-validator.spec.js +373 -0
  83. package/src/definition/model/properties/property-definition.d.ts +20 -0
  84. package/src/definition/model/relations/index.d.ts +3 -0
  85. package/src/definition/model/relations/index.js +2 -0
  86. package/src/definition/model/relations/relation-definition.d.ts +254 -0
  87. package/src/definition/model/relations/relation-type.d.ts +9 -0
  88. package/src/definition/model/relations/relation-type.js +9 -0
  89. package/src/definition/model/relations/relations-definition-validator.d.ts +15 -0
  90. package/src/definition/model/relations/relations-definition-validator.js +449 -0
  91. package/src/definition/model/relations/relations-definition-validator.spec.js +772 -0
  92. package/src/errors/index.d.ts +3 -0
  93. package/src/errors/index.js +3 -0
  94. package/src/errors/invalid-argument-error.d.ts +6 -0
  95. package/src/errors/invalid-argument-error.js +6 -0
  96. package/src/errors/invalid-argument-error.spec.js +33 -0
  97. package/src/errors/invalid-operator-value-error.d.ts +13 -0
  98. package/src/errors/invalid-operator-value-error.js +24 -0
  99. package/src/errors/invalid-operator-value-error.spec.js +11 -0
  100. package/src/errors/not-implemented-error.d.ts +6 -0
  101. package/src/errors/not-implemented-error.js +6 -0
  102. package/src/errors/not-implemented-error.spec.js +33 -0
  103. package/src/filter/fields-clause-tool.d.ts +38 -0
  104. package/src/filter/fields-clause-tool.js +88 -0
  105. package/src/filter/fields-clause-tool.spec.js +133 -0
  106. package/src/filter/filter.d.ts +335 -0
  107. package/src/filter/include-clause-tool.d.ts +53 -0
  108. package/src/filter/include-clause-tool.js +364 -0
  109. package/src/filter/include-clause-tool.spec.js +653 -0
  110. package/src/filter/index.d.ts +7 -0
  111. package/src/filter/index.js +6 -0
  112. package/src/filter/operator-clause-tool.d.ts +223 -0
  113. package/src/filter/operator-clause-tool.js +515 -0
  114. package/src/filter/operator-clause-tool.spec.js +1064 -0
  115. package/src/filter/order-clause-tool.d.ts +32 -0
  116. package/src/filter/order-clause-tool.js +97 -0
  117. package/src/filter/order-clause-tool.spec.js +438 -0
  118. package/src/filter/slice-clause-tool.d.ts +30 -0
  119. package/src/filter/slice-clause-tool.js +65 -0
  120. package/src/filter/slice-clause-tool.spec.js +117 -0
  121. package/src/filter/where-clause-tool.d.ts +23 -0
  122. package/src/filter/where-clause-tool.js +165 -0
  123. package/src/filter/where-clause-tool.spec.js +280 -0
  124. package/src/index.d.ts +9 -0
  125. package/src/index.js +8 -0
  126. package/src/relations/belongs-to-resolver.d.ts +46 -0
  127. package/src/relations/belongs-to-resolver.js +242 -0
  128. package/src/relations/belongs-to-resolver.spec.js +1047 -0
  129. package/src/relations/has-many-resolver.d.ts +67 -0
  130. package/src/relations/has-many-resolver.js +317 -0
  131. package/src/relations/has-many-resolver.spec.js +2911 -0
  132. package/src/relations/has-one-resolver.d.ts +67 -0
  133. package/src/relations/has-one-resolver.js +311 -0
  134. package/src/relations/has-one-resolver.spec.js +2274 -0
  135. package/src/relations/index.d.ts +4 -0
  136. package/src/relations/index.js +4 -0
  137. package/src/relations/references-many-resolver.d.ts +27 -0
  138. package/src/relations/references-many-resolver.js +113 -0
  139. package/src/relations/references-many-resolver.spec.js +631 -0
  140. package/src/repository/index.d.ts +2 -0
  141. package/src/repository/index.js +2 -0
  142. package/src/repository/repository-registry.d.ts +29 -0
  143. package/src/repository/repository-registry.js +57 -0
  144. package/src/repository/repository-registry.spec.js +38 -0
  145. package/src/repository/repository.d.ts +164 -0
  146. package/src/repository/repository.js +207 -0
  147. package/src/repository/repository.spec.js +202 -0
  148. package/src/schema.d.ts +37 -0
  149. package/src/schema.js +41 -0
  150. package/src/types.d.ts +30 -0
  151. package/src/utils/capitalize.d.ts +6 -0
  152. package/src/utils/capitalize.js +10 -0
  153. package/src/utils/capitalize.spec.js +14 -0
  154. package/src/utils/clone-deep.d.ts +6 -0
  155. package/src/utils/clone-deep.js +61 -0
  156. package/src/utils/clone-deep.spec.js +28 -0
  157. package/src/utils/exclude-object-keys.d.ts +10 -0
  158. package/src/utils/exclude-object-keys.js +20 -0
  159. package/src/utils/exclude-object-keys.spec.js +49 -0
  160. package/src/utils/get-ctor-name.d.ts +6 -0
  161. package/src/utils/get-ctor-name.js +11 -0
  162. package/src/utils/get-ctor-name.spec.js +17 -0
  163. package/src/utils/get-value-by-path.d.ts +12 -0
  164. package/src/utils/get-value-by-path.js +23 -0
  165. package/src/utils/get-value-by-path.spec.js +36 -0
  166. package/src/utils/index.d.ts +10 -0
  167. package/src/utils/index.js +10 -0
  168. package/src/utils/is-ctor.d.ts +7 -0
  169. package/src/utils/is-ctor.js +10 -0
  170. package/src/utils/is-ctor.spec.js +26 -0
  171. package/src/utils/is-pure-object.d.ts +6 -0
  172. package/src/utils/is-pure-object.js +15 -0
  173. package/src/utils/is-pure-object.spec.js +25 -0
  174. package/src/utils/select-object-keys.d.ts +10 -0
  175. package/src/utils/select-object-keys.js +37 -0
  176. package/src/utils/select-object-keys.spec.js +40 -0
  177. package/src/utils/singularize.d.ts +6 -0
  178. package/src/utils/singularize.js +22 -0
  179. package/src/utils/singularize.spec.js +23 -0
  180. package/src/utils/string-to-regexp.d.ts +10 -0
  181. package/src/utils/string-to-regexp.js +22 -0
  182. package/src/utils/string-to-regexp.spec.js +35 -0
  183. package/tsconfig.json +9 -0
@@ -0,0 +1,117 @@
1
+ import {expect} from 'chai';
2
+ import {format} from '@e22m4u/js-format';
3
+ import {SliceClauseTool} from './slice-clause-tool.js';
4
+
5
+ const S = new SliceClauseTool();
6
+
7
+ describe('SliceClauseTool', function () {
8
+ describe('filter', function () {
9
+ it('does nothing if no clauses provided', function () {
10
+ const objects = [{id: 1}, {id: 2}, {id: 3}];
11
+ const result = S.slice(objects);
12
+ expect(result).to.be.eql(objects);
13
+ });
14
+
15
+ it('does nothing if a given skip is zero', function () {
16
+ const objects = [{id: 1}, {id: 2}, {id: 3}];
17
+ const result = S.slice(objects, 0);
18
+ expect(result).to.be.eql(objects);
19
+ });
20
+
21
+ it('uses a given skip to exclude array elements from start', function () {
22
+ const objects = [{id: 1}, {id: 2}, {id: 3}];
23
+ const result = S.slice(objects, 2);
24
+ expect(result).to.have.length(1);
25
+ expect(result[0]).to.be.eql(objects[2]);
26
+ });
27
+
28
+ it('returns an empty array if skipping too much', function () {
29
+ const objects = [{id: 1}, {id: 2}, {id: 3}];
30
+ const result = S.slice(objects, 10);
31
+ expect(result).to.have.length(0);
32
+ });
33
+
34
+ it('does nothing if a given limit is zero', function () {
35
+ const objects = [{id: 1}, {id: 2}, {id: 3}];
36
+ const result = S.slice(objects, undefined, 0);
37
+ expect(result).to.be.eql(objects);
38
+ });
39
+
40
+ it('uses a given limit to trim a given array', function () {
41
+ const objects = [{id: 1}, {id: 2}, {id: 3}];
42
+ const result = S.slice(objects, undefined, 2);
43
+ expect(result).to.have.length(2);
44
+ expect(result[0]).to.be.eql(objects[0]);
45
+ expect(result[1]).to.be.eql(objects[1]);
46
+ });
47
+
48
+ it('able to combine a skip and a limit option together', function () {
49
+ const objects = [{id: 1}, {id: 2}, {id: 3}];
50
+ const result = S.slice(objects, 1, 1);
51
+ expect(result).to.have.length(1);
52
+ expect(result[0]).to.be.eql(objects[1]);
53
+ });
54
+
55
+ it('throws an error if a first argument is not an array', function () {
56
+ const throwable = () => S.slice(10);
57
+ expect(throwable).to.throw(
58
+ 'A first argument of SliceClauseTool.slice ' +
59
+ 'should be an Array, but 10 given.',
60
+ );
61
+ });
62
+
63
+ it('throws an error if the given "skip" option is not a number', function () {
64
+ const throwable = () => S.slice([], 'invalid');
65
+ expect(throwable).to.throw(
66
+ 'The provided option "skip" should be a Number, but "invalid" given.',
67
+ );
68
+ });
69
+
70
+ it('throws an error if the given "limit" option is not a number', function () {
71
+ const throwable = () => S.slice([], undefined, 'invalid');
72
+ expect(throwable).to.throw(
73
+ 'The provided option "limit" should be a Number, but "invalid" given.',
74
+ );
75
+ });
76
+ });
77
+
78
+ describe('validateSkipClause', function () {
79
+ it('requires a number value or a falsy value', function () {
80
+ const validate = v => () => SliceClauseTool.validateSkipClause(v);
81
+ const error = v =>
82
+ format(
83
+ 'The provided option "skip" should be a Number, but %s given.',
84
+ v,
85
+ );
86
+ expect(validate('str')).to.throw(error('"str"'));
87
+ expect(validate(true)).to.throw(error('true'));
88
+ expect(validate([])).to.throw(error('Array'));
89
+ validate('')();
90
+ validate(false)();
91
+ validate(undefined)();
92
+ validate(null)();
93
+ validate(10)();
94
+ validate(0)();
95
+ });
96
+ });
97
+
98
+ describe('validateLimitClause', function () {
99
+ it('requires a number value or a falsy value', function () {
100
+ const validate = v => () => SliceClauseTool.validateLimitClause(v);
101
+ const error = v =>
102
+ format(
103
+ 'The provided option "limit" should be a Number, but %s given.',
104
+ v,
105
+ );
106
+ expect(validate('str')).to.throw(error('"str"'));
107
+ expect(validate(true)).to.throw(error('true'));
108
+ expect(validate([])).to.throw(error('Array'));
109
+ validate('')();
110
+ validate(false)();
111
+ validate(undefined)();
112
+ validate(null)();
113
+ validate(10)();
114
+ validate(0)();
115
+ });
116
+ });
117
+ });
@@ -0,0 +1,23 @@
1
+ import {ModelData} from '../types.js';
2
+ import {WhereClause} from './filter.js';
3
+ import {Service} from '@e22m4u/js-service';
4
+
5
+ /**
6
+ * Where clause tool.
7
+ */
8
+ export declare class WhereClauseTool extends Service {
9
+ /**
10
+ * Filter.
11
+ *
12
+ * @param entities
13
+ * @param where
14
+ */
15
+ filter(entities: ModelData[], where: WhereClause | undefined): ModelData[];
16
+
17
+ /**
18
+ * Validate where clause.
19
+ *
20
+ * @param clause
21
+ */
22
+ static validateWhereClause(clause: WhereClause | undefined): void;
23
+ }
@@ -0,0 +1,165 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {getValueByPath} from '../utils/index.js';
3
+ import {InvalidArgumentError} from '../errors/index.js';
4
+ import {OperatorClauseTool} from './operator-clause-tool.js';
5
+
6
+ /**
7
+ * Where clause tool.
8
+ *
9
+ * @typedef {object|Function} WhereClause
10
+ */
11
+ export class WhereClauseTool extends Service {
12
+ /**
13
+ * Filter by where clause.
14
+ *
15
+ * @example
16
+ * ```
17
+ * const entities = [
18
+ * {foo: 1, bar: 'a'},
19
+ * {foo: 2, bar: 'b'},
20
+ * {foo: 3, bar: 'b'},
21
+ * {foo: 4, bar: 'b'},
22
+ * ];
23
+ *
24
+ * const result = filterByWhereClause(entities, {
25
+ * foo: {gt: 2},
26
+ * bar: 'b',
27
+ * });
28
+ *
29
+ * console.log(result);
30
+ * // [
31
+ * // {foo: 3, bar: 'b'},
32
+ * // {foo: 4, bar: 'b'},
33
+ * // ];
34
+ *
35
+ * ```
36
+ *
37
+ * @param {object[]} entities
38
+ * @param {WhereClause|undefined} where
39
+ * @returns {object[]}
40
+ */
41
+ filter(entities, where = undefined) {
42
+ if (!Array.isArray(entities))
43
+ throw new InvalidArgumentError(
44
+ 'A first argument of WhereUtils.filter ' +
45
+ 'should be an Array of Objects, but %v given.',
46
+ entities,
47
+ );
48
+ if (!where) return entities;
49
+ return entities.filter(this._createFilter(where));
50
+ }
51
+
52
+ /**
53
+ * Create where filter.
54
+ *
55
+ * @param {WhereClause} whereClause
56
+ * @returns {Function}
57
+ */
58
+ _createFilter(whereClause) {
59
+ if (typeof whereClause === 'function') return whereClause;
60
+ if (typeof whereClause !== 'object')
61
+ throw new InvalidArgumentError(
62
+ 'The provided option "where" should be an Object, but %v given.',
63
+ whereClause,
64
+ );
65
+ const keys = Object.keys(whereClause);
66
+ return data => {
67
+ if (typeof data !== 'object')
68
+ throw new InvalidArgumentError(
69
+ 'A first argument of WhereUtils.filter ' +
70
+ 'should be an Array of Objects, but %v given.',
71
+ data,
72
+ );
73
+ return keys.every(key => {
74
+ // AndClause (recursion)
75
+ if (key === 'and' && key in whereClause) {
76
+ const andClause = whereClause[key];
77
+ if (Array.isArray(andClause))
78
+ return andClause.every(clause => this._createFilter(clause)(data));
79
+ // OrClause (recursion)
80
+ } else if (key === 'or' && key in whereClause) {
81
+ const orClause = whereClause[key];
82
+ if (Array.isArray(orClause))
83
+ return orClause.some(clause => this._createFilter(clause)(data));
84
+ }
85
+ // PropertiesClause (properties)
86
+ const value = getValueByPath(data, key);
87
+ const matcher = whereClause[key];
88
+ // Property value is an array.
89
+ if (Array.isArray(value)) {
90
+ // {neq: ...}
91
+ if (
92
+ typeof matcher === 'object' &&
93
+ matcher !== null &&
94
+ 'neq' in matcher &&
95
+ matcher.neq !== undefined
96
+ ) {
97
+ // The following condition is for the case where
98
+ // we are querying with a neq filter, and when
99
+ // the value is an empty array ([]).
100
+ if (value.length === 0) return true;
101
+ // The neq operator requires each element
102
+ // of the array to be excluded.
103
+ return value.every((el, index) => {
104
+ const where = {};
105
+ where[index] = matcher;
106
+ return this._createFilter(where)({...value});
107
+ });
108
+ }
109
+ // Requires one of an array elements to be match.
110
+ return value.some((el, index) => {
111
+ const where = {};
112
+ where[index] = matcher;
113
+ return this._createFilter(where)({...value});
114
+ });
115
+ }
116
+ // Test property value.
117
+ if (this._test(matcher, value)) return true;
118
+ });
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Value testing.
124
+ *
125
+ * @param {*} example
126
+ * @param {*} value
127
+ * @returns {boolean}
128
+ */
129
+ _test(example, value) {
130
+ // Test null.
131
+ if (example == null) {
132
+ return value == null;
133
+ }
134
+ // Test RegExp.
135
+ // noinspection ALL
136
+ if (example instanceof RegExp) {
137
+ if (typeof value === 'string') return !!value.match(example);
138
+ return false;
139
+ }
140
+ // Operator clause.
141
+ if (typeof example === 'object') {
142
+ const operatorsTest = this.getService(OperatorClauseTool).testAll(
143
+ example,
144
+ value,
145
+ );
146
+ if (operatorsTest !== undefined) return operatorsTest;
147
+ }
148
+ // Not strict equality.
149
+ return example == value;
150
+ }
151
+
152
+ /**
153
+ * Validate where clause.
154
+ *
155
+ * @param {WhereClause|undefined} clause
156
+ */
157
+ static validateWhereClause(clause) {
158
+ if (!clause) return;
159
+ if (typeof clause !== 'object' || Array.isArray(clause))
160
+ throw new InvalidArgumentError(
161
+ 'The provided option "where" should be an Object, but %v given.',
162
+ clause,
163
+ );
164
+ }
165
+ }
@@ -0,0 +1,280 @@
1
+ import {expect} from 'chai';
2
+ import {format} from '@e22m4u/js-format';
3
+ import {WhereClauseTool} from './where-clause-tool.js';
4
+
5
+ const S = new WhereClauseTool();
6
+
7
+ const OBJECTS = [
8
+ {
9
+ id: 1,
10
+ name: 'John',
11
+ surname: 'Doe',
12
+ age: 21,
13
+ hobbies: ['bicycle', 'yoga'],
14
+ nickname: 'Spear',
15
+ birthdate: '2002-04-14',
16
+ },
17
+ {
18
+ id: 2,
19
+ name: 'Mary',
20
+ surname: 'Smith',
21
+ age: 21,
22
+ hobbies: ['yoga', 'meditation'],
23
+ nickname: 'Flower',
24
+ birthdate: '2002-01-12',
25
+ },
26
+ {
27
+ id: 3,
28
+ name: 'James',
29
+ surname: 'Smith',
30
+ age: 21,
31
+ hobbies: [],
32
+ nickname: null,
33
+ birthdate: '2002-03-01',
34
+ },
35
+ {
36
+ id: 4,
37
+ name: 'Oliver',
38
+ surname: 'Smith',
39
+ age: 32,
40
+ hobbies: ['bicycle'],
41
+ birthdate: '1991-06-24',
42
+ },
43
+ ];
44
+
45
+ describe('WhereClauseTool', function () {
46
+ describe('filter', function () {
47
+ it('returns the same array if no given condition', function () {
48
+ const result = S.filter(OBJECTS);
49
+ expect(result).to.be.eql(OBJECTS);
50
+ });
51
+
52
+ it('returns a filtered array by matched properties', function () {
53
+ const result = S.filter(OBJECTS, {surname: 'Smith', age: 21});
54
+ expect(result).to.have.length(2);
55
+ expect(result[0]).to.be.eql(OBJECTS[1]);
56
+ expect(result[1]).to.be.eql(OBJECTS[2]);
57
+ });
58
+
59
+ it('the and operator requires each given condition to be met', function () {
60
+ const result = S.filter(OBJECTS, {
61
+ and: [{name: 'James'}, {age: 21}],
62
+ });
63
+ expect(result).to.have.length(1);
64
+ expect(result[0]).to.be.eql(OBJECTS[2]);
65
+ });
66
+
67
+ it('the or operator requires one of a given condition to be met', function () {
68
+ const result = S.filter(OBJECTS, {
69
+ or: [{name: 'James'}, {age: 21}],
70
+ });
71
+ expect(result).to.have.length(3);
72
+ expect(result[0]).to.be.eql(OBJECTS[0]);
73
+ expect(result[1]).to.be.eql(OBJECTS[1]);
74
+ expect(result[2]).to.be.eql(OBJECTS[2]);
75
+ });
76
+
77
+ it('uses property value to match an array value', function () {
78
+ const result = S.filter(OBJECTS, {hobbies: 'yoga'});
79
+ expect(result).to.have.length(2);
80
+ expect(result[0]).to.be.eql(OBJECTS[0]);
81
+ expect(result[1]).to.be.eql(OBJECTS[1]);
82
+ });
83
+
84
+ it('uses given RegExp to match a property value', function () {
85
+ const result = S.filter(OBJECTS, {surname: /^Sm.+/});
86
+ expect(result).to.have.length(3);
87
+ expect(result[0]).to.be.eql(OBJECTS[1]);
88
+ expect(result[1]).to.be.eql(OBJECTS[2]);
89
+ expect(result[2]).to.be.eql(OBJECTS[3]);
90
+ });
91
+
92
+ it('uses given RegExp to match an array value', function () {
93
+ const result = S.filter(OBJECTS, {hobbies: /^\w+cycle/});
94
+ expect(result).to.have.length(2);
95
+ expect(result[0]).to.be.eql(OBJECTS[0]);
96
+ expect(result[1]).to.be.eql(OBJECTS[3]);
97
+ });
98
+
99
+ it('skips not supported values for RegExp', function () {
100
+ const result = S.filter(OBJECTS, {id: /test/});
101
+ expect(result).to.be.empty;
102
+ });
103
+
104
+ it('uses an "eq" operator to match equality', function () {
105
+ const result = S.filter(OBJECTS, {name: {eq: 'John'}});
106
+ expect(result).to.have.length(1);
107
+ expect(result[0]).to.be.eql(OBJECTS[0]);
108
+ });
109
+
110
+ it('uses a "neq" operator to match non-equality', function () {
111
+ const result = S.filter(OBJECTS, {name: {neq: 'John'}});
112
+ expect(result).to.have.length(3);
113
+ expect(result[0]).to.be.eql(OBJECTS[1]);
114
+ expect(result[1]).to.be.eql(OBJECTS[2]);
115
+ expect(result[2]).to.be.eql(OBJECTS[3]);
116
+ });
117
+
118
+ it('uses a "neq" operator to match an empty array', function () {
119
+ const result = S.filter(OBJECTS, {hobbies: {neq: 'bicycle'}});
120
+ expect(result).to.have.length(2);
121
+ expect(result[0]).to.be.eql(OBJECTS[1]);
122
+ expect(result[1]).to.be.eql(OBJECTS[2]);
123
+ });
124
+
125
+ it('uses a "gt" operator to compare values', function () {
126
+ const result = S.filter(OBJECTS, {id: {gt: 2}});
127
+ expect(result).to.have.length(2);
128
+ expect(result[0]).to.be.eql(OBJECTS[2]);
129
+ expect(result[1]).to.be.eql(OBJECTS[3]);
130
+ });
131
+
132
+ it('uses a "gte" operator to compare values', function () {
133
+ const result = S.filter(OBJECTS, {id: {gte: 2}});
134
+ expect(result).to.have.length(3);
135
+ expect(result[0]).to.be.eql(OBJECTS[1]);
136
+ expect(result[1]).to.be.eql(OBJECTS[2]);
137
+ expect(result[2]).to.be.eql(OBJECTS[3]);
138
+ });
139
+
140
+ it('uses a "lt" operator to compare values', function () {
141
+ const result = S.filter(OBJECTS, {id: {lt: 3}});
142
+ expect(result).to.have.length(2);
143
+ expect(result[0]).to.be.eql(OBJECTS[0]);
144
+ expect(result[1]).to.be.eql(OBJECTS[1]);
145
+ });
146
+
147
+ it('uses a "lte" operator to compare values', function () {
148
+ const result = S.filter(OBJECTS, {id: {lte: 3}});
149
+ expect(result).to.have.length(3);
150
+ expect(result[0]).to.be.eql(OBJECTS[0]);
151
+ expect(result[1]).to.be.eql(OBJECTS[1]);
152
+ expect(result[2]).to.be.eql(OBJECTS[2]);
153
+ });
154
+
155
+ it('uses a "inq" operator to compare values', function () {
156
+ const result = S.filter(OBJECTS, {id: {inq: [2, 3]}});
157
+ expect(result).to.have.length(2);
158
+ expect(result[0]).to.be.eql(OBJECTS[1]);
159
+ expect(result[1]).to.be.eql(OBJECTS[2]);
160
+ });
161
+
162
+ it('uses a "nin" operator to compare values', function () {
163
+ const result = S.filter(OBJECTS, {id: {nin: [2, 3]}});
164
+ expect(result).to.have.length(2);
165
+ expect(result[0]).to.be.eql(OBJECTS[0]);
166
+ expect(result[1]).to.be.eql(OBJECTS[3]);
167
+ });
168
+
169
+ it('uses a "between" operator to compare values', function () {
170
+ const result = S.filter(OBJECTS, {id: {between: [2, 3]}});
171
+ expect(result).to.have.length(2);
172
+ expect(result[0]).to.be.eql(OBJECTS[1]);
173
+ expect(result[1]).to.be.eql(OBJECTS[2]);
174
+ });
175
+
176
+ it('uses an "exists" operator to check existence', function () {
177
+ const result = S.filter(OBJECTS, {nickname: {exists: true}});
178
+ expect(result).to.have.length(3);
179
+ expect(result[0]).to.be.eql(OBJECTS[0]);
180
+ expect(result[1]).to.be.eql(OBJECTS[1]);
181
+ expect(result[2]).to.be.eql(OBJECTS[2]);
182
+ });
183
+
184
+ it('uses an "exists" operator to check non-existence', function () {
185
+ const result = S.filter(OBJECTS, {nickname: {exists: false}});
186
+ expect(result).to.have.length(1);
187
+ expect(result[0]).to.be.eql(OBJECTS[3]);
188
+ });
189
+
190
+ it('uses a "like" operator to match by a substring', function () {
191
+ const result = S.filter(OBJECTS, {name: {like: 'liv'}});
192
+ expect(result).to.have.length(1);
193
+ expect(result[0]).to.be.eql(OBJECTS[3]);
194
+ });
195
+
196
+ it('uses a "nlike" operator to exclude by a substring', function () {
197
+ const result = S.filter(OBJECTS, {name: {nlike: 'liv'}});
198
+ expect(result).to.have.length(3);
199
+ expect(result[0]).to.be.eql(OBJECTS[0]);
200
+ expect(result[1]).to.be.eql(OBJECTS[1]);
201
+ expect(result[2]).to.be.eql(OBJECTS[2]);
202
+ });
203
+
204
+ it('uses a "ilike" operator to case-insensitively matching by a substring', function () {
205
+ const result = S.filter(OBJECTS, {name: {ilike: 'LIV'}});
206
+ expect(result).to.have.length(1);
207
+ expect(result[0]).to.be.eql(OBJECTS[3]);
208
+ });
209
+
210
+ it('uses a "nilike" operator to exclude case-insensitively by a substring', function () {
211
+ const result = S.filter(OBJECTS, {name: {nilike: 'LIV'}});
212
+ expect(result).to.have.length(3);
213
+ expect(result[0]).to.be.eql(OBJECTS[0]);
214
+ expect(result[1]).to.be.eql(OBJECTS[1]);
215
+ expect(result[2]).to.be.eql(OBJECTS[2]);
216
+ });
217
+
218
+ it('uses a "regexp" operator to compare values', function () {
219
+ const result = S.filter(OBJECTS, {name: {regexp: '^Jam.*'}});
220
+ expect(result).to.have.length(1);
221
+ expect(result[0]).to.be.eql(OBJECTS[2]);
222
+ });
223
+
224
+ it('uses a null to match an undefined and null value', function () {
225
+ const result = S.filter(OBJECTS, {nickname: null});
226
+ expect(result).to.have.length(2);
227
+ expect(result[0]).to.be.eql(OBJECTS[2]);
228
+ expect(result[1]).to.be.eql(OBJECTS[3]);
229
+ });
230
+
231
+ it('uses a given function to filter values', function () {
232
+ const result = S.filter(OBJECTS, v => v.nickname === 'Flower');
233
+ expect(result).to.have.length(1);
234
+ expect(result[0]).to.be.eql(OBJECTS[1]);
235
+ });
236
+
237
+ it('throws an error if a first argument is not an Array', function () {
238
+ const throwable = () => S.filter(10, {});
239
+ expect(throwable).to.throw(
240
+ 'A first argument of WhereUtils.filter ' +
241
+ 'should be an Array of Objects, but 10 given.',
242
+ );
243
+ });
244
+
245
+ it('throws an error if elements of a first argument is not an Object', function () {
246
+ const throwable = () => S.filter([10], {});
247
+ expect(throwable).to.throw(
248
+ 'A first argument of WhereUtils.filter ' +
249
+ 'should be an Array of Objects, but 10 given.',
250
+ );
251
+ });
252
+
253
+ it('throws an error if a provided second argument is not an Object', function () {
254
+ const throwable = () => S.filter([], 10);
255
+ expect(throwable).to.throw(
256
+ 'The provided option "where" should be an Object, but 10 given.',
257
+ );
258
+ });
259
+ });
260
+
261
+ describe('validateWhereClause', function () {
262
+ it('requires an object value or a falsy value', function () {
263
+ const validate = v => () => WhereClauseTool.validateWhereClause(v);
264
+ const error = v =>
265
+ format(
266
+ 'The provided option "where" should be an Object, but %s given.',
267
+ v,
268
+ );
269
+ expect(validate('str')).to.throw(error('"str"'));
270
+ expect(validate(10)).to.throw(error('10'));
271
+ expect(validate(true)).to.throw(error('true'));
272
+ expect(validate([])).to.throw(error('Array'));
273
+ validate('')();
274
+ validate(false)();
275
+ validate(undefined)();
276
+ validate(null)();
277
+ validate({})();
278
+ });
279
+ });
280
+ });
package/src/index.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ export * from './types.js';
2
+ export * from './schema.js';
3
+ export * from './utils/index.js';
4
+ export * from './filter/index.js';
5
+ export * from './errors/index.js';
6
+ export * from './adapter/index.js';
7
+ export * from './relations/index.js';
8
+ export * from './definition/index.js';
9
+ export * from './repository/index.js';
package/src/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export * from './schema.js';
2
+ export * from './utils/index.js';
3
+ export * from './errors/index.js';
4
+ export * from './filter/index.js';
5
+ export * from './adapter/index.js';
6
+ export * from './relations/index.js';
7
+ export * from './definition/index.js';
8
+ export * from './repository/index.js';
@@ -0,0 +1,46 @@
1
+ import {ModelData} from '../types.js';
2
+ import {Filter} from '../filter/index.js';
3
+ import {Service} from '@e22m4u/js-service';
4
+
5
+ /**
6
+ * Belongs to resolver.
7
+ */
8
+ export declare class BelongsToResolver extends Service {
9
+ /**
10
+ * Include to.
11
+ *
12
+ * @param entities
13
+ * @param sourceName
14
+ * @param targetName
15
+ * @param relationName
16
+ * @param foreignKey
17
+ * @param scope
18
+ */
19
+ includeTo(
20
+ entities: ModelData[],
21
+ sourceName: string,
22
+ targetName: string,
23
+ relationName: string,
24
+ foreignKey?: string,
25
+ scope?: Filter,
26
+ ): Promise<void>;
27
+
28
+ /**
29
+ * Include polymorphic to.
30
+ *
31
+ * @param entities
32
+ * @param sourceName
33
+ * @param relationName
34
+ * @param foreignKey
35
+ * @param discriminator
36
+ * @param scope
37
+ */
38
+ includePolymorphicTo(
39
+ entities: ModelData[],
40
+ sourceName: string,
41
+ relationName: string,
42
+ foreignKey?: string,
43
+ discriminator?: string,
44
+ scope?: Filter,
45
+ ): Promise<void>;
46
+ }