@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,772 @@
1
+ import {expect} from 'chai';
2
+ import {format} from '@e22m4u/js-format';
3
+ import {RelationType} from './relation-type.js';
4
+ import {RelationsDefinitionValidator} from './relations-definition-validator.js';
5
+
6
+ const S = new RelationsDefinitionValidator();
7
+
8
+ describe('RelationsDefinitionValidator', function () {
9
+ describe('validate', function () {
10
+ it('requires a first argument to be a non-empty string', function () {
11
+ const validate = v => () => S.validate(v, {});
12
+ const error = v =>
13
+ format(
14
+ 'A first argument of RelationsDefinitionValidator.validate ' +
15
+ 'should be a non-empty String, but %s given.',
16
+ v,
17
+ );
18
+ expect(validate('')).to.throw(error('""'));
19
+ expect(validate(10)).to.throw(error('10'));
20
+ expect(validate(true)).to.throw(error('true'));
21
+ expect(validate(false)).to.throw(error('false'));
22
+ expect(validate([])).to.throw(error('Array'));
23
+ expect(validate({})).to.throw(error('Object'));
24
+ expect(validate(undefined)).to.throw(error('undefined'));
25
+ expect(validate(null)).to.throw(error('null'));
26
+ validate('model')();
27
+ });
28
+
29
+ it('requires a second argument to be an object', function () {
30
+ const validate = v => () => S.validate('model', v);
31
+ const error = v =>
32
+ format(
33
+ 'The provided option "relations" of the model "model" ' +
34
+ 'should be an Object, but %s given.',
35
+ v,
36
+ );
37
+ expect(validate('str')).to.throw(error('"str"'));
38
+ expect(validate(10)).to.throw(error('10'));
39
+ expect(validate(true)).to.throw(error('true'));
40
+ expect(validate(false)).to.throw(error('false'));
41
+ expect(validate([])).to.throw(error('Array'));
42
+ expect(validate(undefined)).to.throw(error('undefined'));
43
+ expect(validate(null)).to.throw(error('null'));
44
+ validate({})();
45
+ });
46
+
47
+ it('requires a relation name to be a non-empty string', function () {
48
+ const validate = v => () => S.validate('model', v);
49
+ const error = v =>
50
+ format(
51
+ 'The relation name of the model "model" should be ' +
52
+ 'a non-empty String, but %s given.',
53
+ v,
54
+ );
55
+ expect(validate({['']: {}})).to.throw(error('""'));
56
+ validate({foo: {type: RelationType.BELONGS_TO, model: 'model'}})();
57
+ });
58
+
59
+ it('requires a relation definition to be an object', function () {
60
+ const validate = v => () => S.validate('model', {foo: v});
61
+ const error = v =>
62
+ format(
63
+ 'The relation "foo" of the model "model" should ' +
64
+ 'be an Object, but %s given.',
65
+ v,
66
+ );
67
+ expect(validate('str')).to.throw(error('"str"'));
68
+ expect(validate(10)).to.throw(error('10'));
69
+ expect(validate(true)).to.throw(error('true'));
70
+ expect(validate(false)).to.throw(error('false'));
71
+ expect(validate([])).to.throw(error('Array'));
72
+ expect(validate(undefined)).to.throw(error('undefined'));
73
+ expect(validate(null)).to.throw(error('null'));
74
+ validate({type: RelationType.BELONGS_TO, model: 'model'})();
75
+ });
76
+
77
+ it('requires the option "type" to be a RelationType', function () {
78
+ const validate = v => () => {
79
+ const foo = {type: v, model: 'model'};
80
+ S.validate('model', {foo});
81
+ };
82
+ const error = v =>
83
+ format(
84
+ 'The relation "foo" of the model "model" requires the option "type" ' +
85
+ 'to have one of relation types: %l, but %s given.',
86
+ Object.values(RelationType),
87
+ v,
88
+ );
89
+ expect(validate('str')).to.throw(error('"str"'));
90
+ expect(validate(10)).to.throw(error('10'));
91
+ expect(validate(true)).to.throw(error('true'));
92
+ expect(validate(false)).to.throw(error('false'));
93
+ expect(validate([])).to.throw(error('Array'));
94
+ expect(validate({})).to.throw(error('Object'));
95
+ expect(validate(undefined)).to.throw(error('undefined'));
96
+ expect(validate(null)).to.throw(error('null'));
97
+ validate(RelationType.BELONGS_TO)();
98
+ });
99
+
100
+ describe('belongsTo', function () {
101
+ describe('a regular relation', function () {
102
+ it('requires the option "model" to be a non-empty string', function () {
103
+ const validate = v => {
104
+ const foo = {
105
+ type: RelationType.BELONGS_TO,
106
+ model: v,
107
+ };
108
+ return () => S.validate('model', {foo});
109
+ };
110
+ const error = v =>
111
+ format(
112
+ 'The relation "foo" of the model "model" has the type "belongsTo", ' +
113
+ 'so it requires the option "model" to be a non-empty String, ' +
114
+ 'but %s given.',
115
+ v,
116
+ );
117
+ expect(validate('')).to.throw(error('""'));
118
+ expect(validate(10)).to.throw(error('10'));
119
+ expect(validate(true)).to.throw(error('true'));
120
+ expect(validate(false)).to.throw(error('false'));
121
+ expect(validate({})).to.throw(error('Object'));
122
+ expect(validate([])).to.throw(error('Array'));
123
+ expect(validate(undefined)).to.throw(error('undefined'));
124
+ expect(validate(null)).to.throw(error('null'));
125
+ validate('model')();
126
+ });
127
+
128
+ it('expects the provided option "foreignKey" to be a string', function () {
129
+ const validate = v => {
130
+ const foo = {
131
+ type: RelationType.BELONGS_TO,
132
+ model: 'model',
133
+ foreignKey: v,
134
+ };
135
+ return () => S.validate('model', {foo});
136
+ };
137
+ const error = v =>
138
+ format(
139
+ 'The relation "foo" of the model "model" has the type "belongsTo", ' +
140
+ 'so it expects the provided option "foreignKey" to be a String, ' +
141
+ 'but %s given.',
142
+ v,
143
+ );
144
+ expect(validate(10)).to.throw(error('10'));
145
+ expect(validate(true)).to.throw(error('true'));
146
+ expect(validate({})).to.throw(error('Object'));
147
+ expect(validate([])).to.throw(error('Array'));
148
+ validate('foreignKey')();
149
+ validate('')();
150
+ validate(false)();
151
+ validate(undefined)();
152
+ validate(null)();
153
+ });
154
+
155
+ it('throws an error if the option "discriminator" is provided', function () {
156
+ const throwable = () =>
157
+ S.validate('model', {
158
+ foo: {
159
+ type: RelationType.BELONGS_TO,
160
+ model: 'model',
161
+ discriminator: 'referenceType',
162
+ },
163
+ });
164
+ expect(throwable).to.throw(
165
+ 'The relation "foo" of the model "model" is a non-polymorphic "belongsTo" relation, ' +
166
+ 'so it should not have the option "discriminator" to be provided.',
167
+ );
168
+ });
169
+ });
170
+
171
+ describe('a polymorphic relation', function () {
172
+ it('requires the option "polymorphic" to be a boolean', function () {
173
+ const validate = v => {
174
+ const foo = {
175
+ type: RelationType.BELONGS_TO,
176
+ polymorphic: v,
177
+ };
178
+ return () => S.validate('model', {foo});
179
+ };
180
+ const error = v =>
181
+ format(
182
+ 'The relation "foo" of the model "model" has the type "belongsTo", ' +
183
+ 'so it expects the option "polymorphic" to be a Boolean, ' +
184
+ 'but %s given.',
185
+ v,
186
+ );
187
+ expect(validate('str')).to.throw(error('"str"'));
188
+ expect(validate(10)).to.throw(error('10'));
189
+ expect(validate([])).to.throw(error('Array'));
190
+ expect(validate({})).to.throw(error('Object'));
191
+ validate(true)();
192
+ });
193
+
194
+ it('expects the provided option "foreignKey" to be a string', function () {
195
+ const validate = v => {
196
+ const foo = {
197
+ type: RelationType.BELONGS_TO,
198
+ polymorphic: true,
199
+ foreignKey: v,
200
+ };
201
+ return () => S.validate('model', {foo});
202
+ };
203
+ const error = v =>
204
+ format(
205
+ 'The relation "foo" of the model "model" is a polymorphic "belongsTo" relation, ' +
206
+ 'so it expects the provided option "foreignKey" to be a String, ' +
207
+ 'but %s given.',
208
+ v,
209
+ );
210
+ expect(validate(10)).to.throw(error('10'));
211
+ expect(validate(true)).to.throw(error('true'));
212
+ expect(validate({})).to.throw(error('Object'));
213
+ expect(validate([])).to.throw(error('Array'));
214
+ validate('foreignKey')();
215
+ validate('')();
216
+ validate(false)();
217
+ validate(undefined)();
218
+ validate(null)();
219
+ });
220
+
221
+ it('expects the provided option "discriminator" to be a string', function () {
222
+ const validate = v => {
223
+ const foo = {
224
+ type: RelationType.BELONGS_TO,
225
+ polymorphic: true,
226
+ discriminator: v,
227
+ };
228
+ return () => S.validate('model', {foo});
229
+ };
230
+ const error = v =>
231
+ format(
232
+ 'The relation "foo" of the model "model" is a polymorphic "belongsTo" relation, ' +
233
+ 'so it expects the provided option "discriminator" to be a String, ' +
234
+ 'but %s given.',
235
+ v,
236
+ );
237
+ expect(validate(10)).to.throw(error('10'));
238
+ expect(validate(true)).to.throw(error('true'));
239
+ expect(validate({})).to.throw(error('Object'));
240
+ expect(validate([])).to.throw(error('Array'));
241
+ validate('discriminator')();
242
+ validate('')();
243
+ validate(false)();
244
+ validate(undefined)();
245
+ validate(null)();
246
+ });
247
+ });
248
+ });
249
+
250
+ describe('hasOne', function () {
251
+ describe('a regular relation', function () {
252
+ it('requires the option "model" to be a non-empty string', function () {
253
+ const validate = v => {
254
+ const foo = {
255
+ type: RelationType.HAS_ONE,
256
+ model: 'model',
257
+ foreignKey: v,
258
+ };
259
+ return () => S.validate('model', {foo});
260
+ };
261
+ const error = v =>
262
+ format(
263
+ 'The relation "foo" of the model "model" has the type "hasOne", ' +
264
+ 'so it requires the option "foreignKey" to be a non-empty String, ' +
265
+ 'but %s given.',
266
+ v,
267
+ );
268
+ expect(validate('')).to.throw(error('""'));
269
+ expect(validate(10)).to.throw(error('10'));
270
+ expect(validate(true)).to.throw(error('true'));
271
+ expect(validate(false)).to.throw(error('false'));
272
+ expect(validate({})).to.throw(error('Object'));
273
+ expect(validate([])).to.throw(error('Array'));
274
+ expect(validate(undefined)).to.throw(error('undefined'));
275
+ expect(validate(null)).to.throw(error('null'));
276
+ validate('modelId')();
277
+ });
278
+
279
+ it('requires the option "foreignKey" to be a string', function () {
280
+ const validate = v => {
281
+ const foo = {
282
+ type: RelationType.HAS_ONE,
283
+ model: v,
284
+ foreignKey: 'modelId',
285
+ };
286
+ return () => S.validate('model', {foo});
287
+ };
288
+ const error = v =>
289
+ format(
290
+ 'The relation "foo" of the model "model" has the type "hasOne", ' +
291
+ 'so it requires the option "model" to be a non-empty String, ' +
292
+ 'but %s given.',
293
+ v,
294
+ );
295
+ expect(validate('')).to.throw(error('""'));
296
+ expect(validate(10)).to.throw(error('10'));
297
+ expect(validate(true)).to.throw(error('true'));
298
+ expect(validate(false)).to.throw(error('false'));
299
+ expect(validate({})).to.throw(error('Object'));
300
+ expect(validate([])).to.throw(error('Array'));
301
+ expect(validate(undefined)).to.throw(error('undefined'));
302
+ expect(validate(null)).to.throw(error('null'));
303
+ validate('model')();
304
+ });
305
+
306
+ it('throws an error if the option "discriminator" is provided', function () {
307
+ const throwable = () =>
308
+ S.validate('model', {
309
+ foo: {
310
+ type: RelationType.HAS_ONE,
311
+ model: 'model',
312
+ foreignKey: 'modelId',
313
+ discriminator: 'modelType',
314
+ },
315
+ });
316
+ expect(throwable).to.throw(
317
+ 'The relation "foo" of the model "model" is a non-polymorphic "hasOne" relation, ' +
318
+ 'so it should not have the option "discriminator" to be provided.',
319
+ );
320
+ });
321
+ });
322
+
323
+ describe('a polymorphic relation with a target relation name', function () {
324
+ it('requires the option "model" to be a non-empty string', function () {
325
+ const validate = v => {
326
+ const foo = {
327
+ type: RelationType.HAS_ONE,
328
+ model: v,
329
+ polymorphic: 'reference',
330
+ };
331
+ return () => S.validate('model', {foo});
332
+ };
333
+ const error = v =>
334
+ format(
335
+ 'The relation "foo" of the model "model" has the type "hasOne", ' +
336
+ 'so it requires the option "model" to be a non-empty String, ' +
337
+ 'but %s given.',
338
+ v,
339
+ );
340
+ expect(validate('')).to.throw(error('""'));
341
+ expect(validate(10)).to.throw(error('10'));
342
+ expect(validate(true)).to.throw(error('true'));
343
+ expect(validate(false)).to.throw(error('false'));
344
+ expect(validate({})).to.throw(error('Object'));
345
+ expect(validate([])).to.throw(error('Array'));
346
+ expect(validate(undefined)).to.throw(error('undefined'));
347
+ expect(validate(null)).to.throw(error('null'));
348
+ validate('model')();
349
+ });
350
+
351
+ it('throws an error if the option "foreignKey" is provided', function () {
352
+ const throwable = () =>
353
+ S.validate('model', {
354
+ foo: {
355
+ type: RelationType.HAS_ONE,
356
+ model: 'model',
357
+ polymorphic: 'reference',
358
+ foreignKey: 'referenceId',
359
+ },
360
+ });
361
+ expect(throwable).to.throw(
362
+ 'The relation "foo" of the model "model" has the option "polymorphic" with ' +
363
+ 'a String value, so it should not have the option "foreignKey" ' +
364
+ 'to be provided.',
365
+ );
366
+ });
367
+
368
+ it('throws an error if the option "discriminator" is provided', function () {
369
+ const throwable = () =>
370
+ S.validate('model', {
371
+ foo: {
372
+ type: RelationType.HAS_ONE,
373
+ model: 'model',
374
+ polymorphic: 'reference',
375
+ discriminator: 'referenceType',
376
+ },
377
+ });
378
+ expect(throwable).to.throw(
379
+ 'The relation "foo" of the model "model" has the option "polymorphic" with ' +
380
+ 'a String value, so it should not have the option "discriminator" ' +
381
+ 'to be provided.',
382
+ );
383
+ });
384
+ });
385
+
386
+ describe('a polymorphic relation with target relation keys', function () {
387
+ it('requires the option "model" to be a non-empty string', function () {
388
+ const validate = v => {
389
+ const foo = {
390
+ type: RelationType.HAS_ONE,
391
+ model: v,
392
+ polymorphic: true,
393
+ foreignKey: 'referenceId',
394
+ discriminator: 'referenceType',
395
+ };
396
+ return () => S.validate('model', {foo});
397
+ };
398
+ const error = v =>
399
+ format(
400
+ 'The relation "foo" of the model "model" has the type "hasOne", ' +
401
+ 'so it requires the option "model" to be a non-empty String, ' +
402
+ 'but %s given.',
403
+ v,
404
+ );
405
+ expect(validate('')).to.throw(error('""'));
406
+ expect(validate(10)).to.throw(error('10'));
407
+ expect(validate(true)).to.throw(error('true'));
408
+ expect(validate(false)).to.throw(error('false'));
409
+ expect(validate({})).to.throw(error('Object'));
410
+ expect(validate([])).to.throw(error('Array'));
411
+ expect(validate(undefined)).to.throw(error('undefined'));
412
+ expect(validate(null)).to.throw(error('null'));
413
+ validate('model')();
414
+ });
415
+
416
+ it('requires the option "foreignKey" to be a non-empty string', function () {
417
+ const validate = v => {
418
+ const foo = {
419
+ type: RelationType.HAS_ONE,
420
+ model: 'model',
421
+ polymorphic: true,
422
+ foreignKey: v,
423
+ discriminator: 'referenceType',
424
+ };
425
+ return () => S.validate('model', {foo});
426
+ };
427
+ const error = v =>
428
+ format(
429
+ 'The relation "foo" of the model "model" has the option "polymorphic" ' +
430
+ 'with "true" value, so it requires the option "foreignKey" ' +
431
+ 'to be a non-empty String, but %s given.',
432
+ v,
433
+ );
434
+ expect(validate('')).to.throw(error('""'));
435
+ expect(validate(10)).to.throw(error('10'));
436
+ expect(validate(true)).to.throw(error('true'));
437
+ expect(validate(false)).to.throw(error('false'));
438
+ expect(validate({})).to.throw(error('Object'));
439
+ expect(validate([])).to.throw(error('Array'));
440
+ expect(validate(undefined)).to.throw(error('undefined'));
441
+ expect(validate(null)).to.throw(error('null'));
442
+ validate('referenceId')();
443
+ });
444
+
445
+ it('requires the option "discriminator" to be a non-empty string', function () {
446
+ const validate = v => {
447
+ const foo = {
448
+ type: RelationType.HAS_ONE,
449
+ model: 'model',
450
+ polymorphic: true,
451
+ foreignKey: 'referenceId',
452
+ discriminator: v,
453
+ };
454
+ return () => S.validate('model', {foo});
455
+ };
456
+ const error = v =>
457
+ format(
458
+ 'The relation "foo" of the model "model" has the option "polymorphic" ' +
459
+ 'with "true" value, so it requires the option "discriminator" ' +
460
+ 'to be a non-empty String, but %s given.',
461
+ v,
462
+ );
463
+ expect(validate('')).to.throw(error('""'));
464
+ expect(validate(10)).to.throw(error('10'));
465
+ expect(validate(true)).to.throw(error('true'));
466
+ expect(validate(false)).to.throw(error('false'));
467
+ expect(validate({})).to.throw(error('Object'));
468
+ expect(validate([])).to.throw(error('Array'));
469
+ expect(validate(undefined)).to.throw(error('undefined'));
470
+ expect(validate(null)).to.throw(error('null'));
471
+ validate('referenceType')();
472
+ });
473
+ });
474
+ });
475
+
476
+ describe('hasMany', function () {
477
+ describe('a regular relation', function () {
478
+ it('requires the option "model" to be a non-empty string', function () {
479
+ const validate = v => {
480
+ const foo = {
481
+ type: RelationType.HAS_MANY,
482
+ model: 'model',
483
+ foreignKey: v,
484
+ };
485
+ return () => S.validate('model', {foo});
486
+ };
487
+ const error = v =>
488
+ format(
489
+ 'The relation "foo" of the model "model" has the type "hasMany", ' +
490
+ 'so it requires the option "foreignKey" to be a non-empty String, ' +
491
+ 'but %s given.',
492
+ v,
493
+ );
494
+ expect(validate('')).to.throw(error('""'));
495
+ expect(validate(10)).to.throw(error('10'));
496
+ expect(validate(true)).to.throw(error('true'));
497
+ expect(validate(false)).to.throw(error('false'));
498
+ expect(validate({})).to.throw(error('Object'));
499
+ expect(validate([])).to.throw(error('Array'));
500
+ expect(validate(undefined)).to.throw(error('undefined'));
501
+ expect(validate(null)).to.throw(error('null'));
502
+ validate('modelId')();
503
+ });
504
+
505
+ it('requires the option "foreignKey" to be a string', function () {
506
+ const validate = v => {
507
+ const foo = {
508
+ type: RelationType.HAS_MANY,
509
+ model: v,
510
+ foreignKey: 'modelId',
511
+ };
512
+ return () => S.validate('model', {foo});
513
+ };
514
+ const error = v =>
515
+ format(
516
+ 'The relation "foo" of the model "model" has the type "hasMany", ' +
517
+ 'so it requires the option "model" to be a non-empty String, ' +
518
+ 'but %s given.',
519
+ v,
520
+ );
521
+ expect(validate('')).to.throw(error('""'));
522
+ expect(validate(10)).to.throw(error('10'));
523
+ expect(validate(true)).to.throw(error('true'));
524
+ expect(validate(false)).to.throw(error('false'));
525
+ expect(validate({})).to.throw(error('Object'));
526
+ expect(validate([])).to.throw(error('Array'));
527
+ expect(validate(undefined)).to.throw(error('undefined'));
528
+ expect(validate(null)).to.throw(error('null'));
529
+ validate('model')();
530
+ });
531
+
532
+ it('throws an error if the option "discriminator" is provided', function () {
533
+ const throwable = () =>
534
+ S.validate('model', {
535
+ foo: {
536
+ type: RelationType.HAS_MANY,
537
+ model: 'model',
538
+ foreignKey: 'modelId',
539
+ discriminator: 'modelType',
540
+ },
541
+ });
542
+ expect(throwable).to.throw(
543
+ 'The relation "foo" of the model "model" is a non-polymorphic "hasMany" ' +
544
+ 'relation, so it should not have the option "discriminator" to be provided.',
545
+ );
546
+ });
547
+ });
548
+
549
+ describe('a polymorphic relation with a target relation name', function () {
550
+ it('requires the option "model" to be a non-empty string', function () {
551
+ const validate = v => {
552
+ const foo = {
553
+ type: RelationType.HAS_MANY,
554
+ model: v,
555
+ polymorphic: 'reference',
556
+ };
557
+ return () => S.validate('model', {foo});
558
+ };
559
+ const error = v =>
560
+ format(
561
+ 'The relation "foo" of the model "model" has the type "hasMany", ' +
562
+ 'so it requires the option "model" to be a non-empty String, ' +
563
+ 'but %s given.',
564
+ v,
565
+ );
566
+ expect(validate('')).to.throw(error('""'));
567
+ expect(validate(10)).to.throw(error('10'));
568
+ expect(validate(true)).to.throw(error('true'));
569
+ expect(validate(false)).to.throw(error('false'));
570
+ expect(validate({})).to.throw(error('Object'));
571
+ expect(validate([])).to.throw(error('Array'));
572
+ expect(validate(undefined)).to.throw(error('undefined'));
573
+ expect(validate(null)).to.throw(error('null'));
574
+ validate('model')();
575
+ });
576
+
577
+ it('throws an error if the option "foreignKey" is provided', function () {
578
+ const throwable = () =>
579
+ S.validate('model', {
580
+ foo: {
581
+ type: RelationType.HAS_MANY,
582
+ model: 'model',
583
+ polymorphic: 'reference',
584
+ foreignKey: 'referenceId',
585
+ },
586
+ });
587
+ expect(throwable).to.throw(
588
+ 'The relation "foo" of the model "model" has the option "polymorphic" ' +
589
+ 'with a String value, so it should not have the option "foreignKey" ' +
590
+ 'to be provided.',
591
+ );
592
+ });
593
+
594
+ it('throws an error if the option "discriminator" is provided', function () {
595
+ const throwable = () =>
596
+ S.validate('model', {
597
+ foo: {
598
+ type: RelationType.HAS_MANY,
599
+ model: 'model',
600
+ polymorphic: 'reference',
601
+ discriminator: 'referenceType',
602
+ },
603
+ });
604
+ expect(throwable).to.throw(
605
+ 'The relation "foo" of the model "model" has the option "polymorphic" with ' +
606
+ 'a String value, so it should not have the option "discriminator" ' +
607
+ 'to be provided.',
608
+ );
609
+ });
610
+ });
611
+
612
+ describe('a polymorphic relation with target relation keys', function () {
613
+ it('requires the option "model" to be a non-empty string', function () {
614
+ const validate = v => {
615
+ const foo = {
616
+ type: RelationType.HAS_MANY,
617
+ model: v,
618
+ polymorphic: true,
619
+ foreignKey: 'referenceId',
620
+ discriminator: 'referenceType',
621
+ };
622
+ return () => S.validate('model', {foo});
623
+ };
624
+ const error = v =>
625
+ format(
626
+ 'The relation "foo" of the model "model" has the type "hasMany", ' +
627
+ 'so it requires the option "model" to be a non-empty String, ' +
628
+ 'but %s given.',
629
+ v,
630
+ );
631
+ expect(validate('')).to.throw(error('""'));
632
+ expect(validate(10)).to.throw(error('10'));
633
+ expect(validate(true)).to.throw(error('true'));
634
+ expect(validate(false)).to.throw(error('false'));
635
+ expect(validate({})).to.throw(error('Object'));
636
+ expect(validate([])).to.throw(error('Array'));
637
+ expect(validate(undefined)).to.throw(error('undefined'));
638
+ expect(validate(null)).to.throw(error('null'));
639
+ validate('model')();
640
+ });
641
+
642
+ it('requires the option "foreignKey" to be a non-empty string', function () {
643
+ const validate = v => {
644
+ const foo = {
645
+ type: RelationType.HAS_MANY,
646
+ model: 'model',
647
+ polymorphic: true,
648
+ foreignKey: v,
649
+ discriminator: 'referenceType',
650
+ };
651
+ return () => S.validate('model', {foo});
652
+ };
653
+ const error = v =>
654
+ format(
655
+ 'The relation "foo" of the model "model" has the option "polymorphic" ' +
656
+ 'with "true" value, so it requires the option "foreignKey" ' +
657
+ 'to be a non-empty String, but %s given.',
658
+ v,
659
+ );
660
+ expect(validate('')).to.throw(error('""'));
661
+ expect(validate(10)).to.throw(error('10'));
662
+ expect(validate(true)).to.throw(error('true'));
663
+ expect(validate(false)).to.throw(error('false'));
664
+ expect(validate({})).to.throw(error('Object'));
665
+ expect(validate([])).to.throw(error('Array'));
666
+ expect(validate(undefined)).to.throw(error('undefined'));
667
+ expect(validate(null)).to.throw(error('null'));
668
+ validate('referenceId')();
669
+ });
670
+
671
+ it('requires the option "discriminator" to be a non-empty string', function () {
672
+ const validate = v => {
673
+ const foo = {
674
+ type: RelationType.HAS_MANY,
675
+ model: 'model',
676
+ polymorphic: true,
677
+ foreignKey: 'referenceId',
678
+ discriminator: v,
679
+ };
680
+ return () => S.validate('model', {foo});
681
+ };
682
+ const error = v =>
683
+ format(
684
+ 'The relation "foo" of the model "model" has the option "polymorphic" ' +
685
+ 'with "true" value, so it requires the option "discriminator" ' +
686
+ 'to be a non-empty String, but %s given.',
687
+ v,
688
+ );
689
+ expect(validate('')).to.throw(error('""'));
690
+ expect(validate(10)).to.throw(error('10'));
691
+ expect(validate(true)).to.throw(error('true'));
692
+ expect(validate(false)).to.throw(error('false'));
693
+ expect(validate({})).to.throw(error('Object'));
694
+ expect(validate([])).to.throw(error('Array'));
695
+ expect(validate(undefined)).to.throw(error('undefined'));
696
+ expect(validate(null)).to.throw(error('null'));
697
+ validate('referenceType')();
698
+ });
699
+ });
700
+ });
701
+
702
+ describe('referencesMany', function () {
703
+ it('requires the option "model" to be a non-empty string', function () {
704
+ const validate = v => {
705
+ const foo = {
706
+ type: RelationType.REFERENCES_MANY,
707
+ model: v,
708
+ };
709
+ return () => S.validate('model', {foo});
710
+ };
711
+ const error = v =>
712
+ format(
713
+ 'The relation "foo" of the model "model" has the type "referencesMany", ' +
714
+ 'so it requires the option "model" to be a non-empty String, ' +
715
+ 'but %s given.',
716
+ v,
717
+ );
718
+ expect(validate('')).to.throw(error('""'));
719
+ expect(validate(10)).to.throw(error('10'));
720
+ expect(validate(true)).to.throw(error('true'));
721
+ expect(validate(false)).to.throw(error('false'));
722
+ expect(validate({})).to.throw(error('Object'));
723
+ expect(validate([])).to.throw(error('Array'));
724
+ expect(validate(undefined)).to.throw(error('undefined'));
725
+ expect(validate(null)).to.throw(error('null'));
726
+ validate('model')();
727
+ });
728
+
729
+ it('expects the provided option "foreignKey" to be a string', function () {
730
+ const validate = v => {
731
+ const foo = {
732
+ type: RelationType.REFERENCES_MANY,
733
+ model: 'model',
734
+ foreignKey: v,
735
+ };
736
+ return () => S.validate('model', {foo});
737
+ };
738
+ const error = v =>
739
+ format(
740
+ 'The relation "foo" of the model "model" has the type "referencesMany", ' +
741
+ 'so it expects the provided option "foreignKey" to be a String, ' +
742
+ 'but %s given.',
743
+ v,
744
+ );
745
+ expect(validate(10)).to.throw(error('10'));
746
+ expect(validate(true)).to.throw(error('true'));
747
+ expect(validate({})).to.throw(error('Object'));
748
+ expect(validate([])).to.throw(error('Array'));
749
+ validate('foreignKey')();
750
+ validate('')();
751
+ validate(false)();
752
+ validate(undefined)();
753
+ validate(null)();
754
+ });
755
+
756
+ it('throws an error if the option "discriminator" is provided', function () {
757
+ const throwable = () =>
758
+ S.validate('model', {
759
+ foo: {
760
+ type: RelationType.REFERENCES_MANY,
761
+ model: 'model',
762
+ discriminator: 'referenceType',
763
+ },
764
+ });
765
+ expect(throwable).to.throw(
766
+ 'The relation "foo" of the model "model" has the type "referencesMany", ' +
767
+ 'so it should not have the option "discriminator" to be provided.',
768
+ );
769
+ });
770
+ });
771
+ });
772
+ });