@e22m4u/js-repository 0.1.25 → 0.2.1
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/build-cjs.js +5 -0
- package/dist/cjs/index.cjs +494 -846
- package/package.json +11 -10
- package/src/adapter/adapter-loader.js +6 -2
- package/src/adapter/adapter.js +8 -1
- package/src/adapter/adapter.spec.js +6 -6
- package/src/definition/model/model-data-validator.js +7 -3
- package/src/definition/model/model-data-validator.spec.js +18 -3
- package/src/definition/model/properties/properties-definition-validator.js +37 -15
- package/src/definition/model/properties/properties-definition-validator.spec.js +48 -19
- package/src/definition/model/properties/property-definition.d.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e22m4u/js-repository",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Модуль для работы с базами данных для Node.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"format": "prettier --write \"./src/**/*.js\"",
|
|
21
21
|
"test": "npm run lint && c8 --reporter=text-summary mocha --bail",
|
|
22
22
|
"test:coverage": "npm run lint && c8 --reporter=text mocha --bail",
|
|
23
|
-
"build:cjs": "node build-cjs.js",
|
|
23
|
+
"build:cjs": "rimraf ./dist/cjs && node --no-warnings=ExperimentalWarning build-cjs.js",
|
|
24
24
|
"prepare": "husky"
|
|
25
25
|
},
|
|
26
26
|
"repository": {
|
|
@@ -40,31 +40,32 @@
|
|
|
40
40
|
"homepage": "https://github.com/e22m4u/js-repository",
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@e22m4u/js-format": "0.1.x",
|
|
43
|
-
"@e22m4u/js-service": "0.
|
|
43
|
+
"@e22m4u/js-service": "0.2.x"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@commitlint/cli": "~19.
|
|
47
|
-
"@commitlint/config-conventional": "~19.
|
|
46
|
+
"@commitlint/cli": "~19.6.0",
|
|
47
|
+
"@commitlint/config-conventional": "~19.6.0",
|
|
48
48
|
"@types/chai": "~5.0.1",
|
|
49
49
|
"@types/chai-as-promised": "~8.0.1",
|
|
50
50
|
"@types/chai-spies": "~1.0.6",
|
|
51
|
-
"@types/mocha": "~10.0.
|
|
51
|
+
"@types/mocha": "~10.0.10",
|
|
52
52
|
"c8": "~10.1.2",
|
|
53
53
|
"chai": "~5.1.2",
|
|
54
54
|
"chai-as-promised": "~8.0.0",
|
|
55
55
|
"chai-spies": "~1.1.0",
|
|
56
56
|
"chai-subset": "~1.6.0",
|
|
57
57
|
"esbuild": "~0.24.0",
|
|
58
|
-
"eslint": "~9.
|
|
58
|
+
"eslint": "~9.15.0",
|
|
59
59
|
"eslint-config-prettier": "~9.1.0",
|
|
60
60
|
"eslint-plugin-chai-expect": "~3.1.0",
|
|
61
|
-
"eslint-plugin-jsdoc": "~50.
|
|
61
|
+
"eslint-plugin-jsdoc": "~50.5.0",
|
|
62
62
|
"eslint-plugin-mocha": "~10.5.0",
|
|
63
|
-
"husky": "~9.1.
|
|
63
|
+
"husky": "~9.1.7",
|
|
64
64
|
"mocha": "~10.8.2",
|
|
65
65
|
"prettier": "~3.3.3",
|
|
66
|
+
"rimraf": "~6.0.1",
|
|
66
67
|
"tsx": "~4.19.2",
|
|
67
68
|
"typescript": "~5.6.3",
|
|
68
|
-
"typescript-eslint": "~8.
|
|
69
|
+
"typescript-eslint": "~8.15.0"
|
|
69
70
|
}
|
|
70
71
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {Adapter} from './adapter.js';
|
|
2
2
|
import {Service} from '@e22m4u/js-service';
|
|
3
|
+
import {ADAPTER_CLASS_NAME} from './adapter.js';
|
|
3
4
|
import {InvalidArgumentError} from '../errors/index.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -54,8 +55,11 @@ function findAdapterCtorInModule(module) {
|
|
|
54
55
|
let adapterCtor;
|
|
55
56
|
if (!module || typeof module !== 'object' || Array.isArray(module)) return;
|
|
56
57
|
for (const ctor of Object.values(module)) {
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
if (
|
|
59
|
+
typeof ctor === 'function' &&
|
|
60
|
+
Array.isArray(ctor.kinds) &&
|
|
61
|
+
Adapter.kinds.includes(ADAPTER_CLASS_NAME)
|
|
62
|
+
) {
|
|
59
63
|
adapterCtor = ctor;
|
|
60
64
|
break;
|
|
61
65
|
}
|
package/src/adapter/adapter.js
CHANGED
|
@@ -10,6 +10,13 @@ import {FieldsFilteringDecorator} from './decorator/index.js';
|
|
|
10
10
|
import {DataTransformationDecorator} from './decorator/index.js';
|
|
11
11
|
import {PropertyUniquenessDecorator} from './decorator/index.js';
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Adapter class name.
|
|
15
|
+
*
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
export const ADAPTER_CLASS_NAME = 'Adapter';
|
|
19
|
+
|
|
13
20
|
/**
|
|
14
21
|
* Adapter.
|
|
15
22
|
*/
|
|
@@ -19,7 +26,7 @@ export class Adapter extends Service {
|
|
|
19
26
|
*
|
|
20
27
|
* @type {string}
|
|
21
28
|
*/
|
|
22
|
-
static
|
|
29
|
+
static kinds = [...Service.kinds, ADAPTER_CLASS_NAME];
|
|
23
30
|
|
|
24
31
|
/**
|
|
25
32
|
* Settings.
|
|
@@ -3,6 +3,7 @@ import {chai} from '../chai.js';
|
|
|
3
3
|
import {Schema} from '../schema.js';
|
|
4
4
|
import {Adapter} from './adapter.js';
|
|
5
5
|
import {Service} from '@e22m4u/js-service';
|
|
6
|
+
import {ADAPTER_CLASS_NAME} from './adapter.js';
|
|
6
7
|
import {ServiceContainer} from '@e22m4u/js-service';
|
|
7
8
|
import {InclusionDecorator} from './decorator/index.js';
|
|
8
9
|
import {DefaultValuesDecorator} from './decorator/index.js';
|
|
@@ -15,12 +16,11 @@ import {PropertyUniquenessDecorator} from './decorator/index.js';
|
|
|
15
16
|
const sandbox = chai.spy.sandbox();
|
|
16
17
|
|
|
17
18
|
describe('Adapter', function () {
|
|
18
|
-
it('exposes static property "
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
expect(MyAdapter2.kind).to.be.eq(Adapter.name);
|
|
19
|
+
it('exposes static property "kinds"', function () {
|
|
20
|
+
const kinds = [...Service.kinds, ADAPTER_CLASS_NAME];
|
|
21
|
+
expect(Adapter.kinds).to.be.eql(kinds);
|
|
22
|
+
const MyAdapter = class extends Adapter {};
|
|
23
|
+
expect(MyAdapter.kinds).to.be.eql(kinds);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
describe('constructor', function () {
|
|
@@ -157,11 +157,15 @@ export class ModelDataValidator extends Service {
|
|
|
157
157
|
);
|
|
158
158
|
break;
|
|
159
159
|
// OBJECT
|
|
160
|
-
case DataType.OBJECT:
|
|
160
|
+
case DataType.OBJECT: {
|
|
161
161
|
if (!isPureObject(propValue)) throw createError('an Object');
|
|
162
|
-
if (typeof propDef === 'object'
|
|
163
|
-
|
|
162
|
+
if (typeof propDef === 'object') {
|
|
163
|
+
const modelOptionField = isArrayValue ? 'itemModel' : 'model';
|
|
164
|
+
const modelOptionValue = propDef[modelOptionField];
|
|
165
|
+
if (modelOptionValue) this.validate(modelOptionValue, propValue);
|
|
166
|
+
}
|
|
164
167
|
break;
|
|
168
|
+
}
|
|
165
169
|
}
|
|
166
170
|
}
|
|
167
171
|
|
|
@@ -1651,7 +1651,22 @@ describe('ModelDataValidator', function () {
|
|
|
1651
1651
|
);
|
|
1652
1652
|
});
|
|
1653
1653
|
|
|
1654
|
-
describe('the "
|
|
1654
|
+
describe('the "itemModel" option', function () {
|
|
1655
|
+
it('does not throw an error if the option "itemModel" is not specified in case of Object item type', function () {
|
|
1656
|
+
const S = new Schema();
|
|
1657
|
+
S.defineModel({
|
|
1658
|
+
name: 'model',
|
|
1659
|
+
properties: {
|
|
1660
|
+
foo: {
|
|
1661
|
+
type: DataType.ARRAY,
|
|
1662
|
+
itemType: DataType.OBJECT,
|
|
1663
|
+
},
|
|
1664
|
+
},
|
|
1665
|
+
});
|
|
1666
|
+
const value = {foo: [{a: 1}, {b: 2}]};
|
|
1667
|
+
S.getService(ModelDataValidator).validate('model', value);
|
|
1668
|
+
});
|
|
1669
|
+
|
|
1655
1670
|
it('throws an error when the given object element has an invalid model', function () {
|
|
1656
1671
|
const S = new Schema();
|
|
1657
1672
|
S.defineModel({
|
|
@@ -1667,7 +1682,7 @@ describe('ModelDataValidator', function () {
|
|
|
1667
1682
|
bar: {
|
|
1668
1683
|
type: DataType.ARRAY,
|
|
1669
1684
|
itemType: DataType.OBJECT,
|
|
1670
|
-
|
|
1685
|
+
itemModel: 'modelA',
|
|
1671
1686
|
},
|
|
1672
1687
|
},
|
|
1673
1688
|
});
|
|
@@ -1696,7 +1711,7 @@ describe('ModelDataValidator', function () {
|
|
|
1696
1711
|
bar: {
|
|
1697
1712
|
type: DataType.ARRAY,
|
|
1698
1713
|
itemType: DataType.OBJECT,
|
|
1699
|
-
|
|
1714
|
+
itemModel: 'modelA',
|
|
1700
1715
|
},
|
|
1701
1716
|
},
|
|
1702
1717
|
});
|
|
@@ -112,6 +112,15 @@ export class PropertiesDefinitionValidator extends Service {
|
|
|
112
112
|
propDef.itemType,
|
|
113
113
|
);
|
|
114
114
|
}
|
|
115
|
+
if (propDef.itemModel && typeof propDef.itemModel !== 'string') {
|
|
116
|
+
throw new InvalidArgumentError(
|
|
117
|
+
'The provided option "itemModel" of the property %v in the model %v ' +
|
|
118
|
+
'should be a String, but %v given.',
|
|
119
|
+
propName,
|
|
120
|
+
modelName,
|
|
121
|
+
propDef.itemModel,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
115
124
|
if (propDef.model && typeof propDef.model !== 'string')
|
|
116
125
|
throw new InvalidArgumentError(
|
|
117
126
|
'The provided option "model" of the property %v in the model %v ' +
|
|
@@ -175,37 +184,50 @@ export class PropertiesDefinitionValidator extends Service {
|
|
|
175
184
|
);
|
|
176
185
|
if (propDef.itemType && propDef.type !== Type.ARRAY)
|
|
177
186
|
throw new InvalidArgumentError(
|
|
178
|
-
'The property %v of the model %v has
|
|
187
|
+
'The property %v of the model %v has a non-array type, ' +
|
|
179
188
|
'so it should not have the option "itemType" to be provided.',
|
|
180
189
|
propName,
|
|
181
190
|
modelName,
|
|
182
191
|
propDef.type,
|
|
183
192
|
);
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
193
|
+
if (propDef.itemModel && propDef.type !== Type.ARRAY)
|
|
194
|
+
throw new InvalidArgumentError(
|
|
195
|
+
'The option "itemModel" is not supported for %s property type, ' +
|
|
196
|
+
'so the property %v of the model %v should not have ' +
|
|
197
|
+
'the option "itemModel" to be provided.',
|
|
198
|
+
capitalize(propDef.type),
|
|
199
|
+
propName,
|
|
200
|
+
modelName,
|
|
201
|
+
);
|
|
202
|
+
if (propDef.itemModel && propDef.itemType !== Type.OBJECT) {
|
|
203
|
+
if (propDef.itemType) {
|
|
190
204
|
throw new InvalidArgumentError(
|
|
191
|
-
'The option "
|
|
192
|
-
'
|
|
193
|
-
'the
|
|
194
|
-
capitalize(propDef.type),
|
|
205
|
+
'The provided option "itemModel" requires the option "itemType" ' +
|
|
206
|
+
'to be explicitly set to Object, but the property %v of ' +
|
|
207
|
+
'the model %v has specified item type as %s.',
|
|
195
208
|
propName,
|
|
196
209
|
modelName,
|
|
210
|
+
capitalize(propDef.itemType),
|
|
197
211
|
);
|
|
198
212
|
} else {
|
|
199
213
|
throw new InvalidArgumentError(
|
|
200
|
-
'The option "
|
|
201
|
-
'
|
|
202
|
-
'the
|
|
203
|
-
capitalize(propDef.itemType),
|
|
214
|
+
'The provided option "itemModel" requires the option "itemType" ' +
|
|
215
|
+
'to be explicitly set to Object, but the property %v of ' +
|
|
216
|
+
'the model %v does not have specified item type.',
|
|
204
217
|
propName,
|
|
205
218
|
modelName,
|
|
206
219
|
);
|
|
207
220
|
}
|
|
208
221
|
}
|
|
222
|
+
if (propDef.model && propDef.type !== Type.OBJECT)
|
|
223
|
+
throw new InvalidArgumentError(
|
|
224
|
+
'The option "model" is not supported for %s property type, ' +
|
|
225
|
+
'so the property %v of the model %v should not have ' +
|
|
226
|
+
'the option "model" to be provided.',
|
|
227
|
+
capitalize(propDef.type),
|
|
228
|
+
propName,
|
|
229
|
+
modelName,
|
|
230
|
+
);
|
|
209
231
|
if (propDef.validate != null) {
|
|
210
232
|
const propertyValidatorRegistry = this.getService(
|
|
211
233
|
PropertyValidatorRegistry,
|
|
@@ -133,7 +133,7 @@ describe('PropertiesDefinitionValidator', function () {
|
|
|
133
133
|
validate(DataType.STRING)();
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
-
it('expects provided
|
|
136
|
+
it('expects the provided option "itemType" to be a DataType', function () {
|
|
137
137
|
const validate = v => {
|
|
138
138
|
const foo = {type: DataType.ARRAY, itemType: v};
|
|
139
139
|
return () => S.validate('model', {foo});
|
|
@@ -153,7 +153,29 @@ describe('PropertiesDefinitionValidator', function () {
|
|
|
153
153
|
validate(DataType.STRING)();
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
-
it('expects provided
|
|
156
|
+
it('expects the provided option "itemModel" to be a string', function () {
|
|
157
|
+
const validate = v => {
|
|
158
|
+
const foo = {
|
|
159
|
+
type: DataType.ARRAY,
|
|
160
|
+
itemType: DataType.OBJECT,
|
|
161
|
+
itemModel: v,
|
|
162
|
+
};
|
|
163
|
+
return () => S.validate('model', {foo});
|
|
164
|
+
};
|
|
165
|
+
const error = v =>
|
|
166
|
+
format(
|
|
167
|
+
'The provided option "itemModel" of the property "foo" ' +
|
|
168
|
+
'in the model "model" should be a String, but %s given.',
|
|
169
|
+
v,
|
|
170
|
+
);
|
|
171
|
+
expect(validate(10)).to.throw(error('10'));
|
|
172
|
+
expect(validate(true)).to.throw(error('true'));
|
|
173
|
+
expect(validate([])).to.throw(error('Array'));
|
|
174
|
+
expect(validate({})).to.throw(error('Object'));
|
|
175
|
+
validate('model')();
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('expects the provided option "model" to be a string', function () {
|
|
157
179
|
const validate = v => {
|
|
158
180
|
const foo = {
|
|
159
181
|
type: DataType.OBJECT,
|
|
@@ -174,7 +196,7 @@ describe('PropertiesDefinitionValidator', function () {
|
|
|
174
196
|
validate('model')();
|
|
175
197
|
});
|
|
176
198
|
|
|
177
|
-
it('expects provided
|
|
199
|
+
it('expects the provided option "primaryKey" to be a boolean', function () {
|
|
178
200
|
const validate = v => {
|
|
179
201
|
const foo = {
|
|
180
202
|
type: DataType.STRING,
|
|
@@ -195,7 +217,7 @@ describe('PropertiesDefinitionValidator', function () {
|
|
|
195
217
|
validate(false)();
|
|
196
218
|
});
|
|
197
219
|
|
|
198
|
-
it('expects provided
|
|
220
|
+
it('expects the provided option "columnName" to be a string', function () {
|
|
199
221
|
const validate = v => {
|
|
200
222
|
const foo = {
|
|
201
223
|
type: DataType.STRING,
|
|
@@ -216,7 +238,7 @@ describe('PropertiesDefinitionValidator', function () {
|
|
|
216
238
|
validate('columnName')();
|
|
217
239
|
});
|
|
218
240
|
|
|
219
|
-
it('expects provided
|
|
241
|
+
it('expects the provided option "columnType" to be a string', function () {
|
|
220
242
|
const validate = v => {
|
|
221
243
|
const foo = {
|
|
222
244
|
type: DataType.STRING,
|
|
@@ -237,7 +259,7 @@ describe('PropertiesDefinitionValidator', function () {
|
|
|
237
259
|
validate('columnType')();
|
|
238
260
|
});
|
|
239
261
|
|
|
240
|
-
it('expects provided
|
|
262
|
+
it('expects the provided option "required" to be a boolean', function () {
|
|
241
263
|
const validate = v => {
|
|
242
264
|
const foo = {
|
|
243
265
|
type: DataType.STRING,
|
|
@@ -332,7 +354,7 @@ describe('PropertiesDefinitionValidator', function () {
|
|
|
332
354
|
S.validate('model', {foo});
|
|
333
355
|
};
|
|
334
356
|
const error =
|
|
335
|
-
'The property "foo" of the model "model" has
|
|
357
|
+
'The property "foo" of the model "model" has a non-array type, ' +
|
|
336
358
|
'so it should not have the option "itemType" to be provided.';
|
|
337
359
|
expect(validate(DataType.ANY)).to.throw(error);
|
|
338
360
|
expect(validate(DataType.STRING)).to.throw(error);
|
|
@@ -364,27 +386,34 @@ describe('PropertiesDefinitionValidator', function () {
|
|
|
364
386
|
validate(DataType.OBJECT)();
|
|
365
387
|
});
|
|
366
388
|
|
|
367
|
-
it('the option "
|
|
389
|
+
it('the option "itemModel" requires the "object" item type', function () {
|
|
368
390
|
const validate = v => () => {
|
|
369
391
|
const foo = {
|
|
370
392
|
type: DataType.ARRAY,
|
|
371
393
|
itemType: v,
|
|
372
|
-
|
|
394
|
+
itemModel: 'model',
|
|
373
395
|
};
|
|
374
396
|
S.validate('model', {foo});
|
|
375
397
|
};
|
|
376
|
-
const
|
|
398
|
+
const errorForNonEmpty = v =>
|
|
377
399
|
format(
|
|
378
|
-
'The option "
|
|
379
|
-
'
|
|
380
|
-
'the
|
|
400
|
+
'The provided option "itemModel" requires the option "itemType" ' +
|
|
401
|
+
'to be explicitly set to Object, but the property "foo" of ' +
|
|
402
|
+
'the model "model" has specified item type as %s.',
|
|
381
403
|
v,
|
|
382
404
|
);
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
405
|
+
const errorForEmpty = format(
|
|
406
|
+
'The provided option "itemModel" requires the option "itemType" ' +
|
|
407
|
+
'to be explicitly set to Object, but the property "foo" of ' +
|
|
408
|
+
'the model "model" does not have specified item type.',
|
|
409
|
+
);
|
|
410
|
+
expect(validate(DataType.ANY)).to.throw(errorForNonEmpty('Any'));
|
|
411
|
+
expect(validate(DataType.STRING)).to.throw(errorForNonEmpty('String'));
|
|
412
|
+
expect(validate(DataType.NUMBER)).to.throw(errorForNonEmpty('Number'));
|
|
413
|
+
expect(validate(DataType.BOOLEAN)).to.throw(errorForNonEmpty('Boolean'));
|
|
414
|
+
expect(validate(DataType.ARRAY)).to.throw(errorForNonEmpty('Array'));
|
|
415
|
+
expect(validate(undefined)).to.throw(errorForEmpty);
|
|
416
|
+
expect(validate(null)).to.throw(errorForEmpty);
|
|
388
417
|
validate(DataType.OBJECT)();
|
|
389
418
|
});
|
|
390
419
|
|
|
@@ -491,7 +520,7 @@ describe('PropertiesDefinitionValidator', function () {
|
|
|
491
520
|
validate({myTransformer: true})();
|
|
492
521
|
});
|
|
493
522
|
|
|
494
|
-
it('expects provided
|
|
523
|
+
it('expects the provided option "unique" to be a Boolean or the PropertyUniqueness', function () {
|
|
495
524
|
const validate = v => {
|
|
496
525
|
const foo = {
|
|
497
526
|
type: DataType.STRING,
|