@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.
- package/.c8rc +9 -0
- package/.commitlintrc +5 -0
- package/.editorconfig +13 -0
- package/.eslintignore +1 -0
- package/.eslintrc.cjs +27 -0
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +9 -0
- package/.mocharc.cjs +7 -0
- package/.prettierrc +7 -0
- package/LICENSE +21 -0
- package/README.md +523 -0
- package/mocha.setup.js +10 -0
- package/package.json +57 -0
- package/src/adapter/adapter-loader.d.ts +16 -0
- package/src/adapter/adapter-loader.js +63 -0
- package/src/adapter/adapter-loader.spec.js +31 -0
- package/src/adapter/adapter-registry.d.ts +14 -0
- package/src/adapter/adapter-registry.js +36 -0
- package/src/adapter/adapter-registry.spec.js +36 -0
- package/src/adapter/adapter.d.ts +118 -0
- package/src/adapter/adapter.js +181 -0
- package/src/adapter/adapter.spec.js +144 -0
- package/src/adapter/builtin/memory-adapter.d.ts +118 -0
- package/src/adapter/builtin/memory-adapter.js +342 -0
- package/src/adapter/builtin/memory-adapter.spec.js +2925 -0
- package/src/adapter/decorator/data-sanitizing-decorator.d.ts +13 -0
- package/src/adapter/decorator/data-sanitizing-decorator.js +44 -0
- package/src/adapter/decorator/data-sanitizing-decorator.spec.js +59 -0
- package/src/adapter/decorator/data-validation-decorator.d.ts +13 -0
- package/src/adapter/decorator/data-validation-decorator.js +41 -0
- package/src/adapter/decorator/data-validation-decorator.spec.js +59 -0
- package/src/adapter/decorator/default-values-decorator.d.ts +13 -0
- package/src/adapter/decorator/default-values-decorator.js +57 -0
- package/src/adapter/decorator/default-values-decorator.spec.js +141 -0
- package/src/adapter/decorator/fields-filtering-decorator.d.ts +13 -0
- package/src/adapter/decorator/fields-filtering-decorator.js +72 -0
- package/src/adapter/decorator/fields-filtering-decorator.spec.js +119 -0
- package/src/adapter/decorator/inclusion-decorator.d.ts +13 -0
- package/src/adapter/decorator/inclusion-decorator.js +78 -0
- package/src/adapter/decorator/inclusion-decorator.spec.js +117 -0
- package/src/adapter/decorator/index.d.ts +5 -0
- package/src/adapter/decorator/index.js +5 -0
- package/src/adapter/index.d.ts +3 -0
- package/src/adapter/index.js +3 -0
- package/src/definition/datasource/datasource-definition-validator.d.ts +14 -0
- package/src/definition/datasource/datasource-definition-validator.js +33 -0
- package/src/definition/datasource/datasource-definition-validator.spec.js +63 -0
- package/src/definition/datasource/datasource-definition.d.ts +7 -0
- package/src/definition/datasource/index.d.ts +2 -0
- package/src/definition/datasource/index.js +1 -0
- package/src/definition/definition-registry.d.ts +50 -0
- package/src/definition/definition-registry.js +98 -0
- package/src/definition/definition-registry.spec.js +78 -0
- package/src/definition/index.d.ts +3 -0
- package/src/definition/index.js +3 -0
- package/src/definition/model/index.d.ts +7 -0
- package/src/definition/model/index.js +6 -0
- package/src/definition/model/model-data-sanitizer.d.ts +15 -0
- package/src/definition/model/model-data-sanitizer.js +33 -0
- package/src/definition/model/model-data-validator.d.ts +32 -0
- package/src/definition/model/model-data-validator.js +144 -0
- package/src/definition/model/model-data-validator.spec.js +1889 -0
- package/src/definition/model/model-definition-utils.d.ts +161 -0
- package/src/definition/model/model-definition-utils.js +371 -0
- package/src/definition/model/model-definition-utils.spec.js +1474 -0
- package/src/definition/model/model-definition-validator.d.ts +14 -0
- package/src/definition/model/model-definition-validator.js +83 -0
- package/src/definition/model/model-definition-validator.spec.js +143 -0
- package/src/definition/model/model-definition.d.ts +28 -0
- package/src/definition/model/properties/data-type.d.ts +11 -0
- package/src/definition/model/properties/data-type.js +11 -0
- package/src/definition/model/properties/default-values-definition-validator.d.ts +15 -0
- package/src/definition/model/properties/default-values-definition-validator.js +53 -0
- package/src/definition/model/properties/default-values-definition-validator.spec.js +136 -0
- package/src/definition/model/properties/index.d.ts +5 -0
- package/src/definition/model/properties/index.js +4 -0
- package/src/definition/model/properties/primary-keys-definition-validator.d.ts +15 -0
- package/src/definition/model/properties/primary-keys-definition-validator.js +55 -0
- package/src/definition/model/properties/primary-keys-definition-validator.spec.js +145 -0
- package/src/definition/model/properties/properties-definition-validator.d.ts +15 -0
- package/src/definition/model/properties/properties-definition-validator.js +194 -0
- package/src/definition/model/properties/properties-definition-validator.spec.js +373 -0
- package/src/definition/model/properties/property-definition.d.ts +20 -0
- package/src/definition/model/relations/index.d.ts +3 -0
- package/src/definition/model/relations/index.js +2 -0
- package/src/definition/model/relations/relation-definition.d.ts +254 -0
- package/src/definition/model/relations/relation-type.d.ts +9 -0
- package/src/definition/model/relations/relation-type.js +9 -0
- package/src/definition/model/relations/relations-definition-validator.d.ts +15 -0
- package/src/definition/model/relations/relations-definition-validator.js +449 -0
- package/src/definition/model/relations/relations-definition-validator.spec.js +772 -0
- package/src/errors/index.d.ts +3 -0
- package/src/errors/index.js +3 -0
- package/src/errors/invalid-argument-error.d.ts +6 -0
- package/src/errors/invalid-argument-error.js +6 -0
- package/src/errors/invalid-argument-error.spec.js +33 -0
- package/src/errors/invalid-operator-value-error.d.ts +13 -0
- package/src/errors/invalid-operator-value-error.js +24 -0
- package/src/errors/invalid-operator-value-error.spec.js +11 -0
- package/src/errors/not-implemented-error.d.ts +6 -0
- package/src/errors/not-implemented-error.js +6 -0
- package/src/errors/not-implemented-error.spec.js +33 -0
- package/src/filter/fields-clause-tool.d.ts +38 -0
- package/src/filter/fields-clause-tool.js +88 -0
- package/src/filter/fields-clause-tool.spec.js +133 -0
- package/src/filter/filter.d.ts +335 -0
- package/src/filter/include-clause-tool.d.ts +53 -0
- package/src/filter/include-clause-tool.js +364 -0
- package/src/filter/include-clause-tool.spec.js +653 -0
- package/src/filter/index.d.ts +7 -0
- package/src/filter/index.js +6 -0
- package/src/filter/operator-clause-tool.d.ts +223 -0
- package/src/filter/operator-clause-tool.js +515 -0
- package/src/filter/operator-clause-tool.spec.js +1064 -0
- package/src/filter/order-clause-tool.d.ts +32 -0
- package/src/filter/order-clause-tool.js +97 -0
- package/src/filter/order-clause-tool.spec.js +438 -0
- package/src/filter/slice-clause-tool.d.ts +30 -0
- package/src/filter/slice-clause-tool.js +65 -0
- package/src/filter/slice-clause-tool.spec.js +117 -0
- package/src/filter/where-clause-tool.d.ts +23 -0
- package/src/filter/where-clause-tool.js +165 -0
- package/src/filter/where-clause-tool.spec.js +280 -0
- package/src/index.d.ts +9 -0
- package/src/index.js +8 -0
- package/src/relations/belongs-to-resolver.d.ts +46 -0
- package/src/relations/belongs-to-resolver.js +242 -0
- package/src/relations/belongs-to-resolver.spec.js +1047 -0
- package/src/relations/has-many-resolver.d.ts +67 -0
- package/src/relations/has-many-resolver.js +317 -0
- package/src/relations/has-many-resolver.spec.js +2911 -0
- package/src/relations/has-one-resolver.d.ts +67 -0
- package/src/relations/has-one-resolver.js +311 -0
- package/src/relations/has-one-resolver.spec.js +2274 -0
- package/src/relations/index.d.ts +4 -0
- package/src/relations/index.js +4 -0
- package/src/relations/references-many-resolver.d.ts +27 -0
- package/src/relations/references-many-resolver.js +113 -0
- package/src/relations/references-many-resolver.spec.js +631 -0
- package/src/repository/index.d.ts +2 -0
- package/src/repository/index.js +2 -0
- package/src/repository/repository-registry.d.ts +29 -0
- package/src/repository/repository-registry.js +57 -0
- package/src/repository/repository-registry.spec.js +38 -0
- package/src/repository/repository.d.ts +164 -0
- package/src/repository/repository.js +207 -0
- package/src/repository/repository.spec.js +202 -0
- package/src/schema.d.ts +37 -0
- package/src/schema.js +41 -0
- package/src/types.d.ts +30 -0
- package/src/utils/capitalize.d.ts +6 -0
- package/src/utils/capitalize.js +10 -0
- package/src/utils/capitalize.spec.js +14 -0
- package/src/utils/clone-deep.d.ts +6 -0
- package/src/utils/clone-deep.js +61 -0
- package/src/utils/clone-deep.spec.js +28 -0
- package/src/utils/exclude-object-keys.d.ts +10 -0
- package/src/utils/exclude-object-keys.js +20 -0
- package/src/utils/exclude-object-keys.spec.js +49 -0
- package/src/utils/get-ctor-name.d.ts +6 -0
- package/src/utils/get-ctor-name.js +11 -0
- package/src/utils/get-ctor-name.spec.js +17 -0
- package/src/utils/get-value-by-path.d.ts +12 -0
- package/src/utils/get-value-by-path.js +23 -0
- package/src/utils/get-value-by-path.spec.js +36 -0
- package/src/utils/index.d.ts +10 -0
- package/src/utils/index.js +10 -0
- package/src/utils/is-ctor.d.ts +7 -0
- package/src/utils/is-ctor.js +10 -0
- package/src/utils/is-ctor.spec.js +26 -0
- package/src/utils/is-pure-object.d.ts +6 -0
- package/src/utils/is-pure-object.js +15 -0
- package/src/utils/is-pure-object.spec.js +25 -0
- package/src/utils/select-object-keys.d.ts +10 -0
- package/src/utils/select-object-keys.js +37 -0
- package/src/utils/select-object-keys.spec.js +40 -0
- package/src/utils/singularize.d.ts +6 -0
- package/src/utils/singularize.js +22 -0
- package/src/utils/singularize.spec.js +23 -0
- package/src/utils/string-to-regexp.d.ts +10 -0
- package/src/utils/string-to-regexp.js +22 -0
- package/src/utils/string-to-regexp.spec.js +35 -0
- 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,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 @@
|
|
|
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,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,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
|
+
}
|