@e22m4u/js-repository 0.1.2 → 0.1.4
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/.husky/commit-msg +1 -4
- package/.husky/pre-commit +0 -3
- package/README.md +34 -35
- package/assets/mermaid-diagram.png +0 -0
- package/assets/mermaid-diagram.txt +29 -0
- package/docs/assets/main.js +4 -4
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/Adapter.html +14 -14
- package/docs/classes/AdapterLoader.html +2 -2
- package/docs/classes/AdapterRegistry.html +2 -2
- package/docs/classes/BelongsToResolver.html +3 -3
- package/docs/classes/DatasourceDefinitionValidator.html +2 -2
- package/docs/classes/DefinitionRegistry.html +7 -7
- package/docs/classes/FieldsClauseTool.html +4 -4
- package/docs/classes/HasManyResolver.html +4 -4
- package/docs/classes/HasOneResolver.html +4 -4
- package/docs/classes/IncludeClauseTool.html +6 -6
- package/docs/classes/InvalidArgumentError.html +1 -1
- package/docs/classes/InvalidOperatorValueError.html +2 -2
- package/docs/classes/ModelDataSanitizer.html +2 -2
- package/docs/classes/ModelDataValidator.html +3 -5
- package/docs/classes/ModelDefinitionUtils.html +17 -17
- package/docs/classes/ModelDefinitionValidator.html +2 -2
- package/docs/classes/NotImplementedError.html +1 -1
- package/docs/classes/OperatorClauseTool.html +14 -14
- package/docs/classes/OrderClauseTool.html +4 -4
- package/docs/classes/PrimaryKeysDefinitionValidator.html +2 -2
- package/docs/classes/PropertiesDefinitionValidator.html +2 -2
- package/docs/classes/PropertyValidatorRegistry.html +20 -0
- package/docs/classes/ReferencesManyResolver.html +2 -2
- package/docs/classes/RelationsDefinitionValidator.html +2 -2
- package/docs/classes/Repository.html +17 -17
- package/docs/classes/RepositoryRegistry.html +3 -3
- package/docs/classes/Schema.html +4 -4
- package/docs/classes/SliceClauseTool.html +4 -4
- package/docs/classes/WhereClauseTool.html +3 -3
- package/docs/enums/DataType.html +2 -2
- package/docs/enums/DecoratorTargetType.html +2 -2
- package/docs/enums/RelationType.html +2 -2
- 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/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 +18 -6
- package/docs/interfaces/AndClause.html +2 -2
- package/docs/interfaces/Constructor.html +2 -2
- package/docs/interfaces/OrClause.html +2 -2
- package/docs/modules.html +4 -0
- package/docs/types/AnyObject.html +1 -1
- package/docs/types/BelongsToDefinition.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 +2 -2
- 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/PropertyValidateOptions.html +2 -0
- package/docs/types/PropertyValidator.html +2 -0
- package/docs/types/PropertyValidatorContext.html +2 -0
- 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 +20 -21
- package/src/adapter/decorator/data-validation-decorator.js +18 -10
- package/src/adapter/decorator/data-validation-decorator.spec.js +40 -0
- package/src/definition/model/model-data-validator.d.ts +4 -16
- package/src/definition/model/model-data-validator.js +87 -11
- package/src/definition/model/model-data-validator.spec.js +1172 -442
- package/src/definition/model/properties/index.d.ts +1 -0
- package/src/definition/model/properties/index.js +1 -0
- package/src/definition/model/properties/properties-definition-validator.js +47 -0
- package/src/definition/model/properties/properties-definition-validator.spec.js +50 -0
- package/src/definition/model/properties/property-definition.d.ts +2 -0
- package/src/definition/model/properties/property-validator/builtin/index.d.ts +2 -0
- package/src/definition/model/properties/property-validator/builtin/index.js +2 -0
- package/src/definition/model/properties/property-validator/builtin/max-length-validator.d.ts +6 -0
- package/src/definition/model/properties/property-validator/builtin/max-length-validator.js +28 -0
- package/src/definition/model/properties/property-validator/builtin/max-length-validator.spec.js +65 -0
- package/src/definition/model/properties/property-validator/builtin/min-length-validator.d.ts +6 -0
- package/src/definition/model/properties/property-validator/builtin/min-length-validator.js +28 -0
- package/src/definition/model/properties/property-validator/builtin/min-length-validator.spec.js +65 -0
- package/src/definition/model/properties/property-validator/index.d.ts +2 -0
- package/src/definition/model/properties/property-validator/index.js +2 -0
- package/src/definition/model/properties/property-validator/property-validator-registry.d.ts +29 -0
- package/src/definition/model/properties/property-validator/property-validator-registry.js +74 -0
- package/src/definition/model/properties/property-validator/property-validator-registry.spec.js +120 -0
- package/src/definition/model/properties/property-validator/property-validator.d.ts +30 -0
- package/src/definition/model/properties/property-validator/property-validator.js +1 -0
- package/src/schema.spec.ts +15 -0
|
@@ -2,6 +2,7 @@ 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
4
|
import {InvalidArgumentError} from '../../../errors/index.js';
|
|
5
|
+
import {PropertyValidatorRegistry} from './property-validator/index.js';
|
|
5
6
|
import {PrimaryKeysDefinitionValidator} from './primary-keys-definition-validator.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -203,5 +204,51 @@ export class PropertiesDefinitionValidator extends Service {
|
|
|
203
204
|
);
|
|
204
205
|
}
|
|
205
206
|
}
|
|
207
|
+
if (propDef.validate != null) {
|
|
208
|
+
const propertyValidatorRegistry = this.getService(
|
|
209
|
+
PropertyValidatorRegistry,
|
|
210
|
+
);
|
|
211
|
+
if (propDef.validate && typeof propDef.validate === 'string') {
|
|
212
|
+
if (!propertyValidatorRegistry.hasValidator(propDef.validate))
|
|
213
|
+
throw new InvalidArgumentError(
|
|
214
|
+
'The property validator %v is not found.',
|
|
215
|
+
propDef.validate,
|
|
216
|
+
);
|
|
217
|
+
} else if (Array.isArray(propDef.validate)) {
|
|
218
|
+
for (const validatorName of propDef.validate) {
|
|
219
|
+
if (typeof validatorName !== 'string')
|
|
220
|
+
throw new InvalidArgumentError(
|
|
221
|
+
'The provided option "validate" of the property %v in the model %v ' +
|
|
222
|
+
'has an Array value that should have a non-empty String, ' +
|
|
223
|
+
'but %v given.',
|
|
224
|
+
propName,
|
|
225
|
+
modelName,
|
|
226
|
+
validatorName,
|
|
227
|
+
);
|
|
228
|
+
if (!propertyValidatorRegistry.hasValidator(validatorName))
|
|
229
|
+
throw new InvalidArgumentError(
|
|
230
|
+
'The property validator %v is not found.',
|
|
231
|
+
validatorName,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
} else if (typeof propDef.validate === 'object') {
|
|
235
|
+
for (const validatorName in propDef.validate) {
|
|
236
|
+
if (!propertyValidatorRegistry.hasValidator(validatorName))
|
|
237
|
+
throw new InvalidArgumentError(
|
|
238
|
+
'The property validator %v is not found.',
|
|
239
|
+
validatorName,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
} else {
|
|
243
|
+
throw new InvalidArgumentError(
|
|
244
|
+
'The provided option "validate" of the property %v in the model %v ' +
|
|
245
|
+
'should be a non-empty String, an Array of String or an Object, ' +
|
|
246
|
+
'but %v given.',
|
|
247
|
+
propName,
|
|
248
|
+
modelName,
|
|
249
|
+
propDef.validate,
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
206
253
|
}
|
|
207
254
|
}
|
|
@@ -2,12 +2,15 @@ import chai from 'chai';
|
|
|
2
2
|
import {expect} from 'chai';
|
|
3
3
|
import {DataType} from './data-type.js';
|
|
4
4
|
import {format} from '@e22m4u/js-format';
|
|
5
|
+
import {PropertyValidatorRegistry} from './property-validator/index.js';
|
|
5
6
|
import {PropertiesDefinitionValidator} from './properties-definition-validator.js';
|
|
6
7
|
import {PrimaryKeysDefinitionValidator} from './primary-keys-definition-validator.js';
|
|
7
8
|
|
|
8
9
|
const S = new PropertiesDefinitionValidator();
|
|
9
10
|
const sandbox = chai.spy.sandbox();
|
|
10
11
|
|
|
12
|
+
S.getService(PropertyValidatorRegistry).addValidator('myValidator', () => true);
|
|
13
|
+
|
|
11
14
|
describe('PropertiesDefinitionValidator', function () {
|
|
12
15
|
afterEach(function () {
|
|
13
16
|
sandbox.restore();
|
|
@@ -386,5 +389,52 @@ describe('PropertiesDefinitionValidator', function () {
|
|
|
386
389
|
expect(V.validate).to.have.been.called.once;
|
|
387
390
|
expect(V.validate).to.have.been.called.with.exactly('model', propDefs);
|
|
388
391
|
});
|
|
392
|
+
|
|
393
|
+
it('the option "validate" should have a non-empty String, an Array of String or an Object', function () {
|
|
394
|
+
const validate = v => () => {
|
|
395
|
+
const foo = {
|
|
396
|
+
type: DataType.ANY,
|
|
397
|
+
validate: v,
|
|
398
|
+
};
|
|
399
|
+
S.validate('model', {foo});
|
|
400
|
+
};
|
|
401
|
+
const error = v =>
|
|
402
|
+
format(
|
|
403
|
+
'The provided option "validate" of the property "foo" in the model "model" ' +
|
|
404
|
+
'should be a non-empty String, an Array of String or an Object, ' +
|
|
405
|
+
'but %s given.',
|
|
406
|
+
v,
|
|
407
|
+
);
|
|
408
|
+
expect(validate('')).to.throw(error('""'));
|
|
409
|
+
expect(validate(10)).to.throw(error('10'));
|
|
410
|
+
expect(validate(0)).to.throw(error('0'));
|
|
411
|
+
expect(validate(true)).to.throw(error('true'));
|
|
412
|
+
expect(validate(false)).to.throw(error('false'));
|
|
413
|
+
expect(validate(() => undefined)).to.throw(error('Function'));
|
|
414
|
+
validate('myValidator')();
|
|
415
|
+
validate(['myValidator'])();
|
|
416
|
+
validate([])();
|
|
417
|
+
validate({myValidator: true})();
|
|
418
|
+
validate({})();
|
|
419
|
+
validate(null)();
|
|
420
|
+
validate(undefined)();
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it('the option "validate" requires only existing validator names', function () {
|
|
424
|
+
const validate = v => () => {
|
|
425
|
+
const foo = {
|
|
426
|
+
type: DataType.ANY,
|
|
427
|
+
validate: v,
|
|
428
|
+
};
|
|
429
|
+
S.validate('model', {foo});
|
|
430
|
+
};
|
|
431
|
+
const error = v => format('The property validator %s is not found.', v);
|
|
432
|
+
expect(validate('unknown')).to.throw(error('"unknown"'));
|
|
433
|
+
expect(validate({unknown: true})).to.throw(error('"unknown"'));
|
|
434
|
+
expect(validate(['unknown'])).to.throw(error('"unknown"'));
|
|
435
|
+
validate('myValidator')();
|
|
436
|
+
validate(['myValidator'])();
|
|
437
|
+
validate({myValidator: true})();
|
|
438
|
+
});
|
|
389
439
|
});
|
|
390
440
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {DataType} from './data-type.js';
|
|
2
|
+
import {PropertyValidateOptions} from './property-validator/index.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Full property definition.
|
|
@@ -12,6 +13,7 @@ export declare type FullPropertyDefinition = {
|
|
|
12
13
|
columnType?: string;
|
|
13
14
|
required?: boolean;
|
|
14
15
|
default?: unknown;
|
|
16
|
+
validate?: PropertyValidateOptions;
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
/**
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {InvalidArgumentError} from '../../../../../errors/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Max length validator.
|
|
5
|
+
*
|
|
6
|
+
* @param {*} value
|
|
7
|
+
* @param {number|boolean} options
|
|
8
|
+
* @param {object} context
|
|
9
|
+
* @returns {boolean}
|
|
10
|
+
*/
|
|
11
|
+
export function maxLengthValidator(value, options, context) {
|
|
12
|
+
if (options === false) return true;
|
|
13
|
+
if (typeof options !== 'number')
|
|
14
|
+
throw new InvalidArgumentError(
|
|
15
|
+
'The validator %v requires the "options" argument ' +
|
|
16
|
+
'as a Number, but %v given.',
|
|
17
|
+
context.validatorName,
|
|
18
|
+
options,
|
|
19
|
+
);
|
|
20
|
+
if (typeof value === 'string' || Array.isArray(value))
|
|
21
|
+
return value.length <= options;
|
|
22
|
+
throw new InvalidArgumentError(
|
|
23
|
+
'The property validator %v requires a String ' +
|
|
24
|
+
'or an Array value, but %v given.',
|
|
25
|
+
context.validatorName,
|
|
26
|
+
value,
|
|
27
|
+
);
|
|
28
|
+
}
|
package/src/definition/model/properties/property-validator/builtin/max-length-validator.spec.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {format} from '@e22m4u/js-format';
|
|
3
|
+
import {maxLengthValidator} from './max-length-validator.js';
|
|
4
|
+
|
|
5
|
+
describe('maxLengthValidator', function () {
|
|
6
|
+
it('returns true by the false value in options', function () {
|
|
7
|
+
const res = maxLengthValidator(undefined, false, {});
|
|
8
|
+
expect(res).to.be.true;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('requires the "options" argument to be a number', function () {
|
|
12
|
+
const throwable = v => () =>
|
|
13
|
+
maxLengthValidator('test', v, {
|
|
14
|
+
validatorName: 'myValidator',
|
|
15
|
+
});
|
|
16
|
+
const error = v =>
|
|
17
|
+
format(
|
|
18
|
+
'The validator "myValidator" requires the "options" argument ' +
|
|
19
|
+
'as a Number, but %s given.',
|
|
20
|
+
v,
|
|
21
|
+
);
|
|
22
|
+
expect(throwable('str')).to.throw(error('"str"'));
|
|
23
|
+
expect(throwable('')).to.throw(error('""'));
|
|
24
|
+
expect(throwable(true)).to.throw(error('true'));
|
|
25
|
+
expect(throwable(undefined)).to.throw(error('undefined'));
|
|
26
|
+
expect(throwable(null)).to.throw(error('null'));
|
|
27
|
+
expect(throwable({})).to.throw(error('Object'));
|
|
28
|
+
expect(throwable([])).to.throw(error('Array'));
|
|
29
|
+
expect(throwable(() => undefined)).to.throw(error('Function'));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('a string value', function () {
|
|
33
|
+
it('returns false if the value length is greater than the max length option', function () {
|
|
34
|
+
const res = maxLengthValidator('1234', 3, {});
|
|
35
|
+
expect(res).to.be.false;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('returns true if the value length is equal to the max length option', function () {
|
|
39
|
+
const res = maxLengthValidator('123', 3, {});
|
|
40
|
+
expect(res).to.be.true;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('returns true if the value length is lower than the max length option', function () {
|
|
44
|
+
const res = maxLengthValidator('12', 3, {});
|
|
45
|
+
expect(res).to.be.true;
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('an array value', function () {
|
|
50
|
+
it('returns false if the value length is greater than the max length option', function () {
|
|
51
|
+
const res = maxLengthValidator([1, 2, 3, 4], 3, {});
|
|
52
|
+
expect(res).to.be.false;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('returns true if the value length is equal to the max length option', function () {
|
|
56
|
+
const res = maxLengthValidator([1, 2, 3], 3, {});
|
|
57
|
+
expect(res).to.be.true;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('returns true if the value length is lower than the max length option', function () {
|
|
61
|
+
const res = maxLengthValidator([1, 2], 3, {});
|
|
62
|
+
expect(res).to.be.true;
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {InvalidArgumentError} from '../../../../../errors/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Min length validator.
|
|
5
|
+
*
|
|
6
|
+
* @param {*} value
|
|
7
|
+
* @param {number|boolean} options
|
|
8
|
+
* @param {object} context
|
|
9
|
+
* @returns {boolean}
|
|
10
|
+
*/
|
|
11
|
+
export function minLengthValidator(value, options, context) {
|
|
12
|
+
if (options === false) return true;
|
|
13
|
+
if (typeof options !== 'number')
|
|
14
|
+
throw new InvalidArgumentError(
|
|
15
|
+
'The validator %v requires the "options" argument ' +
|
|
16
|
+
'as a Number, but %v given.',
|
|
17
|
+
context.validatorName,
|
|
18
|
+
options,
|
|
19
|
+
);
|
|
20
|
+
if (typeof value === 'string' || Array.isArray(value))
|
|
21
|
+
return value.length >= options;
|
|
22
|
+
throw new InvalidArgumentError(
|
|
23
|
+
'The property validator %v requires a String ' +
|
|
24
|
+
'or an Array value, but %v given.',
|
|
25
|
+
context.validatorName,
|
|
26
|
+
value,
|
|
27
|
+
);
|
|
28
|
+
}
|
package/src/definition/model/properties/property-validator/builtin/min-length-validator.spec.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {format} from '@e22m4u/js-format';
|
|
3
|
+
import {minLengthValidator} from './min-length-validator.js';
|
|
4
|
+
|
|
5
|
+
describe('minLengthValidator', function () {
|
|
6
|
+
it('returns true by the false value in options', function () {
|
|
7
|
+
const res = minLengthValidator(undefined, false, {});
|
|
8
|
+
expect(res).to.be.true;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('requires the "options" argument to be a number', function () {
|
|
12
|
+
const throwable = v => () =>
|
|
13
|
+
minLengthValidator('test', v, {
|
|
14
|
+
validatorName: 'myValidator',
|
|
15
|
+
});
|
|
16
|
+
const error = v =>
|
|
17
|
+
format(
|
|
18
|
+
'The validator "myValidator" requires the "options" argument ' +
|
|
19
|
+
'as a Number, but %s given.',
|
|
20
|
+
v,
|
|
21
|
+
);
|
|
22
|
+
expect(throwable('str')).to.throw(error('"str"'));
|
|
23
|
+
expect(throwable('')).to.throw(error('""'));
|
|
24
|
+
expect(throwable(true)).to.throw(error('true'));
|
|
25
|
+
expect(throwable(undefined)).to.throw(error('undefined'));
|
|
26
|
+
expect(throwable(null)).to.throw(error('null'));
|
|
27
|
+
expect(throwable({})).to.throw(error('Object'));
|
|
28
|
+
expect(throwable([])).to.throw(error('Array'));
|
|
29
|
+
expect(throwable(() => undefined)).to.throw(error('Function'));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('a string value', function () {
|
|
33
|
+
it('returns false if the value length is lower than the min length option', function () {
|
|
34
|
+
const res = minLengthValidator('12', 3, {});
|
|
35
|
+
expect(res).to.be.false;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('returns true if the value length is equal to the min length option', function () {
|
|
39
|
+
const res = minLengthValidator('123', 3, {});
|
|
40
|
+
expect(res).to.be.true;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('returns true if the value length is greater than the min length option', function () {
|
|
44
|
+
const res = minLengthValidator('1234', 3, {});
|
|
45
|
+
expect(res).to.be.true;
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('an array value', function () {
|
|
50
|
+
it('returns false if the value length is lower than the min length option', function () {
|
|
51
|
+
const res = minLengthValidator([1, 2], 3, {});
|
|
52
|
+
expect(res).to.be.false;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('returns true if the value length is equal to the min length option', function () {
|
|
56
|
+
const res = minLengthValidator([1, 2, 3], 3, {});
|
|
57
|
+
expect(res).to.be.true;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('returns true if the value length is greater than the min length option', function () {
|
|
61
|
+
const res = minLengthValidator([1, 2, 3, 4], 3, {});
|
|
62
|
+
expect(res).to.be.true;
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {Service} from '@e22m4u/js-service';
|
|
2
|
+
import {PropertyValidator} from './property-validator.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Property validator registry.
|
|
6
|
+
*/
|
|
7
|
+
export declare class PropertyValidatorRegistry extends Service {
|
|
8
|
+
/**
|
|
9
|
+
* Add validator.
|
|
10
|
+
*
|
|
11
|
+
* @param name
|
|
12
|
+
* @param validator
|
|
13
|
+
*/
|
|
14
|
+
addValidator(name: string, validator: PropertyValidator): this;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Has validator.
|
|
18
|
+
*
|
|
19
|
+
* @param name
|
|
20
|
+
*/
|
|
21
|
+
hasValidator(name: string): boolean;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get validator.
|
|
25
|
+
*
|
|
26
|
+
* @param name
|
|
27
|
+
*/
|
|
28
|
+
getValidator(name: string): PropertyValidator;
|
|
29
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {Service} from '@e22m4u/js-service';
|
|
2
|
+
import {maxLengthValidator} from './builtin/index.js';
|
|
3
|
+
import {minLengthValidator} from './builtin/index.js';
|
|
4
|
+
import {InvalidArgumentError} from '../../../../errors/index.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Property validator registry.
|
|
8
|
+
*/
|
|
9
|
+
export class PropertyValidatorRegistry extends Service {
|
|
10
|
+
/**
|
|
11
|
+
* Validators.
|
|
12
|
+
*
|
|
13
|
+
* @type {object}
|
|
14
|
+
*/
|
|
15
|
+
_validators = {
|
|
16
|
+
maxLength: maxLengthValidator,
|
|
17
|
+
minLength: minLengthValidator,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Add validator.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} name
|
|
24
|
+
* @param {Function} validator
|
|
25
|
+
* @returns {PropertyValidatorRegistry}
|
|
26
|
+
*/
|
|
27
|
+
addValidator(name, validator) {
|
|
28
|
+
if (!name || typeof name !== 'string')
|
|
29
|
+
throw new InvalidArgumentError(
|
|
30
|
+
'A name of the property validator must ' +
|
|
31
|
+
'be a non-empty String, but %v given.',
|
|
32
|
+
name,
|
|
33
|
+
);
|
|
34
|
+
if (name in this._validators)
|
|
35
|
+
throw new InvalidArgumentError(
|
|
36
|
+
'The property validator %v is already defined.',
|
|
37
|
+
name,
|
|
38
|
+
);
|
|
39
|
+
if (typeof validator !== 'function')
|
|
40
|
+
throw new InvalidArgumentError(
|
|
41
|
+
'The property validator %v must be a Function, but %v given.',
|
|
42
|
+
name,
|
|
43
|
+
validator,
|
|
44
|
+
);
|
|
45
|
+
this._validators[name] = validator;
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Has validator.
|
|
51
|
+
*
|
|
52
|
+
* @param {string} name
|
|
53
|
+
* @returns {boolean}
|
|
54
|
+
*/
|
|
55
|
+
hasValidator(name) {
|
|
56
|
+
return Boolean(this._validators[name]);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get validator.
|
|
61
|
+
*
|
|
62
|
+
* @param {string} name
|
|
63
|
+
* @returns {Function}
|
|
64
|
+
*/
|
|
65
|
+
getValidator(name) {
|
|
66
|
+
const validator = this._validators[name];
|
|
67
|
+
if (!validator)
|
|
68
|
+
throw new InvalidArgumentError(
|
|
69
|
+
'The property validator %v is not defined.',
|
|
70
|
+
name,
|
|
71
|
+
);
|
|
72
|
+
return validator;
|
|
73
|
+
}
|
|
74
|
+
}
|
package/src/definition/model/properties/property-validator/property-validator-registry.spec.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {format} from '@e22m4u/js-format';
|
|
3
|
+
import {PropertyValidatorRegistry} from './property-validator-registry.js';
|
|
4
|
+
|
|
5
|
+
describe('PropertyValidatorRegistry', function () {
|
|
6
|
+
describe('addValidator', function () {
|
|
7
|
+
it('adds a given validator with the name', function () {
|
|
8
|
+
const s = new PropertyValidatorRegistry();
|
|
9
|
+
const myValidator = () => {};
|
|
10
|
+
const res = s.addValidator('myValidator', myValidator);
|
|
11
|
+
expect(res).to.be.eq(s);
|
|
12
|
+
expect(s['_validators']['myValidator']).to.be.eq(myValidator);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('requires the given name to be a non-empty string', function () {
|
|
16
|
+
const s = new PropertyValidatorRegistry();
|
|
17
|
+
const throwable = v => () => s.addValidator(v, () => undefined);
|
|
18
|
+
const error = v =>
|
|
19
|
+
format(
|
|
20
|
+
'A name of the property validator must ' +
|
|
21
|
+
'be a non-empty String, but %s given.',
|
|
22
|
+
v,
|
|
23
|
+
);
|
|
24
|
+
expect(throwable('')).to.throw(error('""'));
|
|
25
|
+
expect(throwable(10)).to.throw(error('10'));
|
|
26
|
+
expect(throwable(0)).to.throw(error('0'));
|
|
27
|
+
expect(throwable(false)).to.throw(error('false'));
|
|
28
|
+
expect(throwable(undefined)).to.throw(error('undefined'));
|
|
29
|
+
expect(throwable(null)).to.throw(error('null'));
|
|
30
|
+
expect(throwable({})).to.throw(error('Object'));
|
|
31
|
+
expect(throwable([])).to.throw(error('Array'));
|
|
32
|
+
expect(throwable(() => undefined)).to.throw(error('Function'));
|
|
33
|
+
throwable('str')();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('throws an error if the given name already exists', function () {
|
|
37
|
+
const s = new PropertyValidatorRegistry();
|
|
38
|
+
s.addValidator('test', () => undefined);
|
|
39
|
+
const throwable = () => s.addValidator('test', () => undefined);
|
|
40
|
+
expect(throwable).to.throw(
|
|
41
|
+
'The property validator "test" is already defined.',
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('requires the given validator to be a function', function () {
|
|
46
|
+
const s = new PropertyValidatorRegistry();
|
|
47
|
+
const throwable = v => () => s.addValidator('test', v);
|
|
48
|
+
const error = v =>
|
|
49
|
+
format(
|
|
50
|
+
'The property validator "test" must be a Function, but %s given.',
|
|
51
|
+
v,
|
|
52
|
+
);
|
|
53
|
+
expect(throwable('str')).to.throw(error('"str"'));
|
|
54
|
+
expect(throwable('')).to.throw(error('""'));
|
|
55
|
+
expect(throwable(10)).to.throw(error('10'));
|
|
56
|
+
expect(throwable(0)).to.throw(error('0'));
|
|
57
|
+
expect(throwable(false)).to.throw(error('false'));
|
|
58
|
+
expect(throwable(undefined)).to.throw(error('undefined'));
|
|
59
|
+
expect(throwable(null)).to.throw(error('null'));
|
|
60
|
+
expect(throwable({})).to.throw(error('Object'));
|
|
61
|
+
expect(throwable([])).to.throw(error('Array'));
|
|
62
|
+
throwable(() => undefined)();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('hasValidator', function () {
|
|
67
|
+
it('returns false for a not existing name', function () {
|
|
68
|
+
const s = new PropertyValidatorRegistry();
|
|
69
|
+
expect(s.hasValidator('str')).to.be.false;
|
|
70
|
+
expect(s.hasValidator('')).to.be.false;
|
|
71
|
+
expect(s.hasValidator(10)).to.be.false;
|
|
72
|
+
expect(s.hasValidator(0)).to.be.false;
|
|
73
|
+
expect(s.hasValidator(true)).to.be.false;
|
|
74
|
+
expect(s.hasValidator(false)).to.be.false;
|
|
75
|
+
expect(s.hasValidator(null)).to.be.false;
|
|
76
|
+
expect(s.hasValidator(undefined)).to.be.false;
|
|
77
|
+
expect(s.hasValidator({})).to.be.false;
|
|
78
|
+
expect(s.hasValidator([])).to.be.false;
|
|
79
|
+
expect(s.hasValidator(() => undefined)).to.be.false;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('returns true for an existing name', function () {
|
|
83
|
+
const s = new PropertyValidatorRegistry();
|
|
84
|
+
expect(s.hasValidator('test')).to.be.false;
|
|
85
|
+
s.addValidator('test', () => undefined);
|
|
86
|
+
expect(s.hasValidator('test')).to.be.true;
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('getValidator', function () {
|
|
91
|
+
it('returns validator by its name', function () {
|
|
92
|
+
const s = new PropertyValidatorRegistry();
|
|
93
|
+
const validator1 = () => undefined;
|
|
94
|
+
const validator2 = () => undefined;
|
|
95
|
+
s.addValidator('foo', validator1);
|
|
96
|
+
s.addValidator('bar', validator2);
|
|
97
|
+
const res1 = s.getValidator('foo');
|
|
98
|
+
const res2 = s.getValidator('bar');
|
|
99
|
+
expect(res1).to.be.eq(validator1);
|
|
100
|
+
expect(res2).to.be.eq(validator2);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('throws an error for a not existed name', function () {
|
|
104
|
+
const s = new PropertyValidatorRegistry();
|
|
105
|
+
const throwable = v => () => s.getValidator(v);
|
|
106
|
+
const error = v => format('The property validator %s is not defined.', v);
|
|
107
|
+
expect(throwable('str')).to.throw(error('"str"'));
|
|
108
|
+
expect(throwable('')).to.throw(error('""'));
|
|
109
|
+
expect(throwable(10)).to.throw(error('10'));
|
|
110
|
+
expect(throwable(0)).to.throw(error('0'));
|
|
111
|
+
expect(throwable(true)).to.throw(error('true'));
|
|
112
|
+
expect(throwable(false)).to.throw(error('false'));
|
|
113
|
+
expect(throwable(null)).to.throw(error('null'));
|
|
114
|
+
expect(throwable(undefined)).to.throw(error('undefined'));
|
|
115
|
+
expect(throwable({})).to.throw(error('Object'));
|
|
116
|
+
expect(throwable([])).to.throw(error('Array'));
|
|
117
|
+
expect(throwable(() => undefined)).to.throw(error('Function'));
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {ServiceContainer} from '@e22m4u/js-service';
|
|
2
|
+
import {FullPropertyDefinition} from '../property-definition.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Property validator context.
|
|
6
|
+
*/
|
|
7
|
+
export type PropertyValidatorContext = {
|
|
8
|
+
validatorName: string,
|
|
9
|
+
modelName: string,
|
|
10
|
+
propName: string,
|
|
11
|
+
propDef: FullPropertyDefinition,
|
|
12
|
+
container: ServiceContainer,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Property validator.
|
|
17
|
+
*/
|
|
18
|
+
export type PropertyValidator = (
|
|
19
|
+
value: unknown,
|
|
20
|
+
options: unknown,
|
|
21
|
+
context: PropertyValidatorContext,
|
|
22
|
+
) => Promise<boolean> | boolean;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Property validate options.
|
|
26
|
+
*/
|
|
27
|
+
export type PropertyValidateOptions =
|
|
28
|
+
| string
|
|
29
|
+
| string[]
|
|
30
|
+
| {[key: string]: unknown};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/src/schema.spec.ts
CHANGED
|
@@ -5,6 +5,15 @@ import {DefinitionRegistry} from './definition/index.js';
|
|
|
5
5
|
|
|
6
6
|
describe('Schema', function () {
|
|
7
7
|
describe('defineDatasource', function () {
|
|
8
|
+
it('returns this', function () {
|
|
9
|
+
const schema = new Schema();
|
|
10
|
+
const res = schema.defineDatasource({
|
|
11
|
+
name: 'datasource',
|
|
12
|
+
adapter: 'memory',
|
|
13
|
+
});
|
|
14
|
+
expect(res).to.be.eq(schema);
|
|
15
|
+
});
|
|
16
|
+
|
|
8
17
|
it('sets the datasource definition', function () {
|
|
9
18
|
const schema = new Schema();
|
|
10
19
|
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
@@ -25,6 +34,12 @@ describe('Schema', function () {
|
|
|
25
34
|
});
|
|
26
35
|
|
|
27
36
|
describe('defineModel', function () {
|
|
37
|
+
it('returns this', function () {
|
|
38
|
+
const schema = new Schema();
|
|
39
|
+
const res = schema.defineModel({name: 'model'});
|
|
40
|
+
expect(res).to.be.eq(schema);
|
|
41
|
+
});
|
|
42
|
+
|
|
28
43
|
it('sets the model definition', function () {
|
|
29
44
|
const schema = new Schema();
|
|
30
45
|
schema.defineModel({name: 'model'});
|