@e22m4u/js-repository 0.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/.c8rc +9 -0
  2. package/.commitlintrc +5 -0
  3. package/.editorconfig +13 -0
  4. package/.eslintignore +1 -0
  5. package/.eslintrc.cjs +27 -0
  6. package/.husky/commit-msg +4 -0
  7. package/.husky/pre-commit +9 -0
  8. package/.mocharc.cjs +7 -0
  9. package/.prettierrc +7 -0
  10. package/LICENSE +21 -0
  11. package/README.md +523 -0
  12. package/mocha.setup.js +10 -0
  13. package/package.json +57 -0
  14. package/src/adapter/adapter-loader.d.ts +16 -0
  15. package/src/adapter/adapter-loader.js +63 -0
  16. package/src/adapter/adapter-loader.spec.js +31 -0
  17. package/src/adapter/adapter-registry.d.ts +14 -0
  18. package/src/adapter/adapter-registry.js +36 -0
  19. package/src/adapter/adapter-registry.spec.js +36 -0
  20. package/src/adapter/adapter.d.ts +118 -0
  21. package/src/adapter/adapter.js +181 -0
  22. package/src/adapter/adapter.spec.js +144 -0
  23. package/src/adapter/builtin/memory-adapter.d.ts +118 -0
  24. package/src/adapter/builtin/memory-adapter.js +342 -0
  25. package/src/adapter/builtin/memory-adapter.spec.js +2925 -0
  26. package/src/adapter/decorator/data-sanitizing-decorator.d.ts +13 -0
  27. package/src/adapter/decorator/data-sanitizing-decorator.js +44 -0
  28. package/src/adapter/decorator/data-sanitizing-decorator.spec.js +59 -0
  29. package/src/adapter/decorator/data-validation-decorator.d.ts +13 -0
  30. package/src/adapter/decorator/data-validation-decorator.js +41 -0
  31. package/src/adapter/decorator/data-validation-decorator.spec.js +59 -0
  32. package/src/adapter/decorator/default-values-decorator.d.ts +13 -0
  33. package/src/adapter/decorator/default-values-decorator.js +57 -0
  34. package/src/adapter/decorator/default-values-decorator.spec.js +141 -0
  35. package/src/adapter/decorator/fields-filtering-decorator.d.ts +13 -0
  36. package/src/adapter/decorator/fields-filtering-decorator.js +72 -0
  37. package/src/adapter/decorator/fields-filtering-decorator.spec.js +119 -0
  38. package/src/adapter/decorator/inclusion-decorator.d.ts +13 -0
  39. package/src/adapter/decorator/inclusion-decorator.js +78 -0
  40. package/src/adapter/decorator/inclusion-decorator.spec.js +117 -0
  41. package/src/adapter/decorator/index.d.ts +5 -0
  42. package/src/adapter/decorator/index.js +5 -0
  43. package/src/adapter/index.d.ts +3 -0
  44. package/src/adapter/index.js +3 -0
  45. package/src/definition/datasource/datasource-definition-validator.d.ts +14 -0
  46. package/src/definition/datasource/datasource-definition-validator.js +33 -0
  47. package/src/definition/datasource/datasource-definition-validator.spec.js +63 -0
  48. package/src/definition/datasource/datasource-definition.d.ts +7 -0
  49. package/src/definition/datasource/index.d.ts +2 -0
  50. package/src/definition/datasource/index.js +1 -0
  51. package/src/definition/definition-registry.d.ts +50 -0
  52. package/src/definition/definition-registry.js +98 -0
  53. package/src/definition/definition-registry.spec.js +78 -0
  54. package/src/definition/index.d.ts +3 -0
  55. package/src/definition/index.js +3 -0
  56. package/src/definition/model/index.d.ts +7 -0
  57. package/src/definition/model/index.js +6 -0
  58. package/src/definition/model/model-data-sanitizer.d.ts +15 -0
  59. package/src/definition/model/model-data-sanitizer.js +33 -0
  60. package/src/definition/model/model-data-validator.d.ts +32 -0
  61. package/src/definition/model/model-data-validator.js +144 -0
  62. package/src/definition/model/model-data-validator.spec.js +1889 -0
  63. package/src/definition/model/model-definition-utils.d.ts +161 -0
  64. package/src/definition/model/model-definition-utils.js +371 -0
  65. package/src/definition/model/model-definition-utils.spec.js +1474 -0
  66. package/src/definition/model/model-definition-validator.d.ts +14 -0
  67. package/src/definition/model/model-definition-validator.js +83 -0
  68. package/src/definition/model/model-definition-validator.spec.js +143 -0
  69. package/src/definition/model/model-definition.d.ts +28 -0
  70. package/src/definition/model/properties/data-type.d.ts +11 -0
  71. package/src/definition/model/properties/data-type.js +11 -0
  72. package/src/definition/model/properties/default-values-definition-validator.d.ts +15 -0
  73. package/src/definition/model/properties/default-values-definition-validator.js +53 -0
  74. package/src/definition/model/properties/default-values-definition-validator.spec.js +136 -0
  75. package/src/definition/model/properties/index.d.ts +5 -0
  76. package/src/definition/model/properties/index.js +4 -0
  77. package/src/definition/model/properties/primary-keys-definition-validator.d.ts +15 -0
  78. package/src/definition/model/properties/primary-keys-definition-validator.js +55 -0
  79. package/src/definition/model/properties/primary-keys-definition-validator.spec.js +145 -0
  80. package/src/definition/model/properties/properties-definition-validator.d.ts +15 -0
  81. package/src/definition/model/properties/properties-definition-validator.js +194 -0
  82. package/src/definition/model/properties/properties-definition-validator.spec.js +373 -0
  83. package/src/definition/model/properties/property-definition.d.ts +20 -0
  84. package/src/definition/model/relations/index.d.ts +3 -0
  85. package/src/definition/model/relations/index.js +2 -0
  86. package/src/definition/model/relations/relation-definition.d.ts +254 -0
  87. package/src/definition/model/relations/relation-type.d.ts +9 -0
  88. package/src/definition/model/relations/relation-type.js +9 -0
  89. package/src/definition/model/relations/relations-definition-validator.d.ts +15 -0
  90. package/src/definition/model/relations/relations-definition-validator.js +449 -0
  91. package/src/definition/model/relations/relations-definition-validator.spec.js +772 -0
  92. package/src/errors/index.d.ts +3 -0
  93. package/src/errors/index.js +3 -0
  94. package/src/errors/invalid-argument-error.d.ts +6 -0
  95. package/src/errors/invalid-argument-error.js +6 -0
  96. package/src/errors/invalid-argument-error.spec.js +33 -0
  97. package/src/errors/invalid-operator-value-error.d.ts +13 -0
  98. package/src/errors/invalid-operator-value-error.js +24 -0
  99. package/src/errors/invalid-operator-value-error.spec.js +11 -0
  100. package/src/errors/not-implemented-error.d.ts +6 -0
  101. package/src/errors/not-implemented-error.js +6 -0
  102. package/src/errors/not-implemented-error.spec.js +33 -0
  103. package/src/filter/fields-clause-tool.d.ts +38 -0
  104. package/src/filter/fields-clause-tool.js +88 -0
  105. package/src/filter/fields-clause-tool.spec.js +133 -0
  106. package/src/filter/filter.d.ts +335 -0
  107. package/src/filter/include-clause-tool.d.ts +53 -0
  108. package/src/filter/include-clause-tool.js +364 -0
  109. package/src/filter/include-clause-tool.spec.js +653 -0
  110. package/src/filter/index.d.ts +7 -0
  111. package/src/filter/index.js +6 -0
  112. package/src/filter/operator-clause-tool.d.ts +223 -0
  113. package/src/filter/operator-clause-tool.js +515 -0
  114. package/src/filter/operator-clause-tool.spec.js +1064 -0
  115. package/src/filter/order-clause-tool.d.ts +32 -0
  116. package/src/filter/order-clause-tool.js +97 -0
  117. package/src/filter/order-clause-tool.spec.js +438 -0
  118. package/src/filter/slice-clause-tool.d.ts +30 -0
  119. package/src/filter/slice-clause-tool.js +65 -0
  120. package/src/filter/slice-clause-tool.spec.js +117 -0
  121. package/src/filter/where-clause-tool.d.ts +23 -0
  122. package/src/filter/where-clause-tool.js +165 -0
  123. package/src/filter/where-clause-tool.spec.js +280 -0
  124. package/src/index.d.ts +9 -0
  125. package/src/index.js +8 -0
  126. package/src/relations/belongs-to-resolver.d.ts +46 -0
  127. package/src/relations/belongs-to-resolver.js +242 -0
  128. package/src/relations/belongs-to-resolver.spec.js +1047 -0
  129. package/src/relations/has-many-resolver.d.ts +67 -0
  130. package/src/relations/has-many-resolver.js +317 -0
  131. package/src/relations/has-many-resolver.spec.js +2911 -0
  132. package/src/relations/has-one-resolver.d.ts +67 -0
  133. package/src/relations/has-one-resolver.js +311 -0
  134. package/src/relations/has-one-resolver.spec.js +2274 -0
  135. package/src/relations/index.d.ts +4 -0
  136. package/src/relations/index.js +4 -0
  137. package/src/relations/references-many-resolver.d.ts +27 -0
  138. package/src/relations/references-many-resolver.js +113 -0
  139. package/src/relations/references-many-resolver.spec.js +631 -0
  140. package/src/repository/index.d.ts +2 -0
  141. package/src/repository/index.js +2 -0
  142. package/src/repository/repository-registry.d.ts +29 -0
  143. package/src/repository/repository-registry.js +57 -0
  144. package/src/repository/repository-registry.spec.js +38 -0
  145. package/src/repository/repository.d.ts +164 -0
  146. package/src/repository/repository.js +207 -0
  147. package/src/repository/repository.spec.js +202 -0
  148. package/src/schema.d.ts +37 -0
  149. package/src/schema.js +41 -0
  150. package/src/types.d.ts +30 -0
  151. package/src/utils/capitalize.d.ts +6 -0
  152. package/src/utils/capitalize.js +10 -0
  153. package/src/utils/capitalize.spec.js +14 -0
  154. package/src/utils/clone-deep.d.ts +6 -0
  155. package/src/utils/clone-deep.js +61 -0
  156. package/src/utils/clone-deep.spec.js +28 -0
  157. package/src/utils/exclude-object-keys.d.ts +10 -0
  158. package/src/utils/exclude-object-keys.js +20 -0
  159. package/src/utils/exclude-object-keys.spec.js +49 -0
  160. package/src/utils/get-ctor-name.d.ts +6 -0
  161. package/src/utils/get-ctor-name.js +11 -0
  162. package/src/utils/get-ctor-name.spec.js +17 -0
  163. package/src/utils/get-value-by-path.d.ts +12 -0
  164. package/src/utils/get-value-by-path.js +23 -0
  165. package/src/utils/get-value-by-path.spec.js +36 -0
  166. package/src/utils/index.d.ts +10 -0
  167. package/src/utils/index.js +10 -0
  168. package/src/utils/is-ctor.d.ts +7 -0
  169. package/src/utils/is-ctor.js +10 -0
  170. package/src/utils/is-ctor.spec.js +26 -0
  171. package/src/utils/is-pure-object.d.ts +6 -0
  172. package/src/utils/is-pure-object.js +15 -0
  173. package/src/utils/is-pure-object.spec.js +25 -0
  174. package/src/utils/select-object-keys.d.ts +10 -0
  175. package/src/utils/select-object-keys.js +37 -0
  176. package/src/utils/select-object-keys.spec.js +40 -0
  177. package/src/utils/singularize.d.ts +6 -0
  178. package/src/utils/singularize.js +22 -0
  179. package/src/utils/singularize.spec.js +23 -0
  180. package/src/utils/string-to-regexp.d.ts +10 -0
  181. package/src/utils/string-to-regexp.js +22 -0
  182. package/src/utils/string-to-regexp.spec.js +35 -0
  183. package/tsconfig.json +9 -0
