@e22m4u/js-repository 0.8.3 → 0.8.5
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/README.md +68 -148
- package/dist/cjs/index.cjs +207 -83
- package/package.json +3 -4
- package/src/adapter/adapter.js +2 -0
- package/src/adapter/adapter.spec.js +39 -41
- package/src/adapter/decorator/index.d.ts +1 -0
- package/src/adapter/decorator/index.js +1 -0
- package/src/adapter/decorator/required-property-decorator.d.ts +14 -0
- package/src/adapter/decorator/required-property-decorator.js +54 -0
- package/src/adapter/decorator/required-property-decorator.spec.js +105 -0
- package/src/definition/model/model-definition-utils.js +6 -9
- package/src/definition/model/model-definition-utils.spec.js +2 -6
- package/src/definition/model/properties/index.d.ts +1 -0
- package/src/definition/model/properties/index.js +1 -0
- package/src/definition/model/properties/property-uniqueness-validator.js +4 -8
- package/src/definition/model/properties/property-uniqueness-validator.spec.js +229 -31
- package/src/definition/model/properties/required-property-validator.d.ts +15 -0
- package/src/definition/model/properties/required-property-validator.js +90 -0
- package/src/definition/model/properties/required-property-validator.spec.js +544 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e22m4u/js-repository",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"description": "Реализация репозитория для работы с базами данных",
|
|
5
5
|
"author": "Mikhail Evstropov <e22m4u@yandex.ru>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,13 +39,12 @@
|
|
|
39
39
|
"prepare": "husky"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@e22m4u/js-empty-values": "~0.3.2",
|
|
43
42
|
"@e22m4u/js-format": "~0.3.2",
|
|
44
43
|
"@e22m4u/js-service": "~0.5.1"
|
|
45
44
|
},
|
|
46
45
|
"devDependencies": {
|
|
47
|
-
"@commitlint/cli": "~20.
|
|
48
|
-
"@commitlint/config-conventional": "~20.
|
|
46
|
+
"@commitlint/cli": "~20.3.0",
|
|
47
|
+
"@commitlint/config-conventional": "~20.3.0",
|
|
49
48
|
"@e22m4u/js-spy": "~0.3.5",
|
|
50
49
|
"@types/chai": "~5.2.3",
|
|
51
50
|
"@types/chai-as-promised": "~8.0.2",
|
package/src/adapter/adapter.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
DefaultValuesDecorator,
|
|
9
9
|
DataSanitizingDecorator,
|
|
10
10
|
FieldsFilteringDecorator,
|
|
11
|
+
RequiredPropertyDecorator,
|
|
11
12
|
PropertyUniquenessDecorator,
|
|
12
13
|
} from './decorator/index.js';
|
|
13
14
|
|
|
@@ -58,6 +59,7 @@ export class Adapter extends Service {
|
|
|
58
59
|
if (this.constructor !== Adapter) {
|
|
59
60
|
this.getService(DataSanitizingDecorator).decorate(this);
|
|
60
61
|
this.getService(DefaultValuesDecorator).decorate(this);
|
|
62
|
+
this.getService(RequiredPropertyDecorator).decorate(this);
|
|
61
63
|
this.getService(PropertyUniquenessDecorator).decorate(this);
|
|
62
64
|
this.getService(FieldsFilteringDecorator).decorate(this);
|
|
63
65
|
this.getService(InclusionDecorator).decorate(this);
|
|
@@ -9,13 +9,14 @@ import {
|
|
|
9
9
|
DefaultValuesDecorator,
|
|
10
10
|
DataSanitizingDecorator,
|
|
11
11
|
FieldsFilteringDecorator,
|
|
12
|
+
RequiredPropertyDecorator,
|
|
12
13
|
PropertyUniquenessDecorator,
|
|
13
14
|
} from './decorator/index.js';
|
|
14
15
|
|
|
15
16
|
const sandbox = createSandbox();
|
|
16
17
|
|
|
17
18
|
describe('Adapter', function () {
|
|
18
|
-
it('
|
|
19
|
+
it('should expose the static property "kinds"', function () {
|
|
19
20
|
const kinds = [...Service.kinds, ADAPTER_CLASS_NAME];
|
|
20
21
|
expect(Adapter.kinds).to.be.eql(kinds);
|
|
21
22
|
const MyAdapter = class extends Adapter {};
|
|
@@ -27,12 +28,12 @@ describe('Adapter', function () {
|
|
|
27
28
|
sandbox.restore();
|
|
28
29
|
});
|
|
29
30
|
|
|
30
|
-
it('
|
|
31
|
+
it('should extend the Service class', function () {
|
|
31
32
|
const adapter = new Adapter();
|
|
32
33
|
expect(adapter).to.be.instanceof(Service);
|
|
33
34
|
});
|
|
34
35
|
|
|
35
|
-
it('
|
|
36
|
+
it('should set given service container and settings', function () {
|
|
36
37
|
const container = new ServiceContainer();
|
|
37
38
|
const settings = {};
|
|
38
39
|
const adapter = new Adapter(container, settings);
|
|
@@ -40,47 +41,36 @@ describe('Adapter', function () {
|
|
|
40
41
|
expect(adapter._settings).to.be.eq(settings);
|
|
41
42
|
});
|
|
42
43
|
|
|
43
|
-
it('
|
|
44
|
+
it('should decorate only when the instance inherits the Adapter class', function () {
|
|
45
|
+
const decCtors = [
|
|
46
|
+
DataSanitizingDecorator,
|
|
47
|
+
DefaultValuesDecorator,
|
|
48
|
+
RequiredPropertyDecorator,
|
|
49
|
+
PropertyUniquenessDecorator,
|
|
50
|
+
FieldsFilteringDecorator,
|
|
51
|
+
InclusionDecorator,
|
|
52
|
+
];
|
|
44
53
|
const dbs = new DatabaseSchema();
|
|
45
|
-
const
|
|
46
|
-
const dec2 = dbs.getService(DefaultValuesDecorator);
|
|
47
|
-
const dec3 = dbs.getService(PropertyUniquenessDecorator);
|
|
48
|
-
const dec4 = dbs.getService(FieldsFilteringDecorator);
|
|
49
|
-
const dec5 = dbs.getService(InclusionDecorator);
|
|
54
|
+
const decs = decCtors.map(ctor => dbs.getService(ctor));
|
|
50
55
|
const order = [];
|
|
51
|
-
const decorate = function (
|
|
52
|
-
expect(
|
|
56
|
+
const decorate = function (...args) {
|
|
57
|
+
expect(args[0]).to.be.instanceof(Adapter);
|
|
58
|
+
expect(args).to.have.length(1);
|
|
53
59
|
order.push(this);
|
|
54
60
|
};
|
|
55
|
-
sandbox.on(
|
|
56
|
-
sandbox.on(dec2, 'decorate', decorate);
|
|
57
|
-
sandbox.on(dec3, 'decorate', decorate);
|
|
58
|
-
sandbox.on(dec4, 'decorate', decorate);
|
|
59
|
-
sandbox.on(dec5, 'decorate', decorate);
|
|
61
|
+
decs.forEach(dec => sandbox.on(dec, 'decorate', decorate));
|
|
60
62
|
new Adapter(dbs.container);
|
|
61
63
|
expect(order).to.be.empty;
|
|
62
|
-
expect(
|
|
63
|
-
expect(dec2.decorate).to.be.not.called;
|
|
64
|
-
expect(dec3.decorate).to.be.not.called;
|
|
65
|
-
expect(dec4.decorate).to.be.not.called;
|
|
66
|
-
expect(dec5.decorate).to.be.not.called;
|
|
64
|
+
decs.forEach(dec => expect(dec.decorate).to.be.not.called);
|
|
67
65
|
class ExtendedAdapter extends Adapter {}
|
|
68
66
|
new ExtendedAdapter(dbs.container);
|
|
69
|
-
expect(order[
|
|
70
|
-
expect(
|
|
71
|
-
expect(order[2]).to.be.eql(dec3);
|
|
72
|
-
expect(order[3]).to.be.eql(dec4);
|
|
73
|
-
expect(order[4]).to.be.eql(dec5);
|
|
74
|
-
expect(dec1.decorate).to.be.called.once;
|
|
75
|
-
expect(dec2.decorate).to.be.called.once;
|
|
76
|
-
expect(dec3.decorate).to.be.called.once;
|
|
77
|
-
expect(dec4.decorate).to.be.called.once;
|
|
78
|
-
expect(dec5.decorate).to.be.called.once;
|
|
67
|
+
decs.forEach((dec, index) => expect(order[index]).to.be.eq(dec));
|
|
68
|
+
decs.forEach(dec => expect(dec.decorate).to.be.called.once);
|
|
79
69
|
});
|
|
80
70
|
});
|
|
81
71
|
|
|
82
72
|
describe('create', function () {
|
|
83
|
-
it('
|
|
73
|
+
it('should throw the "Not implemented"', function () {
|
|
84
74
|
const adapter = new Adapter();
|
|
85
75
|
const throwable = () => adapter.create();
|
|
86
76
|
expect(throwable).to.throw('Adapter.create is not implemented.');
|
|
@@ -88,7 +78,7 @@ describe('Adapter', function () {
|
|
|
88
78
|
});
|
|
89
79
|
|
|
90
80
|
describe('replaceById', function () {
|
|
91
|
-
it('
|
|
81
|
+
it('should throw the "Not implemented"', function () {
|
|
92
82
|
const adapter = new Adapter();
|
|
93
83
|
const throwable = () => adapter.replaceById();
|
|
94
84
|
expect(throwable).to.throw('Adapter.replaceById is not implemented.');
|
|
@@ -96,15 +86,23 @@ describe('Adapter', function () {
|
|
|
96
86
|
});
|
|
97
87
|
|
|
98
88
|
describe('replaceOrCreate', function () {
|
|
99
|
-
it('
|
|
89
|
+
it('should throw the "Not implemented"', function () {
|
|
100
90
|
const adapter = new Adapter();
|
|
101
91
|
const throwable = () => adapter.replaceOrCreate();
|
|
102
92
|
expect(throwable).to.throw('Adapter.replaceOrCreate is not implemented.');
|
|
103
93
|
});
|
|
104
94
|
});
|
|
105
95
|
|
|
96
|
+
describe('patch', function () {
|
|
97
|
+
it('should throw the "Not implemented"', function () {
|
|
98
|
+
const adapter = new Adapter();
|
|
99
|
+
const throwable = () => adapter.patch();
|
|
100
|
+
expect(throwable).to.throw('Adapter.patch is not implemented.');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
106
104
|
describe('patchById', function () {
|
|
107
|
-
it('
|
|
105
|
+
it('should throw the "Not implemented"', function () {
|
|
108
106
|
const adapter = new Adapter();
|
|
109
107
|
const throwable = () => adapter.patchById();
|
|
110
108
|
expect(throwable).to.throw('Adapter.patchById is not implemented.');
|
|
@@ -112,7 +110,7 @@ describe('Adapter', function () {
|
|
|
112
110
|
});
|
|
113
111
|
|
|
114
112
|
describe('find', function () {
|
|
115
|
-
it('
|
|
113
|
+
it('should throw the "Not implemented"', function () {
|
|
116
114
|
const adapter = new Adapter();
|
|
117
115
|
const throwable = () => adapter.find();
|
|
118
116
|
expect(throwable).to.throw('Adapter.find is not implemented.');
|
|
@@ -120,7 +118,7 @@ describe('Adapter', function () {
|
|
|
120
118
|
});
|
|
121
119
|
|
|
122
120
|
describe('findById', function () {
|
|
123
|
-
it('
|
|
121
|
+
it('should throw the "Not implemented"', function () {
|
|
124
122
|
const adapter = new Adapter();
|
|
125
123
|
const throwable = () => adapter.findById();
|
|
126
124
|
expect(throwable).to.throw('Adapter.findById is not implemented.');
|
|
@@ -128,7 +126,7 @@ describe('Adapter', function () {
|
|
|
128
126
|
});
|
|
129
127
|
|
|
130
128
|
describe('delete', function () {
|
|
131
|
-
it('
|
|
129
|
+
it('should throw the "Not implemented"', function () {
|
|
132
130
|
const adapter = new Adapter();
|
|
133
131
|
const throwable = () => adapter.delete();
|
|
134
132
|
expect(throwable).to.throw('Adapter.delete is not implemented.');
|
|
@@ -136,7 +134,7 @@ describe('Adapter', function () {
|
|
|
136
134
|
});
|
|
137
135
|
|
|
138
136
|
describe('deleteById', function () {
|
|
139
|
-
it('
|
|
137
|
+
it('should throw the "Not implemented"', function () {
|
|
140
138
|
const adapter = new Adapter();
|
|
141
139
|
const throwable = () => adapter.deleteById();
|
|
142
140
|
expect(throwable).to.throw('Adapter.deleteById is not implemented.');
|
|
@@ -144,7 +142,7 @@ describe('Adapter', function () {
|
|
|
144
142
|
});
|
|
145
143
|
|
|
146
144
|
describe('exists', function () {
|
|
147
|
-
it('
|
|
145
|
+
it('should throw the "Not implemented"', function () {
|
|
148
146
|
const adapter = new Adapter();
|
|
149
147
|
const throwable = () => adapter.exists();
|
|
150
148
|
expect(throwable).to.throw('Adapter.exists is not implemented.');
|
|
@@ -152,7 +150,7 @@ describe('Adapter', function () {
|
|
|
152
150
|
});
|
|
153
151
|
|
|
154
152
|
describe('count', function () {
|
|
155
|
-
it('
|
|
153
|
+
it('should throw the "Not implemented"', function () {
|
|
156
154
|
const adapter = new Adapter();
|
|
157
155
|
const throwable = () => adapter.count();
|
|
158
156
|
expect(throwable).to.throw('Adapter.count is not implemented.');
|
|
@@ -2,4 +2,5 @@ export * from './inclusion-decorator.js';
|
|
|
2
2
|
export * from './default-values-decorator.js';
|
|
3
3
|
export * from './data-sanitizing-decorator.js';
|
|
4
4
|
export * from './fields-filtering-decorator.js';
|
|
5
|
+
export * from './required-property-decorator.js';
|
|
5
6
|
export * from './property-uniqueness-decorator.js';
|
|
@@ -2,4 +2,5 @@ export * from './inclusion-decorator.js';
|
|
|
2
2
|
export * from './default-values-decorator.js';
|
|
3
3
|
export * from './data-sanitizing-decorator.js';
|
|
4
4
|
export * from './fields-filtering-decorator.js';
|
|
5
|
+
export * from './required-property-decorator.js';
|
|
5
6
|
export * from './property-uniqueness-decorator.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {Adapter} from '../adapter.js';
|
|
2
|
+
import {Service} from '@e22m4u/js-service';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Required property decorator.
|
|
6
|
+
*/
|
|
7
|
+
export declare class RequiredPropertyDecorator extends Service {
|
|
8
|
+
/**
|
|
9
|
+
* Decorate.
|
|
10
|
+
*
|
|
11
|
+
* @param adapter
|
|
12
|
+
*/
|
|
13
|
+
decorate(adapter: Adapter): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {Adapter} from '../adapter.js';
|
|
2
|
+
import {Service} from '@e22m4u/js-service';
|
|
3
|
+
import {InvalidArgumentError} from '../../errors/index.js';
|
|
4
|
+
import {RequiredPropertyValidator} from '../../definition/index.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Required property decorator.
|
|
8
|
+
*/
|
|
9
|
+
export class RequiredPropertyDecorator 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
|
+
'The first argument of RequiredPropertyDecorator.decorate should be ' +
|
|
19
|
+
'an Adapter instance, but %v was given.',
|
|
20
|
+
adapter,
|
|
21
|
+
);
|
|
22
|
+
const validator = this.getService(RequiredPropertyValidator);
|
|
23
|
+
|
|
24
|
+
const create = adapter.create;
|
|
25
|
+
adapter.create = async function (modelName, modelData, filter) {
|
|
26
|
+
validator.validate(modelName, modelData);
|
|
27
|
+
return create.call(this, modelName, modelData, filter);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const replaceById = adapter.replaceById;
|
|
31
|
+
adapter.replaceById = async function (modelName, id, modelData, filter) {
|
|
32
|
+
validator.validate(modelName, modelData);
|
|
33
|
+
return replaceById.call(this, modelName, id, modelData, filter);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const replaceOrCreate = adapter.replaceOrCreate;
|
|
37
|
+
adapter.replaceOrCreate = async function (modelName, modelData, filter) {
|
|
38
|
+
validator.validate(modelName, modelData);
|
|
39
|
+
return replaceOrCreate.call(this, modelName, modelData, filter);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const patch = adapter.patch;
|
|
43
|
+
adapter.patch = async function (modelName, modelData, where) {
|
|
44
|
+
validator.validate(modelName, modelData, true);
|
|
45
|
+
return patch.call(this, modelName, modelData, where);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const patchById = adapter.patchById;
|
|
49
|
+
adapter.patchById = async function (modelName, id, modelData, filter) {
|
|
50
|
+
validator.validate(modelName, modelData, true);
|
|
51
|
+
return patchById.call(this, modelName, id, modelData, filter);
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {Adapter} from '../adapter.js';
|
|
3
|
+
import {createSandbox} from '@e22m4u/js-spy';
|
|
4
|
+
import {DatabaseSchema} from '../../database-schema.js';
|
|
5
|
+
import {RequiredPropertyValidator} from '../../definition/index.js';
|
|
6
|
+
|
|
7
|
+
const dbs = new DatabaseSchema();
|
|
8
|
+
dbs.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(modelData);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line no-unused-vars
|
|
17
|
+
replaceById(modelName, id, modelData, filter = undefined) {
|
|
18
|
+
return Promise.resolve(modelData);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// eslint-disable-next-line no-unused-vars
|
|
22
|
+
replaceOrCreate(modelName, modelData, filter = undefined) {
|
|
23
|
+
return Promise.resolve(modelData);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// eslint-disable-next-line no-unused-vars
|
|
27
|
+
patch(modelName, modelData, where = undefined) {
|
|
28
|
+
return Promise.resolve(modelData);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// eslint-disable-next-line no-unused-vars
|
|
32
|
+
patchById(modelName, id, modelData, filter = undefined) {
|
|
33
|
+
return Promise.resolve(modelData);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const A = dbs.getService(TestAdapter);
|
|
38
|
+
const V = dbs.getService(RequiredPropertyValidator);
|
|
39
|
+
const sandbox = createSandbox();
|
|
40
|
+
|
|
41
|
+
describe('RequiredPropertyDecorator', function () {
|
|
42
|
+
afterEach(function () {
|
|
43
|
+
sandbox.restore();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('overrides the "create" method and validates a given data', async function () {
|
|
47
|
+
const data = {kind: 'data'};
|
|
48
|
+
sandbox.on(V, 'validate', (modelName, modelData, isPartial = false) => {
|
|
49
|
+
expect(modelName).to.be.eq('model');
|
|
50
|
+
expect(modelData).to.be.eql(data);
|
|
51
|
+
expect(isPartial).to.be.false;
|
|
52
|
+
});
|
|
53
|
+
const res = await A.create('model', data);
|
|
54
|
+
expect(res).to.be.eql(data);
|
|
55
|
+
expect(V.validate).to.be.called.once;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('overrides the "replaceById" method and validates a given data', async function () {
|
|
59
|
+
const data = {kind: 'data'};
|
|
60
|
+
sandbox.on(V, 'validate', (modelName, modelData, isPartial = false) => {
|
|
61
|
+
expect(modelName).to.be.eq('model');
|
|
62
|
+
expect(modelData).to.be.eql(data);
|
|
63
|
+
expect(isPartial).to.be.false;
|
|
64
|
+
});
|
|
65
|
+
const res = await A.replaceById('model', 1, data);
|
|
66
|
+
expect(res).to.be.eql(data);
|
|
67
|
+
expect(V.validate).to.be.called.once;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('overrides the "replaceOrCreate" method and validates a given data', async function () {
|
|
71
|
+
const data = {kind: 'data'};
|
|
72
|
+
sandbox.on(V, 'validate', (modelName, modelData, isPartial = false) => {
|
|
73
|
+
expect(modelName).to.be.eq('model');
|
|
74
|
+
expect(modelData).to.be.eql(data);
|
|
75
|
+
expect(isPartial).to.be.false;
|
|
76
|
+
});
|
|
77
|
+
const res = await A.replaceOrCreate('model', data);
|
|
78
|
+
expect(res).to.be.eql(data);
|
|
79
|
+
expect(V.validate).to.be.called.once;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('overrides the "patch" method and validates a given data', async function () {
|
|
83
|
+
const data = {kind: 'data'};
|
|
84
|
+
sandbox.on(V, 'validate', (modelName, modelData, isPartial = false) => {
|
|
85
|
+
expect(modelName).to.be.eq('model');
|
|
86
|
+
expect(modelData).to.be.eql(data);
|
|
87
|
+
expect(isPartial).to.be.true;
|
|
88
|
+
});
|
|
89
|
+
const res = await A.patch('model', data);
|
|
90
|
+
expect(res).to.be.eql(data);
|
|
91
|
+
expect(V.validate).to.be.called.once;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('overrides the "patchById" method and validates a given data', async function () {
|
|
95
|
+
const data = {kind: 'data'};
|
|
96
|
+
sandbox.on(V, 'validate', (modelName, modelData, isPartial = false) => {
|
|
97
|
+
expect(modelName).to.be.eq('model');
|
|
98
|
+
expect(modelData).to.be.eql(data);
|
|
99
|
+
expect(isPartial).to.be.true;
|
|
100
|
+
});
|
|
101
|
+
const res = await A.patchById('model', 1, data);
|
|
102
|
+
expect(res).to.be.eql(data);
|
|
103
|
+
expect(V.validate).to.be.called.once;
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {Service} from '@e22m4u/js-service';
|
|
2
2
|
import {DataType} from './properties/index.js';
|
|
3
|
-
import {EmptyValuesService} from '@e22m4u/js-empty-values';
|
|
4
3
|
import {InvalidArgumentError} from '../../errors/index.js';
|
|
5
4
|
import {DefinitionRegistry} from '../definition-registry.js';
|
|
6
5
|
import {cloneDeep, excludeObjectKeys} from '../../utils/index.js';
|
|
@@ -121,7 +120,7 @@ export class ModelDefinitionUtils extends Service {
|
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
/**
|
|
124
|
-
* Set default values
|
|
123
|
+
* Set default values to empty properties.
|
|
125
124
|
*
|
|
126
125
|
* @param {string} modelName
|
|
127
126
|
* @param {object} modelData
|
|
@@ -139,16 +138,14 @@ export class ModelDefinitionUtils extends Service {
|
|
|
139
138
|
? Object.keys(modelData)
|
|
140
139
|
: Object.keys(propDefs);
|
|
141
140
|
const extendedData = cloneDeep(modelData);
|
|
142
|
-
const emptyValuesService = this.getService(EmptyValuesService);
|
|
143
141
|
propNames.forEach(propName => {
|
|
144
142
|
const propDef = propDefs[propName];
|
|
145
143
|
const propValue = extendedData[propName];
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (!isEmpty) return;
|
|
144
|
+
// если значение свойства не является undefined и null,
|
|
145
|
+
// то свойство пропускается (остается исходное значение)
|
|
146
|
+
if (propValue != null) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
152
149
|
if (
|
|
153
150
|
propDef &&
|
|
154
151
|
typeof propDef === 'object' &&
|
|
@@ -4,7 +4,6 @@ import {createSandbox} from '@e22m4u/js-spy';
|
|
|
4
4
|
import {DataType} from './properties/index.js';
|
|
5
5
|
import {RelationType} from './relations/index.js';
|
|
6
6
|
import {DatabaseSchema} from '../../database-schema.js';
|
|
7
|
-
import {EmptyValuesService} from '@e22m4u/js-empty-values';
|
|
8
7
|
import {InvalidArgumentError} from '../../errors/index.js';
|
|
9
8
|
|
|
10
9
|
import {
|
|
@@ -480,7 +479,7 @@ describe('ModelDefinitionUtils', function () {
|
|
|
480
479
|
expect(result).to.be.eql({foo: 'string'});
|
|
481
480
|
});
|
|
482
481
|
|
|
483
|
-
it('sets a default value if a property
|
|
482
|
+
it('sets a default value if a property value is undefined', function () {
|
|
484
483
|
const dbs = new DatabaseSchema();
|
|
485
484
|
dbs.defineModel({
|
|
486
485
|
name: 'model',
|
|
@@ -491,12 +490,9 @@ describe('ModelDefinitionUtils', function () {
|
|
|
491
490
|
},
|
|
492
491
|
},
|
|
493
492
|
});
|
|
494
|
-
dbs
|
|
495
|
-
.getService(EmptyValuesService)
|
|
496
|
-
.setEmptyValuesOf(DataType.STRING, ['empty']);
|
|
497
493
|
const result = dbs
|
|
498
494
|
.getService(ModelDefinitionUtils)
|
|
499
|
-
.setDefaultValuesToEmptyProperties('model', {foo:
|
|
495
|
+
.setDefaultValuesToEmptyProperties('model', {foo: undefined});
|
|
500
496
|
expect(result).to.be.eql({foo: 'placeholder'});
|
|
501
497
|
});
|
|
502
498
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './data-type.js';
|
|
2
2
|
export * from './property-definition.js';
|
|
3
3
|
export * from './property-uniqueness.js';
|
|
4
|
+
export * from './required-property-validator.js';
|
|
4
5
|
export * from './property-uniqueness-validator.js';
|
|
5
6
|
export * from './properties-definition-validator.js';
|
|
6
7
|
export * from './primary-keys-definition-validator.js';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './data-type.js';
|
|
2
2
|
export * from './property-definition.js';
|
|
3
3
|
export * from './property-uniqueness.js';
|
|
4
|
+
export * from './required-property-validator.js';
|
|
4
5
|
export * from './property-uniqueness-validator.js';
|
|
5
6
|
export * from './properties-definition-validator.js';
|
|
6
7
|
export * from './primary-keys-definition-validator.js';
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {DataType} from './data-type.js';
|
|
2
1
|
import {Service} from '@e22m4u/js-service';
|
|
3
2
|
import {isPlainObject} from '../../../utils/index.js';
|
|
4
|
-
import {EmptyValuesService} from '@e22m4u/js-empty-values';
|
|
5
3
|
import {PropertyUniqueness} from './property-uniqueness.js';
|
|
6
4
|
import {InvalidArgumentError} from '../../../errors/index.js';
|
|
7
5
|
import {ModelDefinitionUtils} from '../model-definition-utils.js';
|
|
@@ -70,7 +68,6 @@ export class PropertyUniquenessValidator extends Service {
|
|
|
70
68
|
propValue,
|
|
71
69
|
);
|
|
72
70
|
let willBeReplaced = undefined;
|
|
73
|
-
const emptyValuesService = this.getService(EmptyValuesService);
|
|
74
71
|
for (const propName of propNames) {
|
|
75
72
|
const propDef = propDefs[propName];
|
|
76
73
|
if (
|
|
@@ -81,12 +78,11 @@ export class PropertyUniquenessValidator extends Service {
|
|
|
81
78
|
) {
|
|
82
79
|
continue;
|
|
83
80
|
}
|
|
84
|
-
// sparse
|
|
81
|
+
// в режиме "sparse" проверка на уникальность
|
|
82
|
+
// должна игнорировать ложные значения
|
|
85
83
|
const propValue = modelData[propName];
|
|
86
|
-
if (propDef.unique === PropertyUniqueness.SPARSE) {
|
|
87
|
-
|
|
88
|
-
const isEmpty = emptyValuesService.isEmptyOf(propType, propValue);
|
|
89
|
-
if (isEmpty) continue;
|
|
84
|
+
if (propDef.unique === PropertyUniqueness.SPARSE && !propValue) {
|
|
85
|
+
continue;
|
|
90
86
|
}
|
|
91
87
|
// create
|
|
92
88
|
if (methodName === 'create') {
|