@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,449 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {RelationType} from './relation-type.js';
3
+ import {RelationType as Type} from './relation-type.js';
4
+ import {InvalidArgumentError} from '../../../errors/index.js';
5
+
6
+ /**
7
+ * Relations definition validator.
8
+ */
9
+ export class RelationsDefinitionValidator extends Service {
10
+ /**
11
+ * Validate.
12
+ *
13
+ * @param {string} modelName
14
+ * @param {object} relDefs
15
+ */
16
+ validate(modelName, relDefs) {
17
+ if (!modelName || typeof modelName !== 'string')
18
+ throw new InvalidArgumentError(
19
+ 'A first argument of RelationsDefinitionValidator.validate ' +
20
+ 'should be a non-empty String, but %v given.',
21
+ modelName,
22
+ );
23
+ if (!relDefs || typeof relDefs !== 'object' || Array.isArray(relDefs))
24
+ throw new InvalidArgumentError(
25
+ 'The provided option "relations" of the model %v ' +
26
+ 'should be an Object, but %v given.',
27
+ modelName,
28
+ relDefs,
29
+ );
30
+ const relNames = Object.keys(relDefs);
31
+ relNames.forEach(relName => {
32
+ const relDef = relDefs[relName];
33
+ this._validateRelation(modelName, relName, relDef);
34
+ });
35
+ }
36
+
37
+ /**
38
+ * Validate relation.
39
+ *
40
+ * @param {string} modelName
41
+ * @param {string} relName
42
+ * @param {object} relDef
43
+ */
44
+ _validateRelation(modelName, relName, relDef) {
45
+ if (!modelName || typeof modelName !== 'string')
46
+ throw new InvalidArgumentError(
47
+ 'A first argument of RelationsDefinitionValidator._validateRelation ' +
48
+ 'should be a non-empty String, but %v given.',
49
+ modelName,
50
+ );
51
+ if (!relName || typeof relName !== 'string')
52
+ throw new InvalidArgumentError(
53
+ 'The relation name of the model %v should be ' +
54
+ 'a non-empty String, but %v given.',
55
+ modelName,
56
+ relName,
57
+ );
58
+ if (!relDef || typeof relDef !== 'object' || Array.isArray(relDef))
59
+ throw new InvalidArgumentError(
60
+ 'The relation %v of the model %v should be an Object, but %v given.',
61
+ relName,
62
+ modelName,
63
+ relDef,
64
+ );
65
+ if (!relDef.type || !Object.values(Type).includes(relDef.type))
66
+ throw new InvalidArgumentError(
67
+ 'The relation %v of the model %v requires the option "type" ' +
68
+ 'to have one of relation types: %l, but %v given.',
69
+ relName,
70
+ modelName,
71
+ Object.values(Type),
72
+ relDef.type,
73
+ );
74
+ this._validateBelongsTo(modelName, relName, relDef);
75
+ this._validateHasOne(modelName, relName, relDef);
76
+ this._validateHasMany(modelName, relName, relDef);
77
+ this._validateReferencesMany(modelName, relName, relDef);
78
+ }
79
+
80
+ /**
81
+ * Validate "belongsTo".
82
+ *
83
+ * @example The regular "belongsTo" relation.
84
+ * ```
85
+ * {
86
+ * type: RelationType.BELONGS_TO,
87
+ * model: 'model',
88
+ * foreignKey: 'modelId', // optional
89
+ * }
90
+ * ```
91
+ *
92
+ * @example The polymorphic "belongsTo" relation.
93
+ * ```
94
+ * {
95
+ * type: RelationType.BELONGS_TO,
96
+ * polymorphic: true,
97
+ * foreignKey: 'referenceId', // optional
98
+ * discriminator: 'referenceType, // optional
99
+ * }
100
+ * ```
101
+ *
102
+ * @param {string} modelName
103
+ * @param {string} relName
104
+ * @param {object} relDef
105
+ * @private
106
+ */
107
+ _validateBelongsTo(modelName, relName, relDef) {
108
+ if (relDef.type !== Type.BELONGS_TO) return;
109
+ if (relDef.polymorphic) {
110
+ // A polymorphic "belongsTo" relation.
111
+ if (typeof relDef.polymorphic !== 'boolean')
112
+ throw new InvalidArgumentError(
113
+ 'The relation %v of the model %v has the type "belongsTo", ' +
114
+ 'so it expects the option "polymorphic" to be a Boolean, ' +
115
+ 'but %v given.',
116
+ relName,
117
+ modelName,
118
+ relDef.polymorphic,
119
+ );
120
+ if (relDef.foreignKey && typeof relDef.foreignKey !== 'string')
121
+ throw new InvalidArgumentError(
122
+ 'The relation %v of the model %v is a polymorphic "belongsTo" relation, ' +
123
+ 'so it expects the provided option "foreignKey" to be a String, ' +
124
+ 'but %v given.',
125
+ relName,
126
+ modelName,
127
+ relDef.foreignKey,
128
+ );
129
+ if (relDef.discriminator && typeof relDef.discriminator !== 'string')
130
+ throw new InvalidArgumentError(
131
+ 'The relation %v of the model %v is a polymorphic "belongsTo" relation, ' +
132
+ 'so it expects the provided option "discriminator" to be a String, ' +
133
+ 'but %v given.',
134
+ relName,
135
+ modelName,
136
+ relDef.discriminator,
137
+ );
138
+ } else {
139
+ // A regular "belongsTo" relation.
140
+ if (!relDef.model || typeof relDef.model !== 'string')
141
+ throw new InvalidArgumentError(
142
+ 'The relation %v of the model %v has the type "belongsTo", ' +
143
+ 'so it requires the option "model" to be a non-empty String, ' +
144
+ 'but %v given.',
145
+ relName,
146
+ modelName,
147
+ relDef.model,
148
+ );
149
+ if (relDef.foreignKey && typeof relDef.foreignKey !== 'string')
150
+ throw new InvalidArgumentError(
151
+ 'The relation %v of the model %v has the type "belongsTo", ' +
152
+ 'so it expects the provided option "foreignKey" to be a String, ' +
153
+ 'but %v given.',
154
+ relName,
155
+ modelName,
156
+ relDef.foreignKey,
157
+ );
158
+ if (relDef.discriminator)
159
+ throw new InvalidArgumentError(
160
+ 'The relation %v of the model %v is a non-polymorphic "belongsTo" relation, ' +
161
+ 'so it should not have the option "discriminator" to be provided.',
162
+ relName,
163
+ modelName,
164
+ );
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Validate "hasOne".
170
+ *
171
+ * @example The regular "hasOne" relation.
172
+ * ```
173
+ * {
174
+ * type: RelationType.HAS_ONE,
175
+ * model: 'model',
176
+ * foreignKey: 'modelId',
177
+ * }
178
+ * ```
179
+ *
180
+ * @example The polymorphic "hasOne" relation with a target relation name.
181
+ * ```
182
+ * {
183
+ * type: RelationType.HAS_ONE,
184
+ * model: 'model',
185
+ * polymorphic: 'reference',
186
+ * }
187
+ * ```
188
+ *
189
+ * @example The polymorphic "hasOne" relation with target relation keys.
190
+ * ```
191
+ * {
192
+ * type: RelationType.HAS_ONE,
193
+ * model: 'model',
194
+ * polymorphic: true,
195
+ * foreignKey: 'referenceId',
196
+ * discriminator: 'referenceType,
197
+ * }
198
+ * ```
199
+ *
200
+ * @param {string} modelName
201
+ * @param {string} relName
202
+ * @param {object} relDef
203
+ * @private
204
+ */
205
+ _validateHasOne(modelName, relName, relDef) {
206
+ if (relDef.type !== RelationType.HAS_ONE) return;
207
+ if (!relDef.model || typeof relDef.model !== 'string')
208
+ throw new InvalidArgumentError(
209
+ 'The relation %v of the model %v has the type "hasOne", ' +
210
+ 'so it requires the option "model" to be a non-empty String, ' +
211
+ 'but %v given.',
212
+ relName,
213
+ modelName,
214
+ relDef.model,
215
+ );
216
+ if (relDef.polymorphic) {
217
+ if (typeof relDef.polymorphic === 'string') {
218
+ // A polymorphic "hasOne" relation with a target relation name.
219
+ if (relDef.foreignKey)
220
+ throw new InvalidArgumentError(
221
+ 'The relation %v of the model %v has the option "polymorphic" with ' +
222
+ 'a String value, so it should not have the option "foreignKey" ' +
223
+ 'to be provided.',
224
+ relName,
225
+ modelName,
226
+ );
227
+ if (relDef.discriminator)
228
+ throw new InvalidArgumentError(
229
+ 'The relation %v of the model %v has the option "polymorphic" with ' +
230
+ 'a String value, so it should not have the option "discriminator" ' +
231
+ 'to be provided.',
232
+ relName,
233
+ modelName,
234
+ );
235
+ } else if (typeof relDef.polymorphic === 'boolean') {
236
+ // A polymorphic "hasOne" relation with target relation keys.
237
+ if (!relDef.foreignKey || typeof relDef.foreignKey !== 'string')
238
+ throw new InvalidArgumentError(
239
+ 'The relation %v of the model %v has the option "polymorphic" ' +
240
+ 'with "true" value, so it requires the option "foreignKey" ' +
241
+ 'to be a non-empty String, but %v given.',
242
+ relName,
243
+ modelName,
244
+ relDef.foreignKey,
245
+ );
246
+ if (!relDef.discriminator || typeof relDef.discriminator !== 'string')
247
+ throw new InvalidArgumentError(
248
+ 'The relation %v of the model %v has the option "polymorphic" ' +
249
+ 'with "true" value, so it requires the option "discriminator" ' +
250
+ 'to be a non-empty String, but %v given.',
251
+ relName,
252
+ modelName,
253
+ relDef.discriminator,
254
+ );
255
+ } else {
256
+ throw new InvalidArgumentError(
257
+ 'The relation %v of the model %v has the type "hasOne", ' +
258
+ 'so it expects the provided option "polymorphic" to be ' +
259
+ 'a String or a Boolean, but %v given.',
260
+ relName,
261
+ modelName,
262
+ relDef.polymorphic,
263
+ );
264
+ }
265
+ } else {
266
+ // A regular "hasOne" relation.
267
+ if (!relDef.foreignKey || typeof relDef.foreignKey !== 'string')
268
+ throw new InvalidArgumentError(
269
+ 'The relation %v of the model %v has the type "hasOne", ' +
270
+ 'so it requires the option "foreignKey" to be a non-empty String, ' +
271
+ 'but %v given.',
272
+ relName,
273
+ modelName,
274
+ relDef.foreignKey,
275
+ );
276
+ if (relDef.discriminator)
277
+ throw new InvalidArgumentError(
278
+ 'The relation %v of the model %v is a non-polymorphic "hasOne" relation, ' +
279
+ 'so it should not have the option "discriminator" to be provided.',
280
+ relName,
281
+ modelName,
282
+ );
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Validate "hasMany".
288
+ *
289
+ * @example The regular "hasMany" relation.
290
+ * ```
291
+ * {
292
+ * type: RelationType.HAS_MANY,
293
+ * model: 'model',
294
+ * foreignKey: 'modelId',
295
+ * }
296
+ * ```
297
+ *
298
+ * @example The polymorphic "hasMany" relation with a target relation name.
299
+ * ```
300
+ * {
301
+ * type: RelationType.HAS_MANY,
302
+ * model: 'model',
303
+ * polymorphic: 'reference',
304
+ * }
305
+ * ```
306
+ *
307
+ * @example The polymorphic "hasMany" relation with target relation keys.
308
+ * ```
309
+ * {
310
+ * type: RelationType.HAS_MANY,
311
+ * model: 'model',
312
+ * polymorphic: true,
313
+ * foreignKey: 'referenceId',
314
+ * discriminator: 'referenceType,
315
+ * }
316
+ * ```
317
+ *
318
+ * @param {string} modelName
319
+ * @param {string} relName
320
+ * @param {object} relDef
321
+ * @private
322
+ */
323
+ _validateHasMany(modelName, relName, relDef) {
324
+ if (relDef.type !== RelationType.HAS_MANY) return;
325
+ if (!relDef.model || typeof relDef.model !== 'string')
326
+ throw new InvalidArgumentError(
327
+ 'The relation %v of the model %v has the type "hasMany", ' +
328
+ 'so it requires the option "model" to be a non-empty String, ' +
329
+ 'but %v given.',
330
+ relName,
331
+ modelName,
332
+ relDef.model,
333
+ );
334
+ if (relDef.polymorphic) {
335
+ if (typeof relDef.polymorphic === 'string') {
336
+ // A polymorphic "hasMany" relation with a target relation name.
337
+ if (relDef.foreignKey)
338
+ throw new InvalidArgumentError(
339
+ 'The relation %v of the model %v has the option "polymorphic" with ' +
340
+ 'a String value, so it should not have the option "foreignKey" ' +
341
+ 'to be provided.',
342
+ relName,
343
+ modelName,
344
+ );
345
+ if (relDef.discriminator)
346
+ throw new InvalidArgumentError(
347
+ 'The relation %v of the model %v has the option "polymorphic" with ' +
348
+ 'a String value, so it should not have the option "discriminator" ' +
349
+ 'to be provided.',
350
+ relName,
351
+ modelName,
352
+ );
353
+ } else if (typeof relDef.polymorphic === 'boolean') {
354
+ // A polymorphic "hasMany" relation with target relation keys.
355
+ if (!relDef.foreignKey || typeof relDef.foreignKey !== 'string')
356
+ throw new InvalidArgumentError(
357
+ 'The relation %v of the model %v has the option "polymorphic" ' +
358
+ 'with "true" value, so it requires the option "foreignKey" ' +
359
+ 'to be a non-empty String, but %v given.',
360
+ relName,
361
+ modelName,
362
+ relDef.foreignKey,
363
+ );
364
+ if (!relDef.discriminator || typeof relDef.discriminator !== 'string')
365
+ throw new InvalidArgumentError(
366
+ 'The relation %v of the model %v has the option "polymorphic" ' +
367
+ 'with "true" value, so it requires the option "discriminator" ' +
368
+ 'to be a non-empty String, but %v given.',
369
+ relName,
370
+ modelName,
371
+ relDef.discriminator,
372
+ );
373
+ } else {
374
+ throw new InvalidArgumentError(
375
+ 'The relation %v of the model %v has the type "hasMany", ' +
376
+ 'so it expects the provided option "polymorphic" to be ' +
377
+ 'a String or a Boolean, but %v given.',
378
+ relName,
379
+ modelName,
380
+ relDef.polymorphic,
381
+ );
382
+ }
383
+ } else {
384
+ // A regular "hasMany" relation.
385
+ if (!relDef.foreignKey || typeof relDef.foreignKey !== 'string')
386
+ throw new InvalidArgumentError(
387
+ 'The relation %v of the model %v has the type "hasMany", ' +
388
+ 'so it requires the option "foreignKey" to be a non-empty String, ' +
389
+ 'but %v given.',
390
+ relName,
391
+ modelName,
392
+ relDef.foreignKey,
393
+ );
394
+ if (relDef.discriminator)
395
+ throw new InvalidArgumentError(
396
+ 'The relation %v of the model %v is a non-polymorphic "hasMany" relation, ' +
397
+ 'so it should not have the option "discriminator" to be provided.',
398
+ relName,
399
+ modelName,
400
+ );
401
+ }
402
+ }
403
+
404
+ /**
405
+ * Validate "referencesMany".
406
+ *
407
+ * @example
408
+ * ```
409
+ * {
410
+ * type: RelationType.REFERENCES_MANY,
411
+ * model: 'model',
412
+ * foreignKey: 'modelIds', // optional
413
+ * }
414
+ * ```
415
+ *
416
+ * @param {string} modelName
417
+ * @param {string} relName
418
+ * @param {object} relDef
419
+ * @private
420
+ */
421
+ _validateReferencesMany(modelName, relName, relDef) {
422
+ if (relDef.type !== Type.REFERENCES_MANY) return;
423
+ if (!relDef.model || typeof relDef.model !== 'string')
424
+ throw new InvalidArgumentError(
425
+ 'The relation %v of the model %v has the type "referencesMany", ' +
426
+ 'so it requires the option "model" to be a non-empty String, ' +
427
+ 'but %v given.',
428
+ relName,
429
+ modelName,
430
+ relDef.model,
431
+ );
432
+ if (relDef.foreignKey && typeof relDef.foreignKey !== 'string')
433
+ throw new InvalidArgumentError(
434
+ 'The relation %v of the model %v has the type "referencesMany", ' +
435
+ 'so it expects the provided option "foreignKey" to be a String, ' +
436
+ 'but %v given.',
437
+ relName,
438
+ modelName,
439
+ relDef.foreignKey,
440
+ );
441
+ if (relDef.discriminator)
442
+ throw new InvalidArgumentError(
443
+ 'The relation %v of the model %v has the type "referencesMany", ' +
444
+ 'so it should not have the option "discriminator" to be provided.',
445
+ relName,
446
+ modelName,
447
+ );
448
+ }
449
+ }