@@ -0,0 +1,14 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {ModelDefinition} from './model-definition.js';
3
+
4
+ /**
5
+ * Model definition validator.
6
+ */
7
+ export declare class ModelDefinitionValidator extends Service {
8
+ /**
9
+ * Validate.
10
+ *
11
+ * @param modelDef
12
+ */
13
+ validate(modelDef: ModelDefinition): void;
14
+ }
@@ -0,0 +1,83 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {InvalidArgumentError} from '../../errors/index.js';
3
+ import {RelationsDefinitionValidator} from './relations/index.js';
4
+ import {PropertiesDefinitionValidator} from './properties/index.js';
5
+
6
+ /**
7
+ * Model definition validator.
8
+ */
9
+ export class ModelDefinitionValidator extends Service {
10
+ /**
11
+ * Validate.
12
+ *
13
+ * @param {object} modelDef
14
+ */
15
+ validate(modelDef) {
16
+ if (!modelDef || typeof modelDef !== 'object' || Array.isArray(modelDef))
17
+ throw new InvalidArgumentError(
18
+ 'The model definition should be an Object, but %v given.',
19
+ modelDef,
20
+ );
21
+ if (!modelDef.name || typeof modelDef.name !== 'string')
22
+ throw new InvalidArgumentError(
23
+ 'The model definition requires the option "name" ' +
24
+ 'as a non-empty String, but %v given.',
25
+ modelDef.name,
26
+ );
27
+ if (modelDef.datasource && typeof modelDef.datasource !== 'string')
28
+ throw new InvalidArgumentError(
29
+ 'The provided option "datasource" of the model %v ' +
30
+ 'should be a String, but %v given.',
31
+ modelDef.name,
32
+ modelDef.datasource,
33
+ );
34
+ if (modelDef.base && typeof modelDef.base !== 'string')
35
+ throw new InvalidArgumentError(
36
+ 'The provided option "base" of the model %v ' +
37
+ 'should be a String, but %v given.',
38
+ modelDef.name,
39
+ modelDef.base,
40
+ );
41
+ if (modelDef.tableName && typeof modelDef.tableName !== 'string')
42
+ throw new InvalidArgumentError(
43
+ 'The provided option "tableName" of the model %v ' +
44
+ 'should be a String, but %v given.',
45
+ modelDef.name,
46
+ modelDef.tableName,
47
+ );
48
+ if (modelDef.properties) {
49
+ if (
50
+ typeof modelDef.properties !== 'object' ||
51
+ Array.isArray(modelDef.properties)
52
+ ) {
53
+ throw new InvalidArgumentError(
54
+ 'The provided option "properties" of the model %v ' +
55
+ 'should be an Object, but %v given.',
56
+ modelDef.name,
57
+ modelDef.properties,
58
+ );
59
+ }
60
+ this.getService(PropertiesDefinitionValidator).validate(
61
+ modelDef.name,
62
+ modelDef.properties,
63
+ );
64
+ }
65
+ if (modelDef.relations) {
66
+ if (
67
+ typeof modelDef.relations !== 'object' ||
68
+ Array.isArray(modelDef.relations)
69
+ ) {
70
+ throw new InvalidArgumentError(
71
+ 'The provided option "relations" of the model %v ' +
72
+ 'should be an Object, but %v given.',
73
+ modelDef.name,
74
+ modelDef.relations,
75
+ );
76
+ }
77
+ this.getService(RelationsDefinitionValidator).validate(
78
+ modelDef.name,
79
+ modelDef.relations,
80
+ );
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,143 @@
1
+ import chai from 'chai';
2
+ import {expect} from 'chai';
3
+ import {format} from '@e22m4u/js-format';
4
+ import {RelationsDefinitionValidator} from './relations/index.js';
5
+ import {PropertiesDefinitionValidator} from './properties/index.js';
6
+ import {ModelDefinitionValidator} from './model-definition-validator.js';
7
+
8
+ const S = new ModelDefinitionValidator();
9
+ const sandbox = chai.spy.sandbox();
10
+
11
+ describe('ModelDefinitionValidator', function () {
12
+ afterEach(function () {
13
+ sandbox.restore();
14
+ });
15
+
16
+ describe('validate', function () {
17
+ it('requires the given definition to be an object', function () {
18
+ const validate = v => () => S.validate(v);
19
+ const error = v =>
20
+ format('The model definition should be an Object, but %s given.', v);
21
+ expect(validate('str')).to.throw(error('"str"'));
22
+ expect(validate(10)).to.throw(error('10'));
23
+ expect(validate(true)).to.throw(error('true'));
24
+ expect(validate(false)).to.throw(error('false'));
25
+ expect(validate([])).to.throw(error('Array'));
26
+ expect(validate(undefined)).to.throw(error('undefined'));
27
+ expect(validate(null)).to.throw(error('null'));
28
+ validate({name: 'model'})();
29
+ });
30
+
31
+ it('requires the option "name" as a non-empty string', function () {
32
+ const validate = v => () => S.validate({name: v});
33
+ const error = v =>
34
+ format(
35
+ 'The model definition requires the option "name" ' +
36
+ 'as a non-empty String, but %s given.',
37
+ v,
38
+ );
39
+ expect(validate('')).to.throw(error('""'));
40
+ expect(validate(10)).to.throw(error('10'));
41
+ expect(validate(true)).to.throw(error('true'));
42
+ expect(validate(false)).to.throw(error('false'));
43
+ expect(validate([])).to.throw(error('Array'));
44
+ expect(validate({})).to.throw(error('Object'));
45
+ expect(validate(undefined)).to.throw(error('undefined'));
46
+ expect(validate(null)).to.throw(error('null'));
47
+ validate('model')();
48
+ });
49
+
50
+ it('expects the provided option "datasource" to be a string', function () {
51
+ const validate = v => () => S.validate({name: 'model', datasource: v});
52
+ const error = v =>
53
+ format(
54
+ 'The provided option "datasource" of the model "model" ' +
55
+ 'should be a String, but %s given.',
56
+ v,
57
+ );
58
+ expect(validate(10)).to.throw(error('10'));
59
+ expect(validate(true)).to.throw(error('true'));
60
+ expect(validate([])).to.throw(error('Array'));
61
+ expect(validate({})).to.throw(error('Object'));
62
+ validate('datasource')();
63
+ });
64
+
65
+ it('expects the provided option "base" to be a string', function () {
66
+ const validate = v => () => S.validate({name: 'model', base: v});
67
+ const error = v =>
68
+ format(
69
+ 'The provided option "base" of the model "model" ' +
70
+ 'should be a String, but %s given.',
71
+ v,
72
+ );
73
+ expect(validate(10)).to.throw(error('10'));
74
+ expect(validate(true)).to.throw(error('true'));
75
+ expect(validate([])).to.throw(error('Array'));
76
+ expect(validate({})).to.throw(error('Object'));
77
+ validate('base')();
78
+ });
79
+
80
+ it('expects the provided option "tableName" to be a string', function () {
81
+ const validate = v => () => S.validate({name: 'model', tableName: v});
82
+ const error = v =>
83
+ format(
84
+ 'The provided option "tableName" of the model "model" ' +
85
+ 'should be a String, but %s given.',
86
+ v,
87
+ );
88
+ expect(validate(10)).to.throw(error('10'));
89
+ expect(validate(true)).to.throw(error('true'));
90
+ expect(validate([])).to.throw(error('Array'));
91
+ expect(validate({})).to.throw(error('Object'));
92
+ validate('tableName')();
93
+ });
94
+
95
+ it('expects the provided option "properties" to be an object', function () {
96
+ const validate = v => () => S.validate({name: 'model', properties: v});
97
+ const error = v =>
98
+ format(
99
+ 'The provided option "properties" of the model "model" ' +
100
+ 'should be an Object, but %s given.',
101
+ v,
102
+ );
103
+ expect(validate('str')).to.throw(error('"str"'));
104
+ expect(validate(10)).to.throw(error('10'));
105
+ expect(validate(true)).to.throw(error('true'));
106
+ expect(validate([])).to.throw(error('Array'));
107
+ validate({})();
108
+ });
109
+
110
+ it('expects the provided option "relations" to be an object', function () {
111
+ const validate = v => () => S.validate({name: 'model', relations: v});
112
+ const error = v =>
113
+ format(
114
+ 'The provided option "relations" of the model "model" ' +
115
+ 'should be an Object, but %s given.',
116
+ v,
117
+ );
118
+ expect(validate('str')).to.throw(error('"str"'));
119
+ expect(validate(10)).to.throw(error('10'));
120
+ expect(validate(true)).to.throw(error('true'));
121
+ expect(validate([])).to.throw(error('Array'));
122
+ validate({})();
123
+ });
124
+
125
+ it('uses PropertiesDefinitionValidator service to validate model properties', function () {
126
+ const V = S.getService(PropertiesDefinitionValidator);
127
+ sandbox.on(V, 'validate');
128
+ const properties = {};
129
+ S.validate({name: 'model', properties});
130
+ expect(V.validate).to.have.been.called.once;
131
+ expect(V.validate).to.have.been.called.with.exactly('model', properties);
132
+ });
133
+
134
+ it('uses RelationsDefinitionValidator service to validate model relations', function () {
135
+ const V = S.getService(RelationsDefinitionValidator);
136
+ sandbox.on(V, 'validate');
137
+ const relations = {};
138
+ S.validate({name: 'model', relations});
139
+ expect(V.validate).to.have.been.called.once;
140
+ expect(V.validate).to.have.been.called.with.exactly('model', relations);
141
+ });
142
+ });
143
+ });
@@ -0,0 +1,28 @@
1
+ import {RelationDefinition} from './relations/index.js';
2
+ import {PropertyDefinition} from './properties/index.js';
3
+
4
+ /**
5
+ * Property definition map.
6
+ */
7
+ export declare type PropertyDefinitionMap = {
8
+ [name: string]: PropertyDefinition;
9
+ };
10
+
11
+ /**
12
+ * Relation definition map.
13
+ */
14
+ export declare type RelationDefinitionMap = {
15
+ [name: string]: RelationDefinition;
16
+ };
17
+
18
+ /**
19
+ * Model definition.
20
+ */
21
+ export declare type ModelDefinition = {
22
+ name: string;
23
+ datasource?: string;
24
+ base?: string;
25
+ tableName?: string;
26
+ properties?: PropertyDefinitionMap;
27
+ relations?: RelationDefinitionMap;
28
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Data type.
3
+ */
4
+ export declare enum DataType {
5
+ ANY = 'any',
6
+ STRING = 'string',
7
+ NUMBER = 'number',
8
+ BOOLEAN = 'boolean',
9
+ ARRAY = 'array',
10
+ OBJECT = 'object',
11
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Data type.
3
+ */
4
+ export const DataType = {
5
+ ANY: 'any',
6
+ STRING: 'string',
7
+ NUMBER: 'number',
8
+ BOOLEAN: 'boolean',
9
+ ARRAY: 'array',
10
+ OBJECT: 'object',
11
+ };
@@ -0,0 +1,15 @@
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
+ }
@@ -0,0 +1,53 @@
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
+ 'A 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
+ }
@@ -0,0 +1,136 @@
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
+ 'A 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
+ });
@@ -0,0 +1,5 @@
1
+ export * from './data-type.js';
2
+ export * from './property-definition.js';
3
+ export * from './properties-definition-validator.js';
4
+ export * from './primary-keys-definition-validator.js';
5
+ export * from './default-values-definition-validator.js';
@@ -0,0 +1,4 @@
1
+ export * from './data-type.js';
2
+ export * from './properties-definition-validator.js';
3
+ export * from './primary-keys-definition-validator.js';
4
+ export * from './default-values-definition-validator.js';
@@ -0,0 +1,15 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {PropertyDefinitionMap} from '../model-definition.js';
3
+
4
+ /**
5
+ * Primary keys definition validator.
6
+ */
7
+ export declare class PrimaryKeysDefinitionValidator extends Service {
8
+ /**
9
+ * Validate.
10
+ *
11
+ * @param modelName
12
+ * @param propDefs
13
+ */
14
+ validate(modelName: string, propDefs: PropertyDefinitionMap): void;
15
+ }
@@ -0,0 +1,55 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {InvalidArgumentError} from '../../../errors/index.js';
3
+ import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '../model-definition-utils.js';
4
+
5
+ /**
6
+ * Primary keys definition validator.
7
+ */
8
+ export class PrimaryKeysDefinitionValidator extends Service {
9
+ /**
10
+ * Validate.
11
+ *
12
+ * @param {string} modelName
13
+ * @param {object} propDefs
14
+ */
15
+ validate(modelName, propDefs) {
16
+ const propNames = Object.keys(propDefs).filter(propName => {
17
+ const propDef = propDefs[propName];
18
+ return propDef && typeof propDef === 'object' && propDef.primaryKey;
19
+ });
20
+ if (propNames.length < 1) {
21
+ const isDefaultPrimaryKeyAlreadyInUse =
22
+ Object.keys(propDefs).includes(DEF_PK);
23
+ if (isDefaultPrimaryKeyAlreadyInUse)
24
+ throw new InvalidArgumentError(
25
+ 'The property name %v of the model %v is defined as a regular property. ' +
26
+ 'In this case, a primary key should be defined explicitly. ' +
27
+ 'Do use the option "primaryKey" to specify the primary key.',
28
+ DEF_PK,
29
+ modelName,
30
+ );
31
+ return;
32
+ }
33
+ if (propNames.length > 1)
34
+ throw new InvalidArgumentError(
35
+ 'The model definition %v should not have ' +
36
+ 'multiple primary keys, but %v keys given.',
37
+ modelName,
38
+ propNames.length,
39
+ );
40
+ const pkPropName = propNames[0];
41
+ const pkPropDef = propDefs[pkPropName];
42
+ if (
43
+ pkPropDef &&
44
+ typeof pkPropDef === 'object' &&
45
+ pkPropDef.default !== undefined
46
+ ) {
47
+ throw new InvalidArgumentError(
48
+ 'Do not specify a default value for the ' +
49
+ 'primary key %v of the model %v.',
50
+ pkPropName,
51
+ modelName,
52
+ );
53
+ }
54
+ }
55
+ }