@e22m4u/js-repository 0.3.2 → 0.4.0

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.
@@ -396,6 +396,23 @@ var init_exclude_object_keys = __esm({
396
396
  }
397
397
  });
398
398
 
399
+ // src/utils/model-name-to-model-key.js
400
+ function modelNameToModelKey(modelName) {
401
+ if (!modelName || typeof modelName !== "string" || /\s/.test(modelName))
402
+ throw new InvalidArgumentError(
403
+ "The model name should be a non-empty String without spaces, but %v given.",
404
+ modelName
405
+ );
406
+ return modelName.toLowerCase().replace(/[-_]/g, "");
407
+ }
408
+ var init_model_name_to_model_key = __esm({
409
+ "src/utils/model-name-to-model-key.js"() {
410
+ "use strict";
411
+ init_errors();
412
+ __name(modelNameToModelKey, "modelNameToModelKey");
413
+ }
414
+ });
415
+
399
416
  // src/utils/get-decorator-target-type.js
400
417
  function getDecoratorTargetType(target, propertyKey, descriptorOrIndex) {
401
418
  const isCtor2 = typeof target === "function";
@@ -452,6 +469,7 @@ var init_utils = __esm({
452
469
  init_transform_promise();
453
470
  init_select_object_keys();
454
471
  init_exclude_object_keys();
472
+ init_model_name_to_model_key();
455
473
  init_get_decorator_target_type();
456
474
  }
457
475
  });
