@e22m4u/js-repository 0.0.36 → 0.0.38

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e22m4u/js-repository",
3
- "version": "0.0.36",
3
+ "version": "0.0.38",
4
4
  "description": "Абстракция для работы с базами данных для Node.js",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -39,9 +39,9 @@ export class Adapter extends Service {
39
39
  this._settings = settings;
40
40
  // decorate only extended classes
41
41
  if (this.constructor !== Adapter) {
42
- this.getService(DataValidationDecorator).decorate(this);
43
42
  this.getService(DataSanitizingDecorator).decorate(this);
44
43
  this.getService(DefaultValuesDecorator).decorate(this);
44
+ this.getService(DataValidationDecorator).decorate(this);
45
45
  this.getService(FieldsFilteringDecorator).decorate(this);
46
46
  this.getService(InclusionDecorator).decorate(this);
47
47
  }
@@ -33,9 +33,9 @@ describe('Adapter', function () {
33
33
 
34
34
  it('decorates only extended adapter', function () {
35
35
  const schema = new Schema();
36
- const dec1 = schema.getService(DataValidationDecorator);
37
- const dec2 = schema.getService(DataSanitizingDecorator);
38
- const dec3 = schema.getService(DefaultValuesDecorator);
36
+ const dec1 = schema.getService(DataSanitizingDecorator);
37
+ const dec2 = schema.getService(DefaultValuesDecorator);
38
+ const dec3 = schema.getService(DataValidationDecorator);
39
39
  const dec4 = schema.getService(FieldsFilteringDecorator);
40
40
  const dec5 = schema.getService(InclusionDecorator);
41
41
  const order = [];
@@ -31,7 +31,7 @@ export class ModelDataValidator extends Service {
31
31
  propNames.forEach(propName => {
32
32
  const propDef = propDefs[propName];
33
33
  if (!propDef) return;
34
- this.validatePropertyValue(
34
+ this._validatePropertyValue(
35
35
  modelName,
36
36
  propName,
37
37
  propDef,
@@ -48,7 +48,7 @@ export class ModelDataValidator extends Service {
48
48
  * @param {string|object} propDef
49
49
  * @param {*} propValue
50
50
  */
51
- validatePropertyValue(modelName, propName, propDef, propValue) {
51
+ _validatePropertyValue(modelName, propName, propDef, propValue) {
52
52
  // undefined and null
53
53
  if (propValue == null) {
54
54
  const isRequired =
@@ -1587,6 +1587,61 @@ describe('ModelDataValidator', function () {
1587
1587
  'an Array, but Object given.',
1588
1588
  );
1589
1589
  });
1590
+
1591
+ describe('the "model" option', function () {
1592
+ it('throws an error when the given object element has an invalid model', function () {
1593
+ const S = new Schema();
1594
+ S.defineModel({
1595
+ name: 'modelA',
1596
+ properties: {
1597
+ foo: DataType.STRING,
1598
+ },
1599
+ });
1600
+ S.defineModel({
1601
+ name: 'modelB',
1602
+ datasource: 'datasource',
1603
+ properties: {
1604
+ bar: {
1605
+ type: DataType.ARRAY,
1606
+ itemType: DataType.OBJECT,
1607
+ model: 'modelA',
1608
+ },
1609
+ },
1610
+ });
1611
+ const throwable = () =>
1612
+ S.getService(ModelDataValidator).validate('modelB', {
1613
+ bar: [{foo: 10}],
1614
+ });
1615
+ expect(throwable).to.throw(
1616
+ 'The property "foo" of the model "modelA" must have ' +
1617
+ 'a String, but Number given.',
1618
+ );
1619
+ });
1620
+
1621
+ it('does not throw an error when the given object element has a valid model', function () {
1622
+ const S = new Schema();
1623
+ S.defineModel({
1624
+ name: 'modelA',
1625
+ properties: {
1626
+ foo: DataType.STRING,
1627
+ },
1628
+ });
1629
+ S.defineModel({
1630
+ name: 'modelB',
1631
+ datasource: 'datasource',
1632
+ properties: {
1633
+ bar: {
1634
+ type: DataType.ARRAY,
1635
+ itemType: DataType.OBJECT,
1636
+ model: 'modelA',
1637
+ },
1638
+ },
1639
+ });
1640
+ S.getService(ModelDataValidator).validate('modelB', {
1641
+ bar: [{foo: '10'}],
1642
+ });
1643
+ });
1644
+ });
1590
1645
  });
1591
1646
  });
1592
1647
 
@@ -1883,6 +1938,59 @@ describe('ModelDataValidator', function () {
1883
1938
  foo: {},
1884
1939
  });
1885
1940
  });
1941
+
1942
+ describe('the "model" option', function () {
1943
+ it('throws an error when the given object has an invalid model', function () {
1944
+ const S = new Schema();
1945
+ S.defineModel({
1946
+ name: 'modelA',
1947
+ properties: {
1948
+ foo: DataType.STRING,
1949
+ },
1950
+ });
1951
+ S.defineModel({
1952
+ name: 'modelB',
1953
+ datasource: 'datasource',
1954
+ properties: {
1955
+ bar: {
1956
+ type: DataType.OBJECT,
1957
+ model: 'modelA',
1958
+ },
1959
+ },
1960
+ });
1961
+ const throwable = () =>
1962
+ S.getService(ModelDataValidator).validate('modelB', {
1963
+ bar: {foo: 10},
1964
+ });
1965
+ expect(throwable).to.throw(
1966
+ 'The property "foo" of the model "modelA" must have ' +
1967
+ 'a String, but Number given.',
1968
+ );
1969
+ });
1970
+
1971
+ it('does not throw an error when the given object has a valid model', function () {
1972
+ const S = new Schema();
1973
+ S.defineModel({
1974
+ name: 'modelA',
1975
+ properties: {
1976
+ foo: DataType.STRING,
1977
+ },
1978
+ });
1979
+ S.defineModel({
1980
+ name: 'modelB',
1981
+ datasource: 'datasource',
1982
+ properties: {
1983
+ bar: {
1984
+ type: DataType.OBJECT,
1985
+ model: 'modelA',
1986
+ },
1987
+ },
1988
+ });
1989
+ S.getService(ModelDataValidator).validate('modelB', {
1990
+ bar: {foo: '10'},
1991
+ });
1992
+ });
1993
+ });
1886
1994
  });
1887
1995
  });
1888
1996
  });
@@ -2,4 +2,3 @@ export * from './data-type.js';
2
2
  export * from './property-definition.js';
3
3
  export * from './properties-definition-validator.js';
4
4
  export * from './primary-keys-definition-validator.js';
5
- export * from './default-values-definition-validator.js';
@@ -1,4 +1,3 @@
1
1
  export * from './data-type.js';
2
2
  export * from './properties-definition-validator.js';
3
3
  export * from './primary-keys-definition-validator.js';
4
- export * from './default-values-definition-validator.js';
@@ -1,8 +1,8 @@
1
1
  import {Service} from '@e22m4u/js-service';
2
2
  import {DataType as Type} from './data-type.js';
3
+ import {capitalize} from '../../../utils/index.js';
3
4
  import {InvalidArgumentError} from '../../../errors/index.js';
4
5
  import {PrimaryKeysDefinitionValidator} from './primary-keys-definition-validator.js';
5
- import {DefaultValuesDefinitionValidator} from './default-values-definition-validator.js';
6
6
 
7
7
  /**
8
8
  * Properties definition validator.
@@ -38,10 +38,6 @@ export class PropertiesDefinitionValidator extends Service {
38
38
  modelName,
39
39
  propDefs,
40
40
  );
41
- this.getService(DefaultValuesDefinitionValidator).validate(
42
- modelName,
43
- propDefs,
44
- );
45
41
  }
46
42
 
47
43
  /**
@@ -182,13 +178,30 @@ export class PropertiesDefinitionValidator extends Service {
182
178
  modelName,
183
179
  propDef.type,
184
180
  );
185
- if (propDef.model && propDef.type !== Type.OBJECT)
186
- throw new InvalidArgumentError(
187
- 'The property %v of the model %v has the non-object type, ' +
188
- 'so it should not have the option "model" to be provided.',
189
- propName,
190
- modelName,
191
- propDef.type,
192
- );
181
+ if (
182
+ propDef.model &&
183
+ propDef.type !== Type.OBJECT &&
184
+ propDef.itemType !== Type.OBJECT
185
+ ) {
186
+ if (propDef.type !== Type.ARRAY) {
187
+ throw new InvalidArgumentError(
188
+ 'The option "model" is not supported for %s property type, ' +
189
+ 'so the property %v of the model %v should not have ' +
190
+ 'the option "model" to be provided.',
191
+ capitalize(propDef.type),
192
+ propName,
193
+ modelName,
194
+ );
195
+ } else {
196
+ throw new InvalidArgumentError(
197
+ 'The option "model" is not supported for Array property type of %s, ' +
198
+ 'so the property %v of the model %v should not have ' +
199
+ 'the option "model" to be provided.',
200
+ capitalize(propDef.itemType),
201
+ propName,
202
+ modelName,
203
+ );
204
+ }
205
+ }
193
206
  }
194
207
  }
@@ -4,7 +4,6 @@ import {DataType} from './data-type.js';
4
4
  import {format} from '@e22m4u/js-format';
5
5
  import {PropertiesDefinitionValidator} from './properties-definition-validator.js';
6
6
  import {PrimaryKeysDefinitionValidator} from './primary-keys-definition-validator.js';
7
- import {DefaultValuesDefinitionValidator} from './default-values-definition-validator.js';
8
7
 
9
8
  const S = new PropertiesDefinitionValidator();
10
9
  const sandbox = chai.spy.sandbox();
@@ -333,7 +332,7 @@ describe('PropertiesDefinitionValidator', function () {
333
332
  validate(DataType.ARRAY);
334
333
  });
335
334
 
336
- it('expects a non-object property should not have the option "model" to be provided', function () {
335
+ it('the option "model" requires the "object" property type', function () {
337
336
  const validate = v => () => {
338
337
  const foo = {
339
338
  type: v,
@@ -341,28 +340,46 @@ describe('PropertiesDefinitionValidator', function () {
341
340
  };
342
341
  S.validate('model', {foo});
343
342
  };
344
- const error =
345
- 'The property "foo" of the model "model" has the non-object type, ' +
346
- 'so it should not have the option "model" to be provided.';
347
- expect(validate(DataType.ANY)).to.throw(error);
348
- expect(validate(DataType.STRING)).to.throw(error);
349
- expect(validate(DataType.NUMBER)).to.throw(error);
350
- expect(validate(DataType.BOOLEAN)).to.throw(error);
351
- expect(validate(DataType.ARRAY)).to.throw(error);
352
- validate(DataType.OBJECT);
343
+ const error = v =>
344
+ format(
345
+ 'The option "model" is not supported for %s property type, ' +
346
+ 'so the property "foo" of the model "model" should not have ' +
347
+ 'the option "model" to be provided.',
348
+ v,
349
+ );
350
+ expect(validate(DataType.ANY)).to.throw(error('Any'));
351
+ expect(validate(DataType.STRING)).to.throw(error('String'));
352
+ expect(validate(DataType.NUMBER)).to.throw(error('Number'));
353
+ expect(validate(DataType.BOOLEAN)).to.throw(error('Boolean'));
354
+ validate(DataType.OBJECT)();
353
355
  });
354
356
 
355
- it('uses PrimaryKeysDefinitionValidator to validate primary keys', function () {
356
- const V = S.getService(PrimaryKeysDefinitionValidator);
357
- sandbox.on(V, 'validate');
358
- const propDefs = {};
359
- S.validate('model', propDefs);
360
- expect(V.validate).to.have.been.called.once;
361
- expect(V.validate).to.have.been.called.with.exactly('model', propDefs);
357
+ it('the option "model" requires the "object" item type', function () {
358
+ const validate = v => () => {
359
+ const foo = {
360
+ type: DataType.ARRAY,
361
+ itemType: v,
362
+ model: 'model',
363
+ };
364
+ S.validate('model', {foo});
365
+ };
366
+ const error = v =>
367
+ format(
368
+ 'The option "model" is not supported for Array property type of %s, ' +
369
+ 'so the property "foo" of the model "model" should not have ' +
370
+ 'the option "model" to be provided.',
371
+ v,
372
+ );
373
+ expect(validate(DataType.ANY)).to.throw(error('Any'));
374
+ expect(validate(DataType.STRING)).to.throw(error('String'));
375
+ expect(validate(DataType.NUMBER)).to.throw(error('Number'));
376
+ expect(validate(DataType.BOOLEAN)).to.throw(error('Boolean'));
377
+ expect(validate(DataType.ARRAY)).to.throw(error('Array'));
378
+ validate(DataType.OBJECT)();
362
379
  });
363
380
 
364
- it('uses DefaultValuesDefinitionValidator to validate default values', function () {
365
- const V = S.getService(DefaultValuesDefinitionValidator);
381
+ it('uses PrimaryKeysDefinitionValidator to validate primary keys', function () {
382
+ const V = S.getService(PrimaryKeysDefinitionValidator);
366
383
  sandbox.on(V, 'validate');
367
384
  const propDefs = {};
368
385
  S.validate('model', propDefs);
@@ -1,5 +1,3 @@
1
- import {ModelData} from '../types.js';
2
-
3
1
  /**
4
2
  * Filter clause.
5
3
  */
@@ -45,20 +43,9 @@ export declare type ItemFilterClause = Pick<FilterClause, 'fields' | 'include'>;
45
43
  * ```
46
44
  */
47
45
  export declare type WhereClause =
48
- | PredicateClause
49
- | PropertiesClause
50
- | AndClause
51
- | OrClause;
52
-
53
- /**
54
- * Predicate clause.
55
- *
56
- * @example
57
- * ```ts
58
- * (value) => value.featured === true;
59
- * ```
60
- */
61
- export type PredicateClause = (value: ModelData) => boolean;
46
+ & PropertiesClause
47
+ & AndClause
48
+ & OrClause;
62
49
 
63
50
  /**
64
51
  * Properties clause.
@@ -56,7 +56,6 @@ export class WhereClauseTool extends Service {
56
56
  * @returns {Function}
57
57
  */
58
58
  _createFilter(whereClause) {
59
- if (typeof whereClause === 'function') return whereClause;
60
59
  if (typeof whereClause !== 'object' || Array.isArray(whereClause))
61
60
  throw new InvalidArgumentError(
62
61
  'The provided option "where" should be an Object, but %v given.',
@@ -272,12 +272,6 @@ describe('WhereClauseTool', function () {
272
272
  expect(result[0]).to.be.eql(OBJECTS[2]);
273
273
  expect(result[1]).to.be.eql(OBJECTS[3]);
274
274
  });
275
-
276
- it('uses the given function to filter values', function () {
277
- const result = S.filter(OBJECTS, v => v.nickname === 'Flower');
278
- expect(result).to.have.length(1);
279
- expect(result[0]).to.be.eql(OBJECTS[1]);
280
- });
281
275
  });
282
276
 
283
277
  describe('validateWhereClause', function () {
@@ -1,15 +0,0 @@
1
- import {Service} from '@e22m4u/js-service';
2
- import {PropertyDefinitionMap} from '../model-definition.js';
3
-
4
- /**
5
- * Default values definition validator.
6
- */
7
- export declare class DefaultValuesDefinitionValidator extends Service {
8
- /**
9
- * Validate.
10
- *
11
- * @param modelName
12
- * @param propDefs
13
- */
14
- validate(modelName: string, propDefs: PropertyDefinitionMap): void;
15
- }
@@ -1,53 +0,0 @@
1
- import {Service} from '@e22m4u/js-service';
2
- import {ModelDataValidator} from '../model-data-validator.js';
3
- import {InvalidArgumentError} from '../../../errors/index.js';
4
-
5
- /**
6
- * Default values definition validator.
7
- */
8
- export class DefaultValuesDefinitionValidator extends Service {
9
- /**
10
- * Validate.
11
- *
12
- * @param {string} modelName
13
- * @param {object} propDefs
14
- */
15
- validate(modelName, propDefs) {
16
- if (!modelName || typeof modelName !== 'string')
17
- throw new InvalidArgumentError(
18
- 'The first argument of DefaultValuesDefinitionValidator.validate ' +
19
- 'should be a non-empty String, but %v given.',
20
- modelName,
21
- );
22
- if (!propDefs || typeof propDefs !== 'object' || Array.isArray(propDefs))
23
- throw new InvalidArgumentError(
24
- 'The provided option "properties" of the model %v ' +
25
- 'should be an Object, but %v given.',
26
- modelName,
27
- propDefs,
28
- );
29
- Object.keys(propDefs).forEach(propName => {
30
- const propDef = propDefs[propName];
31
- if (typeof propDef === 'string') return;
32
- if (!('default' in propDef)) return;
33
- const propValue =
34
- propDef.default instanceof Function
35
- ? propDef.default()
36
- : propDef.default;
37
- try {
38
- this.getService(ModelDataValidator).validatePropertyValue(
39
- modelName,
40
- propName,
41
- propDef,
42
- propValue,
43
- );
44
- } catch (error) {
45
- if (error instanceof InvalidArgumentError)
46
- throw new InvalidArgumentError(
47
- `A default value is invalid. ${error.message}`,
48
- );
49
- throw error;
50
- }
51
- });
52
- }
53
- }
@@ -1,136 +0,0 @@
1
- import {expect} from 'chai';
2
- import {DataType} from './data-type.js';
3
- import {format} from '@e22m4u/js-format';
4
- import {DefaultValuesDefinitionValidator} from './default-values-definition-validator.js';
5
-
6
- const S = new DefaultValuesDefinitionValidator();
7
-
8
- describe('DefaultValuesDefinitionValidator', function () {
9
- describe('validate', function () {
10
- it('requires a first argument to be a non-empty string', function () {
11
- const validate = v => () => S.validate(v, {});
12
- const error = v =>
13
- format(
14
- 'The first argument of DefaultValuesDefinitionValidator.validate ' +
15
- 'should be a non-empty String, but %s given.',
16
- v,
17
- );
18
- expect(validate('')).to.throw(error('""'));
19
- expect(validate(10)).to.throw(error('10'));
20
- expect(validate(true)).to.throw(error('true'));
21
- expect(validate(false)).to.throw(error('false'));
22
- expect(validate([])).to.throw(error('Array'));
23
- expect(validate({})).to.throw(error('Object'));
24
- expect(validate(undefined)).to.throw(error('undefined'));
25
- expect(validate(null)).to.throw(error('null'));
26
- validate('model')();
27
- });
28
-
29
- it('requires a second argument to be an object', function () {
30
- const validate = v => () => S.validate('model', v);
31
- const error = v =>
32
- format(
33
- 'The provided option "properties" of the model "model" ' +
34
- 'should be an Object, but %s given.',
35
- v,
36
- );
37
- expect(validate('str')).to.throw(error('"str"'));
38
- expect(validate(10)).to.throw(error('10'));
39
- expect(validate(true)).to.throw(error('true'));
40
- expect(validate(false)).to.throw(error('false'));
41
- expect(validate([])).to.throw(error('Array'));
42
- expect(validate(undefined)).to.throw(error('undefined'));
43
- expect(validate(null)).to.throw(error('null'));
44
- validate({})();
45
- });
46
-
47
- it('does not throw an error if no properties defined', function () {
48
- S.validate('model', {});
49
- });
50
-
51
- it('does not throw an error if no default value specified for a required property', function () {
52
- S.validate('model', {
53
- foo: {
54
- type: DataType.STRING,
55
- required: true,
56
- },
57
- });
58
- });
59
-
60
- it('does not throw an error if a default value matches a property type', function () {
61
- S.validate('model', {
62
- foo: {
63
- type: DataType.BOOLEAN,
64
- default: false,
65
- },
66
- });
67
- });
68
-
69
- it('does not throw an error if a default value from a factory function matches a property type', function () {
70
- S.validate('model', {
71
- foo: {
72
- type: DataType.BOOLEAN,
73
- default: () => false,
74
- },
75
- });
76
- });
77
-
78
- it('throws an error if a default value does not match a property type', function () {
79
- const throwable = () =>
80
- S.validate('model', {
81
- foo: {
82
- type: DataType.STRING,
83
- default: 10,
84
- },
85
- });
86
- expect(throwable).to.throw(
87
- 'A default value is invalid. The property "foo" of the model ' +
88
- '"model" must have a String, but Number given.',
89
- );
90
- });
91
-
92
- it('throws an error if a default value from a factory function does not match a property type', function () {
93
- const throwable = () =>
94
- S.validate('model', {
95
- foo: {
96
- type: DataType.STRING,
97
- default: () => 10,
98
- },
99
- });
100
- expect(throwable).to.throw(
101
- 'A default value is invalid. The property "foo" of the model ' +
102
- '"model" must have a String, but Number given.',
103
- );
104
- });
105
-
106
- it('throws an error if an array element of a default value does not match an item type', function () {
107
- const throwable = () =>
108
- S.validate('model', {
109
- foo: {
110
- type: DataType.ARRAY,
111
- itemType: DataType.STRING,
112
- default: [10],
113
- },
114
- });
115
- expect(throwable).to.throw(
116
- 'A default value is invalid. The array property "foo" of the model "model" ' +
117
- 'must have a String element, but Number given.',
118
- );
119
- });
120
-
121
- it('throws an error if an array element from a default value factory does not match an item type', function () {
122
- const throwable = () =>
123
- S.validate('model', {
124
- foo: {
125
- type: DataType.ARRAY,
126
- itemType: DataType.STRING,
127
- default: () => [10],
128
- },
129
- });
130
- expect(throwable).to.throw(
131
- 'A default value is invalid. The array property "foo" of the model "model" ' +
132
- 'must have a String element, but Number given.',
133
- );
134
- });
135
- });
136
- });