@e22m4u/js-repository 0.1.9 → 0.1.12

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 (125) hide show
  1. package/README.md +46 -4
  2. package/docs/assets/navigation.js +1 -1
  3. package/docs/assets/search.js +1 -1
  4. package/docs/classes/Adapter.html +1 -1
  5. package/docs/classes/AdapterLoader.html +1 -1
  6. package/docs/classes/AdapterRegistry.html +1 -1
  7. package/docs/classes/BelongsToResolver.html +1 -1
  8. package/docs/classes/DatasourceDefinitionValidator.html +1 -1
  9. package/docs/classes/DefinitionRegistry.html +1 -1
  10. package/docs/classes/EmptyValuesDefiner.html +18 -0
  11. package/docs/classes/FieldsClauseTool.html +1 -1
  12. package/docs/classes/HasManyResolver.html +1 -1
  13. package/docs/classes/HasOneResolver.html +1 -1
  14. package/docs/classes/IncludeClauseTool.html +1 -1
  15. package/docs/classes/InvalidArgumentError.html +1 -1
  16. package/docs/classes/InvalidOperatorValueError.html +1 -1
  17. package/docs/classes/ModelDataSanitizer.html +1 -1
  18. package/docs/classes/ModelDataTransformer.html +1 -1
  19. package/docs/classes/ModelDataValidator.html +1 -1
  20. package/docs/classes/ModelDefinitionUtils.html +20 -18
  21. package/docs/classes/ModelDefinitionValidator.html +1 -1
  22. package/docs/classes/NotImplementedError.html +1 -1
  23. package/docs/classes/OperatorClauseTool.html +1 -1
  24. package/docs/classes/OrderClauseTool.html +1 -1
  25. package/docs/classes/PrimaryKeysDefinitionValidator.html +1 -1
  26. package/docs/classes/PropertiesDefinitionValidator.html +1 -1
  27. package/docs/classes/PropertyTransformerRegistry.html +1 -1
  28. package/docs/classes/PropertyUniquenessValidator.html +1 -1
  29. package/docs/classes/PropertyValidatorRegistry.html +1 -1
  30. package/docs/classes/ReferencesManyResolver.html +1 -1
  31. package/docs/classes/RelationsDefinitionValidator.html +1 -1
  32. package/docs/classes/Repository.html +1 -1
  33. package/docs/classes/RepositoryRegistry.html +1 -1
  34. package/docs/classes/Schema.html +1 -1
  35. package/docs/classes/SliceClauseTool.html +1 -1
  36. package/docs/classes/WhereClauseTool.html +1 -1
  37. package/docs/enums/DataType.html +1 -1
  38. package/docs/enums/DecoratorTargetType.html +1 -1
  39. package/docs/enums/RelationType.html +1 -1
  40. package/docs/functions/capitalize.html +1 -1
  41. package/docs/functions/cloneDeep.html +1 -1
  42. package/docs/functions/excludeObjectKeys.html +1 -1
  43. package/docs/functions/getCtorName.html +1 -1
  44. package/docs/functions/getDecoratorTargetType.html +1 -1
  45. package/docs/functions/getValueByPath.html +1 -1
  46. package/docs/functions/isCtor.html +1 -1
  47. package/docs/functions/isDeepEqual.html +2 -0
  48. package/docs/functions/isPureObject.html +1 -1
  49. package/docs/functions/selectObjectKeys.html +1 -1
  50. package/docs/functions/singularize.html +1 -1
  51. package/docs/functions/stringToRegexp.html +1 -1
  52. package/docs/index.html +62 -6
  53. package/docs/interfaces/AndClause.html +1 -1
  54. package/docs/interfaces/Constructor.html +1 -1
  55. package/docs/interfaces/OrClause.html +1 -1
  56. package/docs/modules.html +4 -1
  57. package/docs/types/AnyObject.html +1 -1
  58. package/docs/types/BelongsToDefinition.html +1 -1
  59. package/docs/types/CountMethod.html +1 -1
  60. package/docs/types/DEFAULT_PRIMARY_KEY_PROPERTY_NAME.html +1 -1
  61. package/docs/types/DatasourceDefinition.html +1 -1
  62. package/docs/types/FieldsClause.html +1 -1
  63. package/docs/types/FilterClause.html +1 -1
  64. package/docs/types/Flatten.html +1 -1
  65. package/docs/types/FullPropertyDefinition.html +1 -1
  66. package/docs/types/HasManyDefinition.html +1 -1
  67. package/docs/types/HasOneDefinition.html +1 -1
  68. package/docs/types/Identity.html +1 -1
  69. package/docs/types/IncludeClause.html +1 -1
  70. package/docs/types/ItemFilterClause.html +1 -1
  71. package/docs/types/ModelData.html +1 -1
  72. package/docs/types/ModelDefinition.html +1 -1
  73. package/docs/types/ModelId.html +1 -1
  74. package/docs/types/NestedIncludeClause.html +1 -1
  75. package/docs/types/NormalizedFieldsClause.html +1 -1
  76. package/docs/types/NormalizedIncludeClause.html +1 -1
  77. package/docs/types/OperatorClause.html +1 -1
  78. package/docs/types/OptionalUnlessRequiredId.html +1 -1
  79. package/docs/types/OrderClause.html +1 -1
  80. package/docs/types/PartialBy.html +1 -1
  81. package/docs/types/PartialWithoutId.html +1 -1
  82. package/docs/types/PolyBelongsToDefinition.html +1 -1
  83. package/docs/types/PolyHasManyDefinitionWithTargetKeys.html +1 -1
  84. package/docs/types/PolyHasManyDefinitionWithTargetRelationName.html +1 -1
  85. package/docs/types/PolyHasOneDefinitionWithTargetKeys.html +1 -1
  86. package/docs/types/PolyHasOneDefinitionWithTargetRelationName.html +1 -1
  87. package/docs/types/PropertiesClause.html +1 -1
  88. package/docs/types/PropertyDefinition.html +1 -1
  89. package/docs/types/PropertyDefinitionMap.html +1 -1
  90. package/docs/types/PropertyTransformOptions.html +1 -1
  91. package/docs/types/PropertyTransformer.html +1 -1
  92. package/docs/types/PropertyTransformerContext.html +1 -1
  93. package/docs/types/PropertyUniqueness.html +2 -0
  94. package/docs/types/PropertyValidateOptions.html +1 -1
  95. package/docs/types/PropertyValidator.html +1 -1
  96. package/docs/types/PropertyValidatorContext.html +1 -1
  97. package/docs/types/ReferencesManyDefinition.html +1 -1
  98. package/docs/types/RelationDefinition.html +1 -1
  99. package/docs/types/RelationDefinitionMap.html +1 -1
  100. package/docs/types/WhereClause.html +1 -1
  101. package/docs/types/WithoutId.html +1 -1
  102. package/package.json +1 -1
  103. package/src/definition/model/model-data-transformer.js +16 -9
  104. package/src/definition/model/model-data-transformer.spec.js +21 -27
  105. package/src/definition/model/model-data-validator.js +21 -8
  106. package/src/definition/model/model-data-validator.spec.js +97 -50
  107. package/src/definition/model/model-definition-utils.d.ts +8 -0
  108. package/src/definition/model/model-definition-utils.js +38 -2
  109. package/src/definition/model/model-definition-utils.spec.js +82 -0
  110. package/src/definition/model/properties/empty-values-definer.d.ts +23 -0
  111. package/src/definition/model/properties/empty-values-definer.js +66 -0
  112. package/src/definition/model/properties/empty-values-definer.spec.js +96 -0
  113. package/src/definition/model/properties/index.d.ts +2 -0
  114. package/src/definition/model/properties/index.js +2 -0
  115. package/src/definition/model/properties/properties-definition-validator.js +8 -2
  116. package/src/definition/model/properties/properties-definition-validator.spec.js +10 -6
  117. package/src/definition/model/properties/property-uniqueness-validator.js +10 -0
  118. package/src/definition/model/properties/property-uniqueness-validator.spec.js +44 -0
  119. package/src/definition/model/properties/property-uniqueness.d.ts +8 -0
  120. package/src/definition/model/properties/property-uniqueness.js +8 -0
  121. package/src/utils/index.d.ts +1 -0
  122. package/src/utils/index.js +1 -0
  123. package/src/utils/is-deep-equal.d.ts +10 -0
  124. package/src/utils/is-deep-equal.js +71 -0
  125. package/src/utils/is-deep-equal.spec.js +238 -0
