@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,1474 @@
1
+ import chai from 'chai';
2
+ import {expect} from 'chai';
3
+ import {Schema} from '../../schema.js';
4
+ import {format} from '@e22m4u/js-format';
5
+ import {DataType} from './properties/index.js';
6
+ import {RelationType} from './relations/index.js';
7
+ import {InvalidArgumentError} from '../../errors/index.js';
8
+ import {ModelDefinitionUtils} from './model-definition-utils.js';
9
+ import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from './model-definition-utils.js';
10
+
11
+ const sandbox = chai.spy.sandbox();
12
+
13
+ describe('ModelDefinitionUtils', function () {
14
+ afterEach(function () {
15
+ sandbox.restore();
16
+ });
17
+
18
+ describe('getPrimaryKeyAsPropertyName', function () {
19
+ it('returns a default property name if no primary key defined', function () {
20
+ const schema = new Schema();
21
+ schema.defineModel({
22
+ name: 'model',
23
+ });
24
+ const result = schema
25
+ .getService(ModelDefinitionUtils)
26
+ .getPrimaryKeyAsPropertyName('model');
27
+ expect(result).to.be.eq(DEF_PK);
28
+ });
29
+
30
+ it('throws an error if a property name of a default primary key already in use as a regular property', function () {
31
+ const schema = new Schema();
32
+ const S = schema.getService(ModelDefinitionUtils);
33
+ sandbox.on(
34
+ S,
35
+ 'getPropertiesDefinitionInBaseModelHierarchy',
36
+ function (modelName) {
37
+ expect(modelName).to.be.eq('model');
38
+ return {[DEF_PK]: DataType.NUMBER};
39
+ },
40
+ );
41
+ const throwable = () => S.getPrimaryKeyAsPropertyName('model');
42
+ expect(throwable).to.throw(
43
+ format(
44
+ 'The property name %v of the model "model" is defined as a regular property. ' +
45
+ 'In this case, a primary key should be defined explicitly. ' +
46
+ 'Do use the option "primaryKey" to specify the primary key.',
47
+ DEF_PK,
48
+ ),
49
+ );
50
+ });
51
+
52
+ it('returns a property name if a primary key has a custom name and a default primary key is used as a regular property', function () {
53
+ const schema = new Schema();
54
+ schema.defineModel({
55
+ name: 'model',
56
+ properties: {
57
+ myId: {
58
+ type: DataType.NUMBER,
59
+ primaryKey: true,
60
+ },
61
+ [DEF_PK]: DataType.NUMBER,
62
+ },
63
+ });
64
+ const result = schema
65
+ .getService(ModelDefinitionUtils)
66
+ .getPrimaryKeyAsPropertyName('model');
67
+ expect(result).to.be.eql('myId');
68
+ });
69
+
70
+ it('returns a property name of a primary key', function () {
71
+ const schema = new Schema();
72
+ schema.defineModel({
73
+ name: 'model',
74
+ properties: {
75
+ foo: {
76
+ type: DataType.NUMBER,
77
+ primaryKey: true,
78
+ },
79
+ bar: {
80
+ type: DataType.NUMBER,
81
+ },
82
+ },
83
+ });
84
+ const result = schema
85
+ .getService(ModelDefinitionUtils)
86
+ .getPrimaryKeyAsPropertyName('model');
87
+ expect(result).to.be.eq('foo');
88
+ });
89
+
90
+ it('uses a base model hierarchy to get a property name of a primary key', function () {
91
+ const schema = new Schema();
92
+ schema.defineModel({
93
+ name: 'modelA',
94
+ properties: {
95
+ foo: {
96
+ type: DataType.STRING,
97
+ primaryKey: true,
98
+ },
99
+ },
100
+ });
101
+ schema.defineModel({
102
+ name: 'modelB',
103
+ base: 'modelA',
104
+ });
105
+ const result = schema
106
+ .getService(ModelDefinitionUtils)
107
+ .getPrimaryKeyAsPropertyName('modelB');
108
+ expect(result).to.be.eq('foo');
109
+ });
110
+ });
111
+
112
+ describe('getPrimaryKeyAsColumnName', function () {
113
+ it('returns a property name of a primary key if a column name is not specified', function () {
114
+ const schema = new Schema();
115
+ schema.defineModel({
116
+ name: 'model',
117
+ properties: {
118
+ foo: {
119
+ type: DataType.NUMBER,
120
+ primaryKey: true,
121
+ },
122
+ bar: {
123
+ type: DataType.NUMBER,
124
+ },
125
+ },
126
+ });
127
+ const result = schema
128
+ .getService(ModelDefinitionUtils)
129
+ .getPrimaryKeyAsColumnName('model');
130
+ expect(result).to.be.eq('foo');
131
+ });
132
+
133
+ it('returns a column name of a primary key if specified', function () {
134
+ const schema = new Schema();
135
+ schema.defineModel({
136
+ name: 'model',
137
+ properties: {
138
+ foo: {
139
+ type: DataType.NUMBER,
140
+ primaryKey: true,
141
+ columnName: 'fooColumn',
142
+ },
143
+ bar: {
144
+ type: DataType.NUMBER,
145
+ },
146
+ },
147
+ });
148
+ const result = schema
149
+ .getService(ModelDefinitionUtils)
150
+ .getPrimaryKeyAsColumnName('model');
151
+ expect(result).to.be.eq('fooColumn');
152
+ });
153
+
154
+ it('returns a default property name if a primary key is not defined', function () {
155
+ const schema = new Schema();
156
+ schema.defineModel({
157
+ name: 'model',
158
+ });
159
+ const result = schema
160
+ .getService(ModelDefinitionUtils)
161
+ .getPrimaryKeyAsColumnName('model');
162
+ expect(result).to.be.eq(DEF_PK);
163
+ });
164
+
165
+ it('throws an error if a property name of a default primary key already in use as a regular property', function () {
166
+ const schema = new Schema();
167
+ const S = schema.getService(ModelDefinitionUtils);
168
+ sandbox.on(
169
+ S,
170
+ 'getPropertiesDefinitionInBaseModelHierarchy',
171
+ function (modelName) {
172
+ expect(modelName).to.be.eq('model');
173
+ return {[DEF_PK]: DataType.NUMBER};
174
+ },
175
+ );
176
+ const throwable = () => S.getPrimaryKeyAsColumnName('model');
177
+ expect(throwable).to.throw(
178
+ format(
179
+ 'The property name %v of the model "model" is defined as a regular property. ' +
180
+ 'In this case, a primary key should be defined explicitly. ' +
181
+ 'Do use the option "primaryKey" to specify the primary key.',
182
+ DEF_PK,
183
+ ),
184
+ );
185
+ });
186
+
187
+ it('returns a property name of a custom primary key when a default primary key is used as a regular property', function () {
188
+ const schema = new Schema();
189
+ schema.defineModel({
190
+ name: 'model',
191
+ properties: {
192
+ myId: {
193
+ type: DataType.NUMBER,
194
+ primaryKey: true,
195
+ },
196
+ [DEF_PK]: DataType.NUMBER,
197
+ },
198
+ });
199
+ const result = schema
200
+ .getService(ModelDefinitionUtils)
201
+ .getPrimaryKeyAsColumnName('model');
202
+ expect(result).to.be.eql('myId');
203
+ });
204
+
205
+ it('uses a base model hierarchy to get a column name of a primary key', function () {
206
+ const schema = new Schema();
207
+ schema.defineModel({
208
+ name: 'modelA',
209
+ properties: {
210
+ foo: {
211
+ type: DataType.STRING,
212
+ primaryKey: true,
213
+ },
214
+ },
215
+ });
216
+ schema.defineModel({
217
+ name: 'modelB',
218
+ base: 'modelA',
219
+ });
220
+ const result = schema
221
+ .getService(ModelDefinitionUtils)
222
+ .getPrimaryKeyAsPropertyName('modelB');
223
+ expect(result).to.be.eq('foo');
224
+ });
225
+ });
226
+
227
+ describe('getTableNameByModelName', function () {
228
+ it('returns a model name if no table name specified', function () {
229
+ const schema = new Schema();
230
+ schema.defineModel({
231
+ name: 'model',
232
+ });
233
+ const result = schema
234
+ .getService(ModelDefinitionUtils)
235
+ .getTableNameByModelName('model');
236
+ expect(result).to.be.eq('model');
237
+ });
238
+
239
+ it('returns a table name from a model definition', function () {
240
+ const schema = new Schema();
241
+ schema.defineModel({
242
+ name: 'model',
243
+ tableName: 'table',
244
+ });
245
+ const result = schema
246
+ .getService(ModelDefinitionUtils)
247
+ .getTableNameByModelName('model');
248
+ expect(result).to.be.eq('table');
249
+ });
250
+ });
251
+
252
+ describe('getColumnNameByPropertyName', function () {
253
+ it('returns a property name if a column name is not defined', function () {
254
+ const schema = new Schema();
255
+ schema.defineModel({
256
+ name: 'model',
257
+ properties: {
258
+ foo: DataType.STRING,
259
+ },
260
+ });
261
+ const result = schema
262
+ .getService(ModelDefinitionUtils)
263
+ .getColumnNameByPropertyName('model', 'foo');
264
+ expect(result).to.be.eq('foo');
265
+ });
266
+
267
+ it('returns a specified column name', function () {
268
+ const schema = new Schema();
269
+ schema.defineModel({
270
+ name: 'model',
271
+ properties: {
272
+ foo: {
273
+ type: DataType.STRING,
274
+ columnName: 'bar',
275
+ },
276
+ },
277
+ });
278
+ const result = schema
279
+ .getService(ModelDefinitionUtils)
280
+ .getColumnNameByPropertyName('model', 'foo');
281
+ expect(result).to.be.eq('bar');
282
+ });
283
+
284
+ it('throws an error if a given property name does not exist', function () {
285
+ const schema = new Schema();
286
+ schema.defineModel({
287
+ name: 'model',
288
+ });
289
+ const throwable = () =>
290
+ schema
291
+ .getService(ModelDefinitionUtils)
292
+ .getColumnNameByPropertyName('model', 'foo');
293
+ expect(throwable).to.throw(InvalidArgumentError);
294
+ });
295
+
296
+ it('uses a base model hierarchy to get a specified column name', function () {
297
+ const schema = new Schema();
298
+ schema.defineModel({
299
+ name: 'modelA',
300
+ properties: {
301
+ foo: {
302
+ type: DataType.STRING,
303
+ columnName: 'fooColumn',
304
+ },
305
+ },
306
+ });
307
+ schema.defineModel({
308
+ name: 'modelB',
309
+ base: 'modelA',
310
+ });
311
+ const result = schema
312
+ .getService(ModelDefinitionUtils)
313
+ .getColumnNameByPropertyName('modelB', 'foo');
314
+ expect(result).to.be.eq('fooColumn');
315
+ });
316
+ });
317
+
318
+ describe('getDefaultPropertyValue', function () {
319
+ it('returns undefined if no default value specified', function () {
320
+ const schema = new Schema();
321
+ schema.defineModel({
322
+ name: 'model',
323
+ properties: {
324
+ foo: DataType.STRING,
325
+ },
326
+ });
327
+ const result = schema
328
+ .getService(ModelDefinitionUtils)
329
+ .getDefaultPropertyValue('model', 'foo');
330
+ expect(result).to.be.undefined;
331
+ });
332
+
333
+ it('returns a default value from a property definition', function () {
334
+ const schema = new Schema();
335
+ schema.defineModel({
336
+ name: 'model',
337
+ properties: {
338
+ foo: {
339
+ type: DataType.STRING,
340
+ default: 'default',
341
+ },
342
+ },
343
+ });
344
+ const result = schema
345
+ .getService(ModelDefinitionUtils)
346
+ .getDefaultPropertyValue('model', 'foo');
347
+ expect(result).to.be.eq('default');
348
+ });
349
+
350
+ it('returns a value from a factory function', function () {
351
+ const schema = new Schema();
352
+ schema.defineModel({
353
+ name: 'model',
354
+ properties: {
355
+ foo: {
356
+ type: DataType.STRING,
357
+ default: () => 'default',
358
+ },
359
+ },
360
+ });
361
+ const result = schema
362
+ .getService(ModelDefinitionUtils)
363
+ .getDefaultPropertyValue('model', 'foo');
364
+ expect(result).to.be.eq('default');
365
+ });
366
+
367
+ it('throws an error if a given property name does not exist', function () {
368
+ const schema = new Schema();
369
+ schema.defineModel({
370
+ name: 'model',
371
+ });
372
+ const throwable = () =>
373
+ schema
374
+ .getService(ModelDefinitionUtils)
375
+ .getDefaultPropertyValue('model', 'foo');
376
+ expect(throwable).to.throw(InvalidArgumentError);
377
+ });
378
+
379
+ it('uses a base model hierarchy to get a specified default value', function () {
380
+ const schema = new Schema();
381
+ schema.defineModel({
382
+ name: 'modelA',
383
+ properties: {
384
+ foo: {
385
+ type: DataType.STRING,
386
+ default: 'default',
387
+ },
388
+ },
389
+ });
390
+ schema.defineModel({
391
+ name: 'modelB',
392
+ base: 'modelA',
393
+ });
394
+ const result = schema
395
+ .getService(ModelDefinitionUtils)
396
+ .getDefaultPropertyValue('modelB', 'foo');
397
+ expect(result).to.be.eq('default');
398
+ });
399
+ });
400
+
401
+ describe('setDefaultValuesToEmptyProperties', function () {
402
+ it('does nothing if no property definitions', function () {
403
+ const schema = new Schema();
404
+ schema.defineModel({
405
+ name: 'model',
406
+ });
407
+ const result = schema
408
+ .getService(ModelDefinitionUtils)
409
+ .setDefaultValuesToEmptyProperties('model', {foo: 'string'});
410
+ expect(result).to.be.eql({foo: 'string'});
411
+ });
412
+
413
+ it('does nothing if no "default" option in property definition', function () {
414
+ const schema = new Schema();
415
+ schema.defineModel({
416
+ name: 'model',
417
+ properties: {
418
+ baz: DataType.STRING,
419
+ qux: DataType.NUMBER,
420
+ },
421
+ });
422
+ const result = schema
423
+ .getService(ModelDefinitionUtils)
424
+ .setDefaultValuesToEmptyProperties('model', {foo: 'string'});
425
+ expect(result).to.be.eql({foo: 'string'});
426
+ });
427
+
428
+ it('sets a default value if a property does not exist', function () {
429
+ const schema = new Schema();
430
+ schema.defineModel({
431
+ name: 'model',
432
+ properties: {
433
+ foo: {
434
+ type: DataType.STRING,
435
+ default: 'string',
436
+ },
437
+ },
438
+ });
439
+ const result = schema
440
+ .getService(ModelDefinitionUtils)
441
+ .setDefaultValuesToEmptyProperties('model', {});
442
+ expect(result).to.be.eql({foo: 'string'});
443
+ });
444
+
445
+ it('sets a default value if a property is undefined', function () {
446
+ const schema = new Schema();
447
+ schema.defineModel({
448
+ name: 'model',
449
+ properties: {
450
+ foo: {
451
+ type: DataType.STRING,
452
+ default: 'string',
453
+ },
454
+ },
455
+ });
456
+ const result = schema
457
+ .getService(ModelDefinitionUtils)
458
+ .setDefaultValuesToEmptyProperties('model', {foo: undefined});
459
+ expect(result).to.be.eql({foo: 'string'});
460
+ });
461
+
462
+ it('sets a default value if a property is null', function () {
463
+ const schema = new Schema();
464
+ schema.defineModel({
465
+ name: 'model',
466
+ properties: {
467
+ foo: {
468
+ type: DataType.STRING,
469
+ default: 'string',
470
+ },
471
+ },
472
+ });
473
+ const result = schema
474
+ .getService(ModelDefinitionUtils)
475
+ .setDefaultValuesToEmptyProperties('model', {foo: null});
476
+ expect(result).to.be.eql({foo: 'string'});
477
+ });
478
+
479
+ it('sets a value from a factory function', function () {
480
+ const schema = new Schema();
481
+ schema.defineModel({
482
+ name: 'model',
483
+ properties: {
484
+ foo: {
485
+ type: DataType.STRING,
486
+ default: () => 'string',
487
+ },
488
+ bar: {
489
+ type: DataType.NUMBER,
490
+ default: () => 10,
491
+ },
492
+ baz: {
493
+ type: DataType.STRING,
494
+ default: () => null,
495
+ },
496
+ qux: {
497
+ type: DataType.STRING,
498
+ default: () => undefined,
499
+ },
500
+ },
501
+ });
502
+ const result = schema
503
+ .getService(ModelDefinitionUtils)
504
+ .setDefaultValuesToEmptyProperties('model', {});
505
+ expect(result).to.be.eql({
506
+ foo: 'string',
507
+ bar: 10,
508
+ baz: null,
509
+ qux: undefined,
510
+ });
511
+ });
512
+
513
+ it('uses a base model hierarchy to set a default values', function () {
514
+ const schema = new Schema();
515
+ schema.defineModel({
516
+ name: 'modelA',
517
+ properties: {
518
+ foo: {
519
+ type: DataType.STRING,
520
+ default: 'string',
521
+ },
522
+ bar: {
523
+ type: DataType.NUMBER,
524
+ default: 10,
525
+ },
526
+ baz: {
527
+ type: DataType.STRING,
528
+ default: null,
529
+ },
530
+ },
531
+ });
532
+ schema.defineModel({
533
+ name: 'modelB',
534
+ base: 'modelA',
535
+ });
536
+ const result = schema
537
+ .getService(ModelDefinitionUtils)
538
+ .setDefaultValuesToEmptyProperties('modelB', {});
539
+ expect(result).to.be.eql({
540
+ foo: 'string',
541
+ bar: 10,
542
+ baz: null,
543
+ });
544
+ });
545
+
546
+ describe('an option "onlyProvidedProperties" is true', function () {
547
+ it('does not set a default value if a property does not exist', function () {
548
+ const schema = new Schema();
549
+ schema.defineModel({
550
+ name: 'model',
551
+ properties: {
552
+ foo: {
553
+ type: DataType.STRING,
554
+ default: 'string',
555
+ },
556
+ },
557
+ });
558
+ const result = schema
559
+ .getService(ModelDefinitionUtils)
560
+ .setDefaultValuesToEmptyProperties('model', {}, true);
561
+ expect(result).to.be.eql({});
562
+ });
563
+
564
+ it('sets a default value if a property is undefined', function () {
565
+ const schema = new Schema();
566
+ schema.defineModel({
567
+ name: 'model',
568
+ properties: {
569
+ foo: {
570
+ type: DataType.STRING,
571
+ default: 'string',
572
+ },
573
+ },
574
+ });
575
+ const result = schema
576
+ .getService(ModelDefinitionUtils)
577
+ .setDefaultValuesToEmptyProperties('model', {foo: undefined}, true);
578
+ expect(result).to.be.eql({foo: 'string'});
579
+ });
580
+
581
+ it('sets a default value if a property is null', function () {
582
+ const schema = new Schema();
583
+ schema.defineModel({
584
+ name: 'model',
585
+ properties: {
586
+ foo: {
587
+ type: DataType.STRING,
588
+ default: 'string',
589
+ },
590
+ },
591
+ });
592
+ const result = schema
593
+ .getService(ModelDefinitionUtils)
594
+ .setDefaultValuesToEmptyProperties('model', {foo: null}, true);
595
+ expect(result).to.be.eql({foo: 'string'});
596
+ });
597
+ });
598
+ });
599
+
600
+ describe('convertPropertyNamesToColumnNames', function () {
601
+ it('does nothing if no property definitions', function () {
602
+ const schema = new Schema();
603
+ schema.defineModel({
604
+ name: 'model',
605
+ });
606
+ const result = schema
607
+ .getService(ModelDefinitionUtils)
608
+ .convertPropertyNamesToColumnNames('model', {foo: 'string'});
609
+ expect(result).to.be.eql({foo: 'string'});
610
+ });
611
+
612
+ it('does nothing if no column name specified', function () {
613
+ const schema = new Schema();
614
+ schema.defineModel({
615
+ name: 'model',
616
+ properties: {
617
+ foo: DataType.STRING,
618
+ bar: DataType.NUMBER,
619
+ },
620
+ });
621
+ const result = schema
622
+ .getService(ModelDefinitionUtils)
623
+ .convertPropertyNamesToColumnNames('model', {foo: 'string'});
624
+ expect(result).to.be.eql({foo: 'string'});
625
+ });
626
+
627
+ it('replaces property names by column names', function () {
628
+ const schema = new Schema();
629
+ schema.defineModel({
630
+ name: 'model',
631
+ properties: {
632
+ foo: {
633
+ type: DataType.STRING,
634
+ columnName: 'fooColumn',
635
+ },
636
+ bar: {
637
+ type: DataType.NUMBER,
638
+ columnName: 'barColumn',
639
+ },
640
+ },
641
+ });
642
+ const result = schema
643
+ .getService(ModelDefinitionUtils)
644
+ .convertPropertyNamesToColumnNames('model', {foo: 'string'});
645
+ expect(result).to.be.eql({fooColumn: 'string'});
646
+ });
647
+
648
+ it('uses a base model hierarchy to replace property names by column names', function () {
649
+ const schema = new Schema();
650
+ schema.defineModel({
651
+ name: 'modelA',
652
+ properties: {
653
+ foo: {
654
+ type: DataType.STRING,
655
+ columnName: 'fooColumn',
656
+ },
657
+ bar: {
658
+ type: DataType.NUMBER,
659
+ columnName: 'barColumn',
660
+ },
661
+ },
662
+ });
663
+ schema.defineModel({
664
+ name: 'modelB',
665
+ base: 'modelA',
666
+ });
667
+ const result = schema
668
+ .getService(ModelDefinitionUtils)
669
+ .convertPropertyNamesToColumnNames('modelB', {foo: 'string'});
670
+ expect(result).to.be.eql({fooColumn: 'string'});
671
+ });
672
+ });
673
+
674
+ describe('convertColumnNamesToPropertyNames', function () {
675
+ it('does nothing if no property definitions', function () {
676
+ const schema = new Schema();
677
+ schema.defineModel({
678
+ name: 'model',
679
+ });
680
+ const result = schema
681
+ .getService(ModelDefinitionUtils)
682
+ .convertColumnNamesToPropertyNames('model', {foo: 'string'});
683
+ expect(result).to.be.eql({foo: 'string'});
684
+ });
685
+
686
+ it('does nothing if no column name specified', function () {
687
+ const schema = new Schema();
688
+ schema.defineModel({
689
+ name: 'model',
690
+ properties: {
691
+ foo: DataType.STRING,
692
+ bar: DataType.NUMBER,
693
+ },
694
+ });
695
+ const result = schema
696
+ .getService(ModelDefinitionUtils)
697
+ .convertColumnNamesToPropertyNames('model', {foo: 'string'});
698
+ expect(result).to.be.eql({foo: 'string'});
699
+ });
700
+
701
+ it('replaces column names by property names', function () {
702
+ const schema = new Schema();
703
+ schema.defineModel({
704
+ name: 'model',
705
+ properties: {
706
+ foo: {
707
+ type: DataType.STRING,
708
+ columnName: 'fooColumn',
709
+ },
710
+ bar: {
711
+ type: DataType.NUMBER,
712
+ columnName: 'barColumn',
713
+ },
714
+ },
715
+ });
716
+ const result = schema
717
+ .getService(ModelDefinitionUtils)
718
+ .convertColumnNamesToPropertyNames('model', {fooColumn: 'string'});
719
+ expect(result).to.be.eql({foo: 'string'});
720
+ });
721
+
722
+ it('uses a base model hierarchy to replace column names by property names', function () {
723
+ const schema = new Schema();
724
+ schema.defineModel({
725
+ name: 'modelA',
726
+ properties: {
727
+ foo: {
728
+ type: DataType.STRING,
729
+ columnName: 'fooColumn',
730
+ },
731
+ bar: {
732
+ type: DataType.NUMBER,
733
+ columnName: 'barColumn',
734
+ },
735
+ },
736
+ });
737
+ schema.defineModel({
738
+ name: 'modelB',
739
+ base: 'modelA',
740
+ });
741
+ const result = schema
742
+ .getService(ModelDefinitionUtils)
743
+ .convertColumnNamesToPropertyNames('modelA', {fooColumn: 'string'});
744
+ expect(result).to.be.eql({foo: 'string'});
745
+ });
746
+ });
747
+
748
+ describe('getDataTypeByPropertyName', function () {
749
+ it('returns a property type of a short property definition', function () {
750
+ const schema = new Schema();
751
+ schema.defineModel({
752
+ name: 'model',
753
+ properties: {
754
+ foo: DataType.STRING,
755
+ },
756
+ });
757
+ const result = schema
758
+ .getService(ModelDefinitionUtils)
759
+ .getDataTypeByPropertyName('model', 'foo');
760
+ expect(result).to.be.eq(DataType.STRING);
761
+ });
762
+
763
+ it('returns a property type of a full property definition', function () {
764
+ const schema = new Schema();
765
+ schema.defineModel({
766
+ name: 'model',
767
+ properties: {
768
+ foo: {
769
+ type: DataType.STRING,
770
+ },
771
+ },
772
+ });
773
+ const result = schema
774
+ .getService(ModelDefinitionUtils)
775
+ .getDataTypeByPropertyName('model', 'foo');
776
+ expect(result).to.be.eq(DataType.STRING);
777
+ });
778
+
779
+ it('throws an error if a property name does not exist', function () {
780
+ const schema = new Schema();
781
+ schema.defineModel({
782
+ name: 'model',
783
+ });
784
+ const throwable = () =>
785
+ schema
786
+ .getService(ModelDefinitionUtils)
787
+ .getDataTypeByPropertyName('model', 'property');
788
+ expect(throwable).to.throw(InvalidArgumentError);
789
+ });
790
+
791
+ it('uses a base model hierarchy to get a type from a short property definition', function () {
792
+ const schema = new Schema();
793
+ schema.defineModel({
794
+ name: 'modelA',
795
+ properties: {
796
+ foo: DataType.STRING,
797
+ },
798
+ });
799
+ schema.defineModel({
800
+ name: 'modelB',
801
+ base: 'modelA',
802
+ });
803
+ const result = schema
804
+ .getService(ModelDefinitionUtils)
805
+ .getDataTypeByPropertyName('modelB', 'foo');
806
+ expect(result).to.be.eq(DataType.STRING);
807
+ });
808
+
809
+ it('uses a base model hierarchy to get a type from a full property definition', function () {
810
+ const schema = new Schema();
811
+ schema.defineModel({
812
+ name: 'modelA',
813
+ properties: {
814
+ foo: {
815
+ type: DataType.STRING,
816
+ },
817
+ },
818
+ });
819
+ schema.defineModel({
820
+ name: 'modelB',
821
+ base: 'modelA',
822
+ });
823
+ const result = schema
824
+ .getService(ModelDefinitionUtils)
825
+ .getDataTypeByPropertyName('modelB', 'foo');
826
+ expect(result).to.be.eq(DataType.STRING);
827
+ });
828
+ });
829
+
830
+ describe('getOwnPropertiesDefinitionWithoutPrimaryKeys', function () {
831
+ it('returns an empty object if a model does not have properties', function () {
832
+ const schema = new Schema();
833
+ schema.defineModel({
834
+ name: 'model',
835
+ });
836
+ const result = schema
837
+ .getService(ModelDefinitionUtils)
838
+ .getOwnPropertiesDefinitionWithoutPrimaryKeys('model');
839
+ expect(result).to.be.eql({});
840
+ });
841
+
842
+ it('returns a properties definition without primary keys', function () {
843
+ const schema = new Schema();
844
+ schema.defineModel({
845
+ name: 'model',
846
+ properties: {
847
+ id: {
848
+ type: DataType.STRING,
849
+ primaryKey: true,
850
+ },
851
+ foo: DataType.STRING,
852
+ bar: DataType.STRING,
853
+ },
854
+ });
855
+ const result = schema
856
+ .getService(ModelDefinitionUtils)
857
+ .getOwnPropertiesDefinitionWithoutPrimaryKeys('model');
858
+ expect(result).to.be.eql({
859
+ foo: DataType.STRING,
860
+ bar: DataType.STRING,
861
+ });
862
+ });
863
+
864
+ it('returns its own properties definition even it has a base model properties', function () {
865
+ const schema = new Schema();
866
+ schema.defineModel({
867
+ name: 'modelA',
868
+ properties: {
869
+ id: {
870
+ type: DataType.STRING,
871
+ primaryKey: true,
872
+ },
873
+ foo: DataType.STRING,
874
+ bar: DataType.STRING,
875
+ },
876
+ });
877
+ schema.defineModel({
878
+ name: 'modelB',
879
+ base: 'modelA',
880
+ properties: {
881
+ id: {
882
+ type: DataType.NUMBER,
883
+ primaryKey: true,
884
+ },
885
+ foo: DataType.NUMBER,
886
+ },
887
+ });
888
+ const result = schema
889
+ .getService(ModelDefinitionUtils)
890
+ .getOwnPropertiesDefinitionWithoutPrimaryKeys('modelB');
891
+ expect(result).to.be.eql({
892
+ foo: DataType.NUMBER,
893
+ });
894
+ });
895
+ });
896
+
897
+ describe('getOwnPropertiesDefinitionOfPrimaryKeys', function () {
898
+ it('returns an empty object if a model does not have properties', function () {
899
+ const schema = new Schema();
900
+ schema.defineModel({
901
+ name: 'model',
902
+ });
903
+ const result = schema
904
+ .getService(ModelDefinitionUtils)
905
+ .getOwnPropertiesDefinitionOfPrimaryKeys('model');
906
+ expect(result).to.be.eql({});
907
+ });
908
+
909
+ it('returns a properties definition of primary keys', function () {
910
+ const schema = new Schema();
911
+ schema.defineModel({
912
+ name: 'model',
913
+ properties: {
914
+ id: {
915
+ type: DataType.STRING,
916
+ primaryKey: true,
917
+ },
918
+ foo: DataType.STRING,
919
+ bar: DataType.NUMBER,
920
+ },
921
+ });
922
+ const result = schema
923
+ .getService(ModelDefinitionUtils)
924
+ .getOwnPropertiesDefinitionOfPrimaryKeys('model');
925
+ expect(result).to.be.eql({
926
+ id: {
927
+ type: DataType.STRING,
928
+ primaryKey: true,
929
+ },
930
+ });
931
+ });
932
+
933
+ it('returns its own properties definition even it has a base model properties', function () {
934
+ const schema = new Schema();
935
+ schema.defineModel({
936
+ name: 'modelA',
937
+ properties: {
938
+ id: {
939
+ type: DataType.STRING,
940
+ primaryKey: true,
941
+ },
942
+ foo: DataType.STRING,
943
+ bar: DataType.STRING,
944
+ },
945
+ });
946
+ schema.defineModel({
947
+ name: 'modelB',
948
+ base: 'modelA',
949
+ properties: {
950
+ id: {
951
+ type: DataType.NUMBER,
952
+ primaryKey: true,
953
+ },
954
+ foo: DataType.NUMBER,
955
+ },
956
+ });
957
+ const result = schema
958
+ .getService(ModelDefinitionUtils)
959
+ .getOwnPropertiesDefinitionOfPrimaryKeys('modelB');
960
+ expect(result).to.be.eql({
961
+ id: {
962
+ type: DataType.NUMBER,
963
+ primaryKey: true,
964
+ },
965
+ });
966
+ });
967
+ });
968
+
969
+ describe('getPropertiesDefinitionInBaseModelHierarchy', function () {
970
+ it('returns an empty object if a model does not have properties', function () {
971
+ const schema = new Schema();
972
+ schema.defineModel({
973
+ name: 'model',
974
+ });
975
+ const result = schema
976
+ .getService(ModelDefinitionUtils)
977
+ .getPropertiesDefinitionInBaseModelHierarchy('model');
978
+ expect(result).to.be.eql({});
979
+ });
980
+
981
+ it('returns a properties definition of a model', function () {
982
+ const schema = new Schema();
983
+ schema.defineModel({
984
+ name: 'model',
985
+ properties: {
986
+ id: {
987
+ type: DataType.STRING,
988
+ primaryKey: true,
989
+ },
990
+ foo: DataType.STRING,
991
+ bar: DataType.NUMBER,
992
+ },
993
+ });
994
+ const result = schema
995
+ .getService(ModelDefinitionUtils)
996
+ .getPropertiesDefinitionInBaseModelHierarchy('model');
997
+ expect(result).to.be.eql({
998
+ id: {
999
+ type: DataType.STRING,
1000
+ primaryKey: true,
1001
+ },
1002
+ foo: DataType.STRING,
1003
+ bar: DataType.NUMBER,
1004
+ });
1005
+ });
1006
+
1007
+ it('returns a properties definition of an extended model', function () {
1008
+ const schema = new Schema();
1009
+ schema.defineModel({
1010
+ name: 'modelA',
1011
+ properties: {
1012
+ foo: DataType.STRING,
1013
+ },
1014
+ });
1015
+ schema.defineModel({
1016
+ name: 'modelB',
1017
+ base: 'modelA',
1018
+ properties: {
1019
+ bar: DataType.NUMBER,
1020
+ },
1021
+ });
1022
+ const result = schema
1023
+ .getService(ModelDefinitionUtils)
1024
+ .getPropertiesDefinitionInBaseModelHierarchy('modelB');
1025
+ expect(result).to.be.eql({
1026
+ foo: DataType.STRING,
1027
+ bar: DataType.NUMBER,
1028
+ });
1029
+ });
1030
+
1031
+ it('uses child properties in priority over a base model properties', function () {
1032
+ const schema = new Schema();
1033
+ schema.defineModel({
1034
+ name: 'modelA',
1035
+ properties: {
1036
+ id: {
1037
+ type: DataType.STRING,
1038
+ primaryKey: true,
1039
+ },
1040
+ foo: DataType.STRING,
1041
+ bar: DataType.STRING,
1042
+ },
1043
+ });
1044
+ schema.defineModel({
1045
+ name: 'modelB',
1046
+ base: 'modelA',
1047
+ properties: {
1048
+ id: {
1049
+ type: DataType.NUMBER,
1050
+ primaryKey: true,
1051
+ },
1052
+ foo: DataType.NUMBER,
1053
+ },
1054
+ });
1055
+ const result = schema
1056
+ .getService(ModelDefinitionUtils)
1057
+ .getPropertiesDefinitionInBaseModelHierarchy('modelB');
1058
+ expect(result).to.be.eql({
1059
+ id: {
1060
+ type: DataType.NUMBER,
1061
+ primaryKey: true,
1062
+ },
1063
+ foo: DataType.NUMBER,
1064
+ bar: DataType.STRING,
1065
+ });
1066
+ });
1067
+
1068
+ it('uses primary keys from a model closest to child model', function () {
1069
+ const schema = new Schema();
1070
+ schema.defineModel({
1071
+ name: 'modelA',
1072
+ properties: {
1073
+ id1: {
1074
+ type: DataType.STRING,
1075
+ primaryKey: true,
1076
+ },
1077
+ foo: DataType.STRING,
1078
+ },
1079
+ });
1080
+ schema.defineModel({
1081
+ name: 'modelB',
1082
+ base: 'modelA',
1083
+ properties: {
1084
+ id2: {
1085
+ type: DataType.STRING,
1086
+ primaryKey: true,
1087
+ },
1088
+ bar: DataType.NUMBER,
1089
+ },
1090
+ });
1091
+ const result = schema
1092
+ .getService(ModelDefinitionUtils)
1093
+ .getPropertiesDefinitionInBaseModelHierarchy('modelB');
1094
+ expect(result).to.be.eql({
1095
+ id2: {
1096
+ type: DataType.STRING,
1097
+ primaryKey: true,
1098
+ },
1099
+ foo: DataType.STRING,
1100
+ bar: DataType.NUMBER,
1101
+ });
1102
+ });
1103
+
1104
+ it('throws an error for a circular reference', function () {
1105
+ const schema = new Schema();
1106
+ schema.defineModel({
1107
+ name: 'model',
1108
+ base: 'model',
1109
+ });
1110
+ const throwable = () =>
1111
+ schema
1112
+ .getService(ModelDefinitionUtils)
1113
+ .getPropertiesDefinitionInBaseModelHierarchy('model');
1114
+ expect(throwable).to.throw(
1115
+ 'The model "model" has a circular inheritance.',
1116
+ );
1117
+ });
1118
+ });
1119
+
1120
+ describe('getOwnRelationsDefinition', function () {
1121
+ it('returns an empty object if a model does not have relations', function () {
1122
+ const schema = new Schema();
1123
+ schema.defineModel({
1124
+ name: 'model',
1125
+ });
1126
+ const result = schema
1127
+ .getService(ModelDefinitionUtils)
1128
+ .getOwnRelationsDefinition('model');
1129
+ expect(result).to.be.eql({});
1130
+ });
1131
+
1132
+ it('returns a relations definition by a given model', function () {
1133
+ const schema = new Schema();
1134
+ schema.defineModel({
1135
+ name: 'model',
1136
+ relations: {
1137
+ foo: {
1138
+ type: RelationType.BELONGS_TO,
1139
+ model: 'model',
1140
+ },
1141
+ },
1142
+ });
1143
+ const result = schema
1144
+ .getService(ModelDefinitionUtils)
1145
+ .getOwnRelationsDefinition('model');
1146
+ expect(result).to.be.eql({
1147
+ foo: {
1148
+ type: RelationType.BELONGS_TO,
1149
+ model: 'model',
1150
+ },
1151
+ });
1152
+ });
1153
+
1154
+ it('returns its own relations definition even it has a base model relations', function () {
1155
+ const schema = new Schema();
1156
+ schema.defineModel({
1157
+ name: 'modelA',
1158
+ relations: {
1159
+ foo: {
1160
+ type: RelationType.BELONGS_TO,
1161
+ model: 'modelA',
1162
+ },
1163
+ },
1164
+ });
1165
+ schema.defineModel({
1166
+ name: 'modelB',
1167
+ base: 'modelA',
1168
+ relations: {
1169
+ bar: {
1170
+ type: RelationType.BELONGS_TO,
1171
+ model: 'modelB',
1172
+ },
1173
+ },
1174
+ });
1175
+ const result = schema
1176
+ .getService(ModelDefinitionUtils)
1177
+ .getOwnRelationsDefinition('modelB');
1178
+ expect(result).to.be.eql({
1179
+ bar: {
1180
+ type: RelationType.BELONGS_TO,
1181
+ model: 'modelB',
1182
+ },
1183
+ });
1184
+ });
1185
+ });
1186
+
1187
+ describe('getRelationsDefinitionInBaseModelHierarchy', function () {
1188
+ it('returns an empty object if a model does not have relations', function () {
1189
+ const schema = new Schema();
1190
+ schema.defineModel({
1191
+ name: 'model',
1192
+ });
1193
+ const result = schema
1194
+ .getService(ModelDefinitionUtils)
1195
+ .getRelationsDefinitionInBaseModelHierarchy('model');
1196
+ expect(result).to.be.eql({});
1197
+ });
1198
+
1199
+ it('returns a relations definition of a model', function () {
1200
+ const schema = new Schema();
1201
+ schema.defineModel({
1202
+ name: 'model',
1203
+ relations: {
1204
+ foo: {
1205
+ type: RelationType.BELONGS_TO,
1206
+ model: 'model',
1207
+ },
1208
+ bar: {
1209
+ type: RelationType.BELONGS_TO,
1210
+ model: 'model',
1211
+ },
1212
+ },
1213
+ });
1214
+ const result = schema
1215
+ .getService(ModelDefinitionUtils)
1216
+ .getRelationsDefinitionInBaseModelHierarchy('model');
1217
+ expect(result).to.be.eql({
1218
+ foo: {
1219
+ type: RelationType.BELONGS_TO,
1220
+ model: 'model',
1221
+ },
1222
+ bar: {
1223
+ type: RelationType.BELONGS_TO,
1224
+ model: 'model',
1225
+ },
1226
+ });
1227
+ });
1228
+
1229
+ it('returns a relations definition of an extended model', function () {
1230
+ const schema = new Schema();
1231
+ schema.defineModel({
1232
+ name: 'modelA',
1233
+ relations: {
1234
+ foo: {
1235
+ type: RelationType.BELONGS_TO,
1236
+ model: 'modelA',
1237
+ },
1238
+ },
1239
+ });
1240
+ schema.defineModel({
1241
+ name: 'modelB',
1242
+ base: 'modelA',
1243
+ relations: {
1244
+ bar: {
1245
+ type: RelationType.BELONGS_TO,
1246
+ model: 'modelB',
1247
+ },
1248
+ },
1249
+ });
1250
+ const result = schema
1251
+ .getService(ModelDefinitionUtils)
1252
+ .getRelationsDefinitionInBaseModelHierarchy('modelB');
1253
+ expect(result).to.be.eql({
1254
+ foo: {
1255
+ type: RelationType.BELONGS_TO,
1256
+ model: 'modelA',
1257
+ },
1258
+ bar: {
1259
+ type: RelationType.BELONGS_TO,
1260
+ model: 'modelB',
1261
+ },
1262
+ });
1263
+ });
1264
+
1265
+ it('uses child relations in priority over a base model relations', function () {
1266
+ const schema = new Schema();
1267
+ schema.defineModel({
1268
+ name: 'modelA',
1269
+ relations: {
1270
+ foo: {
1271
+ type: RelationType.BELONGS_TO,
1272
+ model: 'modelA',
1273
+ },
1274
+ bar: {
1275
+ type: RelationType.BELONGS_TO,
1276
+ model: 'modelA',
1277
+ },
1278
+ },
1279
+ });
1280
+ schema.defineModel({
1281
+ name: 'modelB',
1282
+ base: 'modelA',
1283
+ relations: {
1284
+ foo: {
1285
+ type: RelationType.REFERENCES_MANY,
1286
+ model: 'modelB',
1287
+ },
1288
+ },
1289
+ });
1290
+ const result = schema
1291
+ .getService(ModelDefinitionUtils)
1292
+ .getRelationsDefinitionInBaseModelHierarchy('modelB');
1293
+ expect(result).to.be.eql({
1294
+ foo: {
1295
+ type: RelationType.REFERENCES_MANY,
1296
+ model: 'modelB',
1297
+ },
1298
+ bar: {
1299
+ type: RelationType.BELONGS_TO,
1300
+ model: 'modelA',
1301
+ },
1302
+ });
1303
+ });
1304
+
1305
+ it('throws an error for a circular reference', function () {
1306
+ const schema = new Schema();
1307
+ schema.defineModel({
1308
+ name: 'model',
1309
+ base: 'model',
1310
+ });
1311
+ const throwable = () =>
1312
+ schema
1313
+ .getService(ModelDefinitionUtils)
1314
+ .getRelationsDefinitionInBaseModelHierarchy('model');
1315
+ expect(throwable).to.throw(
1316
+ 'The model "model" has a circular inheritance.',
1317
+ );
1318
+ });
1319
+ });
1320
+
1321
+ describe('getRelationDefinitionByName', function () {
1322
+ it('throws an error if a given model is not found', function () {
1323
+ const schema = new Schema();
1324
+ const throwable = () =>
1325
+ schema
1326
+ .getService(ModelDefinitionUtils)
1327
+ .getRelationDefinitionByName('model', 'myRelation');
1328
+ expect(throwable).to.throw('The model "model" is not defined.');
1329
+ });
1330
+
1331
+ it('throws an error if a given relation is not found', function () {
1332
+ const schema = new Schema();
1333
+ schema.defineModel({
1334
+ name: 'model',
1335
+ });
1336
+ const throwable = () =>
1337
+ schema
1338
+ .getService(ModelDefinitionUtils)
1339
+ .getRelationDefinitionByName('model', 'myRelation');
1340
+ expect(throwable).to.throw(
1341
+ 'The model "model" does not have relation name "myRelation".',
1342
+ );
1343
+ });
1344
+
1345
+ it('returns a relation definition by a given name', function () {
1346
+ const schema = new Schema();
1347
+ schema.defineModel({
1348
+ name: 'model',
1349
+ relations: {
1350
+ myRelation: {
1351
+ type: RelationType.BELONGS_TO,
1352
+ model: 'model',
1353
+ },
1354
+ },
1355
+ });
1356
+ const result = schema
1357
+ .getService(ModelDefinitionUtils)
1358
+ .getRelationDefinitionByName('model', 'myRelation');
1359
+ expect(result).to.be.eql({
1360
+ type: RelationType.BELONGS_TO,
1361
+ model: 'model',
1362
+ });
1363
+ });
1364
+
1365
+ it('uses a child relations in priority over a base model relations', function () {
1366
+ const schema = new Schema();
1367
+ schema.defineModel({
1368
+ name: 'modelA',
1369
+ relations: {
1370
+ myRelation: {
1371
+ type: RelationType.BELONGS_TO,
1372
+ model: 'modelA',
1373
+ },
1374
+ },
1375
+ });
1376
+ schema.defineModel({
1377
+ name: 'modelB',
1378
+ base: 'modelA',
1379
+ relations: {
1380
+ myRelation: {
1381
+ type: RelationType.REFERENCES_MANY,
1382
+ model: 'modelA',
1383
+ },
1384
+ },
1385
+ });
1386
+ const result = schema
1387
+ .getService(ModelDefinitionUtils)
1388
+ .getRelationDefinitionByName('modelB', 'myRelation');
1389
+ expect(result).to.be.eql({
1390
+ type: RelationType.REFERENCES_MANY,
1391
+ model: 'modelA',
1392
+ });
1393
+ });
1394
+
1395
+ it('returns a base model relation if a given relation name is not found in a child model', function () {
1396
+ const schema = new Schema();
1397
+ schema.defineModel({
1398
+ name: 'modelA',
1399
+ relations: {
1400
+ myRelation: {
1401
+ type: RelationType.BELONGS_TO,
1402
+ model: 'modelA',
1403
+ },
1404
+ },
1405
+ });
1406
+ schema.defineModel({
1407
+ name: 'modelB',
1408
+ base: 'modelA',
1409
+ });
1410
+ const result = schema
1411
+ .getService(ModelDefinitionUtils)
1412
+ .getRelationDefinitionByName('modelB', 'myRelation');
1413
+ expect(result).to.be.eql({
1414
+ type: RelationType.BELONGS_TO,
1415
+ model: 'modelA',
1416
+ });
1417
+ });
1418
+ });
1419
+
1420
+ describe('excludeObjectKeysByRelationNames', function () {
1421
+ it('excludes object keys by relation names', function () {
1422
+ const schema = new Schema();
1423
+ schema.defineModel({
1424
+ name: 'model',
1425
+ relations: {
1426
+ baz: {
1427
+ type: RelationType.BELONGS_TO,
1428
+ model: 'model',
1429
+ },
1430
+ qux: {
1431
+ type: RelationType.BELONGS_TO,
1432
+ model: 'model',
1433
+ },
1434
+ },
1435
+ });
1436
+ const input = {
1437
+ foo: 'fooVal',
1438
+ bar: {val: 'barVal'},
1439
+ baz: 'bazVal',
1440
+ qux: {val: 'quxVal'},
1441
+ };
1442
+ const result = schema
1443
+ .getService(ModelDefinitionUtils)
1444
+ .excludeObjectKeysByRelationNames('model', input);
1445
+ expect(result).to.be.eql({foo: 'fooVal', bar: {val: 'barVal'}});
1446
+ expect(result).to.be.not.eq(input);
1447
+ });
1448
+
1449
+ it('requires a given object as an object', function () {
1450
+ const schema = new Schema();
1451
+ schema.defineModel({name: 'model'});
1452
+ const throwable = v => () =>
1453
+ schema
1454
+ .getService(ModelDefinitionUtils)
1455
+ .excludeObjectKeysByRelationNames('model', v);
1456
+ const error = v =>
1457
+ format(
1458
+ 'The second argument of ModelDefinitionUtils.excludeObjectKeysByRelationNames ' +
1459
+ 'must be an Object, but %s given.',
1460
+ v,
1461
+ );
1462
+ expect(throwable('')).to.throw(error('""'));
1463
+ expect(throwable('str')).to.throw(error('"str"'));
1464
+ expect(throwable(10)).to.throw(error('10'));
1465
+ expect(throwable(true)).to.throw(error('true'));
1466
+ expect(throwable(false)).to.throw(error('false'));
1467
+ expect(throwable([])).to.throw(error('Array'));
1468
+ expect(throwable(undefined)).to.throw(error('undefined'));
1469
+ expect(throwable(null)).to.throw(error('null'));
1470
+ throwable({})();
1471
+ throwable({foo: 'bar'})();
1472
+ });
1473
+ });
1474
+ });