@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,44 @@
|
|
|
1
|
+
import {Adapter} from '../adapter.js';
|
|
2
|
+
import {Service} from '@e22m4u/js-service';
|
|
3
|
+
import {InvalidArgumentError} from '../../errors/index.js';
|
|
4
|
+
import {ModelDataSanitizer} from '../../definition/index.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Data sanitizing decorator.
|
|
8
|
+
*/
|
|
9
|
+
export class DataSanitizingDecorator 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 DataSanitizingDecorator.decorate must be ' +
|
|
19
|
+
'an Adapter instance, but %v given.',
|
|
20
|
+
adapter,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const sanitizer = adapter.getService(ModelDataSanitizer);
|
|
24
|
+
const sanitize = (...args) => sanitizer.sanitize(...args);
|
|
25
|
+
|
|
26
|
+
const create = adapter.create;
|
|
27
|
+
adapter.create = async function (modelName, modelData, filter) {
|
|
28
|
+
modelData = sanitize(modelName, modelData);
|
|
29
|
+
return create.call(this, modelName, modelData, filter);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const replaceById = adapter.replaceById;
|
|
33
|
+
adapter.replaceById = async function (modelName, id, modelData, filter) {
|
|
34
|
+
modelData = sanitize(modelName, modelData);
|
|
35
|
+
return replaceById.call(this, modelName, id, modelData, filter);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const patchById = adapter.patchById;
|
|
39
|
+
adapter.patchById = async function (modelName, id, modelData, filter) {
|
|
40
|
+
modelData = sanitize(modelName, modelData);
|
|
41
|
+
return patchById.call(this, modelName, id, modelData, filter);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import chai from 'chai';
|
|
2
|
+
import {expect} from 'chai';
|
|
3
|
+
import {Adapter} from '../adapter.js';
|
|
4
|
+
import {Schema} from '../../schema.js';
|
|
5
|
+
import {ModelDataSanitizer} from '../../definition/index.js';
|
|
6
|
+
|
|
7
|
+
const S = new Schema();
|
|
8
|
+
S.defineModel({name: 'model'});
|
|
9
|
+
|
|
10
|
+
class TestAdapter extends Adapter {
|
|
11
|
+
// eslint-disable-next-line no-unused-vars
|
|
12
|
+
create(modelName, modelData, filter = undefined) {
|
|
13
|
+
return Promise.resolve({});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line no-unused-vars
|
|
17
|
+
replaceById(modelName, id, modelData, filter = undefined) {
|
|
18
|
+
return Promise.resolve({});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// eslint-disable-next-line no-unused-vars
|
|
22
|
+
patchById(modelName, id, modelData, filter = undefined) {
|
|
23
|
+
return Promise.resolve({});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const A = S.getService(TestAdapter);
|
|
28
|
+
const V = S.getService(ModelDataSanitizer);
|
|
29
|
+
const sandbox = chai.spy.sandbox();
|
|
30
|
+
|
|
31
|
+
describe('DataSanitizingDecorator', function () {
|
|
32
|
+
afterEach(function () {
|
|
33
|
+
sandbox.restore();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('overrides the "create" method and sanitizes a given data', async function () {
|
|
37
|
+
sandbox.on(V, 'sanitize');
|
|
38
|
+
const data = {};
|
|
39
|
+
await A.create('model', data);
|
|
40
|
+
expect(V.sanitize).to.be.called.once;
|
|
41
|
+
expect(V.sanitize).to.be.called.with.exactly('model', data);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('overrides the "replaceById" method and sanitizes a given data', async function () {
|
|
45
|
+
sandbox.on(V, 'sanitize');
|
|
46
|
+
const data = {};
|
|
47
|
+
await A.replaceById('model', 1, data);
|
|
48
|
+
expect(V.sanitize).to.be.called.once;
|
|
49
|
+
expect(V.sanitize).to.be.called.with.exactly('model', data);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('overrides the "patchById" method and sanitizes a given data', async function () {
|
|
53
|
+
sandbox.on(V, 'sanitize');
|
|
54
|
+
const data = {};
|
|
55
|
+
await A.patchById('model', 1, data);
|
|
56
|
+
expect(V.sanitize).to.be.called.once;
|
|
57
|
+
expect(V.sanitize).to.be.called.with.exactly('model', data);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {Adapter} from '../adapter.js';
|
|
2
|
+
import {Service} from '@e22m4u/js-service';
|
|
3
|
+
import {InvalidArgumentError} from '../../errors/index.js';
|
|
4
|
+
import {ModelDataValidator} from '../../definition/index.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Data validation decorator.
|
|
8
|
+
*/
|
|
9
|
+
export class DataValidationDecorator 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 DataValidationDecorator.decorate must be ' +
|
|
19
|
+
'an Adapter instance, but %v given.',
|
|
20
|
+
adapter,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const create = adapter.create;
|
|
24
|
+
adapter.create = function (modelName, modelData, filter) {
|
|
25
|
+
this.getService(ModelDataValidator).validate(modelName, modelData);
|
|
26
|
+
return create.call(this, modelName, modelData, filter);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const replaceById = adapter.replaceById;
|
|
30
|
+
adapter.replaceById = function (modelName, id, modelData, filter) {
|
|
31
|
+
this.getService(ModelDataValidator).validate(modelName, modelData);
|
|
32
|
+
return replaceById.call(this, modelName, id, modelData, filter);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const patchById = adapter.patchById;
|
|
36
|
+
adapter.patchById = function (modelName, id, modelData, filter) {
|
|
37
|
+
this.getService(ModelDataValidator).validate(modelName, modelData, true);
|
|
38
|
+
return patchById.call(this, modelName, id, modelData, filter);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import chai from 'chai';
|
|
2
|
+
import {expect} from 'chai';
|
|
3
|
+
import {Adapter} from '../adapter.js';
|
|
4
|
+
import {Schema} from '../../schema.js';
|
|
5
|
+
import {ModelDataValidator} from '../../definition/index.js';
|
|
6
|
+
|
|
7
|
+
const S = new Schema();
|
|
8
|
+
S.defineModel({name: 'model'});
|
|
9
|
+
|
|
10
|
+
class TestAdapter extends Adapter {
|
|
11
|
+
// eslint-disable-next-line no-unused-vars
|
|
12
|
+
create(modelName, modelData, filter = undefined) {
|
|
13
|
+
return Promise.resolve({});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line no-unused-vars
|
|
17
|
+
replaceById(modelName, id, modelData, filter = undefined) {
|
|
18
|
+
return Promise.resolve({});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// eslint-disable-next-line no-unused-vars
|
|
22
|
+
patchById(modelName, id, modelData, filter = undefined) {
|
|
23
|
+
return Promise.resolve({});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const A = S.getService(TestAdapter);
|
|
28
|
+
const V = S.getService(ModelDataValidator);
|
|
29
|
+
const sandbox = chai.spy.sandbox();
|
|
30
|
+
|
|
31
|
+
describe('DataValidationDecorator', function () {
|
|
32
|
+
afterEach(function () {
|
|
33
|
+
sandbox.restore();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('overrides the "create" method and validates a given data', async function () {
|
|
37
|
+
sandbox.on(V, 'validate');
|
|
38
|
+
const data = {};
|
|
39
|
+
await A.create('model', data);
|
|
40
|
+
expect(V.validate).to.be.called.once;
|
|
41
|
+
expect(V.validate).to.be.called.with.exactly('model', data);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('overrides the "replaceById" method and validates a given data', async function () {
|
|
45
|
+
sandbox.on(V, 'validate');
|
|
46
|
+
const data = {};
|
|
47
|
+
await A.replaceById('model', 1, data);
|
|
48
|
+
expect(V.validate).to.be.called.once;
|
|
49
|
+
expect(V.validate).to.be.called.with.exactly('model', data);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('overrides the "patchById" method and validates a given data', async function () {
|
|
53
|
+
sandbox.on(V, 'validate');
|
|
54
|
+
const data = {};
|
|
55
|
+
await A.patchById('model', 1, data);
|
|
56
|
+
expect(V.validate).to.be.called.once;
|
|
57
|
+
expect(V.validate).to.be.called.with.exactly('model', data, true);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {Adapter} from '../adapter.js';
|
|
2
|
+
import {Service} from '@e22m4u/js-service';
|
|
3
|
+
import {InvalidArgumentError} from '../../errors/index.js';
|
|
4
|
+
import {ModelDefinitionUtils} from '../../definition/index.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Default values decorator.
|
|
8
|
+
*/
|
|
9
|
+
export class DefaultValuesDecorator 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 DefaultValuesDecorator.decorate must be ' +
|
|
19
|
+
'an Adapter instance, but %v given.',
|
|
20
|
+
adapter,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const utils = adapter.getService(ModelDefinitionUtils);
|
|
24
|
+
const setDefaults = (...args) =>
|
|
25
|
+
utils.setDefaultValuesToEmptyProperties(...args);
|
|
26
|
+
|
|
27
|
+
const create = adapter.create;
|
|
28
|
+
adapter.create = function (modelName, modelData, filter) {
|
|
29
|
+
modelData = setDefaults(modelName, modelData);
|
|
30
|
+
return create.call(this, modelName, modelData, filter);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const replaceById = adapter.replaceById;
|
|
34
|
+
adapter.replaceById = function (modelName, id, modelData, filter) {
|
|
35
|
+
modelData = setDefaults(modelName, modelData);
|
|
36
|
+
return replaceById.call(this, modelName, id, modelData, filter);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const patchById = adapter.patchById;
|
|
40
|
+
adapter.patchById = function (modelName, id, modelData, filter) {
|
|
41
|
+
modelData = setDefaults(modelName, modelData, true);
|
|
42
|
+
return patchById.call(this, modelName, id, modelData, filter);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const find = adapter.find;
|
|
46
|
+
adapter.find = async function (modelName, filter) {
|
|
47
|
+
const modelItems = await find.call(this, modelName, filter);
|
|
48
|
+
return modelItems.map(modelItem => setDefaults(modelName, modelItem));
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const findById = adapter.findById;
|
|
52
|
+
adapter.findById = async function (modelName, id, filter) {
|
|
53
|
+
const retvalData = await findById.call(this, modelName, id, filter);
|
|
54
|
+
return setDefaults(modelName, retvalData);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import chai from 'chai';
|
|
2
|
+
import {expect} from 'chai';
|
|
3
|
+
import {Adapter} from '../adapter.js';
|
|
4
|
+
import {Schema} from '../../schema.js';
|
|
5
|
+
import {DataType} from '../../definition/index.js';
|
|
6
|
+
import {ModelDefinitionUtils} from '../../definition/index.js';
|
|
7
|
+
|
|
8
|
+
const S = new Schema();
|
|
9
|
+
S.defineModel({
|
|
10
|
+
name: 'model',
|
|
11
|
+
properties: {
|
|
12
|
+
prop: {
|
|
13
|
+
type: DataType.STRING,
|
|
14
|
+
default: 'value',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const INPUT_DATA = {};
|
|
20
|
+
|
|
21
|
+
class TestAdapter extends Adapter {
|
|
22
|
+
// eslint-disable-next-line no-unused-vars
|
|
23
|
+
async create(modelName, modelData, filter = undefined) {
|
|
24
|
+
return modelData;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// eslint-disable-next-line no-unused-vars
|
|
28
|
+
async replaceById(modelName, id, modelData, filter = undefined) {
|
|
29
|
+
return modelData;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// eslint-disable-next-line no-unused-vars
|
|
33
|
+
async patchById(modelName, id, modelData, filter = undefined) {
|
|
34
|
+
return modelData;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// eslint-disable-next-line no-unused-vars
|
|
38
|
+
async find(modelName, filter = undefined) {
|
|
39
|
+
return [INPUT_DATA];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// eslint-disable-next-line no-unused-vars
|
|
43
|
+
async findById(modelName, id, filter = undefined) {
|
|
44
|
+
return INPUT_DATA;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const A = S.getService(TestAdapter);
|
|
49
|
+
const U = S.getService(ModelDefinitionUtils);
|
|
50
|
+
const sandbox = chai.spy.sandbox();
|
|
51
|
+
|
|
52
|
+
describe('DefaultValuesDecorator', function () {
|
|
53
|
+
afterEach(function () {
|
|
54
|
+
sandbox.restore();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('overrides the "create" method method and sets default values to input data', async function () {
|
|
58
|
+
sandbox.on(U, 'setDefaultValuesToEmptyProperties');
|
|
59
|
+
const retval = await A.create('model', INPUT_DATA);
|
|
60
|
+
expect(retval).to.be.eql({prop: 'value'});
|
|
61
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.once;
|
|
62
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.with.exactly(
|
|
63
|
+
'model',
|
|
64
|
+
INPUT_DATA,
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('overrides the "replaceById" method and sets default values to input data', async function () {
|
|
69
|
+
sandbox.on(U, 'setDefaultValuesToEmptyProperties');
|
|
70
|
+
const retval = await A.replaceById('model', 1, INPUT_DATA);
|
|
71
|
+
expect(retval).to.be.eql({prop: 'value'});
|
|
72
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.once;
|
|
73
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.with.exactly(
|
|
74
|
+
'model',
|
|
75
|
+
INPUT_DATA,
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('overrides the "patchById" method and sets default values to input data', function () {
|
|
80
|
+
it('does not set default values to not existing properties of input data', async function () {
|
|
81
|
+
sandbox.on(U, 'setDefaultValuesToEmptyProperties');
|
|
82
|
+
const data = {};
|
|
83
|
+
const retval = await A.patchById('model', 1, data);
|
|
84
|
+
expect(retval).to.be.eql({});
|
|
85
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.once;
|
|
86
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.with.exactly(
|
|
87
|
+
'model',
|
|
88
|
+
data,
|
|
89
|
+
true,
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('does set default values to input properties of null', async function () {
|
|
94
|
+
sandbox.on(U, 'setDefaultValuesToEmptyProperties');
|
|
95
|
+
const data = {prop: null};
|
|
96
|
+
const retval = await A.patchById('model', 2, data);
|
|
97
|
+
expect(retval).to.be.eql({prop: 'value'});
|
|
98
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.once;
|
|
99
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.with.exactly(
|
|
100
|
+
'model',
|
|
101
|
+
data,
|
|
102
|
+
true,
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('does set default values to input properties of undefined', async function () {
|
|
107
|
+
sandbox.on(U, 'setDefaultValuesToEmptyProperties');
|
|
108
|
+
const data = {prop: undefined};
|
|
109
|
+
const retval = await A.patchById('model', 3, data);
|
|
110
|
+
expect(retval).to.be.eql({prop: 'value'});
|
|
111
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.once;
|
|
112
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.with.exactly(
|
|
113
|
+
'model',
|
|
114
|
+
data,
|
|
115
|
+
true,
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('overrides the "find" method and sets default values to output data', async function () {
|
|
121
|
+
sandbox.on(U, 'setDefaultValuesToEmptyProperties');
|
|
122
|
+
const retval = await A.find('model');
|
|
123
|
+
expect(retval).to.be.eql([{prop: 'value'}]);
|
|
124
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.once;
|
|
125
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.with.exactly(
|
|
126
|
+
'model',
|
|
127
|
+
INPUT_DATA,
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('overrides the "findById" method and sets default values to output data', async function () {
|
|
132
|
+
sandbox.on(U, 'setDefaultValuesToEmptyProperties');
|
|
133
|
+
const retval = await A.findById('model', 1);
|
|
134
|
+
expect(retval).to.be.eql({prop: 'value'});
|
|
135
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.once;
|
|
136
|
+
expect(U.setDefaultValuesToEmptyProperties).to.be.called.with.exactly(
|
|
137
|
+
'model',
|
|
138
|
+
INPUT_DATA,
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {Adapter} from '../adapter.js';
|
|
2
|
+
import {Service} from '@e22m4u/js-service';
|
|
3
|
+
import {FieldsClauseTool} from '../../filter/index.js';
|
|
4
|
+
import {InvalidArgumentError} from '../../errors/index.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Fields filtering decorator.
|
|
8
|
+
*/
|
|
9
|
+
export class FieldsFilteringDecorator 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 FieldsFilteringDecorator.decorate must be ' +
|
|
19
|
+
'an Adapter instance, but %v given.',
|
|
20
|
+
adapter,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const tool = adapter.getService(FieldsClauseTool);
|
|
24
|
+
const selectFields = (...args) => tool.filter(...args);
|
|
25
|
+
|
|
26
|
+
const create = adapter.create;
|
|
27
|
+
adapter.create = async function (modelName, modelData, filter) {
|
|
28
|
+
let result = await create.call(this, modelName, modelData, filter);
|
|
29
|
+
if (filter && typeof filter === 'object' && filter.fields)
|
|
30
|
+
result = selectFields(result, modelName, filter.fields);
|
|
31
|
+
return result;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const replaceById = adapter.replaceById;
|
|
35
|
+
adapter.replaceById = async function (modelName, id, modelData, filter) {
|
|
36
|
+
let result = await replaceById.call(
|
|
37
|
+
this,
|
|
38
|
+
modelName,
|
|
39
|
+
id,
|
|
40
|
+
modelData,
|
|
41
|
+
filter,
|
|
42
|
+
);
|
|
43
|
+
if (filter && typeof filter === 'object' && filter.fields)
|
|
44
|
+
result = selectFields(result, modelName, filter.fields);
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const patchById = adapter.patchById;
|
|
49
|
+
adapter.patchById = async function (modelName, id, modelData, filter) {
|
|
50
|
+
let result = await patchById.call(this, modelName, id, modelData, filter);
|
|
51
|
+
if (filter && typeof filter === 'object' && filter.fields)
|
|
52
|
+
result = selectFields(result, modelName, filter.fields);
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const find = adapter.find;
|
|
57
|
+
adapter.find = async function (modelName, filter) {
|
|
58
|
+
let result = await find.call(this, modelName, filter);
|
|
59
|
+
if (filter && typeof filter === 'object' && filter.fields)
|
|
60
|
+
result = selectFields(result, modelName, filter.fields);
|
|
61
|
+
return result;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const findById = adapter.findById;
|
|
65
|
+
adapter.findById = async function (modelName, id, filter) {
|
|
66
|
+
let result = await findById.call(this, modelName, id, filter);
|
|
67
|
+
if (filter && typeof filter === 'object' && filter.fields)
|
|
68
|
+
result = selectFields(result, modelName, filter.fields);
|
|
69
|
+
return result;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import chai from 'chai';
|
|
2
|
+
import {expect} from 'chai';
|
|
3
|
+
import {Adapter} from '../adapter.js';
|
|
4
|
+
import {Schema} from '../../schema.js';
|
|
5
|
+
import {FieldsClauseTool} from '../../filter/index.js';
|
|
6
|
+
|
|
7
|
+
const S = new Schema();
|
|
8
|
+
const MODEL_NAME = 'model';
|
|
9
|
+
S.defineModel({name: MODEL_NAME});
|
|
10
|
+
|
|
11
|
+
const FILTER = {fields: ['foo', 'bar']};
|
|
12
|
+
const MODEL_DATA = {
|
|
13
|
+
foo: 'fooVal',
|
|
14
|
+
bar: 'barVal',
|
|
15
|
+
baz: 'bazVal',
|
|
16
|
+
qux: 'quxVal',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const RETVAL_DATA = {
|
|
20
|
+
foo: MODEL_DATA.foo,
|
|
21
|
+
bar: MODEL_DATA.bar,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
class TestAdapter extends Adapter {
|
|
25
|
+
// eslint-disable-next-line no-unused-vars
|
|
26
|
+
async create(modelName, modelData, filter = undefined) {
|
|
27
|
+
return MODEL_DATA;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// eslint-disable-next-line no-unused-vars
|
|
31
|
+
async replaceById(modelName, id, modelData, filter = undefined) {
|
|
32
|
+
return MODEL_DATA;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// eslint-disable-next-line no-unused-vars
|
|
36
|
+
async patchById(modelName, id, modelData, filter = undefined) {
|
|
37
|
+
return MODEL_DATA;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// eslint-disable-next-line no-unused-vars
|
|
41
|
+
async find(modelName, filter = undefined) {
|
|
42
|
+
return [MODEL_DATA];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// eslint-disable-next-line no-unused-vars
|
|
46
|
+
async findById(modelName, id, filter = undefined) {
|
|
47
|
+
return MODEL_DATA;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const A = S.getService(TestAdapter);
|
|
52
|
+
const T = S.getService(FieldsClauseTool);
|
|
53
|
+
const sandbox = chai.spy.sandbox();
|
|
54
|
+
|
|
55
|
+
describe('FieldsFilteringDecorator', function () {
|
|
56
|
+
afterEach(function () {
|
|
57
|
+
sandbox.restore();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('overrides the "create" method method and filtering output fields', async function () {
|
|
61
|
+
sandbox.on(T, 'filter');
|
|
62
|
+
const retval = await A.create(MODEL_NAME, {}, FILTER);
|
|
63
|
+
expect(retval).to.be.eql(RETVAL_DATA);
|
|
64
|
+
expect(T.filter).to.be.called.once;
|
|
65
|
+
expect(T.filter).to.be.called.with.exactly(
|
|
66
|
+
MODEL_DATA,
|
|
67
|
+
MODEL_NAME,
|
|
68
|
+
FILTER.fields,
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('overrides the "replaceById" method and filtering output fields', async function () {
|
|
73
|
+
sandbox.on(T, 'filter');
|
|
74
|
+
const retval = await A.replaceById(MODEL_NAME, 1, {}, FILTER);
|
|
75
|
+
expect(retval).to.be.eql(RETVAL_DATA);
|
|
76
|
+
expect(T.filter).to.be.called.once;
|
|
77
|
+
expect(T.filter).to.be.called.with.exactly(
|
|
78
|
+
MODEL_DATA,
|
|
79
|
+
MODEL_NAME,
|
|
80
|
+
FILTER.fields,
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('overrides the "patchById" method and filtering output fields', async function () {
|
|
85
|
+
sandbox.on(T, 'filter');
|
|
86
|
+
const retval = await A.patchById(MODEL_NAME, 1, {}, FILTER);
|
|
87
|
+
expect(retval).to.be.eql(RETVAL_DATA);
|
|
88
|
+
expect(T.filter).to.be.called.once;
|
|
89
|
+
expect(T.filter).to.be.called.with.exactly(
|
|
90
|
+
MODEL_DATA,
|
|
91
|
+
MODEL_NAME,
|
|
92
|
+
FILTER.fields,
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('overrides the "find" method and filtering output fields', async function () {
|
|
97
|
+
sandbox.on(T, 'filter', function (entities, modelName, fields) {
|
|
98
|
+
expect(entities).to.be.eql([MODEL_DATA]);
|
|
99
|
+
expect(modelName).to.be.eq(MODEL_NAME);
|
|
100
|
+
expect(fields).to.be.eql(FILTER.fields);
|
|
101
|
+
return [RETVAL_DATA];
|
|
102
|
+
});
|
|
103
|
+
const retval = await A.find(MODEL_NAME, FILTER);
|
|
104
|
+
expect(retval).to.be.eql([RETVAL_DATA]);
|
|
105
|
+
expect(T.filter).to.be.called.once;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('overrides the "findById" method and filtering output fields', async function () {
|
|
109
|
+
sandbox.on(T, 'filter');
|
|
110
|
+
const retval = await A.findById(MODEL_NAME, 1, FILTER);
|
|
111
|
+
expect(retval).to.be.eql(RETVAL_DATA);
|
|
112
|
+
expect(T.filter).to.be.called.once;
|
|
113
|
+
expect(T.filter).to.be.called.with.exactly(
|
|
114
|
+
MODEL_DATA,
|
|
115
|
+
MODEL_NAME,
|
|
116
|
+
FILTER.fields,
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
});
|