@@ -2,6 +2,7 @@ import {expect} from 'chai';
2
2
  import {Schema} from '../../schema.js';
3
3
  import {format} from '@e22m4u/js-format';
4
4
  import {DataType} from './properties/index.js';
5
+ import {EmptyValuesDefiner} from './properties/index.js';
5
6
  import {ModelDataValidator} from './model-data-validator.js';
6
7
  import {DefinitionRegistry} from '../definition-registry.js';
7
8
  import {PropertyValidatorRegistry} from './properties/index.js';
@@ -114,6 +115,28 @@ describe('ModelDataValidator', function () {
114
115
  );
115
116
  });
116
117
 
118
+ it('throws an error if a required property has an empty value', function () {
119
+ const schema = new Schema();
120
+ schema.defineModel({
121
+ name: 'model',
122
+ properties: {
123
+ foo: {
124
+ type: DataType.STRING,
125
+ required: true,
126
+ },
127
+ },
128
+ });
129
+ schema
130
+ .getService(EmptyValuesDefiner)
131
+ .setEmptyValuesOf(DataType.STRING, ['empty']);
132
+ const throwable = () =>
133
+ schema.getService(ModelDataValidator).validate('model', {foo: 'empty'});
134
+ expect(throwable).to.throw(
135
+ 'The property "foo" of the model "model" ' +
136
+ 'is required, but "empty" given.',
137
+ );
138
+ });
139
+
117
140
  describe('an option "isPartial" is true', function () {
118
141
  it('does not throw an error if a given data does not have a required property', function () {
119
142
  const schema = new Schema();
@@ -169,9 +192,47 @@ describe('ModelDataValidator', function () {
169
192
  'The property "foo" of the model "model" is required, but null given.',
170
193
  );
171
194
  });
195
+
196
+ it('throws an error if a required property has an empty value', function () {
197
+ const schema = new Schema();
198
+ schema.defineModel({
199
+ name: 'model',
200
+ properties: {
201
+ foo: {
202
+ type: DataType.STRING,
203
+ required: true,
204
+ },
205
+ },
206
+ });
207
+ schema
208
+ .getService(EmptyValuesDefiner)
209
+ .setEmptyValuesOf(DataType.STRING, [5]);
210
+ const throwable = () =>
211
+ schema
212
+ .getService(ModelDataValidator)
213
+ .validate('model', {foo: 5}, true);
214
+ expect(throwable).to.throw(
215
+ 'The property "foo" of the model "model" is required, but 5 given.',
216
+ );
217
+ });
172
218
  });
173
219
 
174
220
  describe('validate by property type', function () {
221
+ it('skips validation for an empty value', function () {
222
+ const S = new Schema();
223
+ S.defineModel({
224
+ name: 'model',
225
+ datasource: 'datasource',
226
+ properties: {
227
+ foo: {
228
+ type: DataType.STRING,
229
+ },
230
+ },
231
+ });
232
+ S.getService(EmptyValuesDefiner).setEmptyValuesOf(DataType.STRING, [5]);
233
+ S.getService(ModelDataValidator).validate('model', {foo: 5});
234
+ });
235
+
175
236
  describe('DataType.ANY', function () {
176
237
  describe('ShortPropertyDefinition', function () {
177
238
  it('does not throw an error if an undefined given', function () {
@@ -1998,8 +2059,27 @@ describe('ModelDataValidator', function () {
1998
2059
  });
1999
2060
 
2000
2061
  describe('validate by property validators', function () {
2062
+ it('skips validation for an empty value', function () {
2063
+ const S = new Schema();
2064
+ S.getService(PropertyValidatorRegistry).addValidator(
2065
+ 'myValidator',
2066
+ () => false,
2067
+ );
2068
+ S.defineModel({
2069
+ name: 'model',
2070
+ properties: {
2071
+ foo: {
2072
+ type: DataType.STRING,
2073
+ validate: 'myValidator',
2074
+ },
2075
+ },
2076
+ });
2077
+ S.getService(EmptyValuesDefiner).setEmptyValuesOf(DataType.STRING, [5]);
2078
+ S.getService(ModelDataValidator).validate('model', {foo: 5});
2079
+ });
2080
+
2001
2081
  describe('the option "validate" with the string value', function () {
2002
- it('validates a property value even is not provided', function () {
2082
+ it('does not validate a property value if it is not provided', function () {
2003
2083
  const S = new Schema();
2004
2084
  S.getService(PropertyValidatorRegistry).addValidator(
2005
2085
  'myValidator',
@@ -2015,14 +2095,10 @@ describe('ModelDataValidator', function () {
2015
2095
  },
2016
2096
  });
2017
2097
  const validator = S.getService(ModelDataValidator);
2018
- const throwable = () => validator.validate('model', {});
2019
- expect(throwable).to.throw(
2020
- 'The property "foo" of the model "model" has an invalid value undefined ' +
2021
- 'that caught by the validator "myValidator".',
2022
- );
2098
+ validator.validate('model', {});
2023
2099
  });
2024
2100
 
2025
- it('validates undefined and null values', function () {
2101
+ it('does not validate undefined and null values', function () {
2026
2102
  const S = new Schema();
2027
2103
  S.getService(PropertyValidatorRegistry).addValidator(
2028
2104
  'myValidator',
@@ -2038,15 +2114,8 @@ describe('ModelDataValidator', function () {
2038
2114
  },
2039
2115
  });
2040
2116
  const validator = S.getService(ModelDataValidator);
2041
- const throwable = v => () => validator.validate('model', {foo: v});
2042
- const error = v =>
2043
- format(
2044
- 'The property "foo" of the model "model" has an invalid value %s ' +
2045
- 'that caught by the validator "myValidator".',
2046
- v,
2047
- );
2048
- expect(throwable(undefined)).to.throw(error('undefined'));
2049
- expect(throwable(null)).to.throw(error('null'));
2117
+ validator.validate('model', {foo: undefined});
2118
+ validator.validate('model', {foo: null});
2050
2119
  });
2051
2120
 
2052
2121
  it('throws an error from the validator', function () {
@@ -2233,7 +2302,7 @@ describe('ModelDataValidator', function () {
2233
2302
  });
2234
2303
  });
2235
2304
 
2236
- it('validates a property value even is not provided', function () {
2305
+ it('does not validate a property value if it is not provided', function () {
2237
2306
  const S = new Schema();
2238
2307
  S.getService(PropertyValidatorRegistry).addValidator(
2239
2308
  'myValidator',
@@ -2249,14 +2318,10 @@ describe('ModelDataValidator', function () {
2249
2318
  },
2250
2319
  });
2251
2320
  const validator = S.getService(ModelDataValidator);
2252
- const throwable = () => validator.validate('model', {});
2253
- expect(throwable).to.throw(
2254
- 'The property "foo" of the model "model" has an invalid value undefined ' +
2255
- 'that caught by the validator "myValidator".',
2256
- );
2321
+ validator.validate('model', {});
2257
2322
  });
2258
2323
 
2259
- it('validates undefined and null values', function () {
2324
+ it('does not validate undefined and null values', function () {
2260
2325
  const S = new Schema();
2261
2326
  S.getService(PropertyValidatorRegistry).addValidator(
2262
2327
  'myValidator',
@@ -2272,15 +2337,8 @@ describe('ModelDataValidator', function () {
2272
2337
  },
2273
2338
  });
2274
2339
  const validator = S.getService(ModelDataValidator);
2275
- const throwable = v => () => validator.validate('model', {foo: v});
2276
- const error = v =>
2277
- format(
2278
- 'The property "foo" of the model "model" has an invalid value %s ' +
2279
- 'that caught by the validator "myValidator".',
2280
- v,
2281
- );
2282
- expect(throwable(undefined)).to.throw(error('undefined'));
2283
- expect(throwable(null)).to.throw(error('null'));
2340
+ validator.validate('model', {foo: undefined});
2341
+ validator.validate('model', {foo: null});
2284
2342
  });
2285
2343
 
2286
2344
  it('throws an error from the validator', function () {
@@ -2468,7 +2526,7 @@ describe('ModelDataValidator', function () {
2468
2526
  });
2469
2527
  });
2470
2528
 
2471
- it('validates a property value even is not provided', function () {
2529
+ it('does not validate a property value if it is not provided', function () {
2472
2530
  const S = new Schema();
2473
2531
  S.getService(PropertyValidatorRegistry).addValidator(
2474
2532
  'myValidator',
@@ -2486,14 +2544,10 @@ describe('ModelDataValidator', function () {
2486
2544
  },
2487
2545
  });
2488
2546
  const validator = S.getService(ModelDataValidator);
2489
- const throwable = () => validator.validate('model', {});
2490
- expect(throwable).to.throw(
2491
- 'The property "foo" of the model "model" has an invalid value undefined ' +
2492
- 'that caught by the validator "myValidator".',
2493
- );
2547
+ validator.validate('model', {});
2494
2548
  });
2495
2549
 
2496
- it('validates undefined and null values', function () {
2550
+ it('does not validate undefined and null values', function () {
2497
2551
  const S = new Schema();
2498
2552
  S.getService(PropertyValidatorRegistry).addValidator(
2499
2553
  'myValidator',
@@ -2511,15 +2565,8 @@ describe('ModelDataValidator', function () {
2511
2565
  },
2512
2566
  });
2513
2567
  const validator = S.getService(ModelDataValidator);
2514
- const throwable = v => () => validator.validate('model', {foo: v});
2515
- const error = v =>
2516
- format(
2517
- 'The property "foo" of the model "model" has an invalid value %s ' +
2518
- 'that caught by the validator "myValidator".',
2519
- v,
2520
- );
2521
- expect(throwable(undefined)).to.throw(error('undefined'));
2522
- expect(throwable(null)).to.throw(error('null'));
2568
+ validator.validate('model', {foo: undefined});
2569
+ validator.validate('model', {foo: null});
2523
2570
  });
2524
2571
 
2525
2572
  it('throws an error from the validator', function () {
@@ -2748,7 +2795,7 @@ describe('ModelDataValidator', function () {
2748
2795
  name: 'model',
2749
2796
  properties: {
2750
2797
  foo: {
2751
- type: DataType.STRING,
2798
+ type: DataType.ANY,
2752
2799
  validate: undefined,
2753
2800
  },
2754
2801
  },
@@ -2757,7 +2804,7 @@ describe('ModelDataValidator', function () {
2757
2804
  const throwable = v => () => {
2758
2805
  const models = schema.getService(DefinitionRegistry)['_models'];
2759
2806
  models.model.properties.foo.validate = v;
2760
- V.validate('model', {});
2807
+ V.validate('model', {foo: 'bar'});
2761
2808
  };
2762
2809
  const error = v =>
2763
2810
  format(
@@ -2,6 +2,7 @@ import {ModelData} from '../../types.js';
2
2
  import {Service} from '@e22m4u/js-service';
3
3
  import {DataType} from './properties/index.js';
4
4
  import {RelationDefinition} from './relations/index.js';
5
+ import {PropertyDefinition} from './properties/index.js';
5
6
  import {PropertyDefinitionMap} from './model-definition.js';
6
7
  import {RelationDefinitionMap} from './model-definition.js';
7
8
 
@@ -94,6 +95,13 @@ export declare class ModelDefinitionUtils extends Service {
94
95
  */
95
96
  getDataTypeByPropertyName(modelName: string, propertyName: string): DataType;
96
97
 
98
+ /**
99
+ * Get data type from property definition.
100
+ *
101
+ * @param propDef
102
+ */
103
+ getDataTypeFromPropertyDefinition(propDef: PropertyDefinition): DataType;
104
+
97
105
  /**
98
106
  * Get own properties definition of primary keys.
99
107
  *
@@ -2,6 +2,7 @@ import {Service} from '@e22m4u/js-service';
2
2
  import {DataType} from './properties/index.js';
3
3
  import {cloneDeep} from '../../utils/index.js';
4
4
  import {excludeObjectKeys} from '../../utils/index.js';
5
+ import {EmptyValuesDefiner} from './properties/index.js';
5
6
  import {InvalidArgumentError} from '../../errors/index.js';
6
7
  import {DefinitionRegistry} from '../definition-registry.js';
7
8
 
@@ -139,10 +140,16 @@ export class ModelDefinitionUtils extends Service {
139
140
  ? Object.keys(modelData)
140
141
  : Object.keys(propDefs);
141
142
  const extendedData = cloneDeep(modelData);
143
+ const emptyValueDefiner = this.getService(EmptyValuesDefiner);
142
144
  propNames.forEach(propName => {
143
- const value = extendedData[propName];
144
- if (value != null) return;
145
145
  const propDef = propDefs[propName];
146
+ const propValue = extendedData[propName];
147
+ const propType =
148
+ propDef != null
149
+ ? this.getDataTypeFromPropertyDefinition(propDef)
150
+ : DataType.ANY;
151
+ const isEmpty = emptyValueDefiner.isEmpty(propType, propValue);
152
+ if (!isEmpty) return;
146
153
  if (
147
154
  propDef &&
148
155
  typeof propDef === 'object' &&
@@ -226,6 +233,35 @@ export class ModelDefinitionUtils extends Service {
226
233
  return propDef.type;
227
234
  }
228
235
 
236
+ /**
237
+ * Get data type from property definition.
238
+ *
239
+ * @param {object} propDef
240
+ * @returns {string}
241
+ */
242
+ getDataTypeFromPropertyDefinition(propDef) {
243
+ if (
244
+ (!propDef || typeof propDef !== 'object') &&
245
+ !Object.values(DataType).includes(propDef)
246
+ ) {
247
+ throw new InvalidArgumentError(
248
+ 'The argument "propDef" of the ModelDefinitionUtils.getDataTypeFromPropertyDefinition ' +
249
+ 'should be an Object or the DataType enum, but %v given.',
250
+ propDef,
251
+ );
252
+ }
253
+ if (typeof propDef === 'string') return propDef;
254
+ const dataType = propDef.type;
255
+ if (!Object.values(DataType).includes(dataType))
256
+ throw new InvalidArgumentError(
257
+ 'The given Object to the ModelDefinitionUtils.getDataTypeFromPropertyDefinition ' +
258
+ 'should have the "type" property with one of values: %l, but %v given.',
259
+ Object.values(DataType),
260
+ propDef.type,
261
+ );
262
+ return dataType;
263
+ }
264
+
229
265
  /**
230
266
  * Get own properties definition of primary keys.
231
267
  *
@@ -4,6 +4,7 @@ import {Schema} from '../../schema.js';
4
4
  import {format} from '@e22m4u/js-format';
5
5
  import {DataType} from './properties/index.js';
6
6
  import {RelationType} from './relations/index.js';
7
+ import {EmptyValuesDefiner} from './properties/index.js';
7
8
  import {InvalidArgumentError} from '../../errors/index.js';
8
9
  import {ModelDefinitionUtils} from './model-definition-utils.js';
9
10
  import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from './model-definition-utils.js';
@@ -476,6 +477,26 @@ describe('ModelDefinitionUtils', function () {
476
477
  expect(result).to.be.eql({foo: 'string'});
477
478
  });
478
479
 
480
+ it('sets a default value if a property has an empty value', function () {
481
+ const schema = new Schema();
482
+ schema.defineModel({
483
+ name: 'model',
484
+ properties: {
485
+ foo: {
486
+ type: DataType.STRING,
487
+ default: 'placeholder',
488
+ },
489
+ },
490
+ });
491
+ schema
492
+ .getService(EmptyValuesDefiner)
493
+ .setEmptyValuesOf(DataType.STRING, ['empty']);
494
+ const result = schema
495
+ .getService(ModelDefinitionUtils)
496
+ .setDefaultValuesToEmptyProperties('model', {foo: 'empty'});
497
+ expect(result).to.be.eql({foo: 'placeholder'});
498
+ });
499
+
479
500
  it('sets a value from a factory function', function () {
480
501
  const schema = new Schema();
481
502
  schema.defineModel({
@@ -827,6 +848,67 @@ describe('ModelDefinitionUtils', function () {
827
848
  });
828
849
  });
829
850
 
851
+ describe('getDataTypeFromPropertyDefinition', function () {
852
+ it('requires the given argument "propDef" must be an Object or DataType', function () {
853
+ const schema = new Schema();
854
+ const S = schema.getService(ModelDefinitionUtils);
855
+ const throwable = v => () => S.getDataTypeFromPropertyDefinition(v);
856
+ const error = v =>
857
+ format(
858
+ 'The argument "propDef" of the ModelDefinitionUtils.getDataTypeFromPropertyDefinition ' +
859
+ 'should be an Object or the DataType enum, but %s given.',
860
+ v,
861
+ );
862
+ expect(throwable('str')).to.throw(error('"str"'));
863
+ expect(throwable('')).to.throw(error('""'));
864
+ expect(throwable(10)).to.throw(error('10'));
865
+ expect(throwable(0)).to.throw(error('0'));
866
+ expect(throwable(true)).to.throw(error('true'));
867
+ expect(throwable(false)).to.throw(error('false'));
868
+ expect(throwable(undefined)).to.throw(error('undefined'));
869
+ expect(throwable(null)).to.throw(error('null'));
870
+ throwable(DataType.ANY)();
871
+ throwable({type: DataType.ANY})();
872
+ });
873
+
874
+ it('requires the given Object to have the "type" property with the DataType enum', function () {
875
+ const schema = new Schema();
876
+ const S = schema.getService(ModelDefinitionUtils);
877
+ const throwable = v => () =>
878
+ S.getDataTypeFromPropertyDefinition({type: v});
879
+ const error = v =>
880
+ format(
881
+ 'The given Object to the ModelDefinitionUtils.getDataTypeFromPropertyDefinition ' +
882
+ 'should have the "type" property with one of values: %l, but %s given.',
883
+ Object.values(DataType),
884
+ v,
885
+ );
886
+ expect(throwable('str')).to.throw(error('"str"'));
887
+ expect(throwable('')).to.throw(error('""'));
888
+ expect(throwable(10)).to.throw(error('10'));
889
+ expect(throwable(0)).to.throw(error('0'));
890
+ expect(throwable(true)).to.throw(error('true'));
891
+ expect(throwable(false)).to.throw(error('false'));
892
+ expect(throwable(undefined)).to.throw(error('undefined'));
893
+ expect(throwable(null)).to.throw(error('null'));
894
+ throwable(DataType.ANY)();
895
+ });
896
+
897
+ it('returns the DataType from the given DataType enum', function () {
898
+ const schema = new Schema();
899
+ const S = schema.getService(ModelDefinitionUtils);
900
+ const res = S.getDataTypeFromPropertyDefinition(DataType.STRING);
901
+ expect(res).to.be.eq(DataType.STRING);
902
+ });
903
+
904
+ it('returns the DataType from the given PropertyDefinition', function () {
905
+ const schema = new Schema();
906
+ const S = schema.getService(ModelDefinitionUtils);
907
+ const res = S.getDataTypeFromPropertyDefinition({type: DataType.STRING});
908
+ expect(res).to.be.eq(DataType.STRING);
909
+ });
910
+ });
911
+
830
912
  describe('getOwnPropertiesDefinitionWithoutPrimaryKeys', function () {
831
913
  it('returns an empty object if a model does not have properties', function () {
832
914
  const schema = new Schema();
@@ -0,0 +1,23 @@
1
+ import {DataType} from './data-type.js';
2
+ import {Service} from '@e22m4u/js-service';
3
+
4
+ /**
5
+ * Empty values definer.
6
+ */
7
+ export class EmptyValuesDefiner extends Service {
8
+ /**
9
+ * Set empty values of.
10
+ *
11
+ * @param dataType
12
+ * @param emptyValues
13
+ */
14
+ setEmptyValuesOf(dataType: DataType, emptyValues: unknown[]): this;
15
+
16
+ /**
17
+ * Is empty.
18
+ *
19
+ * @param dataType
20
+ * @param value
21
+ */
22
+ isEmpty(dataType: DataType, value: unknown): boolean;
23
+ }
@@ -0,0 +1,66 @@
1
+ import {DataType} from './data-type.js';
2
+ import {Service} from '@e22m4u/js-service';
3
+ import {isDeepEqual} from '../../../utils/index.js';
4
+ import {InvalidArgumentError} from '../../../errors/index.js';
5
+
6
+ /**
7
+ * Empty values definer.
8
+ */
9
+ export class EmptyValuesDefiner extends Service {
10
+ /**
11
+ * Empty values map.
12
+ *
13
+ * @type {Map<string, *[]>}
14
+ */
15
+ _emptyValuesMap = new Map([
16
+ [DataType.ANY, [undefined, null]],
17
+ [DataType.STRING, [undefined, null, '']],
18
+ [DataType.NUMBER, [undefined, null, 0]],
19
+ [DataType.BOOLEAN, [undefined, null]],
20
+ [DataType.ARRAY, [undefined, null, []]],
21
+ [DataType.OBJECT, [undefined, null, {}]],
22
+ ]);
23
+
24
+ /**
25
+ * Set empty values of data type.
26
+ *
27
+ * @param {string} dataType
28
+ * @param {*[]} emptyValues
29
+ * @returns {EmptyValuesDefiner}
30
+ */
31
+ setEmptyValuesOf(dataType, emptyValues) {
32
+ if (!Object.values(DataType).includes(dataType))
33
+ throw new InvalidArgumentError(
34
+ 'The argument "dataType" of the EmptyValuesDefiner.setEmptyValuesOf ' +
35
+ 'must be one of data types: %l, but %v given.',
36
+ Object.values(DataType),
37
+ dataType,
38
+ );
39
+ if (!Array.isArray(emptyValues))
40
+ throw new InvalidArgumentError(
41
+ 'The argument "emptyValues" of the EmptyValuesDefiner.setEmptyValuesOf ' +
42
+ 'must be an Array, but %v given.',
43
+ emptyValues,
44
+ );
45
+ this._emptyValuesMap.set(dataType, emptyValues);
46
+ return this;
47
+ }
48
+
49
+ /**
50
+ * Is empty.
51
+ *
52
+ * @param {string} dataType
53
+ * @param {*} value
54
+ * @returns {boolean}
55
+ */
56
+ isEmpty(dataType, value) {
57
+ if (!Object.values(DataType).includes(dataType))
58
+ throw new InvalidArgumentError(
59
+ 'The argument "dataType" of the EmptyValuesDefiner.isEmpty ' +
60
+ 'must be one of data types: %l, but %v given.',
61
+ Object.values(DataType),
62
+ dataType,
63
+ );
64
+ return this._emptyValuesMap.get(dataType).some(v => isDeepEqual(v, value));
65
+ }
66
+ }
@@ -0,0 +1,96 @@
1
+ import {expect} from 'chai';
2
+ import {DataType} from './data-type.js';
3
+ import {format} from '@e22m4u/js-format';
4
+ import {Schema} from '../../../schema.js';
5
+ import {EmptyValuesDefiner} from './empty-values-definer.js';
6
+
7
+ const getEmptyValues = (definer, dataType) => {
8
+ return definer['_emptyValuesMap'].get(dataType);
9
+ };
10
+
11
+ describe('EmptyValuesDefiner', function () {
12
+ describe('_emptyValuesMap', function () {
13
+ it('has default values', function () {
14
+ const schema = new Schema();
15
+ const S = schema.getService(EmptyValuesDefiner);
16
+ expect(Array.from(S['_emptyValuesMap'])).to.be.eql([
17
+ [DataType.ANY, [undefined, null]],
18
+ [DataType.STRING, [undefined, null, '']],
19
+ [DataType.NUMBER, [undefined, null, 0]],
20
+ [DataType.BOOLEAN, [undefined, null]],
21
+ [DataType.ARRAY, [undefined, null, []]],
22
+ [DataType.OBJECT, [undefined, null, {}]],
23
+ ]);
24
+ });
25
+ });
26
+
27
+ describe('setEmptyValuesOf', function () {
28
+ it('requires the parameter "dataType" to be a DataType enum', function () {
29
+ const schema = new Schema();
30
+ const S = schema.getService(EmptyValuesDefiner);
31
+ const throwable = v => () => S.setEmptyValuesOf(v, []);
32
+ const error = v =>
33
+ format(
34
+ 'The argument "dataType" of the EmptyValuesDefiner.setEmptyValuesOf ' +
35
+ 'must be one of data types: %l, but %s given.',
36
+ Object.values(DataType),
37
+ v,
38
+ );
39
+ expect(throwable('str')).to.throw(error('"str"'));
40
+ expect(throwable('')).to.throw(error('""'));
41
+ expect(throwable(10)).to.throw(error('10'));
42
+ expect(throwable(0)).to.throw(error('0'));
43
+ expect(throwable(true)).to.throw(error('true'));
44
+ expect(throwable(false)).to.throw(error('false'));
45
+ expect(throwable(undefined)).to.throw(error('undefined'));
46
+ expect(throwable(null)).to.throw(error('null'));
47
+ expect(throwable({})).to.throw(error('Object'));
48
+ expect(throwable([])).to.throw(error('Array'));
49
+ throwable(DataType.ANY)();
50
+ });
51
+
52
+ it('requires the parameter "emptyValues" to be an Array', function () {
53
+ const schema = new Schema();
54
+ const S = schema.getService(EmptyValuesDefiner);
55
+ const throwable = v => () => S.setEmptyValuesOf(DataType.ANY, v);
56
+ const error = v =>
57
+ format(
58
+ 'The argument "emptyValues" of the EmptyValuesDefiner.setEmptyValuesOf ' +
59
+ 'must be an Array, but %s given.',
60
+ v,
61
+ );
62
+ expect(throwable('str')).to.throw(error('"str"'));
63
+ expect(throwable('')).to.throw(error('""'));
64
+ expect(throwable(10)).to.throw(error('10'));
65
+ expect(throwable(0)).to.throw(error('0'));
66
+ expect(throwable(true)).to.throw(error('true'));
67
+ expect(throwable(false)).to.throw(error('false'));
68
+ expect(throwable(undefined)).to.throw(error('undefined'));
69
+ expect(throwable(null)).to.throw(error('null'));
70
+ expect(throwable({})).to.throw(error('Object'));
71
+ throwable([])();
72
+ throwable([1, 2, 3])();
73
+ });
74
+
75
+ it('overrides default values of the given data type', function () {
76
+ const schema = new Schema();
77
+ const S = schema.getService(EmptyValuesDefiner);
78
+ expect(getEmptyValues(S, DataType.ANY)).eql([undefined, null]);
79
+ S.setEmptyValuesOf(DataType.ANY, [1, 2, 3]);
80
+ expect(getEmptyValues(S, DataType.ANY)).eql([1, 2, 3]);
81
+ });
82
+ });
83
+
84
+ describe('isEmpty', function () {
85
+ it('returns true if the given value exists in the given type', function () {
86
+ const schema = new Schema();
87
+ const S = schema.getService(EmptyValuesDefiner);
88
+ S.setEmptyValuesOf(DataType.ANY, []);
89
+ expect(S.isEmpty(DataType.ANY, 'foo')).to.be.false;
90
+ S.setEmptyValuesOf(DataType.ANY, ['bar']);
91
+ expect(S.isEmpty(DataType.ANY, 'foo')).to.be.false;
92
+ S.setEmptyValuesOf(DataType.ANY, ['bar', 'foo']);
93
+ expect(S.isEmpty(DataType.ANY, 'foo')).to.be.true;
94
+ });
95
+ });
96
+ });
@@ -1,5 +1,7 @@
1
1
  export * from './data-type.js';
2
2
  export * from './property-definition.js';
3
+ export * from './property-uniqueness.js';
4
+ export * from './empty-values-definer.js';
3
5
  export * from './property-validator/index.js';
4
6
  export * from './property-transformer/index.js';
5
7
  export * from './property-uniqueness-validator.js';
@@ -1,5 +1,7 @@
1
1
  export * from './data-type.js';
2
2
  export * from './property-definition.js';
3
+ export * from './property-uniqueness.js';
4
+ export * from './empty-values-definer.js';
3
5
  export * from './property-validator/index.js';
4
6
  export * from './property-transformer/index.js';
5
7
  export * from './property-uniqueness-validator.js';
@@ -1,6 +1,7 @@
1
1
  import {Service} from '@e22m4u/js-service';
2
2
  import {DataType as Type} from './data-type.js';
3
3
  import {capitalize} from '../../../utils/index.js';
4
+ import {PropertyUniqueness} from './property-uniqueness.js';
4
5
  import {InvalidArgumentError} from '../../../errors/index.js';
5
6
  import {PropertyValidatorRegistry} from './property-validator/index.js';
6
7
  import {PropertyTransformerRegistry} from './property-transformer/index.js';
@@ -297,14 +298,19 @@ export class PropertiesDefinitionValidator extends Service {
297
298
  );
298
299
  }
299
300
  }
300
- if (propDef.unique && typeof propDef.unique !== 'boolean')
301
+ if (
302
+ propDef.unique &&
303
+ !Object.values(PropertyUniqueness).includes(propDef.unique)
304
+ ) {
301
305
  throw new InvalidArgumentError(
302
306
  'The provided option "unique" of the property %v in the model %v ' +
303
- 'should be a Boolean, but %v given.',
307
+ 'should be one of values: %l, but %v given.',
304
308
  propName,
305
309
  modelName,
310
+ Object.values(PropertyUniqueness),
306
311
  propDef.unique,
307
312
  );
313
+ }
308
314
  if (propDef.unique && propDef.primaryKey)
309
315
  throw new InvalidArgumentError(
310
316
  'The property %v of the model %v is a primary key, ' +