@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,78 @@
1
+ import {Adapter} from '../adapter.js';
2
+ import {Service} from '@e22m4u/js-service';
3
+ import {IncludeClauseTool} from '../../filter/index.js';
4
+ import {InvalidArgumentError} from '../../errors/index.js';
5
+
6
+ /**
7
+ * Inclusion decorator.
8
+ */
9
+ export class InclusionDecorator extends Service {
10
+ /**
11
+ * Decorate.
12
+ *
13
+ * @param {Adapter} adapter
14
+ */
15
+ decorate(adapter) {
16
+ if (!adapter || !(adapter instanceof Adapter))
17
+ throw new InvalidArgumentError(
18
+ 'A first argument of InclusionDecorator.decorate must be ' +
19
+ 'an Adapter instance, but %v given.',
20
+ adapter,
21
+ );
22
+
23
+ const tool = adapter.getService(IncludeClauseTool);
24
+ const includeTo = (...args) => tool.includeTo(...args);
25
+
26
+ const create = adapter.create;
27
+ adapter.create = async function (modelName, modelData, filter) {
28
+ const retvalData = await create.call(this, modelName, modelData, filter);
29
+ if (filter && typeof filter === 'object' && filter.include)
30
+ await includeTo([retvalData], modelName, filter.include);
31
+ return retvalData;
32
+ };
33
+
34
+ const replaceById = adapter.replaceById;
35
+ adapter.replaceById = async function (modelName, id, modelData, filter) {
36
+ const retvalData = await replaceById.call(
37
+ this,
38
+ modelName,
39
+ id,
40
+ modelData,
41
+ filter,
42
+ );
43
+ if (filter && typeof filter === 'object' && filter.include)
44
+ await includeTo([retvalData], modelName, filter.include);
45
+ return retvalData;
46
+ };
47
+
48
+ const patchById = adapter.patchById;
49
+ adapter.patchById = async function (modelName, id, modelData, filter) {
50
+ const retvalData = await patchById.call(
51
+ this,
52
+ modelName,
53
+ id,
54
+ modelData,
55
+ filter,
56
+ );
57
+ if (filter && typeof filter === 'object' && filter.include)
58
+ await includeTo([retvalData], modelName, filter.include);
59
+ return retvalData;
60
+ };
61
+
62
+ const find = adapter.find;
63
+ adapter.find = async function (modelName, filter) {
64
+ const modelItems = await find.call(this, modelName, filter);
65
+ if (filter && typeof filter === 'object' && filter.include)
66
+ await includeTo(modelItems, modelName, filter.include);
67
+ return modelItems;
68
+ };
69
+
70
+ const findById = adapter.findById;
71
+ adapter.findById = async function (modelName, id, filter) {
72
+ const retvalData = await findById.call(this, modelName, id, filter);
73
+ if (filter && typeof filter === 'object' && filter.include)
74
+ await includeTo([retvalData], modelName, filter.include);
75
+ return retvalData;
76
+ };
77
+ }
78
+ }
@@ -0,0 +1,117 @@
1
+ import chai from 'chai';
2
+ import {expect} from 'chai';
3
+ import {Adapter} from '../adapter.js';
4
+ import {Schema} from '../../schema.js';
5
+ import {IncludeClauseTool} from '../../filter/index.js';
6
+
7
+ const S = new Schema();
8
+ S.defineModel({name: 'model'});
9
+ const FILTER = {include: 'parent'};
10
+
11
+ const MODEL_DATA = {
12
+ foo: 'fooVal',
13
+ bar: 'barVal',
14
+ };
15
+
16
+ const RETVAL_DATA = {
17
+ foo: MODEL_DATA.foo,
18
+ bar: MODEL_DATA.bar,
19
+ baz: 'bazVal',
20
+ };
21
+
22
+ class TestAdapter extends Adapter {
23
+ // eslint-disable-next-line no-unused-vars
24
+ async create(modelName, modelData, filter = undefined) {
25
+ return Object.assign({}, MODEL_DATA);
26
+ }
27
+
28
+ // eslint-disable-next-line no-unused-vars
29
+ async replaceById(modelName, id, modelData, filter = undefined) {
30
+ return Object.assign({}, MODEL_DATA);
31
+ }
32
+
33
+ // eslint-disable-next-line no-unused-vars
34
+ async patchById(modelName, id, modelData, filter = undefined) {
35
+ return Object.assign({}, MODEL_DATA);
36
+ }
37
+
38
+ // eslint-disable-next-line no-unused-vars
39
+ async find(modelName, filter = undefined) {
40
+ return [Object.assign({}, MODEL_DATA)];
41
+ }
42
+
43
+ // eslint-disable-next-line no-unused-vars
44
+ async findById(modelName, id, filter = undefined) {
45
+ return Object.assign({}, MODEL_DATA);
46
+ }
47
+ }
48
+
49
+ const A = S.getService(TestAdapter);
50
+ const T = S.getService(IncludeClauseTool);
51
+ const sandbox = chai.spy.sandbox();
52
+
53
+ describe('InclusionDecorator', function () {
54
+ afterEach(function () {
55
+ sandbox.restore();
56
+ });
57
+
58
+ it('overrides the "create" method method and applies clause inclusion', async function () {
59
+ sandbox.on(T, 'includeTo', function (entities, modelName, clause) {
60
+ expect(entities).to.be.eql([MODEL_DATA]);
61
+ expect(modelName).to.be.eql('model');
62
+ expect(clause).to.be.eql(FILTER.include);
63
+ Object.assign(entities[0], RETVAL_DATA);
64
+ });
65
+ const retval = await A.create('model', {}, FILTER);
66
+ expect(retval).to.be.eql(RETVAL_DATA);
67
+ expect(T.includeTo).to.be.called.once;
68
+ });
69
+
70
+ it('overrides the "replaceById" method and applies clause inclusion', async function () {
71
+ sandbox.on(T, 'includeTo', function (entities, modelName, clause) {
72
+ expect(entities).to.be.eql([MODEL_DATA]);
73
+ expect(modelName).to.be.eql('model');
74
+ expect(clause).to.be.eql(FILTER.include);
75
+ Object.assign(entities[0], RETVAL_DATA);
76
+ });
77
+ const retval = await A.replaceById('model', 1, {}, FILTER);
78
+ expect(retval).to.be.eql(RETVAL_DATA);
79
+ expect(T.includeTo).to.be.called.once;
80
+ });
81
+
82
+ it('overrides the "patchById" method and applies clause inclusion', async function () {
83
+ sandbox.on(T, 'includeTo', function (entities, modelName, clause) {
84
+ expect(entities).to.be.eql([MODEL_DATA]);
85
+ expect(modelName).to.be.eql('model');
86
+ expect(clause).to.be.eql(FILTER.include);
87
+ Object.assign(entities[0], RETVAL_DATA);
88
+ });
89
+ const retval = await A.patchById('model', 1, {}, FILTER);
90
+ expect(retval).to.be.eql(RETVAL_DATA);
91
+ expect(T.includeTo).to.be.called.once;
92
+ });
93
+
94
+ it('overrides the "find" method and applies clause inclusion', async function () {
95
+ sandbox.on(T, 'includeTo', function (entities, modelName, clause) {
96
+ expect(entities).to.be.eql([MODEL_DATA]);
97
+ expect(modelName).to.be.eql('model');
98
+ expect(clause).to.be.eql(FILTER.include);
99
+ Object.assign(entities[0], RETVAL_DATA);
100
+ });
101
+ const retval = await A.find('model', FILTER);
102
+ expect(retval).to.be.eql([RETVAL_DATA]);
103
+ expect(T.includeTo).to.be.called.once;
104
+ });
105
+
106
+ it('overrides the "findById" method and applies clause inclusion', async function () {
107
+ sandbox.on(T, 'includeTo', function (entities, modelName, clause) {
108
+ expect(entities).to.be.eql([MODEL_DATA]);
109
+ expect(modelName).to.be.eql('model');
110
+ expect(clause).to.be.eql(FILTER.include);
111
+ Object.assign(entities[0], RETVAL_DATA);
112
+ });
113
+ const retval = await A.findById('model', 1, FILTER);
114
+ expect(retval).to.be.eql(RETVAL_DATA);
115
+ expect(T.includeTo).to.be.called.once;
116
+ });
117
+ });
@@ -0,0 +1,5 @@
1
+ export * from './inclusion-decorator.js';
2
+ export * from './default-values-decorator.js';
3
+ export * from './data-sanitizing-decorator.js';
4
+ export * from './data-validation-decorator.js';
5
+ export * from './fields-filtering-decorator.js';
@@ -0,0 +1,5 @@
1
+ export * from './inclusion-decorator.js';
2
+ export * from './default-values-decorator.js';
3
+ export * from './data-sanitizing-decorator.js';
4
+ export * from './data-validation-decorator.js';
5
+ export * from './fields-filtering-decorator.js';
@@ -0,0 +1,3 @@
1
+ export * from './adapter.js';
2
+ export * from './adapter-loader.js';
3
+ export * from './adapter-registry.js';
@@ -0,0 +1,3 @@
1
+ export * from './adapter.js';
2
+ export * from './adapter-loader.js';
3
+ export * from './adapter-registry.js';
@@ -0,0 +1,14 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {DatasourceDefinition} from './datasource-definition.js';
3
+
4
+ /**
5
+ * Datasource definition validator.
6
+ */
7
+ export declare class DatasourceDefinitionValidator extends Service {
8
+ /**
9
+ * Validate.
10
+ *
11
+ * @param datasourceDef
12
+ */
13
+ validate(datasourceDef: DatasourceDefinition): void;
14
+ }
@@ -0,0 +1,33 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {InvalidArgumentError} from '../../errors/index.js';
3
+
4
+ /**
5
+ * Datasource definition validator.
6
+ */
7
+ export class DatasourceDefinitionValidator extends Service {
8
+ /**
9
+ * Validate.
10
+ *
11
+ * @param {object} datasourceDef
12
+ */
13
+ validate(datasourceDef) {
14
+ if (!datasourceDef || typeof datasourceDef !== 'object')
15
+ throw new InvalidArgumentError(
16
+ 'The datasource definition should be an Object, but %v given.',
17
+ datasourceDef,
18
+ );
19
+ if (!datasourceDef.name || typeof datasourceDef.name !== 'string')
20
+ throw new InvalidArgumentError(
21
+ 'The datasource definition requires the option "name" ' +
22
+ 'as a non-empty String, but %v given.',
23
+ datasourceDef.name,
24
+ );
25
+ if (!datasourceDef.adapter || typeof datasourceDef.adapter !== 'string')
26
+ throw new InvalidArgumentError(
27
+ 'The datasource %v requires the option "adapter" ' +
28
+ 'as a non-empty String, but %v given.',
29
+ datasourceDef.name,
30
+ datasourceDef.adapter,
31
+ );
32
+ }
33
+ }
@@ -0,0 +1,63 @@
1
+ import {expect} from 'chai';
2
+ import {format} from '@e22m4u/js-format';
3
+ import {DatasourceDefinitionValidator} from './datasource-definition-validator.js';
4
+
5
+ const S = new DatasourceDefinitionValidator();
6
+
7
+ describe('DatasourceDefinitionValidator', function () {
8
+ describe('validate', function () {
9
+ it('requires a given definition to be an object', function () {
10
+ const validate = v => () => S.validate(v);
11
+ const error = v =>
12
+ format(
13
+ 'The datasource definition should be an Object, but %s given.',
14
+ v,
15
+ );
16
+ expect(validate('str')).to.throw(error('"str"'));
17
+ expect(validate(10)).to.throw(error('10'));
18
+ expect(validate(true)).to.throw(error('true'));
19
+ expect(validate(false)).to.throw(error('false'));
20
+ expect(validate(undefined)).to.throw(error('undefined'));
21
+ expect(validate(null)).to.throw(error('null'));
22
+ validate({name: 'datasource', adapter: 'adapter'})();
23
+ });
24
+
25
+ it('requires the option "name" as a non-empty string', function () {
26
+ const validate = v => () => S.validate({name: v, adapter: 'adapter'});
27
+ const error = v =>
28
+ format(
29
+ 'The datasource definition requires the option "name" ' +
30
+ 'as a non-empty String, but %s given.',
31
+ v,
32
+ );
33
+ expect(validate('')).to.throw(error('""'));
34
+ expect(validate(10)).to.throw(error('10'));
35
+ expect(validate(true)).to.throw(error('true'));
36
+ expect(validate(false)).to.throw(error('false'));
37
+ expect(validate([])).to.throw(error('Array'));
38
+ expect(validate({})).to.throw(error('Object'));
39
+ expect(validate(undefined)).to.throw(error('undefined'));
40
+ expect(validate(null)).to.throw(error('null'));
41
+ validate('datasource')();
42
+ });
43
+
44
+ it('requires the option "adapter" to be a non-empty string', function () {
45
+ const validate = v => () => S.validate({name: 'datasource', adapter: v});
46
+ const error = v =>
47
+ format(
48
+ 'The datasource "datasource" requires the option "adapter" ' +
49
+ 'as a non-empty String, but %s given.',
50
+ v,
51
+ );
52
+ expect(validate('')).to.throw(error('""'));
53
+ expect(validate(10)).to.throw(error('10'));
54
+ expect(validate(true)).to.throw(error('true'));
55
+ expect(validate(false)).to.throw(error('false'));
56
+ expect(validate([])).to.throw(error('Array'));
57
+ expect(validate({})).to.throw(error('Object'));
58
+ expect(validate(undefined)).to.throw(error('undefined'));
59
+ expect(validate(null)).to.throw(error('null'));
60
+ validate('adapter')();
61
+ });
62
+ });
63
+ });
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Datasource definition.
3
+ */
4
+ export declare type DatasourceDefinition = {
5
+ name: string;
6
+ adapter: string;
7
+ };
@@ -0,0 +1,2 @@
1
+ export * from './datasource-definition.js';
2
+ export * from './datasource-definition-validator.js';
@@ -0,0 +1 @@
1
+ export * from './datasource-definition-validator.js';
@@ -0,0 +1,50 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {ModelDefinition} from './model/index.js';
3
+ import {DatasourceDefinition} from './datasource/index.js';
4
+
5
+ /**
6
+ * Definition registry.
7
+ */
8
+ export declare class DefinitionRegistry extends Service {
9
+ /**
10
+ * Add datasource.
11
+ *
12
+ * @param datasourceDef
13
+ */
14
+ addDatasource(datasourceDef: DatasourceDefinition): void;
15
+
16
+ /**
17
+ * Has datasource.
18
+ *
19
+ * @param name
20
+ */
21
+ hasDatasource(name: string): boolean;
22
+
23
+ /**
24
+ * Get datasource.
25
+ *
26
+ * @param name
27
+ */
28
+ getDatasource(name: string): DatasourceDefinition;
29
+
30
+ /**
31
+ * Add model.
32
+ *
33
+ * @param modelDef
34
+ */
35
+ addModel(modelDef: ModelDefinition): void;
36
+
37
+ /**
38
+ * Has model.
39
+ *
40
+ * @param name
41
+ */
42
+ hasModel(name: string): boolean;
43
+
44
+ /**
45
+ * Get model.
46
+ *
47
+ * @param name
48
+ */
49
+ getModel(name: string): ModelDefinition;
50
+ }
@@ -0,0 +1,98 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {InvalidArgumentError} from '../errors/index.js';
3
+ import {ModelDefinitionValidator} from './model/index.js';
4
+ import {DatasourceDefinitionValidator} from '../definition/index.js';
5
+
6
+ /**
7
+ * Definition registry.
8
+ */
9
+ export class DefinitionRegistry extends Service {
10
+ /**
11
+ * Datasources.
12
+ *
13
+ * @type {object}
14
+ */
15
+ _datasources = {};
16
+
17
+ /**
18
+ * Models.
19
+ *
20
+ * @type {object}
21
+ */
22
+ _models = {};
23
+
24
+ /**
25
+ * Add datasource.
26
+ *
27
+ * @param {object} datasourceDef
28
+ */
29
+ addDatasource(datasourceDef) {
30
+ this.getService(DatasourceDefinitionValidator).validate(datasourceDef);
31
+ const name = datasourceDef.name;
32
+ if (name in this._datasources)
33
+ throw new InvalidArgumentError(
34
+ 'The datasource %v is already defined.',
35
+ name,
36
+ );
37
+ this._datasources[name] = datasourceDef;
38
+ }
39
+
40
+ /**
41
+ * Has datasource.
42
+ *
43
+ * @param {string} name
44
+ * @returns {boolean}
45
+ */
46
+ hasDatasource(name) {
47
+ return Boolean(this._datasources[name]);
48
+ }
49
+
50
+ /**
51
+ * Get datasource.
52
+ *
53
+ * @param {string} name
54
+ * @returns {object}
55
+ */
56
+ getDatasource(name) {
57
+ const datasourceDef = this._datasources[name];
58
+ if (!datasourceDef)
59
+ throw new InvalidArgumentError('The datasource %v is not defined.', name);
60
+ return datasourceDef;
61
+ }
62
+
63
+ /**
64
+ * Add model.
65
+ *
66
+ * @param {object} modelDef
67
+ */
68
+ addModel(modelDef) {
69
+ this.getService(ModelDefinitionValidator).validate(modelDef);
70
+ const name = modelDef.name;
71
+ if (name in this._models)
72
+ throw new InvalidArgumentError('The model %v is already defined.', name);
73
+ this._models[name] = modelDef;
74
+ }
75
+
76
+ /**
77
+ * Has model.
78
+ *
79
+ * @param {string} name
80
+ * @returns {boolean}
81
+ */
82
+ hasModel(name) {
83
+ return Boolean(this._models[name]);
84
+ }
85
+
86
+ /**
87
+ * Get model.
88
+ *
89
+ * @param {string} name
90
+ * @returns {object}
91
+ */
92
+ getModel(name) {
93
+ const modelDef = this._models[name];
94
+ if (!modelDef)
95
+ throw new InvalidArgumentError('The model %v is not defined.', name);
96
+ return modelDef;
97
+ }
98
+ }
@@ -0,0 +1,78 @@
1
+ import chai from 'chai';
2
+ import {expect} from 'chai';
3
+ import {ModelDefinitionValidator} from './model/index.js';
4
+ import {DefinitionRegistry} from './definition-registry.js';
5
+ import {DatasourceDefinitionValidator} from '../definition/index.js';
6
+
7
+ const sandbox = chai.spy.sandbox();
8
+
9
+ describe('DefinitionRegistry', function () {
10
+ let S;
11
+ beforeEach(function () {
12
+ S = new DefinitionRegistry();
13
+ });
14
+
15
+ afterEach(function () {
16
+ sandbox.restore();
17
+ });
18
+
19
+ it('sets a given datasource to the state', function () {
20
+ const datasource = {name: 'datasource', adapter: 'adapter'};
21
+ S.addDatasource(datasource);
22
+ const result = S.getDatasource('datasource');
23
+ expect(result).to.be.eql(datasource);
24
+ });
25
+
26
+ it('throws an error if a given datasource is already defined', function () {
27
+ const datasource1 = {name: 'datasource', adapter: 'adapter'};
28
+ const datasource2 = {name: 'datasource', adapter: 'adapter'};
29
+ S.addDatasource(datasource1);
30
+ const throwable = () => S.addDatasource(datasource2);
31
+ expect(throwable).to.throw(
32
+ 'The datasource "datasource" is already defined.',
33
+ );
34
+ });
35
+
36
+ it('throws an error when getting a not defined datasource', function () {
37
+ const throwable = () => S.getDatasource('undefined');
38
+ expect(throwable).to.throw('The datasource "undefined" is not defined.');
39
+ });
40
+
41
+ it('uses DatasourceDefinitionValidator to validate a given datasource', function () {
42
+ const V = S.getService(DatasourceDefinitionValidator);
43
+ sandbox.on(V, 'validate');
44
+ const datasource = {name: 'datasource', adapter: 'adapter'};
45
+ S.addDatasource(datasource);
46
+ expect(V.validate).to.have.been.called.once;
47
+ expect(V.validate).to.have.been.called.with.exactly(datasource);
48
+ });
49
+
50
+ it('sets a given model to the state', function () {
51
+ const model = {name: 'model'};
52
+ S.addModel(model);
53
+ const result = S.getModel('model');
54
+ expect(result).to.be.eql(model);
55
+ });
56
+
57
+ it('throws an error if a given model is already defined', function () {
58
+ const model1 = {name: 'model'};
59
+ const model2 = {name: 'model'};
60
+ S.addModel(model1);
61
+ const throwable = () => S.addModel(model2);
62
+ expect(throwable).to.throw('The model "model" is already defined.');
63
+ });
64
+
65
+ it('throws an error when getting a not defined model', function () {
66
+ const throwable = () => S.getModel('undefined');
67
+ expect(throwable).to.throw('The model "undefined" is not defined.');
68
+ });
69
+
70
+ it('uses ModelDefinitionValidator to validate a given model', function () {
71
+ const V = S.getService(ModelDefinitionValidator);
72
+ sandbox.on(V, 'validate');
73
+ const model = {name: 'model'};
74
+ S.addModel(model);
75
+ expect(V.validate).to.have.been.called.once;
76
+ expect(V.validate).to.have.been.called.with.exactly(model);
77
+ });
78
+ });
@@ -0,0 +1,3 @@
1
+ export * from './model/index.js';
2
+ export * from './datasource/index.js';
3
+ export * from './definition-registry.js';
@@ -0,0 +1,3 @@
1
+ export * from './model/index.js';
2
+ export * from './datasource/index.js';
3
+ export * from './definition-registry.js';
@@ -0,0 +1,7 @@
1
+ export * from './relations/index.js';
2
+ export * from './properties/index.js';
3
+ export * from './model-definition.js';
4
+ export * from './model-data-validator.js';
5
+ export * from './model-data-sanitizer.js';
6
+ export * from './model-definition-utils.js';
7
+ export * from './model-definition-validator.js';
@@ -0,0 +1,6 @@
1
+ export * from './relations/index.js';
2
+ export * from './properties/index.js';
3
+ export * from './model-data-validator.js';
4
+ export * from './model-data-sanitizer.js';
5
+ export * from './model-definition-utils.js';
6
+ export * from './model-definition-validator.js';
@@ -0,0 +1,15 @@
1
+ import {ModelData} from '../../types.js';
2
+ import {Service} from '@e22m4u/js-service';
3
+
4
+ /**
5
+ * Model data sanitizer.
6
+ */
7
+ export declare class ModelDataSanitizer extends Service {
8
+ /**
9
+ * Sanitize.
10
+ *
11
+ * @param modelName
12
+ * @param modelData
13
+ */
14
+ sanitize(modelName: string, modelData: ModelData): ModelData;
15
+ }
@@ -0,0 +1,33 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {InvalidArgumentError} from '../../errors/index.js';
3
+ import {ModelDefinitionUtils} from './model-definition-utils.js';
4
+
5
+ /**
6
+ * Model data validator.
7
+ */
8
+ export class ModelDataSanitizer extends Service {
9
+ /**
10
+ * Validate.
11
+ *
12
+ * @param {string} modelName
13
+ * @param {object} modelData
14
+ * @returns {object}
15
+ */
16
+ sanitize(modelName, modelData) {
17
+ if (!modelName || typeof modelName !== 'string')
18
+ throw new InvalidArgumentError(
19
+ 'The first argument of ModelDataSanitizer.sanitize ' +
20
+ 'must be a string, but %v given.',
21
+ modelName,
22
+ );
23
+ if (!modelData || typeof modelData !== 'object')
24
+ throw new InvalidArgumentError(
25
+ 'The second argument of ModelDataSanitizer.sanitize ' +
26
+ 'must be an Object, but %v given.',
27
+ modelData,
28
+ );
29
+ return this.getService(
30
+ ModelDefinitionUtils,
31
+ ).excludeObjectKeysByRelationNames(modelName, modelData);
32
+ }
33
+ }