@e22m4u/js-repository 0.8.8 → 0.8.10
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 +86 -16
- package/dist/cjs/index.cjs +105 -113
- package/eslint.config.js +0 -4
- package/package.json +23 -23
- package/src/definition/definition-registry.d.ts +10 -0
- package/src/definition/definition-registry.js +25 -13
- package/src/definition/definition-registry.spec.js +60 -111
- package/src/repository/repository-registry.js +2 -4
- package/src/repository/repository-registry.spec.js +0 -19
- package/src/utils/index.d.ts +0 -1
- package/src/utils/index.js +0 -1
- package/src/utils/model-name-to-model-key.d.ts +0 -6
- package/src/utils/model-name-to-model-key.js +0 -18
- package/src/utils/model-name-to-model-key.spec.js +0 -94
package/README.md
CHANGED
|
@@ -3,18 +3,21 @@
|
|
|
3
3
|

|
|
4
4
|

|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
ORM/ODM библиотека для Node.js, реализующая слой управления данными на основе
|
|
7
|
+
паттерна «Репозиторий». Унифицирует интерфейс различных баз данных, фильтрацию
|
|
8
|
+
и работу со связанными документами независимо от источника.
|
|
7
9
|
|
|
8
10
|
## Содержание
|
|
9
11
|
|
|
10
12
|
- [Установка](#установка)
|
|
11
13
|
- [Импорт](#импорт)
|
|
12
14
|
- [Описание](#описание)
|
|
13
|
-
- [
|
|
15
|
+
- [Терминология](#терминология)
|
|
16
|
+
- [Базовый пример](#пример)
|
|
14
17
|
- [Схема баз данных](#схема-баз-данных)
|
|
15
18
|
- [Источник данных](#источник-данных)
|
|
16
19
|
- [Модель](#модель)
|
|
17
|
-
- [Свойства](#свойства)
|
|
20
|
+
- [Свойства](#свойства)
|
|
18
21
|
- [Репозиторий](#репозиторий)
|
|
19
22
|
- [create](#repositorycreate)
|
|
20
23
|
- [replaceById](#repositoryreplacebyid)
|
|
@@ -50,10 +53,15 @@ npm install @e22m4u/js-repository
|
|
|
50
53
|
|
|
51
54
|
Опционально устанавливается нужный адаптер.
|
|
52
55
|
|
|
53
|
-
| адаптер | описание
|
|
54
|
-
|
|
55
|
-
| `memory` | Виртуальная база в памяти процесса
|
|
56
|
-
| `mongodb` | MongoDB - документо-ориентированная база данных
|
|
56
|
+
| адаптер | описание | |
|
|
57
|
+
|-----------|---------------------------------------------------|------------------------------------------------------------------------------------|
|
|
58
|
+
| `memory` | Виртуальная база данных в памяти процесса Node.js | *встроенный* |
|
|
59
|
+
| `mongodb` | MongoDB - документо-ориентированная база данных | [*установка*](https://www.npmjs.com/package/@e22m4u/js-repository-mongodb-adapter) |
|
|
60
|
+
|
|
61
|
+
**Утилиты**
|
|
62
|
+
|
|
63
|
+
- [@e22m4u/js-repository-json-schema](https://www.npmjs.com/package/@e22m4u/js-repository-json-schema)
|
|
64
|
+
*Генератор JSON Schema для моделей репозитория*
|
|
57
65
|
|
|
58
66
|
## Импорт
|
|
59
67
|
|
|
@@ -122,11 +130,49 @@ flowchart TD
|
|
|
122
130
|
G-->K
|
|
123
131
|
```
|
|
124
132
|
|
|
133
|
+
### Терминология
|
|
134
|
+
|
|
135
|
+
Описание ключевых понятий.
|
|
136
|
+
|
|
137
|
+
- **Схема баз данных** (*DatabaseSchema*) - хранит определения источников
|
|
138
|
+
данных и моделей. Связывает модели с источниками данных и предоставляет
|
|
139
|
+
доступ к экземплярам репозитория.
|
|
140
|
+
|
|
141
|
+
- **Источник данных** (*Datasource*) - именованная конфигурация подключения
|
|
142
|
+
к базе данных. Содержит название используемого адаптера и параметры соединения.
|
|
143
|
+
|
|
144
|
+
- **Адаптер** (*Adapter*) - низкоуровневая реализация для взаимодействия с
|
|
145
|
+
конкретной СУБД. Обеспечивает совместимость хранилища с унифицированным
|
|
146
|
+
интерфейсом репозитория.
|
|
147
|
+
|
|
148
|
+
- **Коллекция** (*Collection*) - физическая область хранения записей или
|
|
149
|
+
документов в базе данных, ассоциированная с конкретной моделью. В контексте
|
|
150
|
+
реляционных баз данных является эквивалентом таблицы.
|
|
151
|
+
|
|
152
|
+
- **Модель** (*Model*) - структурное описание коллекции базы данных. Содержит
|
|
153
|
+
определения свойств документа и отношений с другими моделями.
|
|
154
|
+
|
|
155
|
+
- **Свойство** (*Property*) - описание отдельного поля модели. Определяет тип
|
|
156
|
+
данных, значение по умолчанию, обязательность наличия и правила проверки
|
|
157
|
+
на уникальность.
|
|
158
|
+
|
|
159
|
+
- **Связь** (*Relation*) - абстракция отношений между моделями. Поддерживает
|
|
160
|
+
классические отношения и полиморфный режим динамического определения
|
|
161
|
+
целевой модели через поле дискриминатора.
|
|
162
|
+
|
|
163
|
+
- **Дискриминатор** (*Discriminator*) - свойство документа в рамках полиморфной
|
|
164
|
+
связи. Хранит строковое название целевой модели, что позволяет динамически
|
|
165
|
+
определять связанную коллекцию при выполнении запросов.
|
|
166
|
+
|
|
167
|
+
- **Репозиторий** (*Repository*) - абстрактный фасад для работы с данными
|
|
168
|
+
конкретной модели. Изолирует логику приложения от деталей реализации
|
|
169
|
+
базы данных. Выполняет операции записи, поиска, обновления и удаления.
|
|
170
|
+
|
|
125
171
|
## Пример
|
|
126
172
|
|
|
127
|
-
Пример демонстрирует создание экземпляра
|
|
128
|
-
и модели `country`.
|
|
129
|
-
|
|
173
|
+
Пример демонстрирует создание экземпляра `DatabaseSchema`, объявление источника
|
|
174
|
+
данных `myDb` и модели `country`. Далее в коллекцию добавляется новый документ,
|
|
175
|
+
содержимого которого выводится в консоль.
|
|
130
176
|
|
|
131
177
|
```
|
|
132
178
|
Страна (country)
|
|
@@ -351,8 +397,8 @@ dbs.defineDatasource({
|
|
|
351
397
|
- `base: string` название наследуемой модели;
|
|
352
398
|
- `tableName: string` название коллекции в базе;
|
|
353
399
|
- `datasource: string` выбранный источник данных;
|
|
354
|
-
- `properties: object` определения свойств (см. [Свойства](
|
|
355
|
-
- `relations: object` определения связей (см. [Связи](
|
|
400
|
+
- `properties: object` определения свойств (см. [Свойства](#свойства));
|
|
401
|
+
- `relations: object` определения связей (см. [Связи](#связи));
|
|
356
402
|
|
|
357
403
|
**Примеры**
|
|
358
404
|
|
|
@@ -368,13 +414,32 @@ dbs.defineModel({
|
|
|
368
414
|
});
|
|
369
415
|
```
|
|
370
416
|
|
|
371
|
-
|
|
417
|
+
### Свойства
|
|
372
418
|
|
|
373
419
|
Параметр `properties` находится в определении модели и принимает объект, ключи
|
|
374
420
|
которого являются свойствами этой модели, а значением тип свойства или объект
|
|
375
|
-
с дополнительными параметрами.
|
|
421
|
+
с дополнительными параметрами. Параметры свойства используется репозиторием
|
|
422
|
+
для проверки документов перед сохранением.
|
|
376
423
|
|
|
377
|
-
|
|
424
|
+
```js
|
|
425
|
+
dbs.defineModel({
|
|
426
|
+
name: 'user',
|
|
427
|
+
properties: {
|
|
428
|
+
// краткая форма (только тип)
|
|
429
|
+
name: DataType.STRING,
|
|
430
|
+
// расширенное определение (см. далее)
|
|
431
|
+
email: {
|
|
432
|
+
type: DataType.STRING,
|
|
433
|
+
unique: PropertyUniqueness.SPARSE,
|
|
434
|
+
default: '',
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
*i. В контексте реляционных баз данных свойства отражают колонки таблицы.*
|
|
441
|
+
|
|
442
|
+
**Типы данных**
|
|
378
443
|
|
|
379
444
|
- `DataType.ANY` разрешено любое значение;
|
|
380
445
|
- `DataType.STRING` только значение типа `string`;
|
|
@@ -383,7 +448,12 @@ dbs.defineModel({
|
|
|
383
448
|
- `DataType.ARRAY` только значение типа `array`;
|
|
384
449
|
- `DataType.OBJECT` только значение типа `object`;
|
|
385
450
|
|
|
386
|
-
|
|
451
|
+
**Параметры свойства**
|
|
452
|
+
|
|
453
|
+
Объект с параметрами (расширенное определение) позволяет задавать значения
|
|
454
|
+
по умолчанию, правила проверки на уникальность и обязательность наличия данных.
|
|
455
|
+
Для массивов и вложенных объектов предусмотрено указание типа элемента
|
|
456
|
+
и название модели.
|
|
387
457
|
|
|
388
458
|
- `type: string` тип допустимого значения (обязательно);
|
|
389
459
|
- `itemType?: string` тип элемента массива (для `type: 'array'`);
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -9,8 +9,13 @@ var __glob = (map) => (path) => {
|
|
|
9
9
|
if (fn) return fn();
|
|
10
10
|
throw new Error("Module not found in bundle: " + path);
|
|
11
11
|
};
|
|
12
|
-
var __esm = (fn, res) => function __init() {
|
|
13
|
-
|
|
12
|
+
var __esm = (fn, res, err) => function __init() {
|
|
13
|
+
if (err) throw err[0];
|
|
14
|
+
try {
|
|
15
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
16
|
+
} catch (e) {
|
|
17
|
+
throw err = [e], e;
|
|
18
|
+
}
|
|
14
19
|
};
|
|
15
20
|
var __export = (target, all) => {
|
|
16
21
|
for (var name in all)
|
|
@@ -419,24 +424,6 @@ var init_exclude_object_keys = __esm({
|
|
|
419
424
|
}
|
|
420
425
|
});
|
|
421
426
|
|
|
422
|
-
// src/utils/model-name-to-model-key.js
|
|
423
|
-
function modelNameToModelKey(modelName) {
|
|
424
|
-
if (!modelName || typeof modelName !== "string" || /\s/.test(modelName)) {
|
|
425
|
-
throw new InvalidArgumentError(
|
|
426
|
-
"Model name must be a non-empty String without spaces, but %v was given.",
|
|
427
|
-
modelName
|
|
428
|
-
);
|
|
429
|
-
}
|
|
430
|
-
return modelName.toLowerCase().replace(/[-_]/g, "");
|
|
431
|
-
}
|
|
432
|
-
var init_model_name_to_model_key = __esm({
|
|
433
|
-
"src/utils/model-name-to-model-key.js"() {
|
|
434
|
-
"use strict";
|
|
435
|
-
init_errors();
|
|
436
|
-
__name(modelNameToModelKey, "modelNameToModelKey");
|
|
437
|
-
}
|
|
438
|
-
});
|
|
439
|
-
|
|
440
427
|
// src/utils/index.js
|
|
441
428
|
var init_utils = __esm({
|
|
442
429
|
"src/utils/index.js"() {
|
|
@@ -452,7 +439,6 @@ var init_utils = __esm({
|
|
|
452
439
|
init_get_value_by_path();
|
|
453
440
|
init_select_object_keys();
|
|
454
441
|
init_exclude_object_keys();
|
|
455
|
-
init_model_name_to_model_key();
|
|
456
442
|
}
|
|
457
443
|
});
|
|
458
444
|
|
|
@@ -1833,17 +1819,65 @@ var init_property_uniqueness = __esm({
|
|
|
1833
1819
|
}
|
|
1834
1820
|
});
|
|
1835
1821
|
|
|
1822
|
+
// src/definition/datasource/datasource-definition-validator.js
|
|
1823
|
+
var import_js_service6, DatasourceDefinitionValidator;
|
|
1824
|
+
var init_datasource_definition_validator = __esm({
|
|
1825
|
+
"src/definition/datasource/datasource-definition-validator.js"() {
|
|
1826
|
+
"use strict";
|
|
1827
|
+
import_js_service6 = require("@e22m4u/js-service");
|
|
1828
|
+
init_errors();
|
|
1829
|
+
DatasourceDefinitionValidator = class extends import_js_service6.Service {
|
|
1830
|
+
static {
|
|
1831
|
+
__name(this, "DatasourceDefinitionValidator");
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Validate.
|
|
1835
|
+
*
|
|
1836
|
+
* @param {object} datasourceDef
|
|
1837
|
+
*/
|
|
1838
|
+
validate(datasourceDef) {
|
|
1839
|
+
if (!datasourceDef || typeof datasourceDef !== "object") {
|
|
1840
|
+
throw new InvalidArgumentError(
|
|
1841
|
+
"Datasource definition must be an Object, but %v was given.",
|
|
1842
|
+
datasourceDef
|
|
1843
|
+
);
|
|
1844
|
+
}
|
|
1845
|
+
if (!datasourceDef.name || typeof datasourceDef.name !== "string") {
|
|
1846
|
+
throw new InvalidArgumentError(
|
|
1847
|
+
'Datasource definition requires the option "name" as a non-empty String, but %v was given.',
|
|
1848
|
+
datasourceDef.name
|
|
1849
|
+
);
|
|
1850
|
+
}
|
|
1851
|
+
if (!datasourceDef.adapter || typeof datasourceDef.adapter !== "string") {
|
|
1852
|
+
throw new InvalidArgumentError(
|
|
1853
|
+
'Datasource %v requires the option "adapter" as a non-empty String, but %v was given.',
|
|
1854
|
+
datasourceDef.name,
|
|
1855
|
+
datasourceDef.adapter
|
|
1856
|
+
);
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
};
|
|
1860
|
+
}
|
|
1861
|
+
});
|
|
1862
|
+
|
|
1863
|
+
// src/definition/datasource/index.js
|
|
1864
|
+
var init_datasource = __esm({
|
|
1865
|
+
"src/definition/datasource/index.js"() {
|
|
1866
|
+
"use strict";
|
|
1867
|
+
init_datasource_definition_validator();
|
|
1868
|
+
}
|
|
1869
|
+
});
|
|
1870
|
+
|
|
1836
1871
|
// src/definition/definition-registry.js
|
|
1837
|
-
var
|
|
1872
|
+
var import_js_service7, DefinitionRegistry;
|
|
1838
1873
|
var init_definition_registry = __esm({
|
|
1839
1874
|
"src/definition/definition-registry.js"() {
|
|
1840
1875
|
"use strict";
|
|
1841
|
-
|
|
1842
|
-
init_utils();
|
|
1876
|
+
import_js_service7 = require("@e22m4u/js-service");
|
|
1843
1877
|
init_errors();
|
|
1844
1878
|
init_model();
|
|
1845
|
-
|
|
1846
|
-
DefinitionRegistry = class extends
|
|
1879
|
+
init_datasource();
|
|
1880
|
+
DefinitionRegistry = class extends import_js_service7.Service {
|
|
1847
1881
|
static {
|
|
1848
1882
|
__name(this, "DefinitionRegistry");
|
|
1849
1883
|
}
|
|
@@ -1894,6 +1928,14 @@ var init_definition_registry = __esm({
|
|
|
1894
1928
|
}
|
|
1895
1929
|
return datasourceDef;
|
|
1896
1930
|
}
|
|
1931
|
+
/**
|
|
1932
|
+
* Get datasource names.
|
|
1933
|
+
*
|
|
1934
|
+
* @returns {string[]}
|
|
1935
|
+
*/
|
|
1936
|
+
getDatasourceNames() {
|
|
1937
|
+
return Object.keys(this._datasources);
|
|
1938
|
+
}
|
|
1897
1939
|
/**
|
|
1898
1940
|
* Add model.
|
|
1899
1941
|
*
|
|
@@ -1901,14 +1943,11 @@ var init_definition_registry = __esm({
|
|
|
1901
1943
|
*/
|
|
1902
1944
|
addModel(modelDef) {
|
|
1903
1945
|
this.getService(ModelDefinitionValidator).validate(modelDef);
|
|
1904
|
-
const
|
|
1905
|
-
if (
|
|
1906
|
-
throw new InvalidArgumentError(
|
|
1907
|
-
"Model %v is already defined.",
|
|
1908
|
-
modelDef.name
|
|
1909
|
-
);
|
|
1946
|
+
const name = modelDef.name;
|
|
1947
|
+
if (name in this._models) {
|
|
1948
|
+
throw new InvalidArgumentError("Model %v is already defined.", name);
|
|
1910
1949
|
}
|
|
1911
|
-
this._models[
|
|
1950
|
+
this._models[name] = modelDef;
|
|
1912
1951
|
}
|
|
1913
1952
|
/**
|
|
1914
1953
|
* Has model.
|
|
@@ -1917,8 +1956,7 @@ var init_definition_registry = __esm({
|
|
|
1917
1956
|
* @returns {boolean}
|
|
1918
1957
|
*/
|
|
1919
1958
|
hasModel(name) {
|
|
1920
|
-
|
|
1921
|
-
return Boolean(this._models[modelKey]);
|
|
1959
|
+
return Boolean(this._models[name]);
|
|
1922
1960
|
}
|
|
1923
1961
|
/**
|
|
1924
1962
|
* Get model.
|
|
@@ -1927,29 +1965,36 @@ var init_definition_registry = __esm({
|
|
|
1927
1965
|
* @returns {object}
|
|
1928
1966
|
*/
|
|
1929
1967
|
getModel(name) {
|
|
1930
|
-
const
|
|
1931
|
-
const modelDef = this._models[modelKey];
|
|
1968
|
+
const modelDef = this._models[name];
|
|
1932
1969
|
if (!modelDef) {
|
|
1933
1970
|
throw new InvalidArgumentError("Model %v is not defined.", name);
|
|
1934
1971
|
}
|
|
1935
1972
|
return modelDef;
|
|
1936
1973
|
}
|
|
1974
|
+
/**
|
|
1975
|
+
* Get model names.
|
|
1976
|
+
*
|
|
1977
|
+
* @returns {string[]}
|
|
1978
|
+
*/
|
|
1979
|
+
getModelNames() {
|
|
1980
|
+
return Object.keys(this._models);
|
|
1981
|
+
}
|
|
1937
1982
|
};
|
|
1938
1983
|
}
|
|
1939
1984
|
});
|
|
1940
1985
|
|
|
1941
1986
|
// src/definition/model/model-definition-utils.js
|
|
1942
|
-
var
|
|
1987
|
+
var import_js_service8, DEFAULT_PRIMARY_KEY_PROPERTY_NAME, ModelDefinitionUtils;
|
|
1943
1988
|
var init_model_definition_utils = __esm({
|
|
1944
1989
|
"src/definition/model/model-definition-utils.js"() {
|
|
1945
1990
|
"use strict";
|
|
1946
|
-
|
|
1991
|
+
import_js_service8 = require("@e22m4u/js-service");
|
|
1947
1992
|
init_properties();
|
|
1948
1993
|
init_errors();
|
|
1949
1994
|
init_definition_registry();
|
|
1950
1995
|
init_utils();
|
|
1951
1996
|
DEFAULT_PRIMARY_KEY_PROPERTY_NAME = "id";
|
|
1952
|
-
ModelDefinitionUtils = class extends
|
|
1997
|
+
ModelDefinitionUtils = class extends import_js_service8.Service {
|
|
1953
1998
|
static {
|
|
1954
1999
|
__name(this, "ModelDefinitionUtils");
|
|
1955
2000
|
}
|
|
@@ -2383,15 +2428,15 @@ var init_model_definition_utils = __esm({
|
|
|
2383
2428
|
});
|
|
2384
2429
|
|
|
2385
2430
|
// src/definition/model/properties/required-property-validator.js
|
|
2386
|
-
var
|
|
2431
|
+
var import_js_service9, RequiredPropertyValidator;
|
|
2387
2432
|
var init_required_property_validator = __esm({
|
|
2388
2433
|
"src/definition/model/properties/required-property-validator.js"() {
|
|
2389
2434
|
"use strict";
|
|
2390
2435
|
init_data_type();
|
|
2391
|
-
|
|
2436
|
+
import_js_service9 = require("@e22m4u/js-service");
|
|
2392
2437
|
init_errors();
|
|
2393
2438
|
init_model_definition_utils();
|
|
2394
|
-
RequiredPropertyValidator = class extends
|
|
2439
|
+
RequiredPropertyValidator = class extends import_js_service9.Service {
|
|
2395
2440
|
static {
|
|
2396
2441
|
__name(this, "RequiredPropertyValidator");
|
|
2397
2442
|
}
|
|
@@ -2456,16 +2501,16 @@ var init_required_property_validator = __esm({
|
|
|
2456
2501
|
});
|
|
2457
2502
|
|
|
2458
2503
|
// src/definition/model/properties/property-uniqueness-validator.js
|
|
2459
|
-
var
|
|
2504
|
+
var import_js_service10, PropertyUniquenessValidator;
|
|
2460
2505
|
var init_property_uniqueness_validator = __esm({
|
|
2461
2506
|
"src/definition/model/properties/property-uniqueness-validator.js"() {
|
|
2462
2507
|
"use strict";
|
|
2463
|
-
|
|
2508
|
+
import_js_service10 = require("@e22m4u/js-service");
|
|
2464
2509
|
init_utils();
|
|
2465
2510
|
init_property_uniqueness();
|
|
2466
2511
|
init_errors();
|
|
2467
2512
|
init_model_definition_utils();
|
|
2468
|
-
PropertyUniquenessValidator = class extends
|
|
2513
|
+
PropertyUniquenessValidator = class extends import_js_service10.Service {
|
|
2469
2514
|
static {
|
|
2470
2515
|
__name(this, "PropertyUniquenessValidator");
|
|
2471
2516
|
}
|
|
@@ -2588,14 +2633,14 @@ var init_property_uniqueness_validator = __esm({
|
|
|
2588
2633
|
});
|
|
2589
2634
|
|
|
2590
2635
|
// src/definition/model/properties/primary-keys-definition-validator.js
|
|
2591
|
-
var
|
|
2636
|
+
var import_js_service11, PrimaryKeysDefinitionValidator;
|
|
2592
2637
|
var init_primary_keys_definition_validator = __esm({
|
|
2593
2638
|
"src/definition/model/properties/primary-keys-definition-validator.js"() {
|
|
2594
2639
|
"use strict";
|
|
2595
|
-
|
|
2640
|
+
import_js_service11 = require("@e22m4u/js-service");
|
|
2596
2641
|
init_errors();
|
|
2597
2642
|
init_model_definition_utils();
|
|
2598
|
-
PrimaryKeysDefinitionValidator = class extends
|
|
2643
|
+
PrimaryKeysDefinitionValidator = class extends import_js_service11.Service {
|
|
2599
2644
|
static {
|
|
2600
2645
|
__name(this, "PrimaryKeysDefinitionValidator");
|
|
2601
2646
|
}
|
|
@@ -2643,17 +2688,17 @@ var init_primary_keys_definition_validator = __esm({
|
|
|
2643
2688
|
});
|
|
2644
2689
|
|
|
2645
2690
|
// src/definition/model/properties/properties-definition-validator.js
|
|
2646
|
-
var
|
|
2691
|
+
var import_js_service12, PropertiesDefinitionValidator;
|
|
2647
2692
|
var init_properties_definition_validator = __esm({
|
|
2648
2693
|
"src/definition/model/properties/properties-definition-validator.js"() {
|
|
2649
2694
|
"use strict";
|
|
2650
|
-
|
|
2695
|
+
import_js_service12 = require("@e22m4u/js-service");
|
|
2651
2696
|
init_data_type();
|
|
2652
2697
|
init_utils();
|
|
2653
2698
|
init_property_uniqueness();
|
|
2654
2699
|
init_errors();
|
|
2655
2700
|
init_primary_keys_definition_validator();
|
|
2656
|
-
PropertiesDefinitionValidator = class extends
|
|
2701
|
+
PropertiesDefinitionValidator = class extends import_js_service12.Service {
|
|
2657
2702
|
static {
|
|
2658
2703
|
__name(this, "PropertiesDefinitionValidator");
|
|
2659
2704
|
}
|
|
@@ -2908,14 +2953,14 @@ var init_model_definition = __esm({
|
|
|
2908
2953
|
});
|
|
2909
2954
|
|
|
2910
2955
|
// src/definition/model/model-data-sanitizer.js
|
|
2911
|
-
var
|
|
2956
|
+
var import_js_service13, ModelDataSanitizer;
|
|
2912
2957
|
var init_model_data_sanitizer = __esm({
|
|
2913
2958
|
"src/definition/model/model-data-sanitizer.js"() {
|
|
2914
2959
|
"use strict";
|
|
2915
|
-
|
|
2960
|
+
import_js_service13 = require("@e22m4u/js-service");
|
|
2916
2961
|
init_errors();
|
|
2917
2962
|
init_model_definition_utils();
|
|
2918
|
-
ModelDataSanitizer = class extends
|
|
2963
|
+
ModelDataSanitizer = class extends import_js_service13.Service {
|
|
2919
2964
|
static {
|
|
2920
2965
|
__name(this, "ModelDataSanitizer");
|
|
2921
2966
|
}
|
|
@@ -2948,15 +2993,15 @@ var init_model_data_sanitizer = __esm({
|
|
|
2948
2993
|
});
|
|
2949
2994
|
|
|
2950
2995
|
// src/definition/model/model-definition-validator.js
|
|
2951
|
-
var
|
|
2996
|
+
var import_js_service14, ModelDefinitionValidator;
|
|
2952
2997
|
var init_model_definition_validator = __esm({
|
|
2953
2998
|
"src/definition/model/model-definition-validator.js"() {
|
|
2954
2999
|
"use strict";
|
|
2955
|
-
|
|
3000
|
+
import_js_service14 = require("@e22m4u/js-service");
|
|
2956
3001
|
init_errors();
|
|
2957
3002
|
init_relations();
|
|
2958
3003
|
init_properties();
|
|
2959
|
-
ModelDefinitionValidator = class extends
|
|
3004
|
+
ModelDefinitionValidator = class extends import_js_service14.Service {
|
|
2960
3005
|
static {
|
|
2961
3006
|
__name(this, "ModelDefinitionValidator");
|
|
2962
3007
|
}
|
|
@@ -3043,55 +3088,6 @@ var init_model = __esm({
|
|
|
3043
3088
|
}
|
|
3044
3089
|
});
|
|
3045
3090
|
|
|
3046
|
-
// src/definition/datasource/datasource-definition-validator.js
|
|
3047
|
-
var import_js_service14, DatasourceDefinitionValidator;
|
|
3048
|
-
var init_datasource_definition_validator = __esm({
|
|
3049
|
-
"src/definition/datasource/datasource-definition-validator.js"() {
|
|
3050
|
-
"use strict";
|
|
3051
|
-
import_js_service14 = require("@e22m4u/js-service");
|
|
3052
|
-
init_errors();
|
|
3053
|
-
DatasourceDefinitionValidator = class extends import_js_service14.Service {
|
|
3054
|
-
static {
|
|
3055
|
-
__name(this, "DatasourceDefinitionValidator");
|
|
3056
|
-
}
|
|
3057
|
-
/**
|
|
3058
|
-
* Validate.
|
|
3059
|
-
*
|
|
3060
|
-
* @param {object} datasourceDef
|
|
3061
|
-
*/
|
|
3062
|
-
validate(datasourceDef) {
|
|
3063
|
-
if (!datasourceDef || typeof datasourceDef !== "object") {
|
|
3064
|
-
throw new InvalidArgumentError(
|
|
3065
|
-
"Datasource definition must be an Object, but %v was given.",
|
|
3066
|
-
datasourceDef
|
|
3067
|
-
);
|
|
3068
|
-
}
|
|
3069
|
-
if (!datasourceDef.name || typeof datasourceDef.name !== "string") {
|
|
3070
|
-
throw new InvalidArgumentError(
|
|
3071
|
-
'Datasource definition requires the option "name" as a non-empty String, but %v was given.',
|
|
3072
|
-
datasourceDef.name
|
|
3073
|
-
);
|
|
3074
|
-
}
|
|
3075
|
-
if (!datasourceDef.adapter || typeof datasourceDef.adapter !== "string") {
|
|
3076
|
-
throw new InvalidArgumentError(
|
|
3077
|
-
'Datasource %v requires the option "adapter" as a non-empty String, but %v was given.',
|
|
3078
|
-
datasourceDef.name,
|
|
3079
|
-
datasourceDef.adapter
|
|
3080
|
-
);
|
|
3081
|
-
}
|
|
3082
|
-
}
|
|
3083
|
-
};
|
|
3084
|
-
}
|
|
3085
|
-
});
|
|
3086
|
-
|
|
3087
|
-
// src/definition/datasource/index.js
|
|
3088
|
-
var init_datasource = __esm({
|
|
3089
|
-
"src/definition/datasource/index.js"() {
|
|
3090
|
-
"use strict";
|
|
3091
|
-
init_datasource_definition_validator();
|
|
3092
|
-
}
|
|
3093
|
-
});
|
|
3094
|
-
|
|
3095
3091
|
// src/definition/index.js
|
|
3096
3092
|
var init_definition = __esm({
|
|
3097
3093
|
"src/definition/index.js"() {
|
|
@@ -4664,7 +4660,6 @@ var init_repository_registry = __esm({
|
|
|
4664
4660
|
"use strict";
|
|
4665
4661
|
import_js_service26 = require("@e22m4u/js-service");
|
|
4666
4662
|
init_repository();
|
|
4667
|
-
init_utils();
|
|
4668
4663
|
init_errors();
|
|
4669
4664
|
RepositoryRegistry = class extends import_js_service26.Service {
|
|
4670
4665
|
static {
|
|
@@ -4704,13 +4699,12 @@ var init_repository_registry = __esm({
|
|
|
4704
4699
|
* @returns {Repository}
|
|
4705
4700
|
*/
|
|
4706
4701
|
getRepository(modelName) {
|
|
4707
|
-
|
|
4708
|
-
let repository = this._repositories[modelKey];
|
|
4702
|
+
let repository = this._repositories[modelName];
|
|
4709
4703
|
if (repository) {
|
|
4710
4704
|
return repository;
|
|
4711
4705
|
}
|
|
4712
4706
|
repository = new this._repositoryCtor(this.container, modelName);
|
|
4713
|
-
this._repositories[
|
|
4707
|
+
this._repositories[modelName] = repository;
|
|
4714
4708
|
return repository;
|
|
4715
4709
|
}
|
|
4716
4710
|
};
|
|
@@ -6073,7 +6067,6 @@ __export(index_exports, {
|
|
|
6073
6067
|
isPlainObject: () => isPlainObject,
|
|
6074
6068
|
isPromise: () => isPromise,
|
|
6075
6069
|
likeToRegexp: () => likeToRegexp,
|
|
6076
|
-
modelNameToModelKey: () => modelNameToModelKey,
|
|
6077
6070
|
selectObjectKeys: () => selectObjectKeys,
|
|
6078
6071
|
singularize: () => singularize,
|
|
6079
6072
|
stringToRegexp: () => stringToRegexp
|
|
@@ -6171,7 +6164,6 @@ init_repository2();
|
|
|
6171
6164
|
isPlainObject,
|
|
6172
6165
|
isPromise,
|
|
6173
6166
|
likeToRegexp,
|
|
6174
|
-
modelNameToModelKey,
|
|
6175
6167
|
selectObjectKeys,
|
|
6176
6168
|
singularize,
|
|
6177
6169
|
stringToRegexp
|
package/eslint.config.js
CHANGED
|
@@ -2,7 +2,6 @@ import globals from 'globals';
|
|
|
2
2
|
import eslintJs from '@eslint/js';
|
|
3
3
|
import eslintJsdocPlugin from 'eslint-plugin-jsdoc';
|
|
4
4
|
import eslintMochaPlugin from 'eslint-plugin-mocha';
|
|
5
|
-
import eslintImportPlugin from 'eslint-plugin-import';
|
|
6
5
|
import eslintPrettierConfig from 'eslint-config-prettier';
|
|
7
6
|
import eslintChaiExpectPlugin from 'eslint-plugin-chai-expect';
|
|
8
7
|
|
|
@@ -18,19 +17,16 @@ export default [{
|
|
|
18
17
|
plugins: {
|
|
19
18
|
'jsdoc': eslintJsdocPlugin,
|
|
20
19
|
'mocha': eslintMochaPlugin,
|
|
21
|
-
'import': eslintImportPlugin,
|
|
22
20
|
'chai-expect': eslintChaiExpectPlugin,
|
|
23
21
|
},
|
|
24
22
|
rules: {
|
|
25
23
|
...eslintJs.configs.recommended.rules,
|
|
26
24
|
...eslintPrettierConfig.rules,
|
|
27
|
-
...eslintImportPlugin.flatConfigs.recommended.rules,
|
|
28
25
|
...eslintMochaPlugin.configs.recommended.rules,
|
|
29
26
|
...eslintChaiExpectPlugin.configs['recommended-flat'].rules,
|
|
30
27
|
...eslintJsdocPlugin.configs['flat/recommended-error'].rules,
|
|
31
28
|
'curly': 'error',
|
|
32
29
|
'no-duplicate-imports': 'error',
|
|
33
|
-
'import/export': 0,
|
|
34
30
|
'jsdoc/reject-any-type': 0,
|
|
35
31
|
'jsdoc/reject-function-type': 0,
|
|
36
32
|
'jsdoc/require-param-description': 0,
|
package/package.json
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e22m4u/js-repository",
|
|
3
|
-
"version": "0.8.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.8.10",
|
|
4
|
+
"description": "ORM/ODM библиотека для работы с базами данных",
|
|
5
5
|
"author": "Mikhail Evstropov <e22m4u@yandex.ru>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
8
|
+
"js-repository",
|
|
9
|
+
"orm",
|
|
10
|
+
"odm",
|
|
11
|
+
"database",
|
|
12
|
+
"datasource",
|
|
13
|
+
"repository",
|
|
14
|
+
"relations"
|
|
14
15
|
],
|
|
15
|
-
"homepage": "https://
|
|
16
|
+
"homepage": "https://github.com/e22m4u/js-repository",
|
|
16
17
|
"repository": {
|
|
17
18
|
"type": "git",
|
|
18
|
-
"url": "git+https://
|
|
19
|
+
"url": "git+https://github.com/e22m4u/js-repository.git"
|
|
19
20
|
},
|
|
20
21
|
"type": "module",
|
|
21
22
|
"types": "./src/index.d.ts",
|
|
@@ -43,27 +44,26 @@
|
|
|
43
44
|
"@e22m4u/js-service": "~0.6.2"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
|
-
"@commitlint/cli": "~
|
|
47
|
-
"@commitlint/config-conventional": "~
|
|
47
|
+
"@commitlint/cli": "~21.2.1",
|
|
48
|
+
"@commitlint/config-conventional": "~21.2.0",
|
|
48
49
|
"@e22m4u/js-spy": "~0.3.6",
|
|
49
|
-
"@eslint/js": "~
|
|
50
|
+
"@eslint/js": "~10.0.1",
|
|
50
51
|
"@types/chai": "~5.2.3",
|
|
51
52
|
"@types/chai-as-promised": "~8.0.2",
|
|
52
53
|
"@types/mocha": "~10.0.10",
|
|
53
|
-
"c8": "~
|
|
54
|
+
"c8": "~12.0.0",
|
|
54
55
|
"chai": "~6.2.2",
|
|
55
56
|
"chai-as-promised": "~8.0.2",
|
|
56
|
-
"esbuild": "~0.
|
|
57
|
-
"eslint": "~
|
|
57
|
+
"esbuild": "~0.28.1",
|
|
58
|
+
"eslint": "~10.7.0",
|
|
58
59
|
"eslint-config-prettier": "~10.1.8",
|
|
59
|
-
"eslint-plugin-chai-expect": "~4.
|
|
60
|
-
"eslint-plugin-
|
|
61
|
-
"eslint-plugin-
|
|
62
|
-
"eslint-plugin-mocha": "~11.2.0",
|
|
60
|
+
"eslint-plugin-chai-expect": "~4.1.0",
|
|
61
|
+
"eslint-plugin-jsdoc": "~63.2.0",
|
|
62
|
+
"eslint-plugin-mocha": "~11.3.0",
|
|
63
63
|
"husky": "~9.1.7",
|
|
64
|
-
"mocha": "~11.7.
|
|
65
|
-
"prettier": "~3.
|
|
64
|
+
"mocha": "~11.7.6",
|
|
65
|
+
"prettier": "~3.9.6",
|
|
66
66
|
"rimraf": "~6.1.3",
|
|
67
|
-
"typescript": "~
|
|
67
|
+
"typescript": "~7.0.2"
|
|
68
68
|
}
|
|
69
69
|
}
|
|
@@ -27,6 +27,11 @@ export declare class DefinitionRegistry extends Service {
|
|
|
27
27
|
*/
|
|
28
28
|
getDatasource(name: string): DatasourceDefinition;
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Get datasource names.
|
|
32
|
+
*/
|
|
33
|
+
getDatasourceNames(): string[];
|
|
34
|
+
|
|
30
35
|
/**
|
|
31
36
|
* Add model.
|
|
32
37
|
*
|
|
@@ -47,4 +52,9 @@ export declare class DefinitionRegistry extends Service {
|
|
|
47
52
|
* @param name
|
|
48
53
|
*/
|
|
49
54
|
getModel(name: string): ModelDefinition;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get model names.
|
|
58
|
+
*/
|
|
59
|
+
getModelNames(): string[];
|
|
50
60
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import {Service} from '@e22m4u/js-service';
|
|
2
|
-
import {modelNameToModelKey} from '../utils/index.js';
|
|
3
2
|
import {InvalidArgumentError} from '../errors/index.js';
|
|
4
3
|
import {ModelDefinitionValidator} from './model/index.js';
|
|
5
|
-
import {DatasourceDefinitionValidator} from '
|
|
4
|
+
import {DatasourceDefinitionValidator} from './datasource/index.js';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Definition registry.
|
|
@@ -60,6 +59,15 @@ export class DefinitionRegistry extends Service {
|
|
|
60
59
|
return datasourceDef;
|
|
61
60
|
}
|
|
62
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Get datasource names.
|
|
64
|
+
*
|
|
65
|
+
* @returns {string[]}
|
|
66
|
+
*/
|
|
67
|
+
getDatasourceNames() {
|
|
68
|
+
return Object.keys(this._datasources);
|
|
69
|
+
}
|
|
70
|
+
|
|
63
71
|
/**
|
|
64
72
|
* Add model.
|
|
65
73
|
*
|
|
@@ -67,14 +75,11 @@ export class DefinitionRegistry extends Service {
|
|
|
67
75
|
*/
|
|
68
76
|
addModel(modelDef) {
|
|
69
77
|
this.getService(ModelDefinitionValidator).validate(modelDef);
|
|
70
|
-
const
|
|
71
|
-
if (
|
|
72
|
-
throw new InvalidArgumentError(
|
|
73
|
-
'Model %v is already defined.',
|
|
74
|
-
modelDef.name,
|
|
75
|
-
);
|
|
78
|
+
const name = modelDef.name;
|
|
79
|
+
if (name in this._models) {
|
|
80
|
+
throw new InvalidArgumentError('Model %v is already defined.', name);
|
|
76
81
|
}
|
|
77
|
-
this._models[
|
|
82
|
+
this._models[name] = modelDef;
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
/**
|
|
@@ -84,8 +89,7 @@ export class DefinitionRegistry extends Service {
|
|
|
84
89
|
* @returns {boolean}
|
|
85
90
|
*/
|
|
86
91
|
hasModel(name) {
|
|
87
|
-
|
|
88
|
-
return Boolean(this._models[modelKey]);
|
|
92
|
+
return Boolean(this._models[name]);
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
/**
|
|
@@ -95,11 +99,19 @@ export class DefinitionRegistry extends Service {
|
|
|
95
99
|
* @returns {object}
|
|
96
100
|
*/
|
|
97
101
|
getModel(name) {
|
|
98
|
-
const
|
|
99
|
-
const modelDef = this._models[modelKey];
|
|
102
|
+
const modelDef = this._models[name];
|
|
100
103
|
if (!modelDef) {
|
|
101
104
|
throw new InvalidArgumentError('Model %v is not defined.', name);
|
|
102
105
|
}
|
|
103
106
|
return modelDef;
|
|
104
107
|
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get model names.
|
|
111
|
+
*
|
|
112
|
+
* @returns {string[]}
|
|
113
|
+
*/
|
|
114
|
+
getModelNames() {
|
|
115
|
+
return Object.keys(this._models);
|
|
116
|
+
}
|
|
105
117
|
}
|
|
@@ -1,42 +1,33 @@
|
|
|
1
1
|
import {expect} from 'chai';
|
|
2
|
-
import {
|
|
2
|
+
import {createSpy} from '@e22m4u/js-spy';
|
|
3
3
|
import {ModelDefinitionValidator} from './model/index.js';
|
|
4
4
|
import {DefinitionRegistry} from './definition-registry.js';
|
|
5
5
|
import {DatasourceDefinitionValidator} from '../definition/index.js';
|
|
6
6
|
|
|
7
|
-
const sandbox = createSandbox();
|
|
8
|
-
|
|
9
7
|
describe('DefinitionRegistry', function () {
|
|
10
|
-
let S;
|
|
11
|
-
|
|
12
|
-
beforeEach(function () {
|
|
13
|
-
S = new DefinitionRegistry();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
afterEach(function () {
|
|
17
|
-
sandbox.restore();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
8
|
describe('addDatasource', function () {
|
|
21
|
-
it('
|
|
9
|
+
it('should add the given datasource to the registry', function () {
|
|
22
10
|
const datasource = {name: 'datasource', adapter: 'adapter'};
|
|
11
|
+
const S = new DefinitionRegistry();
|
|
23
12
|
S.addDatasource(datasource);
|
|
24
13
|
const result = S.getDatasource('datasource');
|
|
25
14
|
expect(result).to.be.eql(datasource);
|
|
26
15
|
});
|
|
27
16
|
|
|
28
|
-
it('
|
|
17
|
+
it('should use DatasourceDefinitionValidator to validate the given datasource', function () {
|
|
18
|
+
const S = new DefinitionRegistry();
|
|
29
19
|
const V = S.getService(DatasourceDefinitionValidator);
|
|
30
|
-
|
|
20
|
+
createSpy(V, 'validate');
|
|
31
21
|
const datasource = {name: 'datasource', adapter: 'adapter'};
|
|
32
22
|
S.addDatasource(datasource);
|
|
33
23
|
expect(V.validate).to.have.been.called.once;
|
|
34
24
|
expect(V.validate).to.have.been.called.with(datasource);
|
|
35
25
|
});
|
|
36
26
|
|
|
37
|
-
it('
|
|
27
|
+
it('should throw an error when the given datasource is already defined', function () {
|
|
38
28
|
const datasource1 = {name: 'datasource', adapter: 'adapter'};
|
|
39
29
|
const datasource2 = {name: 'datasource', adapter: 'adapter'};
|
|
30
|
+
const S = new DefinitionRegistry();
|
|
40
31
|
S.addDatasource(datasource1);
|
|
41
32
|
const throwable = () => S.addDatasource(datasource2);
|
|
42
33
|
expect(throwable).to.throw('Datasource "datasource" is already defined.');
|
|
@@ -44,8 +35,9 @@ describe('DefinitionRegistry', function () {
|
|
|
44
35
|
});
|
|
45
36
|
|
|
46
37
|
describe('hasDatasource', function () {
|
|
47
|
-
it('should
|
|
38
|
+
it('should return true when the datasource name is registered', function () {
|
|
48
39
|
const datasource = {name: 'datasource', adapter: 'adapter'};
|
|
40
|
+
const S = new DefinitionRegistry();
|
|
49
41
|
expect(S.hasDatasource(datasource.name)).to.be.false;
|
|
50
42
|
S.addDatasource(datasource);
|
|
51
43
|
expect(S.hasDatasource(datasource.name)).to.be.true;
|
|
@@ -53,39 +45,62 @@ describe('DefinitionRegistry', function () {
|
|
|
53
45
|
});
|
|
54
46
|
|
|
55
47
|
describe('getDatasource', function () {
|
|
56
|
-
it('
|
|
48
|
+
it('should return the registered datasource for its name', function () {
|
|
57
49
|
const datasource = {name: 'datasource', adapter: 'adapter'};
|
|
50
|
+
const S = new DefinitionRegistry();
|
|
58
51
|
S.addDatasource(datasource);
|
|
59
52
|
const result = S.getDatasource('datasource');
|
|
60
53
|
expect(result).to.be.eql(datasource);
|
|
61
54
|
});
|
|
62
55
|
|
|
63
|
-
it('
|
|
56
|
+
it('should throw an error when the datasource name is not registered', function () {
|
|
57
|
+
const S = new DefinitionRegistry();
|
|
64
58
|
const throwable = () => S.getDatasource('undefined');
|
|
65
59
|
expect(throwable).to.throw('Datasource "undefined" is not defined.');
|
|
66
60
|
});
|
|
67
61
|
});
|
|
68
62
|
|
|
63
|
+
describe('getDatasourceNames', function () {
|
|
64
|
+
it('should return an array of datasource names in the definition order', function () {
|
|
65
|
+
const datasource1 = {name: 'datasource1', adapter: 'adapter'};
|
|
66
|
+
const datasource2 = {name: 'datasource2', adapter: 'adapter'};
|
|
67
|
+
const datasource3 = {name: 'datasource3', adapter: 'adapter'};
|
|
68
|
+
const S = new DefinitionRegistry();
|
|
69
|
+
expect(S.getDatasourceNames()).to.be.eql([]);
|
|
70
|
+
S.addDatasource(datasource1);
|
|
71
|
+
S.addDatasource(datasource2);
|
|
72
|
+
S.addDatasource(datasource3);
|
|
73
|
+
expect(S.getDatasourceNames()).to.be.eql([
|
|
74
|
+
datasource1.name,
|
|
75
|
+
datasource2.name,
|
|
76
|
+
datasource3.name,
|
|
77
|
+
]);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
69
81
|
describe('addModel', function () {
|
|
70
|
-
it('
|
|
82
|
+
it('should add the given model to the registry', function () {
|
|
71
83
|
const model = {name: 'model'};
|
|
84
|
+
const S = new DefinitionRegistry();
|
|
72
85
|
S.addModel(model);
|
|
73
86
|
const result = S.getModel('model');
|
|
74
87
|
expect(result).to.be.eql(model);
|
|
75
88
|
});
|
|
76
89
|
|
|
77
|
-
it('
|
|
90
|
+
it('should use ModelDefinitionValidator to validate the given model', function () {
|
|
91
|
+
const S = new DefinitionRegistry();
|
|
78
92
|
const V = S.getService(ModelDefinitionValidator);
|
|
79
|
-
|
|
93
|
+
createSpy(V, 'validate');
|
|
80
94
|
const model = {name: 'model'};
|
|
81
95
|
S.addModel(model);
|
|
82
96
|
expect(V.validate).to.have.been.called.once;
|
|
83
97
|
expect(V.validate).to.have.been.called.with(model);
|
|
84
98
|
});
|
|
85
99
|
|
|
86
|
-
it('
|
|
100
|
+
it('should throw an error when the model name is already registered', function () {
|
|
87
101
|
const model1 = {name: 'TestModel'};
|
|
88
102
|
const model2 = {name: 'TestModel'};
|
|
103
|
+
const S = new DefinitionRegistry();
|
|
89
104
|
S.addModel(model1);
|
|
90
105
|
const throwable = () => S.addModel(model2);
|
|
91
106
|
expect(throwable).to.throw('Model "TestModel" is already defined.');
|
|
@@ -93,112 +108,46 @@ describe('DefinitionRegistry', function () {
|
|
|
93
108
|
});
|
|
94
109
|
|
|
95
110
|
describe('hasModel', function () {
|
|
96
|
-
it('should
|
|
111
|
+
it('should return true when the model name is registered', function () {
|
|
97
112
|
const model = {name: 'model'};
|
|
113
|
+
const S = new DefinitionRegistry();
|
|
98
114
|
expect(S.hasModel(model.name)).to.be.false;
|
|
99
115
|
S.addModel(model);
|
|
100
116
|
expect(S.hasModel(model.name)).to.be.true;
|
|
101
117
|
});
|
|
102
|
-
|
|
103
|
-
it('should ignore naming convention of the model name', function () {
|
|
104
|
-
const model = {name: 'UserProfileDetails'};
|
|
105
|
-
const modelNames = [
|
|
106
|
-
'userProfileDetails',
|
|
107
|
-
'UserProfileDetails',
|
|
108
|
-
'user-profile-details',
|
|
109
|
-
'user_profile_details',
|
|
110
|
-
'USER-PROFILE-DETAILS',
|
|
111
|
-
'USER_PROFILE_DETAILS',
|
|
112
|
-
'USERPROFILEDETAILS',
|
|
113
|
-
'userprofiledetails',
|
|
114
|
-
];
|
|
115
|
-
modelNames.forEach(v => expect(S.hasModel(v)).to.be.false);
|
|
116
|
-
S.addModel(model);
|
|
117
|
-
modelNames.forEach(v => expect(S.hasModel(v)).to.be.true);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('should respect numbers in the model name', function () {
|
|
121
|
-
const model1 = {name: 'UserProfileDetails1'};
|
|
122
|
-
const modelNames1 = [
|
|
123
|
-
'userProfileDetails1',
|
|
124
|
-
'UserProfileDetails1',
|
|
125
|
-
'user-profile-details-1',
|
|
126
|
-
'user_profile_details_1',
|
|
127
|
-
'USER-PROFILE-DETAILS-1',
|
|
128
|
-
'USER_PROFILE_DETAILS_1',
|
|
129
|
-
'USERPROFILEDETAILS1',
|
|
130
|
-
'userprofiledetails1',
|
|
131
|
-
];
|
|
132
|
-
const modelNames2 = [
|
|
133
|
-
'userProfileDetails2',
|
|
134
|
-
'UserProfileDetails2',
|
|
135
|
-
'user-profile-details-2',
|
|
136
|
-
'user_profile_details_2',
|
|
137
|
-
'USER-PROFILE-DETAILS-2',
|
|
138
|
-
'USER_PROFILE_DETAILS_2',
|
|
139
|
-
'USERPROFILEDETAILS2',
|
|
140
|
-
'userprofiledetails2',
|
|
141
|
-
];
|
|
142
|
-
S.addModel(model1);
|
|
143
|
-
modelNames1.forEach(v => expect(S.hasModel(v)).to.be.true);
|
|
144
|
-
modelNames2.forEach(v => expect(S.hasModel(v)).to.be.false);
|
|
145
|
-
});
|
|
146
118
|
});
|
|
147
119
|
|
|
148
120
|
describe('getModel', function () {
|
|
149
|
-
it('
|
|
121
|
+
it('should return the model definition for the model name', function () {
|
|
150
122
|
const model = {name: 'model'};
|
|
123
|
+
const S = new DefinitionRegistry();
|
|
151
124
|
S.addModel(model);
|
|
152
125
|
const result = S.getModel('model');
|
|
153
126
|
expect(result).to.be.eql(model);
|
|
154
127
|
});
|
|
155
128
|
|
|
156
|
-
it('
|
|
129
|
+
it('should throw an error when the model name is not registered', function () {
|
|
130
|
+
const S = new DefinitionRegistry();
|
|
157
131
|
const throwable = () => S.getModel('undefined');
|
|
158
132
|
expect(throwable).to.throw('Model "undefined" is not defined.');
|
|
159
133
|
});
|
|
134
|
+
});
|
|
160
135
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
'USER-PROFILE-DETAILS',
|
|
169
|
-
'USER_PROFILE_DETAILS',
|
|
170
|
-
'USERPROFILEDETAILS',
|
|
171
|
-
'userprofiledetails',
|
|
172
|
-
];
|
|
173
|
-
S.addModel(model);
|
|
174
|
-
modelNames.forEach(v => expect(S.getModel(v)).to.be.eq(model));
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('should respect numbers in the model name', function () {
|
|
178
|
-
const model1 = {name: 'userProfileDetails1'};
|
|
179
|
-
const modelNames1 = [
|
|
180
|
-
'userProfileDetails1',
|
|
181
|
-
'UserProfileDetails1',
|
|
182
|
-
'user-profile-details-1',
|
|
183
|
-
'user_profile_details_1',
|
|
184
|
-
'USER-PROFILE-DETAILS-1',
|
|
185
|
-
'USER_PROFILE_DETAILS_1',
|
|
186
|
-
'USERPROFILEDETAILS1',
|
|
187
|
-
'userprofiledetails1',
|
|
188
|
-
];
|
|
189
|
-
const modelNames2 = [
|
|
190
|
-
'userProfileDetails2',
|
|
191
|
-
'UserProfileDetails2',
|
|
192
|
-
'user-profile-details-2',
|
|
193
|
-
'user_profile_details_2',
|
|
194
|
-
'USER-PROFILE-DETAILS-2',
|
|
195
|
-
'USER_PROFILE_DETAILS_2',
|
|
196
|
-
'USERPROFILEDETAILS2',
|
|
197
|
-
'userprofiledetails2',
|
|
198
|
-
];
|
|
136
|
+
describe('getModelNames', function () {
|
|
137
|
+
it('should return an array of model names in the definition order', function () {
|
|
138
|
+
const model1 = {name: 'model1'};
|
|
139
|
+
const model2 = {name: 'model2'};
|
|
140
|
+
const model3 = {name: 'model3'};
|
|
141
|
+
const S = new DefinitionRegistry();
|
|
142
|
+
expect(S.getModelNames()).to.be.eql([]);
|
|
199
143
|
S.addModel(model1);
|
|
200
|
-
|
|
201
|
-
|
|
144
|
+
S.addModel(model2);
|
|
145
|
+
S.addModel(model3);
|
|
146
|
+
expect(S.getModelNames()).to.be.eql([
|
|
147
|
+
model1.name,
|
|
148
|
+
model2.name,
|
|
149
|
+
model3.name,
|
|
150
|
+
]);
|
|
202
151
|
});
|
|
203
152
|
});
|
|
204
153
|
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {Service} from '@e22m4u/js-service';
|
|
2
2
|
import {Repository} from './repository.js';
|
|
3
|
-
import {modelNameToModelKey} from '../utils/index.js';
|
|
4
3
|
import {InvalidArgumentError} from '../errors/index.js';
|
|
5
4
|
|
|
6
5
|
/**
|
|
@@ -49,13 +48,12 @@ export class RepositoryRegistry extends Service {
|
|
|
49
48
|
* @returns {Repository}
|
|
50
49
|
*/
|
|
51
50
|
getRepository(modelName) {
|
|
52
|
-
|
|
53
|
-
let repository = this._repositories[modelKey];
|
|
51
|
+
let repository = this._repositories[modelName];
|
|
54
52
|
if (repository) {
|
|
55
53
|
return repository;
|
|
56
54
|
}
|
|
57
55
|
repository = new this._repositoryCtor(this.container, modelName);
|
|
58
|
-
this._repositories[
|
|
56
|
+
this._repositories[modelName] = repository;
|
|
59
57
|
return repository;
|
|
60
58
|
}
|
|
61
59
|
}
|
|
@@ -35,25 +35,6 @@ describe('RepositoryRegistry', function () {
|
|
|
35
35
|
expect(repA2).to.be.not.eq(repB2);
|
|
36
36
|
});
|
|
37
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
38
|
it('should respect numbers in the model name', function () {
|
|
58
39
|
const dbs = new DatabaseSchema();
|
|
59
40
|
dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
|
package/src/utils/index.d.ts
CHANGED
package/src/utils/index.js
CHANGED
|
@@ -1,18 +0,0 @@
|
|
|
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
|
-
'Model name must be a non-empty String ' +
|
|
13
|
-
'without spaces, but %v was given.',
|
|
14
|
-
modelName,
|
|
15
|
-
);
|
|
16
|
-
}
|
|
17
|
-
return modelName.toLowerCase().replace(/[-_]/g, '');
|
|
18
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
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
|
-
'USER-PROFILE-DETAILS',
|
|
18
|
-
'USER_PROFILE_DETAILS',
|
|
19
|
-
'USERPROFILEDETAILS',
|
|
20
|
-
'userprofiledetails',
|
|
21
|
-
];
|
|
22
|
-
modelNames.forEach(v =>
|
|
23
|
-
expect(modelNameToModelKey(v)).to.be.eq('userprofiledetails'),
|
|
24
|
-
);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should handle a mixed string with uppercase, hyphens and underscores', function () {
|
|
28
|
-
const modelName = 'User_Profile-Details';
|
|
29
|
-
const expected = 'userprofiledetails';
|
|
30
|
-
expect(modelNameToModelKey(modelName)).to.be.eq(expected);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should not remove numbers from the string', function () {
|
|
34
|
-
const modelName = 'Type1-Model_2';
|
|
35
|
-
const expected = 'type1model2';
|
|
36
|
-
expect(modelNameToModelKey(modelName)).to.be.eq(expected);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should throw an error for an empty string', function () {
|
|
40
|
-
const throwable = () => modelNameToModelKey('');
|
|
41
|
-
expect(throwable).to.throw(
|
|
42
|
-
'Model name must be a non-empty String ' +
|
|
43
|
-
'without spaces, but "" was given.',
|
|
44
|
-
);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should throw an error for a string with spaces', function () {
|
|
48
|
-
const throwable = () => modelNameToModelKey('user profile');
|
|
49
|
-
expect(throwable).to.throw(
|
|
50
|
-
'Model name must be a non-empty String ' +
|
|
51
|
-
'without spaces, but "user profile" was given.',
|
|
52
|
-
);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should throw an error for null', function () {
|
|
56
|
-
const throwable = () => modelNameToModelKey(null);
|
|
57
|
-
expect(throwable).to.throw(
|
|
58
|
-
'Model name must be a non-empty String ' +
|
|
59
|
-
'without spaces, but null was given.',
|
|
60
|
-
);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should throw an error for undefined', function () {
|
|
64
|
-
const throwable = () => modelNameToModelKey(undefined);
|
|
65
|
-
expect(throwable).to.throw(
|
|
66
|
-
'Model name must be a non-empty String ' +
|
|
67
|
-
'without spaces, but undefined was given.',
|
|
68
|
-
);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should throw an error for a number', function () {
|
|
72
|
-
const throwable = () => modelNameToModelKey(123);
|
|
73
|
-
expect(throwable).to.throw(
|
|
74
|
-
'Model name must be a non-empty String ' +
|
|
75
|
-
'without spaces, but 123 was given.',
|
|
76
|
-
);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should throw an error for an object', function () {
|
|
80
|
-
const throwable = () => modelNameToModelKey({name: 'test'});
|
|
81
|
-
expect(throwable).to.throw(
|
|
82
|
-
'Model name must be a non-empty String ' +
|
|
83
|
-
'without spaces, but Object was given.',
|
|
84
|
-
);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should throw an error for an array', function () {
|
|
88
|
-
const throwable = () => modelNameToModelKey(['test']);
|
|
89
|
-
expect(throwable).to.throw(
|
|
90
|
-
'Model name must be a non-empty String ' +
|
|
91
|
-
'without spaces, but Array was given.',
|
|
92
|
-
);
|
|
93
|
-
});
|
|
94
|
-
});
|