@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.
- package/README.md +46 -4
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/Adapter.html +1 -1
- package/docs/classes/AdapterLoader.html +1 -1
- package/docs/classes/AdapterRegistry.html +1 -1
- package/docs/classes/BelongsToResolver.html +1 -1
- package/docs/classes/DatasourceDefinitionValidator.html +1 -1
- package/docs/classes/DefinitionRegistry.html +1 -1
- package/docs/classes/EmptyValuesDefiner.html +18 -0
- package/docs/classes/FieldsClauseTool.html +1 -1
- package/docs/classes/HasManyResolver.html +1 -1
- package/docs/classes/HasOneResolver.html +1 -1
- package/docs/classes/IncludeClauseTool.html +1 -1
- package/docs/classes/InvalidArgumentError.html +1 -1
- package/docs/classes/InvalidOperatorValueError.html +1 -1
- package/docs/classes/ModelDataSanitizer.html +1 -1
- package/docs/classes/ModelDataTransformer.html +1 -1
- package/docs/classes/ModelDataValidator.html +1 -1
- package/docs/classes/ModelDefinitionUtils.html +20 -18
- package/docs/classes/ModelDefinitionValidator.html +1 -1
- package/docs/classes/NotImplementedError.html +1 -1
- package/docs/classes/OperatorClauseTool.html +1 -1
- package/docs/classes/OrderClauseTool.html +1 -1
- package/docs/classes/PrimaryKeysDefinitionValidator.html +1 -1
- package/docs/classes/PropertiesDefinitionValidator.html +1 -1
- package/docs/classes/PropertyTransformerRegistry.html +1 -1
- package/docs/classes/PropertyUniquenessValidator.html +1 -1
- package/docs/classes/PropertyValidatorRegistry.html +1 -1
- package/docs/classes/ReferencesManyResolver.html +1 -1
- package/docs/classes/RelationsDefinitionValidator.html +1 -1
- package/docs/classes/Repository.html +1 -1
- package/docs/classes/RepositoryRegistry.html +1 -1
- package/docs/classes/Schema.html +1 -1
- package/docs/classes/SliceClauseTool.html +1 -1
- package/docs/classes/WhereClauseTool.html +1 -1
- package/docs/enums/DataType.html +1 -1
- package/docs/enums/DecoratorTargetType.html +1 -1
- package/docs/enums/RelationType.html +1 -1
- package/docs/functions/capitalize.html +1 -1
- package/docs/functions/cloneDeep.html +1 -1
- package/docs/functions/excludeObjectKeys.html +1 -1
- package/docs/functions/getCtorName.html +1 -1
- package/docs/functions/getDecoratorTargetType.html +1 -1
- package/docs/functions/getValueByPath.html +1 -1
- package/docs/functions/isCtor.html +1 -1
- package/docs/functions/isDeepEqual.html +2 -0
- package/docs/functions/isPureObject.html +1 -1
- package/docs/functions/selectObjectKeys.html +1 -1
- package/docs/functions/singularize.html +1 -1
- package/docs/functions/stringToRegexp.html +1 -1
- package/docs/index.html +62 -6
- package/docs/interfaces/AndClause.html +1 -1
- package/docs/interfaces/Constructor.html +1 -1
- package/docs/interfaces/OrClause.html +1 -1
- package/docs/modules.html +4 -1
- package/docs/types/AnyObject.html +1 -1
- package/docs/types/BelongsToDefinition.html +1 -1
- package/docs/types/CountMethod.html +1 -1
- package/docs/types/DEFAULT_PRIMARY_KEY_PROPERTY_NAME.html +1 -1
- package/docs/types/DatasourceDefinition.html +1 -1
- package/docs/types/FieldsClause.html +1 -1
- package/docs/types/FilterClause.html +1 -1
- package/docs/types/Flatten.html +1 -1
- package/docs/types/FullPropertyDefinition.html +1 -1
- package/docs/types/HasManyDefinition.html +1 -1
- package/docs/types/HasOneDefinition.html +1 -1
- package/docs/types/Identity.html +1 -1
- package/docs/types/IncludeClause.html +1 -1
- package/docs/types/ItemFilterClause.html +1 -1
- package/docs/types/ModelData.html +1 -1
- package/docs/types/ModelDefinition.html +1 -1
- package/docs/types/ModelId.html +1 -1
- package/docs/types/NestedIncludeClause.html +1 -1
- package/docs/types/NormalizedFieldsClause.html +1 -1
- package/docs/types/NormalizedIncludeClause.html +1 -1
- package/docs/types/OperatorClause.html +1 -1
- package/docs/types/OptionalUnlessRequiredId.html +1 -1
- package/docs/types/OrderClause.html +1 -1
- package/docs/types/PartialBy.html +1 -1
- package/docs/types/PartialWithoutId.html +1 -1
- package/docs/types/PolyBelongsToDefinition.html +1 -1
- package/docs/types/PolyHasManyDefinitionWithTargetKeys.html +1 -1
- package/docs/types/PolyHasManyDefinitionWithTargetRelationName.html +1 -1
- package/docs/types/PolyHasOneDefinitionWithTargetKeys.html +1 -1
- package/docs/types/PolyHasOneDefinitionWithTargetRelationName.html +1 -1
- package/docs/types/PropertiesClause.html +1 -1
- package/docs/types/PropertyDefinition.html +1 -1
- package/docs/types/PropertyDefinitionMap.html +1 -1
- package/docs/types/PropertyTransformOptions.html +1 -1
- package/docs/types/PropertyTransformer.html +1 -1
- package/docs/types/PropertyTransformerContext.html +1 -1
- package/docs/types/PropertyUniqueness.html +2 -0
- package/docs/types/PropertyValidateOptions.html +1 -1
- package/docs/types/PropertyValidator.html +1 -1
- package/docs/types/PropertyValidatorContext.html +1 -1
- package/docs/types/ReferencesManyDefinition.html +1 -1
- package/docs/types/RelationDefinition.html +1 -1
- package/docs/types/RelationDefinitionMap.html +1 -1
- package/docs/types/WhereClause.html +1 -1
- package/docs/types/WithoutId.html +1 -1
- package/package.json +1 -1
- package/src/definition/model/model-data-transformer.js +16 -9
- package/src/definition/model/model-data-transformer.spec.js +21 -27
- package/src/definition/model/model-data-validator.js +21 -8
- package/src/definition/model/model-data-validator.spec.js +97 -50
- package/src/definition/model/model-definition-utils.d.ts +8 -0
- package/src/definition/model/model-definition-utils.js +38 -2
- package/src/definition/model/model-definition-utils.spec.js +82 -0
- package/src/definition/model/properties/empty-values-definer.d.ts +23 -0
- package/src/definition/model/properties/empty-values-definer.js +66 -0
- package/src/definition/model/properties/empty-values-definer.spec.js +96 -0
- package/src/definition/model/properties/index.d.ts +2 -0
- package/src/definition/model/properties/index.js +2 -0
- package/src/definition/model/properties/properties-definition-validator.js +8 -2
- package/src/definition/model/properties/properties-definition-validator.spec.js +10 -6
- package/src/definition/model/properties/property-uniqueness-validator.js +10 -0
- package/src/definition/model/properties/property-uniqueness-validator.spec.js +44 -0
- package/src/definition/model/properties/property-uniqueness.d.ts +8 -0
- package/src/definition/model/properties/property-uniqueness.js +8 -0
- package/src/utils/index.d.ts +1 -0
- package/src/utils/index.js +1 -0
- package/src/utils/is-deep-equal.d.ts +10 -0
- package/src/utils/is-deep-equal.js +71 -0
- 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('
|
|
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
|
-
|
|
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('
|
|
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
|
-
|
|
2042
|
-
|
|
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('
|
|
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
|
-
|
|
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('
|
|
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
|
-
|
|
2276
|
-
|
|
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('
|
|
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
|
-
|
|
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('
|
|
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
|
-
|
|
2515
|
-
|
|
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.
|
|
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 (
|
|
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
|
|
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, ' +
|