@@ -2040,6 +2058,7 @@ var init_definition_registry = __esm({
2040
2058
  "src/definition/definition-registry.js"() {
2041
2059
  "use strict";
2042
2060
  import_js_service8 = require("@e22m4u/js-service");
2061
+ init_utils();
2043
2062
  init_errors();
2044
2063
  init_model();
2045
2064
  init_definition();
@@ -2099,10 +2118,13 @@ var init_definition_registry = __esm({
2099
2118
  */
2100
2119
  addModel(modelDef) {
2101
2120
  this.getService(ModelDefinitionValidator).validate(modelDef);
2102
- const name = modelDef.name;
2103
- if (name in this._models)
2104
- throw new InvalidArgumentError("The model %v is already defined.", name);
2105
- this._models[name] = modelDef;
2121
+ const modelKey = modelNameToModelKey(modelDef.name);
2122
+ if (modelKey in this._models)
2123
+ throw new InvalidArgumentError(
2124
+ "The model %v is already defined.",
2125
+ modelDef.name
2126
+ );
2127
+ this._models[modelKey] = modelDef;
2106
2128
  }
2107
2129
  /**
2108
2130
  * Has model.
@@ -2111,7 +2133,8 @@ var init_definition_registry = __esm({
2111
2133
  * @returns {boolean}
2112
2134
  */
2113
2135
  hasModel(name) {
2114
- return Boolean(this._models[name]);
2136
+ const modelKey = modelNameToModelKey(name);
2137
+ return Boolean(this._models[modelKey]);
2115
2138
  }
2116
2139
  /**
2117
2140
  * Get model.
@@ -2120,7 +2143,8 @@ var init_definition_registry = __esm({
2120
2143
  * @returns {object}
2121
2144
  */
2122
2145
  getModel(name) {
2123
- const modelDef = this._models[name];
2146
+ const modelKey = modelNameToModelKey(name);
2147
+ const modelDef = this._models[modelKey];
2124
2148
  if (!modelDef)
2125
2149
  throw new InvalidArgumentError("The model %v is not defined.", name);
2126
2150
  return modelDef;
@@ -5060,6 +5084,7 @@ var init_repository_registry = __esm({
5060
5084
  "use strict";
5061
5085
  import_js_service30 = require("@e22m4u/js-service");
5062
5086
  init_repository();
5087
+ init_utils();
5063
5088
  init_errors();
5064
5089
  _RepositoryRegistry = class _RepositoryRegistry extends import_js_service30.Service {
5065
5090
  /**
@@ -5096,10 +5121,11 @@ var init_repository_registry = __esm({
5096
5121
  * @returns {Repository}
5097
5122
  */
5098
5123
  getRepository(modelName) {
5099
- let repository = this._repositories[modelName];
5124
+ const modelKey = modelNameToModelKey(modelName);
5125
+ let repository = this._repositories[modelKey];
5100
5126
  if (repository) return repository;
5101
5127
  repository = new this._repositoryCtor(this.container, modelName);
5102
- this._repositories[modelName] = repository;
5128
+ this._repositories[modelKey] = repository;
5103
5129
  return repository;
5104
5130
  }
5105
5131
  };
@@ -6361,6 +6387,7 @@ __export(index_exports, {
6361
6387
  isDeepEqual: () => isDeepEqual,
6362
6388
  isPromise: () => isPromise,
6363
6389
  isPureObject: () => isPureObject,
6390
+ modelNameToModelKey: () => modelNameToModelKey,
6364
6391
  selectObjectKeys: () => selectObjectKeys,
6365
6392
  singularize: () => singularize,
6366
6393
  stringToRegexp: () => stringToRegexp,
@@ -6465,6 +6492,7 @@ init_repository2();
6465
6492
  isDeepEqual,
6466
6493
  isPromise,
6467
6494
  isPureObject,
6495
+ modelNameToModelKey,
6468
6496
  selectObjectKeys,
6469
6497
  singularize,
6470
6498
  stringToRegexp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e22m4u/js-repository",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "Реализация репозитория для работы с базами данных в Node.js",
5
5
  "author": "Mikhail Evstropov <e22m4u@yandex.ru>",
6
6
  "license": "MIT",
@@ -41,7 +41,7 @@
41
41
  "dependencies": {
42
42
  "@e22m4u/js-empty-values": "~0.0.2",
43
43
  "@e22m4u/js-format": "~0.1.8",
44
- "@e22m4u/js-service": "~0.3.3"
44
+ "@e22m4u/js-service": "~0.3.6"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@commitlint/cli": "~19.8.1",
@@ -51,21 +51,21 @@
51
51
  "@types/chai-spies": "~1.0.6",
52
52
  "@types/mocha": "~10.0.10",
53
53
  "c8": "~10.1.3",
54
- "chai": "~5.2.1",
55
- "chai-as-promised": "~8.0.1",
54
+ "chai": "~6.0.1",
55
+ "chai-as-promised": "~8.0.2",
56
56
  "chai-spies": "~1.1.0",
57
- "esbuild": "~0.25.8",
58
- "eslint": "~9.32.0",
57
+ "esbuild": "~0.25.9",
58
+ "eslint": "~9.34.0",
59
59
  "eslint-config-prettier": "~10.1.8",
60
60
  "eslint-plugin-chai-expect": "~3.1.0",
61
- "eslint-plugin-jsdoc": "~52.0.2",
61
+ "eslint-plugin-jsdoc": "~54.1.1",
62
62
  "eslint-plugin-mocha": "~11.1.0",
63
63
  "husky": "~9.1.7",
64
64
  "mocha": "~11.7.1",
65
65
  "prettier": "~3.6.2",
66
66
  "rimraf": "~6.0.1",
67
67
  "ts-node": "~10.9.2",
68
- "typescript": "~5.8.3",
69
- "typescript-eslint": "~8.39.0"
68
+ "typescript": "~5.9.2",
69
+ "typescript-eslint": "~8.41.0"
70
70
  }
71
71
  }
@@ -32,6 +32,6 @@ export declare class DatabaseSchema extends Service {
32
32
  getRepository<
33
33
  Data extends object = ModelData,
34
34
  IdType extends ModelId = ModelId,
35
- IdName extends string = DEFAULT_PRIMARY_KEY_PROPERTY_NAME,
35
+ IdName extends string = typeof DEFAULT_PRIMARY_KEY_PROPERTY_NAME,
36
36
  >(modelName: string): Repository<Data, IdType, IdName>;
37
37
  }
@@ -1,4 +1,5 @@
1
1
  import {Service} from '@e22m4u/js-service';
2
+ import {modelNameToModelKey} from '../utils/index.js';
2
3
  import {InvalidArgumentError} from '../errors/index.js';
3
4
  import {ModelDefinitionValidator} from './model/index.js';
4
5
  import {DatasourceDefinitionValidator} from '../definition/index.js';
@@ -67,10 +68,13 @@ export class DefinitionRegistry extends Service {
67
68
  */
68
69
  addModel(modelDef) {
69
70
  this.getService(ModelDefinitionValidator).validate(modelDef);
70
- const name = modelDef.name;
71
- if (name in this._models)
72
- throw new InvalidArgumentError('The model %v is already defined.', name);
73
- this._models[name] = modelDef;
71
+ const modelKey = modelNameToModelKey(modelDef.name);
72
+ if (modelKey in this._models)
73
+ throw new InvalidArgumentError(
74
+ 'The model %v is already defined.',
75
+ modelDef.name,
76
+ );
77
+ this._models[modelKey] = modelDef;
74
78
  }
75
79
 
76
80
  /**
@@ -80,7 +84,8 @@ export class DefinitionRegistry extends Service {
80
84
  * @returns {boolean}
81
85
  */
82
86
  hasModel(name) {
83
- return Boolean(this._models[name]);
87
+ const modelKey = modelNameToModelKey(name);
88
+ return Boolean(this._models[modelKey]);
84
89
  }
85
90
 
86
91
  /**
@@ -90,7 +95,8 @@ export class DefinitionRegistry extends Service {
90
95
  * @returns {object}
91
96
  */
92
97
  getModel(name) {
93
- const modelDef = this._models[name];
98
+ const modelKey = modelNameToModelKey(name);
99
+ const modelDef = this._models[modelKey];
94
100
  if (!modelDef)
95
101
  throw new InvalidArgumentError('The model %v is not defined.', name);
96
102
  return modelDef;
@@ -17,63 +17,190 @@ describe('DefinitionRegistry', function () {
17
17
  sandbox.restore();
18
18
  });
19
19
 
20
- it('sets a given datasource to the state', function () {
21
- const datasource = {name: 'datasource', adapter: 'adapter'};
22
- S.addDatasource(datasource);
23
- const result = S.getDatasource('datasource');
24
- expect(result).to.be.eql(datasource);
25
- });
20
+ describe('addDatasource', function () {
21
+ it('adds the given datasource to the registry', function () {
22
+ const datasource = {name: 'datasource', adapter: 'adapter'};
23
+ S.addDatasource(datasource);
24
+ const result = S.getDatasource('datasource');
25
+ expect(result).to.be.eql(datasource);
26
+ });
26
27
 
27
- it('throws an error if a given datasource is already defined', function () {
28
- const datasource1 = {name: 'datasource', adapter: 'adapter'};
29
- const datasource2 = {name: 'datasource', adapter: 'adapter'};
30
- S.addDatasource(datasource1);
31
- const throwable = () => S.addDatasource(datasource2);
32
- expect(throwable).to.throw(
33
- 'The datasource "datasource" is already defined.',
34
- );
35
- });
28
+ it('uses DatasourceDefinitionValidator to validate a given datasource', function () {
29
+ const V = S.getService(DatasourceDefinitionValidator);
30
+ sandbox.on(V, 'validate');
31
+ const datasource = {name: 'datasource', adapter: 'adapter'};
32
+ S.addDatasource(datasource);
33
+ expect(V.validate).to.have.been.called.once;
34
+ expect(V.validate).to.have.been.called.with.exactly(datasource);
35
+ });
36
36
 
37
- it('throws an error when getting a not defined datasource', function () {
38
- const throwable = () => S.getDatasource('undefined');
39
- expect(throwable).to.throw('The datasource "undefined" is not defined.');
37
+ it('throws an error if a given datasource is already defined', function () {
38
+ const datasource1 = {name: 'datasource', adapter: 'adapter'};
39
+ const datasource2 = {name: 'datasource', adapter: 'adapter'};
40
+ S.addDatasource(datasource1);
41
+ const throwable = () => S.addDatasource(datasource2);
42
+ expect(throwable).to.throw(
43
+ 'The datasource "datasource" is already defined.',
44
+ );
45
+ });
40
46
  });
41
47
 
42
- it('uses DatasourceDefinitionValidator to validate a given datasource', function () {
43
- const V = S.getService(DatasourceDefinitionValidator);
44
- sandbox.on(V, 'validate');
45
- const datasource = {name: 'datasource', adapter: 'adapter'};
46
- S.addDatasource(datasource);
47
- expect(V.validate).to.have.been.called.once;
48
- expect(V.validate).to.have.been.called.with.exactly(datasource);
48
+ describe('hasDatasource', function () {
49
+ it('should check the datasource registration by its name', function () {
50
+ const datasource = {name: 'datasource', adapter: 'adapter'};
51
+ expect(S.hasDatasource(datasource.name)).to.be.false;
52
+ S.addDatasource(datasource);
53
+ expect(S.hasDatasource(datasource.name)).to.be.true;
54
+ });
49
55
  });
50
56
 
51
- it('sets a given model to the state', function () {
52
- const model = {name: 'model'};
53
- S.addModel(model);
54
- const result = S.getModel('model');
55
- expect(result).to.be.eql(model);
57
+ describe('getDatasource', function () {
58
+ it('returns the datasource by its name', function () {
59
+ const datasource = {name: 'datasource', adapter: 'adapter'};
60
+ S.addDatasource(datasource);
61
+ const result = S.getDatasource('datasource');
62
+ expect(result).to.be.eql(datasource);
63
+ });
64
+
65
+ it('throws an error if ths datasource is not defined', function () {
66
+ const throwable = () => S.getDatasource('undefined');
67
+ expect(throwable).to.throw('The datasource "undefined" is not defined.');
68
+ });
56
69
  });
57
70
 
58
- it('throws an error if a given model is already defined', function () {
59
- const model1 = {name: 'model'};
60
- const model2 = {name: 'model'};
61
- S.addModel(model1);
62
- const throwable = () => S.addModel(model2);
63
- expect(throwable).to.throw('The model "model" is already defined.');
71
+ describe('addModel', function () {
72
+ it('adds the given model to the registry', function () {
73
+ const model = {name: 'model'};
74
+ S.addModel(model);
75
+ const result = S.getModel('model');
76
+ expect(result).to.be.eql(model);
77
+ });
78
+
79
+ it('uses ModelDefinitionValidator to validate a given model', function () {
80
+ const V = S.getService(ModelDefinitionValidator);
81
+ sandbox.on(V, 'validate');
82
+ const model = {name: 'model'};
83
+ S.addModel(model);
84
+ expect(V.validate).to.have.been.called.once;
85
+ expect(V.validate).to.have.been.called.with.exactly(model);
86
+ });
87
+
88
+ it('throws an error if a given model is already defined', function () {
89
+ const model1 = {name: 'TestModel'};
90
+ const model2 = {name: 'TestModel'};
91
+ S.addModel(model1);
92
+ const throwable = () => S.addModel(model2);
93
+ expect(throwable).to.throw('The model "TestModel" is already defined.');
94
+ });
64
95
  });
65
96
 
66
- it('throws an error when getting a not defined model', function () {
67
- const throwable = () => S.getModel('undefined');
68
- expect(throwable).to.throw('The model "undefined" is not defined.');
97
+ describe('hasModel', function () {
98
+ it('should check the model registration by its name', function () {
99
+ const model = {name: 'model'};
100
+ expect(S.hasModel(model.name)).to.be.false;
101
+ S.addModel(model);
102
+ expect(S.hasModel(model.name)).to.be.true;
103
+ });
104
+
105
+ it('should ignore naming convention of the model name', function () {
106
+ const model = {name: 'UserProfileDetails'};
107
+ const modelNames = [
108
+ 'userProfileDetails',
109
+ 'UserProfileDetails',
110
+ 'user-profile-details',
111
+ 'user_profile_details',
112
+ 'USER-PROFILE-DETAILS',
113
+ 'USER_PROFILE_DETAILS',
114
+ 'USERPROFILEDETAILS',
115
+ 'userprofiledetails',
116
+ ];
117
+ modelNames.forEach(v => expect(S.hasModel(v)).to.be.false);
118
+ S.addModel(model);
119
+ modelNames.forEach(v => expect(S.hasModel(v)).to.be.true);
120
+ });
121
+
122
+ it('should respect numbers in the model name', function () {
123
+ const model1 = {name: 'UserProfileDetails1'};
124
+ const modelNames1 = [
125
+ 'userProfileDetails1',
126
+ 'UserProfileDetails1',
127
+ 'user-profile-details-1',
128
+ 'user_profile_details_1',
129
+ 'USER-PROFILE-DETAILS-1',
130
+ 'USER_PROFILE_DETAILS_1',
131
+ 'USERPROFILEDETAILS1',
132
+ 'userprofiledetails1',
133
+ ];
134
+ const modelNames2 = [
135
+ 'userProfileDetails2',
136
+ 'UserProfileDetails2',
137
+ 'user-profile-details-2',
138
+ 'user_profile_details_2',
139
+ 'USER-PROFILE-DETAILS-2',
140
+ 'USER_PROFILE_DETAILS_2',
141
+ 'USERPROFILEDETAILS2',
142
+ 'userprofiledetails2',
143
+ ];
144
+ S.addModel(model1);
145
+ modelNames1.forEach(v => expect(S.hasModel(v)).to.be.true);
146
+ modelNames2.forEach(v => expect(S.hasModel(v)).to.be.false);
147
+ });
69
148
  });
70
149
 
71
- it('uses ModelDefinitionValidator to validate a given model', function () {
72
- const V = S.getService(ModelDefinitionValidator);
73
- sandbox.on(V, 'validate');
74
- const model = {name: 'model'};
75
- S.addModel(model);
76
- expect(V.validate).to.have.been.called.once;
77
- expect(V.validate).to.have.been.called.with.exactly(model);
150
+ describe('getModel', function () {
151
+ it('returns the model by its name', function () {
152
+ const model = {name: 'model'};
153
+ S.addModel(model);
154
+ const result = S.getModel('model');
155
+ expect(result).to.be.eql(model);
156
+ });
157
+
158
+ it('throws an error if the model is not defined', function () {
159
+ const throwable = () => S.getModel('undefined');
160
+ expect(throwable).to.throw('The model "undefined" is not defined.');
161
+ });
162
+
163
+ it('should ignore naming convention of the model name', function () {
164
+ const model = {name: 'userProfileDetails'};
165
+ const modelNames = [
166
+ 'userProfileDetails',
167
+ 'UserProfileDetails',
168
+ 'user-profile-details',
169
+ 'user_profile_details',
170
+ 'USER-PROFILE-DETAILS',
171
+ 'USER_PROFILE_DETAILS',
172
+ 'USERPROFILEDETAILS',
173
+ 'userprofiledetails',
174
+ ];
175
+ S.addModel(model);
176
+ modelNames.forEach(v => expect(S.getModel(v)).to.be.eq(model));
177
+ });
178
+
179
+ it('should respect numbers in the model name', function () {
180
+ const model1 = {name: 'userProfileDetails1'};
181
+ const modelNames1 = [
182
+ 'userProfileDetails1',
183
+ 'UserProfileDetails1',
184
+ 'user-profile-details-1',
185
+ 'user_profile_details_1',
186
+ 'USER-PROFILE-DETAILS-1',
187
+ 'USER_PROFILE_DETAILS_1',
188
+ 'USERPROFILEDETAILS1',
189
+ 'userprofiledetails1',
190
+ ];
191
+ const modelNames2 = [
192
+ 'userProfileDetails2',
193
+ 'UserProfileDetails2',
194
+ 'user-profile-details-2',
195
+ 'user_profile_details_2',
196
+ 'USER-PROFILE-DETAILS-2',
197
+ 'USER_PROFILE_DETAILS_2',
198
+ 'USERPROFILEDETAILS2',
199
+ 'userprofiledetails2',
200
+ ];
201
+ S.addModel(model1);
202
+ modelNames1.forEach(v => expect(S.getModel(v)).to.be.eq(model1));
203
+ modelNames2.forEach(v => expect(() => S.getModel(v)).to.throw(Error));
204
+ });
78
205
  });
79
206
  });
@@ -9,7 +9,7 @@ import {RelationDefinitionMap} from './model-definition.js';
9
9
  /**
10
10
  * Default primary key property name.
11
11
  */
12
- export type DEFAULT_PRIMARY_KEY_PROPERTY_NAME = 'id';
12
+ export const DEFAULT_PRIMARY_KEY_PROPERTY_NAME: 'id';
13
13
 
14
14
  /**
15
15
  * Model definition utils.
@@ -24,6 +24,6 @@ export declare class RepositoryRegistry extends Service {
24
24
  getRepository<
25
25
  Data extends ModelData = ModelData,
26
26
  IdType extends ModelId = ModelId,
27
- IdName extends string = DEFAULT_PRIMARY_KEY_PROPERTY_NAME,
27
+ IdName extends string = typeof DEFAULT_PRIMARY_KEY_PROPERTY_NAME,
28
28
  >(modelName: string): Repository<Data, IdType, IdName>;
29
29
  }
@@ -1,5 +1,6 @@
1
1
  import {Service} from '@e22m4u/js-service';
2
2
  import {Repository} from './repository.js';
3
+ import {modelNameToModelKey} from '../utils/index.js';
3
4
  import {InvalidArgumentError} from '../errors/index.js';
4
5
 
5
6
  /**
@@ -48,10 +49,11 @@ export class RepositoryRegistry extends Service {
48
49
  * @returns {Repository}
49
50
  */
50
51
  getRepository(modelName) {
51
- let repository = this._repositories[modelName];
52
+ const modelKey = modelNameToModelKey(modelName);
53
+ let repository = this._repositories[modelKey];
52
54
  if (repository) return repository;
53
55
  repository = new this._repositoryCtor(this.container, modelName);
54
- this._repositories[modelName] = repository;
56
+ this._repositories[modelKey] = repository;
55
57
  return repository;
56
58
  }
57
59
  }
@@ -10,29 +10,59 @@ describe('RepositoryRegistry', function () {
10
10
  const dbs = new DatabaseSchema();
11
11
  dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
12
12
  dbs.defineModel({name: 'model', datasource: 'datasource'});
13
- const registry = dbs.getService(RepositoryRegistry);
14
- registry.setRepositoryCtor(MyRepository);
15
- const rep = registry.getRepository('model');
13
+ const reg = dbs.getService(RepositoryRegistry);
14
+ reg.setRepositoryCtor(MyRepository);
15
+ const rep = reg.getRepository('model');
16
16
  expect(rep).to.be.instanceof(Repository);
17
17
  expect(rep).to.be.instanceof(MyRepository);
18
18
  });
19
19
  });
20
20
 
21
21
  describe('getRepository', function () {
22
- it('uses a given model name to return an existing repository or create the new', function () {
22
+ it('returns an existing repository by the given name or create new one', function () {
23
23
  const dbs = new DatabaseSchema();
24
24
  dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
25
25
  dbs.defineModel({name: 'modelA', datasource: 'datasource'});
26
26
  dbs.defineModel({name: 'modelB', datasource: 'datasource'});
27
- const registry = dbs.getService(RepositoryRegistry);
28
- const repA1 = registry.getRepository('modelA');
29
- const repA2 = registry.getRepository('modelA');
30
- const repB1 = registry.getRepository('modelB');
31
- const repB2 = registry.getRepository('modelB');
27
+ const reg = dbs.getService(RepositoryRegistry);
28
+ const repA1 = reg.getRepository('modelA');
29
+ const repA2 = reg.getRepository('modelA');
30
+ const repB1 = reg.getRepository('modelB');
31
+ const repB2 = reg.getRepository('modelB');
32
32
  expect(repA1).to.be.eq(repA2);
33
33
  expect(repB1).to.be.eq(repB2);
34
34
  expect(repA1).to.be.not.eq(repB1);
35
35
  expect(repA2).to.be.not.eq(repB2);
36
36
  });
37
+
38
+ it('should ignore naming convention of the model name', function () {
39
+ const dbs = new DatabaseSchema();
40
+ const modelName = 'userProfileDetails';
41
+ dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
42
+ dbs.defineModel({name: modelName, datasource: 'datasource'});
43
+ const reg = dbs.getService(RepositoryRegistry);
44
+ const rep = reg.getRepository(modelName);
45
+ const modelNames = [
46
+ 'UserProfileDetails',
47
+ 'user-profile-details',
48
+ 'user_profile_details',
49
+ 'USER-PROFILE-DETAILS',
50
+ 'USER_PROFILE_DETAILS',
51
+ 'USERPROFILEDETAILS',
52
+ 'userprofiledetails',
53
+ ];
54
+ modelNames.forEach(v => expect(reg.getRepository(v)).to.be.eq(rep));
55
+ });
56
+
57
+ it('should respect numbers in the model name', function () {
58
+ const dbs = new DatabaseSchema();
59
+ dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
60
+ dbs.defineModel({name: 'model1', datasource: 'datasource'});
61
+ dbs.defineModel({name: 'model2', datasource: 'datasource'});
62
+ const reg = dbs.getService(RepositoryRegistry);
63
+ const rep1 = reg.getRepository('model1');
64
+ const rep2 = reg.getRepository('model2');
65
+ expect(rep1).to.be.not.eq(rep2);
66
+ });
37
67
  });
38
68
  });
@@ -16,7 +16,7 @@ import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME} from '../definition/index.js';
16
16
  export declare class Repository<
17
17
  Data extends object = ModelData,
18
18
  IdType extends ModelId = ModelId,
19
- IdName extends string = DEFAULT_PRIMARY_KEY_PROPERTY_NAME,
19
+ IdName extends string = typeof DEFAULT_PRIMARY_KEY_PROPERTY_NAME,
20
20
  FlatData extends ModelData = Flatten<Data>,
21
21
  > extends Service {
22
22
  // it fixes unused generic bug
@@ -11,4 +11,5 @@ export * from './get-value-by-path.js';
11
11
  export * from './transform-promise.js';
12
12
  export * from './select-object-keys.js';
13
13
  export * from './exclude-object-keys.js';
14
+ export * from './model-name-to-model-key.js';
14
15
  export * from './get-decorator-target-type.js';
@@ -11,4 +11,5 @@ export * from './get-value-by-path.js';
11
11
  export * from './transform-promise.js';
12
12
  export * from './select-object-keys.js';
13
13
  export * from './exclude-object-keys.js';
14
+ export * from './model-name-to-model-key.js';
14
15
  export * from './get-decorator-target-type.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Model name to model key.
3
+ *
4
+ * @param modelName
5
+ */
6
+ export function modelNameToModelKey(modelName: string): string;
@@ -0,0 +1,17 @@
1
+ import {InvalidArgumentError} from '../errors/index.js';
2
+
3
+ /**
4
+ * Model name to model key.
5
+ *
6
+ * @param {string} modelName
7
+ * @returns {string}
8
+ */
9
+ export function modelNameToModelKey(modelName) {
10
+ if (!modelName || typeof modelName !== 'string' || /\s/.test(modelName))
11
+ throw new InvalidArgumentError(
12
+ 'The model name should be a non-empty String ' +
13
+ 'without spaces, but %v given.',
14
+ modelName,
15
+ );
16
+ return modelName.toLowerCase().replace(/[-_]/g, '');
17
+ }
@@ -0,0 +1,92 @@
1
+ import {expect} from 'chai';
2
+ import {modelNameToModelKey} from './model-name-to-model-key.js';
3
+
4
+ describe('modelNameToModelKey', function () {
5
+ it('should return a simple lowercase string as is', function () {
6
+ expect(modelNameToModelKey('user')).to.be.eq('user');
7
+ });
8
+
9
+ it('should convert to lowercase and remove hyphens and underscores', function () {
10
+ const modelNames = [
11
+ 'userProfileDetails',
12
+ 'UserProfileDetails',
13
+ 'user-profile-details',
14
+ 'user_profile_details',
15
+ 'USER-PROFILE-DETAILS',
16
+ 'USER_PROFILE_DETAILS',
17
+ 'USERPROFILEDETAILS',
18
+ 'userprofiledetails',
19
+ ];
20
+ modelNames.forEach(v =>
21
+ expect(modelNameToModelKey(v)).to.be.eq('userprofiledetails'),
22
+ );
23
+ });
24
+
25
+ it('should handle a mixed string with uppercase, hyphens and underscores', function () {
26
+ const modelName = 'User_Profile-Details';
27
+ const expected = 'userprofiledetails';
28
+ expect(modelNameToModelKey(modelName)).to.be.eq(expected);
29
+ });
30
+
31
+ it('should not remove numbers from the string', function () {
32
+ const modelName = 'Type1-Model_2';
33
+ const expected = 'type1model2';
34
+ expect(modelNameToModelKey(modelName)).to.be.eq(expected);
35
+ });
36
+
37
+ it('should throw an error for an empty string', function () {
38
+ const throwable = () => modelNameToModelKey('');
39
+ expect(throwable).to.throw(
40
+ 'The model name should be a non-empty String ' +
41
+ 'without spaces, but "" given.',
42
+ );
43
+ });
44
+
45
+ it('should throw an error for a string with spaces', function () {
46
+ const throwable = () => modelNameToModelKey('user profile');
47
+ expect(throwable).to.throw(
48
+ 'The model name should be a non-empty String ' +
49
+ 'without spaces, but "user profile" given.',
50
+ );
51
+ });
52
+
53
+ it('should throw an error for null', function () {
54
+ const throwable = () => modelNameToModelKey(null);
55
+ expect(throwable).to.throw(
56
+ 'The model name should be a non-empty String ' +
57
+ 'without spaces, but null given.',
58
+ );
59
+ });
60
+
61
+ it('should throw an error for undefined', function () {
62
+ const throwable = () => modelNameToModelKey(undefined);
63
+ expect(throwable).to.throw(
64
+ 'The model name should be a non-empty String ' +
65
+ 'without spaces, but undefined given.',
66
+ );
67
+ });
68
+
69
+ it('should throw an error for a number', function () {
70
+ const throwable = () => modelNameToModelKey(123);
71
+ expect(throwable).to.throw(
72
+ 'The model name should be a non-empty String ' +
73
+ 'without spaces, but 123 given.',
74
+ );
75
+ });
76
+
77
+ it('should throw an error for an object', function () {
78
+ const throwable = () => modelNameToModelKey({name: 'test'});
79
+ expect(throwable).to.throw(
80
+ 'The model name should be a non-empty String ' +
81
+ 'without spaces, but Object given.',
82
+ );
83
+ });
84
+
85
+ it('should throw an error for an array', function () {
86
+ const throwable = () => modelNameToModelKey(['test']);
87
+ expect(throwable).to.throw(
88
+ 'The model name should be a non-empty String ' +
89
+ 'without spaces, but Array given.',
90
+ );
91
+ });
92
+ });