@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e22m4u/js-repository",
3
- "version": "0.1.25",
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.1.x"
43
+ "@e22m4u/js-service": "0.2.x"
44
44
  },
45
45
  "devDependencies": {
46
- "@commitlint/cli": "~19.5.0",
47
- "@commitlint/config-conventional": "~19.5.0",
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.9",
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.14.0",
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.4.3",
61
+ "eslint-plugin-jsdoc": "~50.5.0",
62
62
  "eslint-plugin-mocha": "~10.5.0",
63
- "husky": "~9.1.6",
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.13.0"
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
- console.log(ctor);
58
- if (typeof ctor === 'function' && ctor.kind === Adapter.name) {
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
  }
@@ -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 kind = 'Adapter';
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 "kind"', function () {
19
- expect(Adapter.kind).to.be.eq(Adapter.name);
20
- const MyAdapter1 = class extends Adapter {};
21
- expect(MyAdapter1.kind).to.be.eq(Adapter.name);
22
- class MyAdapter2 extends Adapter {}
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' && propDef.model)
163
- this.validate(propDef.model, propValue);
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 "model" option', function () {
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
- model: 'modelA',
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
- model: 'modelA',
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 the non-array type, ' +
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
- propDef.model &&
186
- propDef.type !== Type.OBJECT &&
187
- propDef.itemType !== Type.OBJECT
188
- ) {
189
- if (propDef.type !== Type.ARRAY) {
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 "model" is not supported for %s property type, ' +
192
- 'so the property %v of the model %v should not have ' +
193
- 'the option "model" to be provided.',
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 "model" is not supported for Array property type of %s, ' +
201
- 'so the property %v of the model %v should not have ' +
202
- 'the option "model" to be provided.',
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 the option "itemType" to be a DataType', function () {
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 the option "model" to be a string', function () {
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 the option "primaryKey" to be a boolean', function () {
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 the option "columnName" to be a string', function () {
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 the option "columnType" to be a string', function () {
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 the option "required" to be a boolean', function () {
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 the non-array type, ' +
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 "model" requires the "object" item type', function () {
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
- model: 'model',
394
+ itemModel: 'model',
373
395
  };
374
396
  S.validate('model', {foo});
375
397
  };
376
- const error = v =>
398
+ const errorForNonEmpty = v =>
377
399
  format(
378
- 'The option "model" is not supported for Array property type of %s, ' +
379
- 'so the property "foo" of the model "model" should not have ' +
380
- 'the option "model" to be provided.',
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
- expect(validate(DataType.ANY)).to.throw(error('Any'));
384
- expect(validate(DataType.STRING)).to.throw(error('String'));
385
- expect(validate(DataType.NUMBER)).to.throw(error('Number'));
386
- expect(validate(DataType.BOOLEAN)).to.throw(error('Boolean'));
387
- expect(validate(DataType.ARRAY)).to.throw(error('Array'));
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 the option "unique" to be a Boolean or the PropertyUniqueness', function () {
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,
@@ -9,6 +9,7 @@ import {PropertyTransformOptions} from './property-transformer/index.js';
9
9
  export declare type FullPropertyDefinition = {
10
10
  type: DataType;
11
11
  itemType?: DataType;
12
+ itemModel?: string;
12
13
  model?: string;
13
14
  primaryKey?: boolean;
14
15
  columnName?: string;