Browse Source

refactor: rollback

e22m4u 3 days ago
parent
commit
b8a17cb452
100 changed files with 2957 additions and 272 deletions
  1. 3 2
      .mocharc.json
  2. 164 123
      README.md
  3. 114 8
      dist/cjs/index.cjs
  4. 58 29
      eslint.config.js
  5. 0 7
      jsconfig.json
  6. 19 11
      package.json
  7. 16 0
      src/adapter/adapter-loader.d.ts
  8. 4 3
      src/adapter/adapter-loader.js
  9. 14 0
      src/adapter/adapter-registry.d.ts
  10. 153 0
      src/adapter/adapter.d.ts
  11. 5 8
      src/adapter/adapter.js
  12. 9 10
      src/adapter/adapter.spec.js
  13. 148 0
      src/adapter/builtin/memory-adapter.d.ts
  14. 7 8
      src/adapter/builtin/memory-adapter.js
  15. 2 5
      src/adapter/builtin/memory-adapter.spec.js
  16. 14 0
      src/adapter/decorator/data-sanitizing-decorator.d.ts
  17. 14 0
      src/adapter/decorator/default-values-decorator.d.ts
  18. 2 1
      src/adapter/decorator/default-values-decorator.spec.js
  19. 14 0
      src/adapter/decorator/fields-filtering-decorator.d.ts
  20. 14 0
      src/adapter/decorator/inclusion-decorator.d.ts
  21. 5 0
      src/adapter/decorator/index.d.ts
  22. 14 0
      src/adapter/decorator/property-uniqueness-decorator.d.ts
  23. 3 0
      src/adapter/index.d.ts
  24. 37 0
      src/database-schema.d.ts
  25. 2 1
      src/database-schema.js
  26. 17 5
      src/database-schema.spec.ts
  27. 14 0
      src/definition/datasource/datasource-definition-validator.d.ts
  28. 8 0
      src/definition/datasource/datasource-definition.d.ts
  29. 2 0
      src/definition/datasource/index.d.ts
  30. 50 0
      src/definition/definition-registry.d.ts
  31. 3 0
      src/definition/index.d.ts
  32. 6 0
      src/definition/model/index.d.ts
  33. 1 0
      src/definition/model/index.js
  34. 15 0
      src/definition/model/model-data-sanitizer.d.ts
  35. 180 0
      src/definition/model/model-definition-utils.d.ts
  36. 2 1
      src/definition/model/model-definition-utils.js
  37. 2 5
      src/definition/model/model-definition-utils.spec.js
  38. 14 0
      src/definition/model/model-definition-validator.d.ts
  39. 28 0
      src/definition/model/model-definition.d.ts
  40. 1 0
      src/definition/model/model-definition.js
  41. 16 0
      src/definition/model/properties/data-type.d.ts
  42. 6 0
      src/definition/model/properties/index.d.ts
  43. 1 0
      src/definition/model/properties/index.js
  44. 15 0
      src/definition/model/properties/primary-keys-definition-validator.d.ts
  45. 15 0
      src/definition/model/properties/properties-definition-validator.d.ts
  46. 23 0
      src/definition/model/properties/property-definition.d.ts
  47. 1 0
      src/definition/model/properties/property-definition.js
  48. 31 0
      src/definition/model/properties/property-uniqueness-validator.d.ts
  49. 14 0
      src/definition/model/properties/property-uniqueness.d.ts
  50. 3 0
      src/definition/model/relations/index.d.ts
  51. 1 0
      src/definition/model/relations/index.js
  52. 236 0
      src/definition/model/relations/relation-definition.d.ts
  53. 1 0
      src/definition/model/relations/relation-definition.js
  54. 14 0
      src/definition/model/relations/relation-type.d.ts
  55. 15 0
      src/definition/model/relations/relations-definition-validator.d.ts
  56. 5 4
      src/definition/model/relations/relations-definition-validator.js
  57. 3 0
      src/errors/index.d.ts
  58. 6 0
      src/errors/invalid-argument-error.d.ts
  59. 13 0
      src/errors/invalid-operator-value-error.d.ts
  60. 6 0
      src/errors/not-implemented-error.d.ts
  61. 38 0
      src/filter/fields-clause-tool.d.ts
  62. 348 0
      src/filter/filter-clause.d.ts
  63. 55 0
      src/filter/include-clause-tool.d.ts
  64. 6 8
      src/filter/include-clause-tool.js
  65. 7 0
      src/filter/index.d.ts
  66. 224 0
      src/filter/operator-clause-tool.d.ts
  67. 32 0
      src/filter/order-clause-tool.d.ts
  68. 30 0
      src/filter/slice-clause-tool.d.ts
  69. 23 0
      src/filter/where-clause-tool.d.ts
  70. 9 0
      src/index.d.ts
  71. 1 0
      src/index.js
  72. 46 0
      src/relations/belongs-to-resolver.d.ts
  73. 2 1
      src/relations/belongs-to-resolver.js
  74. 3 6
      src/relations/belongs-to-resolver.spec.js
  75. 67 0
      src/relations/has-many-resolver.d.ts
  76. 2 1
      src/relations/has-many-resolver.js
  77. 3 6
      src/relations/has-many-resolver.spec.js
  78. 67 0
      src/relations/has-one-resolver.d.ts
  79. 2 1
      src/relations/has-one-resolver.js
  80. 3 6
      src/relations/has-one-resolver.spec.js
  81. 4 0
      src/relations/index.d.ts
  82. 27 0
      src/relations/references-many-resolver.d.ts
  83. 2 1
      src/relations/references-many-resolver.js
  84. 3 6
      src/relations/references-many-resolver.spec.js
  85. 2 0
      src/repository/index.d.ts
  86. 29 0
      src/repository/repository-registry.d.ts
  87. 183 0
      src/repository/repository.d.ts
  88. 2 1
      src/repository/repository.js
  89. 43 0
      src/types.d.ts
  90. 1 0
      src/types.js
  91. 6 0
      src/utils/capitalize.d.ts
  92. 6 0
      src/utils/clone-deep.d.ts
  93. 10 0
      src/utils/exclude-object-keys.d.ts
  94. 12 0
      src/utils/get-value-by-path.d.ts
  95. 12 0
      src/utils/index.d.ts
  96. 10 0
      src/utils/is-deep-equal.d.ts
  97. 6 0
      src/utils/is-plain-object.d.ts
  98. 4 4
      src/utils/is-plain-object.js
  99. 10 0
      src/utils/is-promise.d.ts
  100. 14 0
      src/utils/like-to-regexp.d.ts

+ 3 - 2
.mocharc.json

@@ -1,4 +1,5 @@
 {
 {
-  "extension": ["js"],
-  "spec": "src/**/*.spec.js"
+  "extension": ["js", "ts"],
+  "spec": "src/**/*.spec.{js,ts}",
+  "require": ["ts-node/register"]
 }
 }

+ 164 - 123
README.md

@@ -40,6 +40,7 @@
   - [Has One (полиморфная)](#has-one-полиморфная-версия)
   - [Has One (полиморфная)](#has-one-полиморфная-версия)
   - [Has Many (полиморфная)](#has-many-полиморфная-версия)
   - [Has Many (полиморфная)](#has-many-полиморфная-версия)
 - [Расширение](#расширение)
 - [Расширение](#расширение)
+- [TypeScript](#typescript)
 - [Тесты](#тесты)
 - [Тесты](#тесты)
 - [Лицензия](#лицензия)
 - [Лицензия](#лицензия)
 
 
@@ -81,10 +82,10 @@ const {DatabaseSchema} = require('@e22m4u/js-repository');
 Кроме того, *модель* может определять классические связи «один к одному»,
 Кроме того, *модель* может определять классические связи «один к одному»,
 «один ко многим» и другие типы отношений между моделями.
 «один ко многим» и другие типы отношений между моделями.
 
 
-Непосредственно чтение и запись данных производятся с помощью *репозитория*,
+Непосредственно чтение и запись данных производится с помощью *репозитория*,
 который есть у каждой модели с объявленным *источником данных*. Репозиторий
 который есть у каждой модели с объявленным *источником данных*. Репозиторий
 может фильтровать запрашиваемые документы, выполнять валидацию свойств
 может фильтровать запрашиваемые документы, выполнять валидацию свойств
-согласно определению модели и встраивать связанные данные в результат
+согласно определению модели, и встраивать связанные данные в результат
 выборки.
 выборки.
 
 
 - *Источник данных* - определяет способ подключения к базе
 - *Источник данных* - определяет способ подключения к базе
@@ -256,36 +257,17 @@ console.log(cityWithCountry);
 
 
 ## Схема
 ## Схема
 
 
-Экземпляр класса `DatabaseSchema` хранит определения источников данных
-и моделей.
+Экземпляр класса `DatabaseSchema` хранит определения источников данных и моделей.
 
 
 **Методы**
 **Методы**
 
 
-Добавить источник
+- `defineDatasource(datasourceDef: object): this` - добавить источник
+- `defineModel(modelDef: object): this` - добавить модель
+- `getRepository(modelName: string): Repository` - получить репозиторий
 
 
-- `defineDatasource(datasourceDef)`
-  - `datasourceDef: object`: определение источника;
-  - результат: `this`;
-
-Добавить модель:
-
-- `defineModel(modelDef)`
-  - `modelDef: object`: определение модели;
-  - результат: `this`;
-
-Получить репозиторий
-
-- `getRepository(modelName)`
-  - `modelName: string` имя модели;
-  - результат: `Repository`;
-
-**Пример**
-
-Ниже приводится пошаговый пример настройки модели `product` и получения
-экземпляра репозитория, с помощью которого можно управлять данными этой
-коллекции.
+**Примеры**
 
 
-1\. Импорт класса и создание экземпляра схемы.
+Импорт класса и создание экземпляра схемы.
 
 
 ```js
 ```js
 import {DatabaseSchema} from '@e22m4u/js-repository';
 import {DatabaseSchema} from '@e22m4u/js-repository';
@@ -293,7 +275,7 @@ import {DatabaseSchema} from '@e22m4u/js-repository';
 const dbs = new DatabaseSchema();
 const dbs = new DatabaseSchema();
 ```
 ```
 
 
-2\. Определение нового источника.
+Определение нового источника.
 
 
 ```js
 ```js
 dbs.defineDatasource({
 dbs.defineDatasource({
@@ -302,7 +284,7 @@ dbs.defineDatasource({
 });
 });
 ```
 ```
 
 
-3\. Определение новой модели.
+Определение новой модели.
 
 
 ```js
 ```js
 dbs.defineModel({
 dbs.defineModel({
@@ -315,7 +297,7 @@ dbs.defineModel({
 });
 });
 ```
 ```
 
 
-4\. Получение репозитория по названию модели.
+Получение репозитория по названию модели.
 
 
 ```js
 ```js
 const productRep = dbs.getRepository('product');
 const productRep = dbs.getRepository('product');
@@ -388,7 +370,7 @@ dbs.defineModel({
 ## Свойства
 ## Свойства
 
 
 Параметр `properties` находится в определении модели и принимает объект, ключи
 Параметр `properties` находится в определении модели и принимает объект, ключи
-которого являются свойствами этой модели, а значениями тип свойства или объект
+которого являются свойствами этой модели, а значением тип свойства или объект
 с дополнительными параметрами.
 с дополнительными параметрами.
 
 
 **Тип данных**
 **Тип данных**
@@ -414,16 +396,15 @@ dbs.defineModel({
 
 
 **Параметр `unique`**
 **Параметр `unique`**
 
 
-Если значением параметра `unique` является `true` или `'strict'`,
-то выполняется строгая проверка на уникальность. В этом режиме
-[пустые значения](#Пустые-значения) так же подлежат проверке,
-где `null` и `undefined` также считаются значениями, которые
-должны быть уникальными.
+Если значением параметра `unique` является `true` или `'strict'`, то выполняется
+строгая проверка на уникальность. В этом режиме [пустые значения](#Пустые-значения)
+так же подлежат проверке, где `null` и `undefined` также считаются значениями,
+которые должны быть уникальными.
 
 
-Режим `'sparse'` проверяет только значения с полезной нагрузкой,
-исключая [пустые значения](#Пустые-значения), список которых отличается
-в зависимости от типа свойства. Например, для типа `string` пустыми
-значениями будут `undefined`, `null` и `''` (пустая строка).
+Режим `'sparse'` проверяет только значения с полезной нагрузкой, исключая
+[пустые значения](#Пустые-значения), список которых отличается в зависимости
+от типа свойства. Например, для типа `string` пустым значением будет `undefined`,
+`null` и `''` (пустая строка).
 
 
 - `unique: true | 'strict'` строгая проверка на уникальность
 - `unique: true | 'strict'` строгая проверка на уникальность
 - `unique: 'sparse'` исключить из проверки [пустые значения](#Пустые-значения)
 - `unique: 'sparse'` исключить из проверки [пустые значения](#Пустые-значения)
@@ -522,15 +503,26 @@ dbs.defineModel({
 **EmptyValuesService**
 **EmptyValuesService**
 
 
 Для переопределения пустых значений необходимо получить экземпляр класса
 Для переопределения пустых значений необходимо получить экземпляр класса
-`EmptyValuesService` из контейнера схемы и вызвать метод `setEmptyValuesOf`,
-который принимает тип данных и массив новых значений.
-
-Сигнатура:
-
-- `setEmptyValuesOf(dataType, emptyValues)`
-  - `dataType: DataType`: строковый литерал типа;
-  - `emptyValues: *[]`: массив новых значений;
-  - результат: `this`;
+`EmptyValuesService` из контейнера схемы и вызвать метод, который принимает
+тип данных и массив новых значений.
+
+Интерфейс:
+
+```ts
+class EmptyValuesService {
+  /**
+   * Установить пустые значения
+   * для определенного типа данных.
+   * 
+   * @param dataType    Тип данных.
+   * @param emptyValues Массив новых пустых значений.
+   */
+  setEmptyValuesOf(
+    dataType: DataType,
+    emptyValues: unknown[],
+  ): this;
+}
+```
 
 
 **Пример**
 **Пример**
 
 
@@ -563,24 +555,24 @@ emptyValuesService.setEmptyValuesOf(DataType.NUMBER, [undefined, null]);
 
 
 **Методы**
 **Методы**
 
 
-- [`create(data, [filter])`](#repositorycreate) создать новый документ;
-- [`replaceById(id, data, [filter])`](#repositoryreplacebyid) заменить документ полностью;
-- [`replaceOrCreate(data, [filter])`](#repositoryreplaceorcreate) заменить или создать новый;
-- [`patchById(id, data, [filter])`](#repositorypatchbyid) обновить документ частично;
-- [`patch(data, [where])`](#repositorypatch) обновить все документы или по условию;
-- [`find([filter])`](#repositoryfind) найти все документы или по условию;
-- [`findOne([filter])`](#repositoryfindone) найти первый документ или по условию;
-- [`findById(id, [filter])`](#repositoryfindbyid) найти документ по идентификатору;
-- [`delete([where])`](#repositorydelete) удалить все документы или по условию;
+- [`create(data, filter = undefined)`](#repositorycreate) создать новый документ;
+- [`replaceById(id, data, filter = undefined)`](#repositoryreplacebyid) заменить документ полностью;
+- [`replaceOrCreate(data, filter = undefined)`](#repositoryreplaceorcreate) заменить или создать новый;
+- [`patchById(id, data, filter = undefined)`](#repositorypatchbyid) обновить документ частично;
+- [`patch(data, where = undefined)`](#repositorypatch) обновить все документы или по условию;
+- [`find(filter = undefined)`](#repositoryfind) найти все документы или по условию;
+- [`findOne(filter = undefined)`](#repositoryfindone) найти первый документ или по условию;
+- [`findById(id, filter = undefined)`](#repositoryfindbyid) найти документ по идентификатору;
+- [`delete(where = undefined)`](#repositorydelete) удалить все документы или по условию;
 - [`deleteById(id)`](#repositorydeletebyid) удалить документ по идентификатору;
 - [`deleteById(id)`](#repositorydeletebyid) удалить документ по идентификатору;
 - [`exists(id)`](#repositoryexists) проверить существование по идентификатору;
 - [`exists(id)`](#repositoryexists) проверить существование по идентификатору;
-- [`count([where])`](#repositorycount) подсчет всех документов или по условию;
+- [`count(where = undefined)`](#repositorycount) подсчет всех документов или по условию;
 
 
 **Аргументы**
 **Аргументы**
 
 
 - `id: number|string` идентификатор (первичный ключ)
 - `id: number|string` идентификатор (первичный ключ)
 - `data: object` данные документа (используется при записи)
 - `data: object` данные документа (используется при записи)
-- `where: object` условия выборки (см. [`where`](#where))
+- `where: object` условия фильтрации (см. [Фильтрация](#Фильтрация))
 - `filter: object` параметры выборки (см. [Фильтрация](#Фильтрация))
 - `filter: object` параметры выборки (см. [Фильтрация](#Фильтрация))
 
 
 **Получение репозитория**
 **Получение репозитория**
@@ -620,10 +612,12 @@ const modelRep = dbs.getRepository('myModel');
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `create(data, [filter])`
-  - `data: object`: данные нового документа;
-  - `filter?: object`: настройки выборки (см. [Фильтрация](#фильтрация));
-  - результат: `Promise<object>`;
+```ts
+create(
+  data: WithOptionalId<FlatData, IdName>,
+  filter?: ItemFilterClause<FlatData>,
+): Promise<FlatData>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -684,11 +678,13 @@ console.log(product);
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `replaceById(id, data, [filter])`
-  - `id: number|string`: идентификатор документа;
-  - `data: object`: новые данные;
-  - `filter?: object`: настройки выборки (см. [Фильтрация](#фильтрация));
-  - результат: `Promise<object>`;
+```ts
+replaceById(
+  id: IdType,
+  data: WithoutId<FlatData, IdName>,
+  filter?: ItemFilterClause<FlatData>,
+): Promise<FlatData>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -724,10 +720,12 @@ console.log(updatedProduct);
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `replaceOrCreate(data, [filter])`
-  - `data: object`: данные документа;
-  - `filter?: object`: настройки выборки (см. [Фильтрация](#фильтрация));
-  - результат: `Promise<object>`;
+```ts
+replaceOrCreate(
+  data: WithOptionalId<FlatData, IdName>,
+  filter?: ItemFilterClause<FlatData>,
+): Promise<FlatData>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -770,11 +768,13 @@ console.log(updatedProduct);
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `patchById(id, data, [filter])`
-  - `id: number|string`: идентификатор обновляемого документа;
-  - `data: object`: новые данные;
-  - `filter?: object`: настройки выборки (см. [Фильтрация](#фильтрация));
-  - результат: `Promise<object>`;
+```ts
+patchById(
+  id: IdType,
+  data: PartialWithoutId<FlatData, IdName>,
+  filter?: ItemFilterClause<FlatData>,
+): Promise<FlatData>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -808,10 +808,12 @@ console.log(updatedProduct);
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `patch(data, [where])`
-  - `data: object`: новые данные;
-  - `where?: object`: условия выборки (см. [`where`](#where));
-  - результат: `Promise<number>`;
+```ts
+patch(
+  data: PartialWithoutId<FlatData, IdName>,
+  where?: WhereClause<FlatData>,
+): Promise<number>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -841,9 +843,9 @@ const totalCount = await productRep.patch({
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `find([filter])`
-  - `filter?: object`: настройки выборки (см. [Фильтрация](#фильтрация));
-  - результат: `Promise<object[]>`;
+```ts
+find(filter?: FilterClause<FlatData>): Promise<FlatData[]>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -877,9 +879,11 @@ const latestProducts = await productRep.find({
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `findOne([filter])`
-  - `filter?: object`: настройки выборки (см. [Фильтрация](#фильтрация));
-  - результат: `Promise<object|undefined>`;
+```ts
+findOne(
+  filter?: FilterClause<FlatData>,
+): Promise<FlatData | undefined>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -910,10 +914,12 @@ if (!product) {
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `findById(id, [filter])`
-  - `id: number|string`: идентификатор документа;
-  - `filter?: object`: настройки выборки (см. [Фильтрация](#фильтрация));
-  - результат: `Promise<object|undefined>`;
+```ts
+findById(
+  id: IdType,
+  filter?: ItemFilterClause<FlatData>,
+): Promise<FlatData>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -944,9 +950,9 @@ const product = await productRep.findById(1, {
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `delete([where])`
-  - `where?: object`: условия выборки (см. [`where`](#where));
-  - результат: `Promise<number>`;
+```ts
+delete(where?: WhereClause<FlatData>): Promise<number>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -971,15 +977,9 @@ const totalCount = await productRep.delete();
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `deleteById(id)`
-  - `id: number|string`: идентификатор документа;
-  - результат: `Promise<boolean>`;
-
-Результат:
-
-- `Promise<boolean>`: логическое значение;
-  - `true`: документ был найден и удален;
-  - `false`: документ не найден;
+```ts
+deleteById(id: IdType): Promise<boolean>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -1001,15 +1001,9 @@ if (wasDeleted) {
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `exists(id)`
-  - `id: number|string`: идентификатор документа;
-  - результат: `Promise<boolean>`;
-
-Результат:
-
-- `Promise<boolean>`: логическое значение;
-  - `true`: документ с таким идентификатором найден;
-  - `false`: идентификатор не найден;
+```ts
+exists(id: IdType): Promise<boolean>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -1029,9 +1023,9 @@ if (productExists) {
 
 
 Сигнатура:
 Сигнатура:
 
 
-- `count([where])`
-  - `where?: object`: условия выборки (см. [`where`](#where));
-  - результат: `Promise<number>`;
+```ts
+count(where?: WhereClause<FlatData>): Promise<number>;
+```
 
 
 **Примеры**
 **Примеры**
 
 
@@ -1051,10 +1045,10 @@ const totalCount = await productRep.count();
 
 
 ## Фильтрация
 ## Фильтрация
 
 
-Некоторые методы репозитория принимают объект настроек возвращаемого
-результата. Максимально широкий набор таких настроек имеет первый
-параметр метода `find`, где ожидается объект, содержащий набор
-опций указанных ниже.
+Некоторые методы репозитория принимают объект настроек, влияющий
+на возвращаемый результат. Максимально широкий набор таких настроек
+имеет первый параметр метода `find`, где ожидается объект содержащий
+набор опций указанных ниже.
 
 
 - `where: object` условия фильтрации по свойствам документа;
 - `where: object` условия фильтрации по свойствам документа;
 - `order: string|string[]` сортировка по указанным свойствам;
 - `order: string|string[]` сортировка по указанным свойствам;
@@ -1923,7 +1917,7 @@ dbs.defineModel({
 
 
 #### Has One (полиморфная версия)
 #### Has One (полиморфная версия)
 
 
-Обратная сторона полиморфной связи `belongsTo` по принципу *"один к одному"*.
+Обратная сторона полиморфная связи `belongsTo` по принципу *"один к одному"*.
 
 
 ```
 ```
     Текущая (company)  <───────┐      Целевая (license)
     Текущая (company)  <───────┐      Целевая (license)
@@ -1990,7 +1984,7 @@ dbs.defineModel({
 
 
 #### Has Many (полиморфная версия)
 #### Has Many (полиморфная версия)
 
 
-Обратная сторона полиморфной связи `belongsTo` по принципу *"один ко многим"*.
+Обратная сторона полиморфная связи `belongsTo` по принципу *"один ко многим"*.
 
 
 ```
 ```
     Текущая (letter)  <─────────┐      Целевая (file)
     Текущая (letter)  <─────────┐      Целевая (file)
@@ -2103,9 +2097,56 @@ const rep = dbs.getRepository('model');
 console.log(rep instanceof MyRepository); // true
 console.log(rep instanceof MyRepository); // true
 ```
 ```
 
 
-*i. Так как экземпляры репозитория кэшируются, то замену конструктора
+*i. Так как экземпляры репозитория кэшируется, то замену конструктора
 следует выполнять до обращения к методу `getRepository`.*
 следует выполнять до обращения к методу `getRepository`.*
 
 
+## TypeScript
+
+Получение типизированного репозитория с указанием интерфейса модели.
+
+```ts
+import {DataType} from '@e22m4u/js-repository';
+import {RelationType} from '@e22m4u/js-repository';
+import {DatabaseSchema} from '@e22m4u/js-repository';
+
+// const dbs = new DatabaseSchema();
+// dbs.defineDatasource ...
+
+// определение модели "city"
+dbs.defineModel({
+  name: 'city',
+  datasource: 'myDatasource',
+  properties: {
+    name: DataType.STRING,
+    timeZone: DataType.STRING,
+  },
+});
+
+// определение интерфейса "city"
+interface City {
+  id: number;
+  name?: string;
+  timeZone?: string;
+}
+
+// при получении репозитория нужной модели
+// можно указать тип документов
+const cityRep = dbs.getRepository<City>('city');
+
+// теперь, методы репозитория возвращают
+// тип City вместо Record<string, unknown>
+const city: City = await cityRep.create({
+  name: 'Moscow',
+  timeZone: 'Europe/Moscow',
+});
+```
+
+Для определения моделей с помощью TypeScript классов,
+рекомендуется использовать специальную версию данного модуля
+[@e22m4u/ts-repository](https://www.npmjs.com/package/@e22m4u/ts-repository),
+поставляемую с набором TypeScript декораторов и дополнительных
+инструментов для работы в TypeScript окружении.
+
 ## Тесты
 ## Тесты
 
 
 ```bash
 ```bash

+ 114 - 8
dist/cjs/index.cjs

@@ -1,3 +1,4 @@
+"use strict";
 var __create = Object.create;
 var __create = Object.create;
 var __defProp = Object.defineProperty;
 var __defProp = Object.defineProperty;
 var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
 var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -45,6 +46,7 @@ function isPromise(value) {
 }
 }
 var init_is_promise = __esm({
 var init_is_promise = __esm({
   "src/utils/is-promise.js"() {
   "src/utils/is-promise.js"() {
+    "use strict";
     __name(isPromise, "isPromise");
     __name(isPromise, "isPromise");
   }
   }
 });
 });
@@ -56,6 +58,7 @@ function capitalize(string) {
 }
 }
 var init_capitalize = __esm({
 var init_capitalize = __esm({
   "src/utils/capitalize.js"() {
   "src/utils/capitalize.js"() {
+    "use strict";
     __name(capitalize, "capitalize");
     __name(capitalize, "capitalize");
   }
   }
 });
 });
@@ -99,6 +102,7 @@ function cloneDeep(value) {
 }
 }
 var init_clone_deep = __esm({
 var init_clone_deep = __esm({
   "src/utils/clone-deep.js"() {
   "src/utils/clone-deep.js"() {
+    "use strict";
     __name(cloneDeep, "cloneDeep");
     __name(cloneDeep, "cloneDeep");
   }
   }
 });
 });
@@ -122,6 +126,7 @@ function singularize(noun) {
 }
 }
 var init_singularize = __esm({
 var init_singularize = __esm({
   "src/utils/singularize.js"() {
   "src/utils/singularize.js"() {
+    "use strict";
     __name(singularize, "singularize");
     __name(singularize, "singularize");
   }
   }
 });
 });
@@ -170,6 +175,7 @@ function isDeepEqual(firstValue, secondValue) {
 }
 }
 var init_is_deep_equal = __esm({
 var init_is_deep_equal = __esm({
   "src/utils/is-deep-equal.js"() {
   "src/utils/is-deep-equal.js"() {
+    "use strict";
     __name(isDeepEqual, "isDeepEqual");
     __name(isDeepEqual, "isDeepEqual");
   }
   }
 });
 });
@@ -178,6 +184,7 @@ var init_is_deep_equal = __esm({
 var import_js_format, _NotImplementedError, NotImplementedError;
 var import_js_format, _NotImplementedError, NotImplementedError;
 var init_not_implemented_error = __esm({
 var init_not_implemented_error = __esm({
   "src/errors/not-implemented-error.js"() {
   "src/errors/not-implemented-error.js"() {
+    "use strict";
     import_js_format = require("@e22m4u/js-format");
     import_js_format = require("@e22m4u/js-format");
     _NotImplementedError = class _NotImplementedError extends import_js_format.Errorf {
     _NotImplementedError = class _NotImplementedError extends import_js_format.Errorf {
     };
     };
@@ -190,6 +197,7 @@ var init_not_implemented_error = __esm({
 var import_js_format2, _InvalidArgumentError, InvalidArgumentError;
 var import_js_format2, _InvalidArgumentError, InvalidArgumentError;
 var init_invalid_argument_error = __esm({
 var init_invalid_argument_error = __esm({
   "src/errors/invalid-argument-error.js"() {
   "src/errors/invalid-argument-error.js"() {
+    "use strict";
     import_js_format2 = require("@e22m4u/js-format");
     import_js_format2 = require("@e22m4u/js-format");
     _InvalidArgumentError = class _InvalidArgumentError extends import_js_format2.Errorf {
     _InvalidArgumentError = class _InvalidArgumentError extends import_js_format2.Errorf {
     };
     };
@@ -202,6 +210,7 @@ var init_invalid_argument_error = __esm({
 var import_js_format3, _InvalidOperatorValueError, InvalidOperatorValueError;
 var import_js_format3, _InvalidOperatorValueError, InvalidOperatorValueError;
 var init_invalid_operator_value_error = __esm({
 var init_invalid_operator_value_error = __esm({
   "src/errors/invalid-operator-value-error.js"() {
   "src/errors/invalid-operator-value-error.js"() {
+    "use strict";
     import_js_format3 = require("@e22m4u/js-format");
     import_js_format3 = require("@e22m4u/js-format");
     _InvalidOperatorValueError = class _InvalidOperatorValueError extends Error {
     _InvalidOperatorValueError = class _InvalidOperatorValueError extends Error {
       /**
       /**
@@ -230,6 +239,7 @@ var init_invalid_operator_value_error = __esm({
 // src/errors/index.js
 // src/errors/index.js
 var init_errors = __esm({
 var init_errors = __esm({
   "src/errors/index.js"() {
   "src/errors/index.js"() {
+    "use strict";
     init_not_implemented_error();
     init_not_implemented_error();
     init_invalid_argument_error();
     init_invalid_argument_error();
     init_invalid_operator_value_error();
     init_invalid_operator_value_error();
@@ -271,6 +281,7 @@ function likeToRegexp(pattern, isCaseInsensitive = false) {
 }
 }
 var init_like_to_regexp = __esm({
 var init_like_to_regexp = __esm({
   "src/utils/like-to-regexp.js"() {
   "src/utils/like-to-regexp.js"() {
+    "use strict";
     init_errors();
     init_errors();
     __name(likeToRegexp, "likeToRegexp");
     __name(likeToRegexp, "likeToRegexp");
   }
   }
@@ -284,6 +295,7 @@ function isPlainObject(value) {
 }
 }
 var init_is_plain_object = __esm({
 var init_is_plain_object = __esm({
   "src/utils/is-plain-object.js"() {
   "src/utils/is-plain-object.js"() {
+    "use strict";
     __name(isPlainObject, "isPlainObject");
     __name(isPlainObject, "isPlainObject");
   }
   }
 });
 });
@@ -297,6 +309,7 @@ function stringToRegexp(pattern, flags = void 0) {
 }
 }
 var init_string_to_regexp = __esm({
 var init_string_to_regexp = __esm({
   "src/utils/string-to-regexp.js"() {
   "src/utils/string-to-regexp.js"() {
+    "use strict";
     __name(stringToRegexp, "stringToRegexp");
     __name(stringToRegexp, "stringToRegexp");
   }
   }
 });
 });
@@ -319,6 +332,7 @@ function getValueByPath(obj, path, orElse = void 0) {
 }
 }
 var init_get_value_by_path = __esm({
 var init_get_value_by_path = __esm({
   "src/utils/get-value-by-path.js"() {
   "src/utils/get-value-by-path.js"() {
+    "use strict";
     __name(getValueByPath, "getValueByPath");
     __name(getValueByPath, "getValueByPath");
   }
   }
 });
 });
@@ -351,6 +365,7 @@ function selectObjectKeys(obj, keys) {
 }
 }
 var init_select_object_keys = __esm({
 var init_select_object_keys = __esm({
   "src/utils/select-object-keys.js"() {
   "src/utils/select-object-keys.js"() {
+    "use strict";
     init_errors();
     init_errors();
     __name(selectObjectKeys, "selectObjectKeys");
     __name(selectObjectKeys, "selectObjectKeys");
   }
   }
@@ -370,6 +385,7 @@ function excludeObjectKeys(obj, keys) {
 }
 }
 var init_exclude_object_keys = __esm({
 var init_exclude_object_keys = __esm({
   "src/utils/exclude-object-keys.js"() {
   "src/utils/exclude-object-keys.js"() {
+    "use strict";
     init_errors();
     init_errors();
     __name(excludeObjectKeys, "excludeObjectKeys");
     __name(excludeObjectKeys, "excludeObjectKeys");
   }
   }
@@ -386,6 +402,7 @@ function modelNameToModelKey(modelName) {
 }
 }
 var init_model_name_to_model_key = __esm({
 var init_model_name_to_model_key = __esm({
   "src/utils/model-name-to-model-key.js"() {
   "src/utils/model-name-to-model-key.js"() {
+    "use strict";
     init_errors();
     init_errors();
     __name(modelNameToModelKey, "modelNameToModelKey");
     __name(modelNameToModelKey, "modelNameToModelKey");
   }
   }
@@ -394,6 +411,7 @@ var init_model_name_to_model_key = __esm({
 // src/utils/index.js
 // src/utils/index.js
 var init_utils = __esm({
 var init_utils = __esm({
   "src/utils/index.js"() {
   "src/utils/index.js"() {
+    "use strict";
     init_is_promise();
     init_is_promise();
     init_capitalize();
     init_capitalize();
     init_clone_deep();
     init_clone_deep();
@@ -413,6 +431,7 @@ var init_utils = __esm({
 var import_js_service, _SliceClauseTool, SliceClauseTool;
 var import_js_service, _SliceClauseTool, SliceClauseTool;
 var init_slice_clause_tool = __esm({
 var init_slice_clause_tool = __esm({
   "src/filter/slice-clause-tool.js"() {
   "src/filter/slice-clause-tool.js"() {
+    "use strict";
     import_js_service = require("@e22m4u/js-service");
     import_js_service = require("@e22m4u/js-service");
     init_errors();
     init_errors();
     _SliceClauseTool = class _SliceClauseTool extends import_js_service.Service {
     _SliceClauseTool = class _SliceClauseTool extends import_js_service.Service {
@@ -495,6 +514,7 @@ function compareFn(a, b) {
 var import_js_service2, _OrderClauseTool, OrderClauseTool;
 var import_js_service2, _OrderClauseTool, OrderClauseTool;
 var init_order_clause_tool = __esm({
 var init_order_clause_tool = __esm({
   "src/filter/order-clause-tool.js"() {
   "src/filter/order-clause-tool.js"() {
+    "use strict";
     import_js_service2 = require("@e22m4u/js-service");
     import_js_service2 = require("@e22m4u/js-service");
     init_utils();
     init_utils();
     init_errors();
     init_errors();
@@ -573,6 +593,7 @@ var init_order_clause_tool = __esm({
 var import_js_service3, _OperatorClauseTool, OperatorClauseTool;
 var import_js_service3, _OperatorClauseTool, OperatorClauseTool;
 var init_operator_clause_tool = __esm({
 var init_operator_clause_tool = __esm({
   "src/filter/operator-clause-tool.js"() {
   "src/filter/operator-clause-tool.js"() {
+    "use strict";
     import_js_service3 = require("@e22m4u/js-service");
     import_js_service3 = require("@e22m4u/js-service");
     init_utils();
     init_utils();
     init_errors();
     init_errors();
@@ -1034,6 +1055,7 @@ var init_operator_clause_tool = __esm({
 var import_js_service4, _WhereClauseTool, WhereClauseTool;
 var import_js_service4, _WhereClauseTool, WhereClauseTool;
 var init_where_clause_tool = __esm({
 var init_where_clause_tool = __esm({
   "src/filter/where-clause-tool.js"() {
   "src/filter/where-clause-tool.js"() {
+    "use strict";
     import_js_service4 = require("@e22m4u/js-service");
     import_js_service4 = require("@e22m4u/js-service");
     init_errors();
     init_errors();
     init_operator_clause_tool();
     init_operator_clause_tool();
@@ -1179,6 +1201,7 @@ var init_where_clause_tool = __esm({
 var RelationType;
 var RelationType;
 var init_relation_type = __esm({
 var init_relation_type = __esm({
   "src/definition/model/relations/relation-type.js"() {
   "src/definition/model/relations/relation-type.js"() {
+    "use strict";
     RelationType = {
     RelationType = {
       BELONGS_TO: "belongsTo",
       BELONGS_TO: "belongsTo",
       HAS_ONE: "hasOne",
       HAS_ONE: "hasOne",
@@ -1188,12 +1211,21 @@ var init_relation_type = __esm({
   }
   }
 });
 });
 
 
+// src/definition/model/relations/relation-definition.js
+var init_relation_definition = __esm({
+  "src/definition/model/relations/relation-definition.js"() {
+    "use strict";
+  }
+});
+
 // src/definition/model/relations/relations-definition-validator.js
 // src/definition/model/relations/relations-definition-validator.js
 var import_js_service5, _RelationsDefinitionValidator, RelationsDefinitionValidator;
 var import_js_service5, _RelationsDefinitionValidator, RelationsDefinitionValidator;
 var init_relations_definition_validator = __esm({
 var init_relations_definition_validator = __esm({
   "src/definition/model/relations/relations-definition-validator.js"() {
   "src/definition/model/relations/relations-definition-validator.js"() {
+    "use strict";
     import_js_service5 = require("@e22m4u/js-service");
     import_js_service5 = require("@e22m4u/js-service");
     init_relation_type();
     init_relation_type();
+    init_relation_type();
     init_errors();
     init_errors();
     _RelationsDefinitionValidator = class _RelationsDefinitionValidator extends import_js_service5.Service {
     _RelationsDefinitionValidator = class _RelationsDefinitionValidator extends import_js_service5.Service {
       /**
       /**
@@ -1580,7 +1612,9 @@ var init_relations_definition_validator = __esm({
 // src/definition/model/relations/index.js
 // src/definition/model/relations/index.js
 var init_relations = __esm({
 var init_relations = __esm({
   "src/definition/model/relations/index.js"() {
   "src/definition/model/relations/index.js"() {
+    "use strict";
     init_relation_type();
     init_relation_type();
+    init_relation_definition();
     init_relations_definition_validator();
     init_relations_definition_validator();
   }
   }
 });
 });
@@ -1589,6 +1623,7 @@ var init_relations = __esm({
 var DataType;
 var DataType;
 var init_data_type = __esm({
 var init_data_type = __esm({
   "src/definition/model/properties/data-type.js"() {
   "src/definition/model/properties/data-type.js"() {
+    "use strict";
     DataType = {
     DataType = {
       ANY: "any",
       ANY: "any",
       STRING: "string",
       STRING: "string",
@@ -1600,10 +1635,18 @@ var init_data_type = __esm({
   }
   }
 });
 });
 
 
+// src/definition/model/properties/property-definition.js
+var init_property_definition = __esm({
+  "src/definition/model/properties/property-definition.js"() {
+    "use strict";
+  }
+});
+
 // src/definition/model/properties/property-uniqueness.js
 // src/definition/model/properties/property-uniqueness.js
 var PropertyUniqueness;
 var PropertyUniqueness;
 var init_property_uniqueness = __esm({
 var init_property_uniqueness = __esm({
   "src/definition/model/properties/property-uniqueness.js"() {
   "src/definition/model/properties/property-uniqueness.js"() {
+    "use strict";
     PropertyUniqueness = {
     PropertyUniqueness = {
       STRICT: "strict",
       STRICT: "strict",
       SPARSE: "sparse",
       SPARSE: "sparse",
@@ -1616,6 +1659,7 @@ var init_property_uniqueness = __esm({
 var import_js_service6, _DefinitionRegistry, DefinitionRegistry;
 var import_js_service6, _DefinitionRegistry, DefinitionRegistry;
 var init_definition_registry = __esm({
 var init_definition_registry = __esm({
   "src/definition/definition-registry.js"() {
   "src/definition/definition-registry.js"() {
+    "use strict";
     import_js_service6 = require("@e22m4u/js-service");
     import_js_service6 = require("@e22m4u/js-service");
     init_utils();
     init_utils();
     init_errors();
     init_errors();
@@ -1718,12 +1762,14 @@ var init_definition_registry = __esm({
 var import_js_service7, import_js_empty_values, DEFAULT_PRIMARY_KEY_PROPERTY_NAME, _ModelDefinitionUtils, ModelDefinitionUtils;
 var import_js_service7, import_js_empty_values, DEFAULT_PRIMARY_KEY_PROPERTY_NAME, _ModelDefinitionUtils, ModelDefinitionUtils;
 var init_model_definition_utils = __esm({
 var init_model_definition_utils = __esm({
   "src/definition/model/model-definition-utils.js"() {
   "src/definition/model/model-definition-utils.js"() {
+    "use strict";
     import_js_service7 = require("@e22m4u/js-service");
     import_js_service7 = require("@e22m4u/js-service");
     init_properties();
     init_properties();
+    init_utils();
+    init_utils();
     import_js_empty_values = require("@e22m4u/js-empty-values");
     import_js_empty_values = require("@e22m4u/js-empty-values");
     init_errors();
     init_errors();
     init_definition_registry();
     init_definition_registry();
-    init_utils();
     DEFAULT_PRIMARY_KEY_PROPERTY_NAME = "id";
     DEFAULT_PRIMARY_KEY_PROPERTY_NAME = "id";
     _ModelDefinitionUtils = class _ModelDefinitionUtils extends import_js_service7.Service {
     _ModelDefinitionUtils = class _ModelDefinitionUtils extends import_js_service7.Service {
       /**
       /**
@@ -2130,6 +2176,7 @@ var init_model_definition_utils = __esm({
 var import_js_service8, import_js_empty_values2, _PropertyUniquenessValidator, PropertyUniquenessValidator;
 var import_js_service8, import_js_empty_values2, _PropertyUniquenessValidator, PropertyUniquenessValidator;
 var init_property_uniqueness_validator = __esm({
 var init_property_uniqueness_validator = __esm({
   "src/definition/model/properties/property-uniqueness-validator.js"() {
   "src/definition/model/properties/property-uniqueness-validator.js"() {
+    "use strict";
     init_data_type();
     init_data_type();
     import_js_service8 = require("@e22m4u/js-service");
     import_js_service8 = require("@e22m4u/js-service");
     init_utils();
     init_utils();
@@ -2249,6 +2296,7 @@ var init_property_uniqueness_validator = __esm({
 var import_js_service9, _PrimaryKeysDefinitionValidator, PrimaryKeysDefinitionValidator;
 var import_js_service9, _PrimaryKeysDefinitionValidator, PrimaryKeysDefinitionValidator;
 var init_primary_keys_definition_validator = __esm({
 var init_primary_keys_definition_validator = __esm({
   "src/definition/model/properties/primary-keys-definition-validator.js"() {
   "src/definition/model/properties/primary-keys-definition-validator.js"() {
+    "use strict";
     import_js_service9 = require("@e22m4u/js-service");
     import_js_service9 = require("@e22m4u/js-service");
     init_errors();
     init_errors();
     init_model_definition_utils();
     init_model_definition_utils();
@@ -2300,6 +2348,7 @@ var init_primary_keys_definition_validator = __esm({
 var import_js_service10, _PropertiesDefinitionValidator, PropertiesDefinitionValidator;
 var import_js_service10, _PropertiesDefinitionValidator, PropertiesDefinitionValidator;
 var init_properties_definition_validator = __esm({
 var init_properties_definition_validator = __esm({
   "src/definition/model/properties/properties-definition-validator.js"() {
   "src/definition/model/properties/properties-definition-validator.js"() {
+    "use strict";
     import_js_service10 = require("@e22m4u/js-service");
     import_js_service10 = require("@e22m4u/js-service");
     init_data_type();
     init_data_type();
     init_utils();
     init_utils();
@@ -2523,7 +2572,9 @@ var init_properties_definition_validator = __esm({
 // src/definition/model/properties/index.js
 // src/definition/model/properties/index.js
 var init_properties = __esm({
 var init_properties = __esm({
   "src/definition/model/properties/index.js"() {
   "src/definition/model/properties/index.js"() {
+    "use strict";
     init_data_type();
     init_data_type();
+    init_property_definition();
     init_property_uniqueness();
     init_property_uniqueness();
     init_property_uniqueness_validator();
     init_property_uniqueness_validator();
     init_properties_definition_validator();
     init_properties_definition_validator();
@@ -2531,10 +2582,18 @@ var init_properties = __esm({
   }
   }
 });
 });
 
 
+// src/definition/model/model-definition.js
+var init_model_definition = __esm({
+  "src/definition/model/model-definition.js"() {
+    "use strict";
+  }
+});
+
 // src/definition/model/model-data-sanitizer.js
 // src/definition/model/model-data-sanitizer.js
 var import_js_service11, _ModelDataSanitizer, ModelDataSanitizer;
 var import_js_service11, _ModelDataSanitizer, ModelDataSanitizer;
 var init_model_data_sanitizer = __esm({
 var init_model_data_sanitizer = __esm({
   "src/definition/model/model-data-sanitizer.js"() {
   "src/definition/model/model-data-sanitizer.js"() {
+    "use strict";
     import_js_service11 = require("@e22m4u/js-service");
     import_js_service11 = require("@e22m4u/js-service");
     init_errors();
     init_errors();
     init_model_definition_utils();
     init_model_definition_utils();
@@ -2571,6 +2630,7 @@ var init_model_data_sanitizer = __esm({
 var import_js_service12, _ModelDefinitionValidator, ModelDefinitionValidator;
 var import_js_service12, _ModelDefinitionValidator, ModelDefinitionValidator;
 var init_model_definition_validator = __esm({
 var init_model_definition_validator = __esm({
   "src/definition/model/model-definition-validator.js"() {
   "src/definition/model/model-definition-validator.js"() {
+    "use strict";
     import_js_service12 = require("@e22m4u/js-service");
     import_js_service12 = require("@e22m4u/js-service");
     init_errors();
     init_errors();
     init_relations();
     init_relations();
@@ -2646,8 +2706,10 @@ var init_model_definition_validator = __esm({
 // src/definition/model/index.js
 // src/definition/model/index.js
 var init_model = __esm({
 var init_model = __esm({
   "src/definition/model/index.js"() {
   "src/definition/model/index.js"() {
+    "use strict";
     init_relations();
     init_relations();
     init_properties();
     init_properties();
+    init_model_definition();
     init_model_data_sanitizer();
     init_model_data_sanitizer();
     init_model_definition_utils();
     init_model_definition_utils();
     init_model_definition_validator();
     init_model_definition_validator();
@@ -2658,6 +2720,7 @@ var init_model = __esm({
 var import_js_service13, _DatasourceDefinitionValidator, DatasourceDefinitionValidator;
 var import_js_service13, _DatasourceDefinitionValidator, DatasourceDefinitionValidator;
 var init_datasource_definition_validator = __esm({
 var init_datasource_definition_validator = __esm({
   "src/definition/datasource/datasource-definition-validator.js"() {
   "src/definition/datasource/datasource-definition-validator.js"() {
+    "use strict";
     import_js_service13 = require("@e22m4u/js-service");
     import_js_service13 = require("@e22m4u/js-service");
     init_errors();
     init_errors();
     _DatasourceDefinitionValidator = class _DatasourceDefinitionValidator extends import_js_service13.Service {
     _DatasourceDefinitionValidator = class _DatasourceDefinitionValidator extends import_js_service13.Service {
@@ -2693,6 +2756,7 @@ var init_datasource_definition_validator = __esm({
 // src/definition/datasource/index.js
 // src/definition/datasource/index.js
 var init_datasource = __esm({
 var init_datasource = __esm({
   "src/definition/datasource/index.js"() {
   "src/definition/datasource/index.js"() {
+    "use strict";
     init_datasource_definition_validator();
     init_datasource_definition_validator();
   }
   }
 });
 });
@@ -2700,6 +2764,7 @@ var init_datasource = __esm({
 // src/definition/index.js
 // src/definition/index.js
 var init_definition = __esm({
 var init_definition = __esm({
   "src/definition/index.js"() {
   "src/definition/index.js"() {
+    "use strict";
     init_model();
     init_model();
     init_datasource();
     init_datasource();
     init_definition_registry();
     init_definition_registry();
@@ -2710,6 +2775,7 @@ var init_definition = __esm({
 var import_js_service14, _FieldsClauseTool, FieldsClauseTool;
 var import_js_service14, _FieldsClauseTool, FieldsClauseTool;
 var init_fields_clause_tool = __esm({
 var init_fields_clause_tool = __esm({
   "src/filter/fields-clause-tool.js"() {
   "src/filter/fields-clause-tool.js"() {
+    "use strict";
     import_js_service14 = require("@e22m4u/js-service");
     import_js_service14 = require("@e22m4u/js-service");
     init_utils();
     init_utils();
     init_errors();
     init_errors();
@@ -2801,6 +2867,7 @@ var init_fields_clause_tool = __esm({
 var import_js_service15, _InclusionDecorator, InclusionDecorator;
 var import_js_service15, _InclusionDecorator, InclusionDecorator;
 var init_inclusion_decorator = __esm({
 var init_inclusion_decorator = __esm({
   "src/adapter/decorator/inclusion-decorator.js"() {
   "src/adapter/decorator/inclusion-decorator.js"() {
+    "use strict";
     init_adapter();
     init_adapter();
     import_js_service15 = require("@e22m4u/js-service");
     import_js_service15 = require("@e22m4u/js-service");
     init_filter();
     init_filter();
@@ -2889,6 +2956,7 @@ var init_inclusion_decorator = __esm({
 var import_js_service16, _DefaultValuesDecorator, DefaultValuesDecorator;
 var import_js_service16, _DefaultValuesDecorator, DefaultValuesDecorator;
 var init_default_values_decorator = __esm({
 var init_default_values_decorator = __esm({
   "src/adapter/decorator/default-values-decorator.js"() {
   "src/adapter/decorator/default-values-decorator.js"() {
+    "use strict";
     init_adapter();
     init_adapter();
     import_js_service16 = require("@e22m4u/js-service");
     import_js_service16 = require("@e22m4u/js-service");
     init_errors();
     init_errors();
@@ -2953,6 +3021,7 @@ var init_default_values_decorator = __esm({
 var import_js_service17, _DataSanitizingDecorator, DataSanitizingDecorator;
 var import_js_service17, _DataSanitizingDecorator, DataSanitizingDecorator;
 var init_data_sanitizing_decorator = __esm({
 var init_data_sanitizing_decorator = __esm({
   "src/adapter/decorator/data-sanitizing-decorator.js"() {
   "src/adapter/decorator/data-sanitizing-decorator.js"() {
+    "use strict";
     init_adapter();
     init_adapter();
     import_js_service17 = require("@e22m4u/js-service");
     import_js_service17 = require("@e22m4u/js-service");
     init_errors();
     init_errors();
@@ -3007,6 +3076,7 @@ var init_data_sanitizing_decorator = __esm({
 var import_js_service18, _FieldsFilteringDecorator, FieldsFilteringDecorator;
 var import_js_service18, _FieldsFilteringDecorator, FieldsFilteringDecorator;
 var init_fields_filtering_decorator = __esm({
 var init_fields_filtering_decorator = __esm({
   "src/adapter/decorator/fields-filtering-decorator.js"() {
   "src/adapter/decorator/fields-filtering-decorator.js"() {
+    "use strict";
     init_adapter();
     init_adapter();
     import_js_service18 = require("@e22m4u/js-service");
     import_js_service18 = require("@e22m4u/js-service");
     init_filter();
     init_filter();
@@ -3089,6 +3159,7 @@ var init_fields_filtering_decorator = __esm({
 var import_js_service19, _PropertyUniquenessDecorator, PropertyUniquenessDecorator;
 var import_js_service19, _PropertyUniquenessDecorator, PropertyUniquenessDecorator;
 var init_property_uniqueness_decorator = __esm({
 var init_property_uniqueness_decorator = __esm({
   "src/adapter/decorator/property-uniqueness-decorator.js"() {
   "src/adapter/decorator/property-uniqueness-decorator.js"() {
+    "use strict";
     init_adapter();
     init_adapter();
     import_js_service19 = require("@e22m4u/js-service");
     import_js_service19 = require("@e22m4u/js-service");
     init_errors();
     init_errors();
@@ -3163,6 +3234,7 @@ var init_property_uniqueness_decorator = __esm({
 // src/adapter/decorator/index.js
 // src/adapter/decorator/index.js
 var init_decorator = __esm({
 var init_decorator = __esm({
   "src/adapter/decorator/index.js"() {
   "src/adapter/decorator/index.js"() {
+    "use strict";
     init_inclusion_decorator();
     init_inclusion_decorator();
     init_default_values_decorator();
     init_default_values_decorator();
     init_data_sanitizing_decorator();
     init_data_sanitizing_decorator();
@@ -3175,9 +3247,14 @@ var init_decorator = __esm({
 var import_js_service20, ADAPTER_CLASS_NAME, _Adapter, Adapter;
 var import_js_service20, ADAPTER_CLASS_NAME, _Adapter, Adapter;
 var init_adapter = __esm({
 var init_adapter = __esm({
   "src/adapter/adapter.js"() {
   "src/adapter/adapter.js"() {
+    "use strict";
     import_js_service20 = require("@e22m4u/js-service");
     import_js_service20 = require("@e22m4u/js-service");
     init_errors();
     init_errors();
     init_decorator();
     init_decorator();
+    init_decorator();
+    init_decorator();
+    init_decorator();
+    init_decorator();
     ADAPTER_CLASS_NAME = "Adapter";
     ADAPTER_CLASS_NAME = "Adapter";
     _Adapter = class _Adapter extends import_js_service20.Service {
     _Adapter = class _Adapter extends import_js_service20.Service {
       /**
       /**
@@ -3382,11 +3459,16 @@ __export(memory_adapter_exports, {
 var _MemoryAdapter, MemoryAdapter;
 var _MemoryAdapter, MemoryAdapter;
 var init_memory_adapter = __esm({
 var init_memory_adapter = __esm({
   "src/adapter/builtin/memory-adapter.js"() {
   "src/adapter/builtin/memory-adapter.js"() {
+    "use strict";
     init_adapter();
     init_adapter();
     init_utils();
     init_utils();
-    init_errors();
+    init_utils();
     init_definition();
     init_definition();
     init_filter();
     init_filter();
+    init_filter();
+    init_filter();
+    init_errors();
+    init_definition();
     _MemoryAdapter = class _MemoryAdapter extends Adapter {
     _MemoryAdapter = class _MemoryAdapter extends Adapter {
       /**
       /**
        * Tables.
        * Tables.
@@ -3797,9 +3879,11 @@ function findAdapterCtorInModule(module2) {
 var import_js_service21, _AdapterLoader, AdapterLoader;
 var import_js_service21, _AdapterLoader, AdapterLoader;
 var init_adapter_loader = __esm({
 var init_adapter_loader = __esm({
   "src/adapter/adapter-loader.js"() {
   "src/adapter/adapter-loader.js"() {
+    "use strict";
+    init_adapter();
     import_js_service21 = require("@e22m4u/js-service");
     import_js_service21 = require("@e22m4u/js-service");
-    init_errors();
     init_adapter();
     init_adapter();
+    init_errors();
     init_();
     init_();
     _AdapterLoader = class _AdapterLoader extends import_js_service21.Service {
     _AdapterLoader = class _AdapterLoader extends import_js_service21.Service {
       /**
       /**
@@ -3819,13 +3903,13 @@ var init_adapter_loader = __esm({
         try {
         try {
           const module2 = await globImport_builtin_adapter_js(`./builtin/${adapterName}-adapter.js`);
           const module2 = await globImport_builtin_adapter_js(`./builtin/${adapterName}-adapter.js`);
           adapterCtor = findAdapterCtorInModule(module2);
           adapterCtor = findAdapterCtorInModule(module2);
-        } catch {
+        } catch (e) {
         }
         }
         if (!adapterCtor)
         if (!adapterCtor)
           try {
           try {
             const module2 = await Promise.resolve().then(() => __toESM(require(`@e22m4u/js-repository-${adapterName}-adapter`)));
             const module2 = await Promise.resolve().then(() => __toESM(require(`@e22m4u/js-repository-${adapterName}-adapter`)));
             adapterCtor = findAdapterCtorInModule(module2);
             adapterCtor = findAdapterCtorInModule(module2);
-          } catch {
+          } catch (e) {
           }
           }
         if (!adapterCtor)
         if (!adapterCtor)
           throw new InvalidArgumentError(
           throw new InvalidArgumentError(
@@ -3845,6 +3929,7 @@ var init_adapter_loader = __esm({
 var import_js_service22, _AdapterRegistry, AdapterRegistry;
 var import_js_service22, _AdapterRegistry, AdapterRegistry;
 var init_adapter_registry = __esm({
 var init_adapter_registry = __esm({
   "src/adapter/adapter-registry.js"() {
   "src/adapter/adapter-registry.js"() {
+    "use strict";
     init_adapter();
     init_adapter();
     import_js_service22 = require("@e22m4u/js-service");
     import_js_service22 = require("@e22m4u/js-service");
     init_adapter_loader();
     init_adapter_loader();
@@ -3883,6 +3968,7 @@ var init_adapter_registry = __esm({
 // src/adapter/index.js
 // src/adapter/index.js
 var init_adapter2 = __esm({
 var init_adapter2 = __esm({
   "src/adapter/index.js"() {
   "src/adapter/index.js"() {
+    "use strict";
     init_adapter();
     init_adapter();
     init_adapter_loader();
     init_adapter_loader();
     init_adapter_registry();
     init_adapter_registry();
@@ -3893,10 +3979,12 @@ var init_adapter2 = __esm({
 var import_js_service23, _Repository, Repository;
 var import_js_service23, _Repository, Repository;
 var init_repository = __esm({
 var init_repository = __esm({
   "src/repository/repository.js"() {
   "src/repository/repository.js"() {
+    "use strict";
     import_js_service23 = require("@e22m4u/js-service");
     import_js_service23 = require("@e22m4u/js-service");
+    init_adapter2();
+    init_adapter2();
     init_errors();
     init_errors();
     init_definition();
     init_definition();
-    init_adapter2();
     _Repository = class _Repository extends import_js_service23.Service {
     _Repository = class _Repository extends import_js_service23.Service {
       /**
       /**
        * Model name.
        * Model name.
@@ -4094,6 +4182,7 @@ var init_repository = __esm({
 var import_js_service24, _RepositoryRegistry, RepositoryRegistry;
 var import_js_service24, _RepositoryRegistry, RepositoryRegistry;
 var init_repository_registry = __esm({
 var init_repository_registry = __esm({
   "src/repository/repository-registry.js"() {
   "src/repository/repository-registry.js"() {
+    "use strict";
     import_js_service24 = require("@e22m4u/js-service");
     import_js_service24 = require("@e22m4u/js-service");
     init_repository();
     init_repository();
     init_utils();
     init_utils();
@@ -4149,6 +4238,7 @@ var init_repository_registry = __esm({
 // src/repository/index.js
 // src/repository/index.js
 var init_repository2 = __esm({
 var init_repository2 = __esm({
   "src/repository/index.js"() {
   "src/repository/index.js"() {
+    "use strict";
     init_repository();
     init_repository();
     init_repository_registry();
     init_repository_registry();
   }
   }
@@ -4158,8 +4248,10 @@ var init_repository2 = __esm({
 var import_js_service25, _HasOneResolver, HasOneResolver;
 var import_js_service25, _HasOneResolver, HasOneResolver;
 var init_has_one_resolver = __esm({
 var init_has_one_resolver = __esm({
   "src/relations/has-one-resolver.js"() {
   "src/relations/has-one-resolver.js"() {
+    "use strict";
     import_js_service25 = require("@e22m4u/js-service");
     import_js_service25 = require("@e22m4u/js-service");
     init_utils();
     init_utils();
+    init_definition();
     init_errors();
     init_errors();
     init_repository2();
     init_repository2();
     init_definition();
     init_definition();
@@ -4411,8 +4503,10 @@ var init_has_one_resolver = __esm({
 var import_js_service26, _HasManyResolver, HasManyResolver;
 var import_js_service26, _HasManyResolver, HasManyResolver;
 var init_has_many_resolver = __esm({
 var init_has_many_resolver = __esm({
   "src/relations/has-many-resolver.js"() {
   "src/relations/has-many-resolver.js"() {
+    "use strict";
     import_js_service26 = require("@e22m4u/js-service");
     import_js_service26 = require("@e22m4u/js-service");
     init_utils();
     init_utils();
+    init_definition();
     init_errors();
     init_errors();
     init_repository2();
     init_repository2();
     init_definition();
     init_definition();
@@ -4674,9 +4768,11 @@ var init_has_many_resolver = __esm({
 var import_js_service27, _BelongsToResolver, BelongsToResolver;
 var import_js_service27, _BelongsToResolver, BelongsToResolver;
 var init_belongs_to_resolver = __esm({
 var init_belongs_to_resolver = __esm({
   "src/relations/belongs-to-resolver.js"() {
   "src/relations/belongs-to-resolver.js"() {
+    "use strict";
     import_js_service27 = require("@e22m4u/js-service");
     import_js_service27 = require("@e22m4u/js-service");
-    init_errors();
     init_utils();
     init_utils();
+    init_utils();
+    init_errors();
     init_repository2();
     init_repository2();
     init_definition();
     init_definition();
     _BelongsToResolver = class _BelongsToResolver extends import_js_service27.Service {
     _BelongsToResolver = class _BelongsToResolver extends import_js_service27.Service {
@@ -4880,9 +4976,11 @@ var init_belongs_to_resolver = __esm({
 var import_js_service28, _ReferencesManyResolver, ReferencesManyResolver;
 var import_js_service28, _ReferencesManyResolver, ReferencesManyResolver;
 var init_references_many_resolver = __esm({
 var init_references_many_resolver = __esm({
   "src/relations/references-many-resolver.js"() {
   "src/relations/references-many-resolver.js"() {
+    "use strict";
     import_js_service28 = require("@e22m4u/js-service");
     import_js_service28 = require("@e22m4u/js-service");
-    init_errors();
     init_utils();
     init_utils();
+    init_utils();
+    init_errors();
     init_repository2();
     init_repository2();
     init_definition();
     init_definition();
     _ReferencesManyResolver = class _ReferencesManyResolver extends import_js_service28.Service {
     _ReferencesManyResolver = class _ReferencesManyResolver extends import_js_service28.Service {
@@ -4978,6 +5076,7 @@ var init_references_many_resolver = __esm({
 // src/relations/index.js
 // src/relations/index.js
 var init_relations2 = __esm({
 var init_relations2 = __esm({
   "src/relations/index.js"() {
   "src/relations/index.js"() {
+    "use strict";
     init_has_one_resolver();
     init_has_one_resolver();
     init_has_many_resolver();
     init_has_many_resolver();
     init_belongs_to_resolver();
     init_belongs_to_resolver();
@@ -4989,11 +5088,16 @@ var init_relations2 = __esm({
 var import_js_service29, _IncludeClauseTool, IncludeClauseTool;
 var import_js_service29, _IncludeClauseTool, IncludeClauseTool;
 var init_include_clause_tool = __esm({
 var init_include_clause_tool = __esm({
   "src/filter/include-clause-tool.js"() {
   "src/filter/include-clause-tool.js"() {
+    "use strict";
     import_js_service29 = require("@e22m4u/js-service");
     import_js_service29 = require("@e22m4u/js-service");
+    init_definition();
+    init_relations2();
+    init_relations2();
     init_where_clause_tool();
     init_where_clause_tool();
     init_order_clause_tool();
     init_order_clause_tool();
     init_slice_clause_tool();
     init_slice_clause_tool();
     init_errors();
     init_errors();
+    init_relations2();
     init_fields_clause_tool();
     init_fields_clause_tool();
     init_definition();
     init_definition();
     init_relations2();
     init_relations2();
@@ -5323,6 +5427,7 @@ var init_include_clause_tool = __esm({
 // src/filter/index.js
 // src/filter/index.js
 var init_filter = __esm({
 var init_filter = __esm({
   "src/filter/index.js"() {
   "src/filter/index.js"() {
+    "use strict";
     init_slice_clause_tool();
     init_slice_clause_tool();
     init_order_clause_tool();
     init_order_clause_tool();
     init_where_clause_tool();
     init_where_clause_tool();
@@ -5389,6 +5494,7 @@ init_adapter2();
 
 
 // src/database-schema.js
 // src/database-schema.js
 var import_js_service30 = require("@e22m4u/js-service");
 var import_js_service30 = require("@e22m4u/js-service");
+init_repository2();
 init_definition();
 init_definition();
 init_repository2();
 init_repository2();
 var _DatabaseSchema = class _DatabaseSchema extends import_js_service30.Service {
 var _DatabaseSchema = class _DatabaseSchema extends import_js_service30.Service {

+ 58 - 29
eslint.config.js

@@ -1,39 +1,68 @@
 import globals from 'globals';
 import globals from 'globals';
 import eslintJs from '@eslint/js';
 import eslintJs from '@eslint/js';
+import eslintTypescript from 'typescript-eslint';
 import eslintJsdocPlugin from 'eslint-plugin-jsdoc';
 import eslintJsdocPlugin from 'eslint-plugin-jsdoc';
 import eslintMochaPlugin from 'eslint-plugin-mocha';
 import eslintMochaPlugin from 'eslint-plugin-mocha';
-import eslintImportPlugin from 'eslint-plugin-import';
 import eslintPrettierConfig from 'eslint-config-prettier';
 import eslintPrettierConfig from 'eslint-config-prettier';
 import eslintChaiExpectPlugin from 'eslint-plugin-chai-expect';
 import eslintChaiExpectPlugin from 'eslint-plugin-chai-expect';
 
 
-export default [{
-  languageOptions: {
-    globals: {
-      ...globals.node,
-      ...globals.es2021,
-      ...globals.mocha,
+export default [
+  {
+    files: ['src/**/*.js'],
+    languageOptions: {
+      globals: {
+        ...globals.node,
+        ...globals.es2021,
+        ...globals.mocha,
+      },
+    },
+    plugins: {
+      'jsdoc': eslintJsdocPlugin,
+      'mocha': eslintMochaPlugin,
+      'chai-expect': eslintChaiExpectPlugin,
+    },
+    rules: {
+      ...eslintJs.configs.recommended.rules,
+      ...eslintPrettierConfig.rules,
+      ...eslintMochaPlugin.configs.recommended.rules,
+      ...eslintChaiExpectPlugin.configs['recommended-flat'].rules,
+      ...eslintJsdocPlugin.configs['flat/recommended-error'].rules,
+      'no-unused-vars': ['error', {'caughtErrors': 'none'}],
+      'jsdoc/reject-any-type': 0,
+      'jsdoc/reject-function-type': 0,
+      'jsdoc/require-param-description': 0,
+      'jsdoc/require-returns-description': 0,
+      'jsdoc/require-property-description': 0,
+      'jsdoc/tag-lines': ['error', 'any', {startLines: 1}],
     },
     },
   },
   },
-  plugins: {
-    'jsdoc': eslintJsdocPlugin,
-    'mocha': eslintMochaPlugin,
-    'import': eslintImportPlugin,
-    'chai-expect': eslintChaiExpectPlugin,
-  },
-  rules: {
-    ...eslintJs.configs.recommended.rules,
-    ...eslintPrettierConfig.rules,
-    ...eslintImportPlugin.flatConfigs.recommended.rules,
-    ...eslintMochaPlugin.configs.recommended.rules,
-    ...eslintChaiExpectPlugin.configs['recommended-flat'].rules,
-    ...eslintJsdocPlugin.configs['flat/recommended-error'].rules,
-    'no-duplicate-imports': 'error',
-    'jsdoc/reject-any-type': 0,
-    'jsdoc/reject-function-type': 0,
-    'jsdoc/require-param-description': 0,
-    'jsdoc/require-returns-description': 0,
-    'jsdoc/require-property-description': 0,
-    'jsdoc/tag-lines': ['error', 'any', {startLines: 1}],
+  {
+    files: ['src/**/*.ts'],
+    ignores: ['src/**/*.d.ts'],
+    languageOptions: {
+      globals: {
+        ...globals.node,
+        ...globals.es2021,
+        ...globals.mocha,
+      },
+      parser: eslintTypescript.parser,
+      parserOptions: {
+        projectService: true,
+        tsconfigRootDir: import.meta.dirname,
+      },
+    },
+    plugins: {
+      '@typescript-eslint': eslintTypescript.plugin,
+      'mocha': eslintMochaPlugin,
+      'chai-expect': eslintChaiExpectPlugin,
+    },
+    rules: {
+      ...eslintJs.configs.recommended.rules,
+      ...eslintPrettierConfig.rules,
+      ...eslintTypescript.configs.recommended.rules,
+      '@typescript-eslint/no-namespace': 0,
+      '@typescript-eslint/no-var-requires': 0,
+      '@typescript-eslint/no-unnecessary-type-constraint': 0,
+    },
   },
   },
-  files: ['src/**/*.js'],
-}];
+];

+ 0 - 7
jsconfig.json

@@ -1,7 +0,0 @@
-{
-  "compilerOptions": {
-    "target": "es2022",
-    "module": "NodeNext",
-    "moduleResolution": "NodeNext"
-  }
-}

+ 19 - 11
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@e22m4u/js-repository",
   "name": "@e22m4u/js-repository",
-  "version": "0.8.0",
+  "version": "0.7.0",
   "description": "Реализация репозитория для работы с базами данных",
   "description": "Реализация репозитория для работы с базами данных",
   "author": "Mikhail Evstropov <e22m4u@yandex.ru>",
   "author": "Mikhail Evstropov <e22m4u@yandex.ru>",
   "license": "MIT",
   "license": "MIT",
@@ -12,15 +12,17 @@
     "Datasource",
     "Datasource",
     "Relations"
     "Relations"
   ],
   ],
-  "homepage": "https://gitrepos.ru/e22m4u/js-repository",
+  "homepage": "https://github.com/e22m4u/js-repository",
   "repository": {
   "repository": {
     "type": "git",
     "type": "git",
-    "url": "git+https://gitrepos.ru/e22m4u/js-repository.git"
+    "url": "git+https://github.com/e22m4u/js-repository.git"
   },
   },
   "type": "module",
   "type": "module",
+  "types": "./src/index.d.ts",
   "module": "./src/index.js",
   "module": "./src/index.js",
   "main": "./dist/cjs/index.cjs",
   "main": "./dist/cjs/index.cjs",
   "exports": {
   "exports": {
+    "types": "./src/index.d.ts",
     "import": "./src/index.js",
     "import": "./src/index.js",
     "require": "./dist/cjs/index.cjs"
     "require": "./dist/cjs/index.cjs"
   },
   },
@@ -28,22 +30,26 @@
     "node": ">=12"
     "node": ">=12"
   },
   },
   "scripts": {
   "scripts": {
-    "lint": "eslint ./src",
-    "lint:fix": "eslint ./src --fix",
+    "lint": "tsc && eslint ./src",
+    "lint:fix": "tsc && eslint ./src --fix",
     "format": "prettier --write \"./src/**/*.js\"",
     "format": "prettier --write \"./src/**/*.js\"",
     "test": "npm run lint && c8 --reporter=text-summary mocha --bail",
     "test": "npm run lint && c8 --reporter=text-summary mocha --bail",
     "test:coverage": "npm run lint && c8 --reporter=text mocha --bail",
     "test:coverage": "npm run lint && c8 --reporter=text mocha --bail",
-    "build:cjs": "rimraf ./dist/cjs && node build-cjs.js",
+    "build:cjs": "rimraf ./dist/cjs && node --no-warnings=ExperimentalWarning build-cjs.js",
     "prepare": "husky"
     "prepare": "husky"
   },
   },
   "dependencies": {
   "dependencies": {
-    "@e22m4u/js-empty-values": "~0.2.0",
-    "@e22m4u/js-format": "~0.3.0",
+    "@e22m4u/js-empty-values": "~0.1.3",
+    "@e22m4u/js-format": "~0.2.1",
     "@e22m4u/js-service": "~0.4.6"
     "@e22m4u/js-service": "~0.4.6"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@commitlint/cli": "~20.1.0",
     "@commitlint/cli": "~20.1.0",
     "@commitlint/config-conventional": "~20.0.0",
     "@commitlint/config-conventional": "~20.0.0",
+    "@types/chai": "~5.2.3",
+    "@types/chai-as-promised": "~8.0.2",
+    "@types/chai-spies": "~1.0.6",
+    "@types/mocha": "~10.0.10",
     "c8": "~10.1.3",
     "c8": "~10.1.3",
     "chai": "~6.2.1",
     "chai": "~6.2.1",
     "chai-as-promised": "~8.0.2",
     "chai-as-promised": "~8.0.2",
@@ -52,12 +58,14 @@
     "eslint": "~9.39.1",
     "eslint": "~9.39.1",
     "eslint-config-prettier": "~10.1.8",
     "eslint-config-prettier": "~10.1.8",
     "eslint-plugin-chai-expect": "~3.1.0",
     "eslint-plugin-chai-expect": "~3.1.0",
-    "eslint-plugin-import": "~2.32.0",
     "eslint-plugin-jsdoc": "~61.4.1",
     "eslint-plugin-jsdoc": "~61.4.1",
     "eslint-plugin-mocha": "~11.2.0",
     "eslint-plugin-mocha": "~11.2.0",
     "husky": "~9.1.7",
     "husky": "~9.1.7",
     "mocha": "~11.7.5",
     "mocha": "~11.7.5",
-    "prettier": "~3.7.3",
-    "rimraf": "~6.1.2"
+    "prettier": "~3.6.2",
+    "rimraf": "~6.1.2",
+    "ts-node": "~10.9.2",
+    "typescript": "~5.9.3",
+    "typescript-eslint": "~8.48.0"
   }
   }
 }
 }

+ 16 - 0
src/adapter/adapter-loader.d.ts

@@ -0,0 +1,16 @@
+import {Adapter} from './adapter.js';
+import {AnyObject} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+
+/**
+ * Adapter loader.
+ */
+export declare class AdapterLoader extends Service {
+  /**
+   * Load by name.
+   *
+   * @param adapterName
+   * @param settings
+   */
+  loadByName(adapterName: string, settings?: AnyObject): Promise<Adapter>;
+}

+ 4 - 3
src/adapter/adapter-loader.js

@@ -1,6 +1,7 @@
+import {Adapter} from './adapter.js';
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
+import {ADAPTER_CLASS_NAME} from './adapter.js';
 import {InvalidArgumentError} from '../errors/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
-import {Adapter, ADAPTER_CLASS_NAME} from './adapter.js';
 
 
 /**
 /**
  * Adapter loader.
  * Adapter loader.
@@ -23,7 +24,7 @@ export class AdapterLoader extends Service {
     try {
     try {
       const module = await import(`./builtin/${adapterName}-adapter.js`);
       const module = await import(`./builtin/${adapterName}-adapter.js`);
       adapterCtor = findAdapterCtorInModule(module);
       adapterCtor = findAdapterCtorInModule(module);
-    } catch {
+    } catch (e) {
       /**/
       /**/
     }
     }
     if (!adapterCtor)
     if (!adapterCtor)
@@ -32,7 +33,7 @@ export class AdapterLoader extends Service {
           `@e22m4u/js-repository-${adapterName}-adapter`
           `@e22m4u/js-repository-${adapterName}-adapter`
         );
         );
         adapterCtor = findAdapterCtorInModule(module);
         adapterCtor = findAdapterCtorInModule(module);
-      } catch {
+      } catch (e) {
         /**/
         /**/
       }
       }
     if (!adapterCtor)
     if (!adapterCtor)

+ 14 - 0
src/adapter/adapter-registry.d.ts

@@ -0,0 +1,14 @@
+import {Adapter} from './adapter.js';
+import {Service} from '@e22m4u/js-service';
+
+/**
+ * Adapter registry.
+ */
+export declare class AdapterRegistry extends Service {
+  /**
+   * Get adapter.
+   *
+   * @param datasourceName
+   */
+  getAdapter(datasourceName: string): Promise<Adapter>;
+}

+ 153 - 0
src/adapter/adapter.d.ts

@@ -0,0 +1,153 @@
+import {ModelId} from '../types.js';
+import {AnyObject} from '../types.js';
+import {ModelData} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+import {WhereClause} from '../filter/index.js';
+import {FilterClause} from '../filter/index.js';
+import {ItemFilterClause} from '../filter/index.js';
+import {ServiceContainer} from '@e22m4u/js-service';
+
+/**
+ * Adapter.
+ */
+export declare class Adapter extends Service {
+  /**
+   * Kinds.
+   */
+  static kinds: string[];
+
+  /**
+   * Settings.
+   */
+  get settings(): AnyObject | undefined;
+
+  /**
+   * Constructor.
+   *
+   * @param container
+   * @param settings
+   */
+  constructor(container?: ServiceContainer, settings?: AnyObject);
+
+  /**
+   * Create.
+   *
+   * @param modelName
+   * @param modelData
+   * @param filter
+   */
+  create(
+    modelName: string,
+    modelData: ModelData,
+    filter?: ItemFilterClause,
+  ): Promise<ModelData>;
+
+  /**
+   * Replace by id.
+   *
+   * @param modelName
+   * @param id
+   * @param modelData
+   * @param filter
+   */
+  replaceById(
+    modelName: string,
+    id: ModelId,
+    modelData: ModelData,
+    filter?: ItemFilterClause,
+  ): Promise<ModelData>;
+
+  /**
+   * Replace or create.
+   *
+   * @param modelName
+   * @param modelData
+   * @param filter
+   */
+  replaceOrCreate(
+    modelName: string,
+    modelData: ModelData,
+    filter?: ItemFilterClause,
+  ): Promise<ModelData>;
+
+  /**
+   * Patch.
+   *
+   * @param modelName
+   * @param modelData
+   * @param where
+   */
+  patch(
+    modelName: string,
+    modelData: ModelData,
+    where?: WhereClause,
+  ): Promise<number>;
+
+  /**
+   * Patch by id.
+   *
+   * @param modelName
+   * @param id
+   * @param modelData
+   * @param filter
+   */
+  patchById(
+    modelName: string,
+    id: ModelId,
+    modelData: ModelData,
+    filter?: ItemFilterClause,
+  ): Promise<ModelData>;
+
+  /**
+   * Find.
+   *
+   * @param modelName
+   * @param filter
+   */
+  find(modelName: string, filter?: FilterClause): Promise<ModelData[]>;
+
+  /**
+   * Find by id.
+   *
+   * @param modelName
+   * @param id
+   * @param filter
+   */
+  findById(
+    modelName: string,
+    id: ModelId,
+    filter?: ItemFilterClause,
+  ): Promise<ModelData>;
+
+  /**
+   * Delete.
+   *
+   * @param modelName
+   * @param where
+   */
+  delete(modelName: string, where?: WhereClause): Promise<number>;
+
+  /**
+   * Delete by id.
+   *
+   * @param modelName
+   * @param id
+   */
+  deleteById(modelName: string, id: ModelId): Promise<boolean>;
+
+  /**
+   * Exists.
+   *
+   * @param modelName
+   * @param id
+   */
+  exists(modelName: string, id: ModelId): Promise<boolean>;
+
+  /**
+   * Count.
+   *
+   * @param modelName
+   * @param where
+   */
+  count(modelName: string, where?: WhereClause): Promise<number>;
+}

+ 5 - 8
src/adapter/adapter.js

@@ -2,14 +2,11 @@
 /* eslint jsdoc/require-returns-check: 0 */
 /* eslint jsdoc/require-returns-check: 0 */
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
 import {NotImplementedError} from '../errors/index.js';
 import {NotImplementedError} from '../errors/index.js';
-
-import {
-  InclusionDecorator,
-  DefaultValuesDecorator,
-  DataSanitizingDecorator,
-  FieldsFilteringDecorator,
-  PropertyUniquenessDecorator,
-} from './decorator/index.js';
+import {InclusionDecorator} from './decorator/index.js';
+import {DefaultValuesDecorator} from './decorator/index.js';
+import {DataSanitizingDecorator} from './decorator/index.js';
+import {FieldsFilteringDecorator} from './decorator/index.js';
+import {PropertyUniquenessDecorator} from './decorator/index.js';
 
 
 /**
 /**
  * Adapter class name.
  * Adapter class name.

+ 9 - 10
src/adapter/adapter.spec.js

@@ -1,16 +1,15 @@
 import {expect} from 'chai';
 import {expect} from 'chai';
 import {chai} from '../chai.js';
 import {chai} from '../chai.js';
+import {Adapter} from './adapter.js';
+import {Service} from '@e22m4u/js-service';
+import {ADAPTER_CLASS_NAME} from './adapter.js';
+import {ServiceContainer} from '@e22m4u/js-service';
 import {DatabaseSchema} from '../database-schema.js';
 import {DatabaseSchema} from '../database-schema.js';
-import {Adapter, ADAPTER_CLASS_NAME} from './adapter.js';
-import {Service, ServiceContainer} from '@e22m4u/js-service';
-
-import {
-  InclusionDecorator,
-  DefaultValuesDecorator,
-  DataSanitizingDecorator,
-  FieldsFilteringDecorator,
-  PropertyUniquenessDecorator,
-} from './decorator/index.js';
+import {InclusionDecorator} from './decorator/index.js';
+import {DefaultValuesDecorator} from './decorator/index.js';
+import {DataSanitizingDecorator} from './decorator/index.js';
+import {FieldsFilteringDecorator} from './decorator/index.js';
+import {PropertyUniquenessDecorator} from './decorator/index.js';
 
 
 const sandbox = chai.spy.sandbox();
 const sandbox = chai.spy.sandbox();
 
 

+ 148 - 0
src/adapter/builtin/memory-adapter.d.ts

@@ -0,0 +1,148 @@
+import {Adapter} from '../adapter.js';
+import {ModelId} from '../../types.js';
+import {AnyObject} from '../../types.js';
+import {ModelData} from '../../types.js';
+import {WhereClause} from '../../filter/index.js';
+import {FilterClause} from '../../filter/index.js';
+import {ServiceContainer} from '@e22m4u/js-service';
+import {ItemFilterClause} from '../../filter/index.js';
+
+/**
+ * Memory adapter.
+ */
+export declare class MemoryAdapter extends Adapter {
+  /**
+   * Settings.
+   */
+  get settings(): AnyObject | undefined;
+
+  /**
+   * Constructor.
+   *
+   * @param container
+   * @param settings
+   */
+  constructor(container?: ServiceContainer, settings?: AnyObject);
+
+  /**
+   * Create.
+   *
+   * @param modelName
+   * @param modelData
+   * @param filter
+   */
+  create(
+    modelName: string,
+    modelData: ModelData,
+    filter?: ItemFilterClause,
+  ): Promise<ModelData>;
+
+  /**
+   * Replace by id.
+   *
+   * @param modelName
+   * @param id
+   * @param modelData
+   * @param filter
+   */
+  replaceById(
+    modelName: string,
+    id: ModelId,
+    modelData: ModelData,
+    filter?: ItemFilterClause,
+  ): Promise<ModelData>;
+
+  /**
+   * Replace or create.
+   *
+   * @param modelName
+   * @param modelData
+   * @param filter
+   */
+  replaceOrCreate(
+    modelName: string,
+    modelData: ModelData,
+    filter?: ItemFilterClause,
+  ): Promise<ModelData>;
+
+  /**
+   * Patch.
+   *
+   * @param modelName
+   * @param modelData
+   * @param where
+   */
+  patch(
+    modelName: string,
+    modelData: ModelData,
+    where?: WhereClause,
+  ): Promise<number>;
+
+  /**
+   * Patch by id.
+   *
+   * @param modelName
+   * @param id
+   * @param modelData
+   * @param filter
+   */
+  patchById(
+    modelName: string,
+    id: ModelId,
+    modelData: ModelData,
+    filter?: ItemFilterClause,
+  ): Promise<ModelData>;
+
+  /**
+   * Find.
+   *
+   * @param modelName
+   * @param filter
+   */
+  find(modelName: string, filter?: FilterClause): Promise<ModelData[]>;
+
+  /**
+   * Find by id.
+   *
+   * @param modelName
+   * @param id
+   * @param filter
+   */
+  findById(
+    modelName: string,
+    id: ModelId,
+    filter?: ItemFilterClause,
+  ): Promise<ModelData>;
+
+  /**
+   * Delete.
+   *
+   * @param modelName
+   * @param where
+   */
+  delete(modelName: string, where?: WhereClause): Promise<number>;
+
+  /**
+   * Delete by id.
+   *
+   * @param modelName
+   * @param id
+   */
+  deleteById(modelName: string, id: ModelId): Promise<boolean>;
+
+  /**
+   * Exists.
+   *
+   * @param modelName
+   * @param id
+   */
+  exists(modelName: string, id: ModelId): Promise<boolean>;
+
+  /**
+   * Count.
+   *
+   * @param modelName
+   * @param where
+   */
+  count(modelName: string, where?: WhereClause): Promise<number>;
+}

+ 7 - 8
src/adapter/builtin/memory-adapter.js

@@ -1,13 +1,12 @@
 import {Adapter} from '../adapter.js';
 import {Adapter} from '../adapter.js';
-import {cloneDeep, capitalize} from '../../utils/index.js';
+import {cloneDeep} from '../../utils/index.js';
+import {capitalize} from '../../utils/index.js';
+import {DataType} from '../../definition/index.js';
+import {SliceClauseTool} from '../../filter/index.js';
+import {WhereClauseTool} from '../../filter/index.js';
+import {OrderClauseTool} from '../../filter/index.js';
 import {InvalidArgumentError} from '../../errors/index.js';
 import {InvalidArgumentError} from '../../errors/index.js';
-import {DataType, ModelDefinitionUtils} from '../../definition/index.js';
-
-import {
-  SliceClauseTool,
-  WhereClauseTool,
-  OrderClauseTool,
-} from '../../filter/index.js';
+import {ModelDefinitionUtils} from '../../definition/index.js';
 
 
 /**
 /**
  * Memory adapter.
  * Memory adapter.

+ 2 - 5
src/adapter/builtin/memory-adapter.spec.js

@@ -1,12 +1,9 @@
 import {expect} from 'chai';
 import {expect} from 'chai';
 import {format} from '@e22m4u/js-format';
 import {format} from '@e22m4u/js-format';
 import {MemoryAdapter} from './memory-adapter.js';
 import {MemoryAdapter} from './memory-adapter.js';
+import {DataType} from '../../definition/index.js';
 import {DatabaseSchema} from '../../database-schema.js';
 import {DatabaseSchema} from '../../database-schema.js';
-
-import {
-  DataType,
-  DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK,
-} from '../../definition/index.js';
+import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '../../definition/index.js';
 
 
 describe('MemoryAdapter', function () {
 describe('MemoryAdapter', function () {
   describe('_getTableOrCreate', function () {
   describe('_getTableOrCreate', function () {

+ 14 - 0
src/adapter/decorator/data-sanitizing-decorator.d.ts

@@ -0,0 +1,14 @@
+import {Adapter} from '../adapter.js';
+import {Service} from '@e22m4u/js-service';
+
+/**
+ * Data sanitizing decorator.
+ */
+export declare class DataSanitizingDecorator extends Service {
+  /**
+   * Decorate.
+   *
+   * @param adapter
+   */
+  decorate(adapter: Adapter): void;
+}

+ 14 - 0
src/adapter/decorator/default-values-decorator.d.ts

@@ -0,0 +1,14 @@
+import {Service} from '@e22m4u/js-service';
+import {Adapter} from '../adapter.js';
+
+/**
+ * Default values decorator.
+ */
+export declare class DefaultValuesDecorator extends Service {
+  /**
+   * Decorate.
+   *
+   * @param adapter
+   */
+  decorate(adapter: Adapter): void;
+}

+ 2 - 1
src/adapter/decorator/default-values-decorator.spec.js

@@ -1,8 +1,9 @@
 import {expect} from 'chai';
 import {expect} from 'chai';
 import {chai} from '../../chai.js';
 import {chai} from '../../chai.js';
 import {Adapter} from '../adapter.js';
 import {Adapter} from '../adapter.js';
+import {DataType} from '../../definition/index.js';
 import {DatabaseSchema} from '../../database-schema.js';
 import {DatabaseSchema} from '../../database-schema.js';
-import {DataType, ModelDefinitionUtils} from '../../definition/index.js';
+import {ModelDefinitionUtils} from '../../definition/index.js';
 
 
 const dbs = new DatabaseSchema();
 const dbs = new DatabaseSchema();
 dbs.defineModel({
 dbs.defineModel({

+ 14 - 0
src/adapter/decorator/fields-filtering-decorator.d.ts

@@ -0,0 +1,14 @@
+import {Service} from '@e22m4u/js-service';
+import {Adapter} from '../adapter.js';
+
+/**
+ * Fields filtering decorator.
+ */
+export declare class FieldsFilteringDecorator extends Service {
+  /**
+   * Decorate.
+   *
+   * @param adapter
+   */
+  decorate(adapter: Adapter): void;
+}

+ 14 - 0
src/adapter/decorator/inclusion-decorator.d.ts

@@ -0,0 +1,14 @@
+import {Service} from '@e22m4u/js-service';
+import {Adapter} from '../adapter.js';
+
+/**
+ * Inclusion decorator.
+ */
+export declare class InclusionDecorator extends Service {
+  /**
+   * Decorate.
+   *
+   * @param adapter
+   */
+  decorate(adapter: Adapter): void;
+}

+ 5 - 0
src/adapter/decorator/index.d.ts

@@ -0,0 +1,5 @@
+export * from './inclusion-decorator.js';
+export * from './default-values-decorator.js';
+export * from './data-sanitizing-decorator.js';
+export * from './fields-filtering-decorator.js';
+export * from './property-uniqueness-decorator.js';

+ 14 - 0
src/adapter/decorator/property-uniqueness-decorator.d.ts

@@ -0,0 +1,14 @@
+import {Adapter} from '../adapter.js';
+import {Service} from '@e22m4u/js-service';
+
+/**
+ * Property uniqueness decorator.
+ */
+export declare class PropertyUniquenessDecorator extends Service {
+  /**
+   * Decorate.
+   *
+   * @param adapter
+   */
+  decorate(adapter: Adapter): void;
+}

+ 3 - 0
src/adapter/index.d.ts

@@ -0,0 +1,3 @@
+export * from './adapter.js';
+export * from './adapter-loader.js';
+export * from './adapter-registry.js';

+ 37 - 0
src/database-schema.d.ts

@@ -0,0 +1,37 @@
+import {ModelId} from './types.js';
+import {ModelData} from './types.js';
+import {Service} from '@e22m4u/js-service';
+import {Repository} from './repository/index.js';
+import {ModelDefinition} from './definition/index.js';
+import {DatasourceDefinition} from './definition/index.js';
+import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME} from './definition/index.js';
+
+/**
+ * Database schema.
+ */
+export declare class DatabaseSchema extends Service {
+  /**
+   * Define datasource.
+   *
+   * @param datasourceDef
+   */
+  defineDatasource(datasourceDef: DatasourceDefinition): this;
+
+  /**
+   * Define model.
+   *
+   * @param modelDef
+   */
+  defineModel(modelDef: ModelDefinition): this;
+
+  /**
+   * Get repository.
+   *
+   * @param modelName
+   */
+  getRepository<
+    Data extends object = ModelData,
+    IdType extends ModelId = ModelId,
+    IdName extends string = typeof DEFAULT_PRIMARY_KEY_PROPERTY_NAME,
+  >(modelName: string): Repository<Data, IdType, IdName>;
+}

+ 2 - 1
src/database-schema.js

@@ -1,6 +1,7 @@
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
+import {Repository} from './repository/index.js';
 import {DefinitionRegistry} from './definition/index.js';
 import {DefinitionRegistry} from './definition/index.js';
-import {Repository, RepositoryRegistry} from './repository/index.js';
+import {RepositoryRegistry} from './repository/index.js';
 
 
 /**
 /**
  * Database schema.
  * Database schema.

+ 17 - 5
src/database-schema.spec.js → src/database-schema.spec.ts

@@ -17,17 +17,16 @@ describe('DatabaseSchema', function () {
     it('sets the datasource definition', function () {
     it('sets the datasource definition', function () {
       const dbs = new DatabaseSchema();
       const dbs = new DatabaseSchema();
       dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
       dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
-      const res = dbs
-        .getService(DefinitionRegistry)
-        .getDatasource('datasource');
+      const res =
+        dbs.getService(DefinitionRegistry).getDatasource('datasource');
       expect(res).to.be.eql({name: 'datasource', adapter: 'memory'});
       expect(res).to.be.eql({name: 'datasource', adapter: 'memory'});
     });
     });
 
 
     it('throws an error if the datasource name already defined', function () {
     it('throws an error if the datasource name already defined', function () {
       const dbs = new DatabaseSchema();
       const dbs = new DatabaseSchema();
       dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
       dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
-      const throwable = () =>
-        dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
+      const throwable =
+        () => dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
       expect(throwable).to.throw(
       expect(throwable).to.throw(
         'The datasource "datasource" is already defined.',
         'The datasource "datasource" is already defined.',
       );
       );
@@ -70,5 +69,18 @@ describe('DatabaseSchema', function () {
       const throwable = () => dbs.getRepository('model');
       const throwable = () => dbs.getRepository('model');
       expect(throwable).to.throw('The model "model" is not defined.');
       expect(throwable).to.throw('The model "model" is not defined.');
     });
     });
+
+    it('uses generic types to define the repository type', function () {
+      const dbs = new DatabaseSchema();
+      dbs.defineDatasource({name: 'datasource', adapter: 'memory'});
+      dbs.defineModel({name: 'model', datasource: 'datasource'});
+      interface MyModel {
+        myId: number;
+      }
+      const res1: Repository = dbs.getRepository('model');
+      const res2: Repository<MyModel, number, 'myId'> =
+        dbs.getRepository<MyModel, number, 'myId'>('model');
+      expect(res1).to.be.eq(res2);
+    });
   });
   });
 });
 });

+ 14 - 0
src/definition/datasource/datasource-definition-validator.d.ts

@@ -0,0 +1,14 @@
+import {Service} from '@e22m4u/js-service';
+import {DatasourceDefinition} from './datasource-definition.js';
+
+/**
+ * Datasource definition validator.
+ */
+export declare class DatasourceDefinitionValidator extends Service {
+  /**
+   * Validate.
+   *
+   * @param datasourceDef
+   */
+  validate(datasourceDef: DatasourceDefinition): void;
+}

+ 8 - 0
src/definition/datasource/datasource-definition.d.ts

@@ -0,0 +1,8 @@
+/**
+ * Datasource definition.
+ */
+export declare type DatasourceDefinition = {
+  name: string;
+  adapter: string;
+  [option: string]: unknown;
+};

+ 2 - 0
src/definition/datasource/index.d.ts

@@ -0,0 +1,2 @@
+export * from './datasource-definition.js';
+export * from './datasource-definition-validator.js';

+ 50 - 0
src/definition/definition-registry.d.ts

@@ -0,0 +1,50 @@
+import {Service} from '@e22m4u/js-service';
+import {ModelDefinition} from './model/index.js';
+import {DatasourceDefinition} from './datasource/index.js';
+
+/**
+ * Definition registry.
+ */
+export declare class DefinitionRegistry extends Service {
+  /**
+   * Add datasource.
+   *
+   * @param datasourceDef
+   */
+  addDatasource(datasourceDef: DatasourceDefinition): void;
+
+  /**
+   * Has datasource.
+   *
+   * @param name
+   */
+  hasDatasource(name: string): boolean;
+
+  /**
+   * Get datasource.
+   *
+   * @param name
+   */
+  getDatasource(name: string): DatasourceDefinition;
+
+  /**
+   * Add model.
+   *
+   * @param modelDef
+   */
+  addModel(modelDef: ModelDefinition): void;
+
+  /**
+   * Has model.
+   *
+   * @param name
+   */
+  hasModel(name: string): boolean;
+
+  /**
+   * Get model.
+   *
+   * @param name
+   */
+  getModel(name: string): ModelDefinition;
+}

+ 3 - 0
src/definition/index.d.ts

@@ -0,0 +1,3 @@
+export * from './model/index.js';
+export * from './datasource/index.js';
+export * from './definition-registry.js';

+ 6 - 0
src/definition/model/index.d.ts

@@ -0,0 +1,6 @@
+export * from './relations/index.js';
+export * from './properties/index.js';
+export * from './model-definition.js';
+export * from './model-data-sanitizer.js';
+export * from './model-definition-utils.js';
+export * from './model-definition-validator.js';

+ 1 - 0
src/definition/model/index.js

@@ -1,5 +1,6 @@
 export * from './relations/index.js';
 export * from './relations/index.js';
 export * from './properties/index.js';
 export * from './properties/index.js';
+export * from './model-definition.js';
 export * from './model-data-sanitizer.js';
 export * from './model-data-sanitizer.js';
 export * from './model-definition-utils.js';
 export * from './model-definition-utils.js';
 export * from './model-definition-validator.js';
 export * from './model-definition-validator.js';

+ 15 - 0
src/definition/model/model-data-sanitizer.d.ts

@@ -0,0 +1,15 @@
+import {ModelData} from '../../types.js';
+import {Service} from '@e22m4u/js-service';
+
+/**
+ * Model data sanitizer.
+ */
+export declare class ModelDataSanitizer extends Service {
+  /**
+   * Sanitize.
+   *
+   * @param modelName
+   * @param modelData
+   */
+  sanitize(modelName: string, modelData: ModelData): ModelData;
+}

+ 180 - 0
src/definition/model/model-definition-utils.d.ts

@@ -0,0 +1,180 @@
+import {ModelData} from '../../types.js';
+import {Service} from '@e22m4u/js-service';
+import {DataType} from './properties/index.js';
+import {RelationDefinition} from './relations/index.js';
+import {PropertyDefinition} from './properties/index.js';
+import {PropertyDefinitionMap} from './model-definition.js';
+import {RelationDefinitionMap} from './model-definition.js';
+
+/**
+ * Default primary key property name.
+ */
+export const DEFAULT_PRIMARY_KEY_PROPERTY_NAME: 'id';
+
+/**
+ * Model definition utils.
+ */
+export declare class ModelDefinitionUtils extends Service {
+  /**
+   * Get primary key as property name.
+   *
+   * @param modelName
+   */
+  getPrimaryKeyAsPropertyName(modelName: string): string;
+
+  /**
+   * Get primary key as column name.
+   *
+   * @param modelName
+   */
+  getPrimaryKeyAsColumnName(modelName: string): string;
+
+  /**
+   * Get table name by model name.
+   *
+   * @param modelName
+   */
+  getTableNameByModelName(modelName: string): string;
+
+  /**
+   * Get column name by property name.
+   *
+   * @param modelName
+   * @param propertyName
+   */
+  getColumnNameByPropertyName(modelName: string, propertyName: string): string;
+
+  /**
+   * Get default property value.
+   *
+   * @param modelName
+   * @param propertyName
+   */
+  getDefaultPropertyValue(modelName: string, propertyName: string): unknown;
+
+  /**
+   * Set default values to empty properties.
+   *
+   * @param modelName
+   * @param modelData
+   * @param onlyProvidedProperties
+   */
+  setDefaultValuesToEmptyProperties<T extends ModelData>(
+    modelName: string,
+    modelData: T,
+    onlyProvidedProperties?: boolean,
+  ): T;
+
+  /**
+   * Convert property names to column names.
+   *
+   * @param modelName
+   * @param modelData
+   */
+  convertPropertyNamesToColumnNames(
+    modelName: string,
+    modelData: ModelData,
+  ): ModelData;
+
+  /**
+   * Convert column names to property names.
+   *
+   * @param modelName
+   * @param tableData
+   */
+  convertColumnNamesToPropertyNames(
+    modelName: string,
+    tableData: ModelData,
+  ): ModelData;
+
+  /**
+   * Get data type by property name.
+   *
+   * @param modelName
+   * @param propertyName
+   */
+  getDataTypeByPropertyName(modelName: string, propertyName: string): DataType;
+
+  /**
+   * Get data type from property definition.
+   *
+   * @param propDef
+   */
+  getDataTypeFromPropertyDefinition(propDef: PropertyDefinition): DataType;
+
+  /**
+   * Get own properties definition of primary keys.
+   *
+   * @param modelName
+   */
+  getOwnPropertiesDefinitionOfPrimaryKeys(
+    modelName: string,
+  ): PropertyDefinitionMap;
+
+  /**
+   * Get own properties definition without primary keys.
+   *
+   * @param modelName
+   */
+  getOwnPropertiesDefinitionWithoutPrimaryKeys(
+    modelName: string,
+  ): PropertyDefinitionMap;
+
+  /**
+   * Get properties definition in base model hierarchy.
+   *
+   * @param modelName
+   */
+  getPropertiesDefinitionInBaseModelHierarchy(
+    modelName: string,
+  ): PropertyDefinitionMap;
+
+  /**
+   * Get own relations definition.
+   *
+   * @param modelName
+   */
+  getOwnRelationsDefinition(modelName: string): RelationDefinitionMap;
+
+  /**
+   * Get relations definition in base model hierarchy.
+   *
+   * @param modelName
+   */
+  getRelationsDefinitionInBaseModelHierarchy(
+    modelName: string,
+  ): RelationDefinitionMap;
+
+  /**
+   * Get relation definition by name.
+   *
+   * @param modelName
+   * @param relationName
+   */
+  getRelationDefinitionByName(
+    modelName: string,
+    relationName: string,
+  ): RelationDefinition;
+
+  /**
+   * Exclude object keys by relation names.
+   *
+   * @param modelName
+   * @param modelData
+   */
+  excludeObjectKeysByRelationNames<T extends ModelData>(
+    modelName: string,
+    modelData: T,
+  ): Partial<T>;
+
+  /**
+   * Get model name of property value if defined.
+   *
+   * @param modelName
+   * @param propertyName
+   */
+  getModelNameOfPropertyValueIfDefined(
+    modelName: string,
+    propertyName: string,
+  ): string | undefined;
+}

+ 2 - 1
src/definition/model/model-definition-utils.js

@@ -1,9 +1,10 @@
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
 import {DataType} from './properties/index.js';
 import {DataType} from './properties/index.js';
+import {cloneDeep} from '../../utils/index.js';
+import {excludeObjectKeys} from '../../utils/index.js';
 import {EmptyValuesService} from '@e22m4u/js-empty-values';
 import {EmptyValuesService} from '@e22m4u/js-empty-values';
 import {InvalidArgumentError} from '../../errors/index.js';
 import {InvalidArgumentError} from '../../errors/index.js';
 import {DefinitionRegistry} from '../definition-registry.js';
 import {DefinitionRegistry} from '../definition-registry.js';
-import {cloneDeep, excludeObjectKeys} from '../../utils/index.js';
 
 
 /**
 /**
  * Default primary key property name.
  * Default primary key property name.

+ 2 - 5
src/definition/model/model-definition-utils.spec.js

@@ -6,11 +6,8 @@ import {RelationType} from './relations/index.js';
 import {DatabaseSchema} from '../../database-schema.js';
 import {DatabaseSchema} from '../../database-schema.js';
 import {EmptyValuesService} from '@e22m4u/js-empty-values';
 import {EmptyValuesService} from '@e22m4u/js-empty-values';
 import {InvalidArgumentError} from '../../errors/index.js';
 import {InvalidArgumentError} from '../../errors/index.js';
-
-import {
-  ModelDefinitionUtils,
-  DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK,
-} from './model-definition-utils.js';
+import {ModelDefinitionUtils} from './model-definition-utils.js';
+import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from './model-definition-utils.js';
 
 
 const sandbox = chai.spy.sandbox();
 const sandbox = chai.spy.sandbox();
 
 

+ 14 - 0
src/definition/model/model-definition-validator.d.ts

@@ -0,0 +1,14 @@
+import {Service} from '@e22m4u/js-service';
+import {ModelDefinition} from './model-definition.js';
+
+/**
+ * Model definition validator.
+ */
+export declare class ModelDefinitionValidator extends Service {
+  /**
+   * Validate.
+   *
+   * @param modelDef
+   */
+  validate(modelDef: ModelDefinition): void;
+}

+ 28 - 0
src/definition/model/model-definition.d.ts

@@ -0,0 +1,28 @@
+import {RelationDefinition} from './relations/index.js';
+import {PropertyDefinition} from './properties/index.js';
+
+/**
+ * Property definition map.
+ */
+export declare type PropertyDefinitionMap = {
+  [name: string]: PropertyDefinition;
+};
+
+/**
+ * Relation definition map.
+ */
+export declare type RelationDefinitionMap = {
+  [name: string]: RelationDefinition;
+};
+
+/**
+ * Model definition.
+ */
+export declare type ModelDefinition = {
+  name: string;
+  datasource?: string;
+  base?: string;
+  tableName?: string;
+  properties?: PropertyDefinitionMap;
+  relations?: RelationDefinitionMap;
+};

+ 1 - 0
src/definition/model/model-definition.js

@@ -0,0 +1 @@
+export {};

+ 16 - 0
src/definition/model/properties/data-type.d.ts

@@ -0,0 +1,16 @@
+/**
+ * Data type.
+ */
+export declare const DataType: {
+  ANY: 'any';
+  STRING: 'string';
+  NUMBER: 'number';
+  BOOLEAN: 'boolean';
+  ARRAY: 'array';
+  OBJECT: 'object';
+};
+
+/**
+ * Type of DataType.
+ */
+export type DataType = (typeof DataType)[keyof typeof DataType];

+ 6 - 0
src/definition/model/properties/index.d.ts

@@ -0,0 +1,6 @@
+export * from './data-type.js';
+export * from './property-definition.js';
+export * from './property-uniqueness.js';
+export * from './property-uniqueness-validator.js';
+export * from './properties-definition-validator.js';
+export * from './primary-keys-definition-validator.js';

+ 1 - 0
src/definition/model/properties/index.js

@@ -1,4 +1,5 @@
 export * from './data-type.js';
 export * from './data-type.js';
+export * from './property-definition.js';
 export * from './property-uniqueness.js';
 export * from './property-uniqueness.js';
 export * from './property-uniqueness-validator.js';
 export * from './property-uniqueness-validator.js';
 export * from './properties-definition-validator.js';
 export * from './properties-definition-validator.js';

+ 15 - 0
src/definition/model/properties/primary-keys-definition-validator.d.ts

@@ -0,0 +1,15 @@
+import {Service} from '@e22m4u/js-service';
+import {PropertyDefinitionMap} from '../model-definition.js';
+
+/**
+ * Primary keys definition validator.
+ */
+export declare class PrimaryKeysDefinitionValidator extends Service {
+  /**
+   * Validate.
+   *
+   * @param modelName
+   * @param propDefs
+   */
+  validate(modelName: string, propDefs: PropertyDefinitionMap): void;
+}

+ 15 - 0
src/definition/model/properties/properties-definition-validator.d.ts

@@ -0,0 +1,15 @@
+import {Service} from '@e22m4u/js-service';
+import {PropertyDefinitionMap} from '../model-definition.js';
+
+/**
+ * Properties definition validator.
+ */
+export declare class PropertiesDefinitionValidator extends Service {
+  /**
+   * Validate.
+   *
+   * @param modelName
+   * @param propDefs
+   */
+  validate(modelName: string, propDefs: PropertyDefinitionMap): void;
+}

+ 23 - 0
src/definition/model/properties/property-definition.d.ts

@@ -0,0 +1,23 @@
+import {DataType} from './data-type.js';
+import {PropertyUniqueness} from './property-uniqueness.js';
+
+/**
+ * Full property definition.
+ */
+export declare type FullPropertyDefinition = {
+  type: DataType;
+  itemType?: DataType;
+  itemModel?: string;
+  model?: string;
+  primaryKey?: boolean;
+  columnName?: string;
+  columnType?: string;
+  required?: boolean;
+  default?: unknown;
+  unique?: boolean | PropertyUniqueness;
+};
+
+/**
+ * Property definition.
+ */
+export declare type PropertyDefinition = DataType | FullPropertyDefinition;

+ 1 - 0
src/definition/model/properties/property-definition.js

@@ -0,0 +1 @@
+export {};

+ 31 - 0
src/definition/model/properties/property-uniqueness-validator.d.ts

@@ -0,0 +1,31 @@
+import {ModelId} from '../../../types.js';
+import {Service} from '@e22m4u/js-service';
+import {ModelData} from '../../../types.js';
+import {WhereClause} from '../../../filter/index.js';
+
+/**
+ * Count method.
+ */
+type CountMethod = (where: WhereClause) => Promise<number>;
+
+/**
+ * Property uniqueness validator.
+ */
+export declare class PropertyUniquenessValidator extends Service {
+  /**
+   * Validate.
+   *
+   * @param countMethod
+   * @param methodName
+   * @param modelName
+   * @param modelData
+   * @param modelId
+   */
+  validate(
+    countMethod: CountMethod,
+    methodName: string,
+    modelName: string,
+    modelData: ModelData,
+    modelId?: ModelId,
+  ): Promise<void>;
+}

+ 14 - 0
src/definition/model/properties/property-uniqueness.d.ts

@@ -0,0 +1,14 @@
+/**
+ * Property uniqueness.
+ */
+export declare const PropertyUniqueness: {
+  STRICT: 'strict';
+  SPARSE: 'sparse';
+  NON_UNIQUE: 'nonUnique';
+};
+
+/**
+ * Type of PropertyUniqueness.
+ */
+export type PropertyUniqueness =
+  (typeof PropertyUniqueness)[keyof typeof PropertyUniqueness];

+ 3 - 0
src/definition/model/relations/index.d.ts

@@ -0,0 +1,3 @@
+export * from './relation-type.js';
+export * from './relation-definition.js';
+export * from './relations-definition-validator.js';

+ 1 - 0
src/definition/model/relations/index.js

@@ -1,2 +1,3 @@
 export * from './relation-type.js';
 export * from './relation-type.js';
+export * from './relation-definition.js';
 export * from './relations-definition-validator.js';
 export * from './relations-definition-validator.js';

+ 236 - 0
src/definition/model/relations/relation-definition.d.ts

@@ -0,0 +1,236 @@
+import {RelationType} from './relation-type.js';
+
+/**
+ * Relation definition.
+ *
+ * @example Available options.
+ * ```ts
+ * {
+ *   type: RelationType;
+ *   model?: string;
+ *   foreignKey?: string;
+ *   polymorphic?: boolean | string;
+ *   discriminator?: string;
+ * }
+ * ```
+ */
+export declare type RelationDefinition =
+  // belongsTo
+  | BelongsToDefinition
+  | PolyBelongsToDefinition
+  // hasOne
+  | HasOneDefinition
+  | PolyHasOneDefinitionWithTargetRelationName
+  | PolyHasOneDefinitionWithTargetKeys
+  // hasMany
+  | HasManyDefinition
+  | PolyHasManyDefinitionWithTargetRelationName
+  | PolyHasManyDefinitionWithTargetKeys
+  // referencesMany
+  | ReferencesManyDefinition;
+
+/**
+ * The regular "belongsTo" relation.
+ *
+ * @example Required options only.
+ * ```
+ * {
+ *   type: 'belongsTo',
+ *   model: 'model',
+ * }
+ * ```
+ *
+ * @example Verbose definition.
+ * ```
+ * {
+ *   type: 'belongsTo',
+ *   model: 'model',
+ *   foreignKey: 'modelId',
+ * }
+ * ```
+ */
+export declare type BelongsToDefinition = {
+  type: typeof RelationType.BELONGS_TO;
+  polymorphic?: false;
+  model: string;
+  foreignKey?: string;
+};
+
+/**
+ * The polymorphic "belongsTo" relation.
+ *
+ * @example Required fields only.
+ * ```
+ * {
+ *   type: 'belongsTo',
+ *   polymorphic: true,
+ * }
+ * ```
+ *
+ * @example Verbose definition.
+ * ```
+ * {
+ *   type: 'belongsTo',
+ *   polymorphic: true,
+ *   foreignKey: 'referenceId',
+ *   discriminator: 'referenceType',
+ * }
+ * ```
+ */
+export declare type PolyBelongsToDefinition = {
+  type: typeof RelationType.BELONGS_TO;
+  polymorphic: true;
+  foreignKey?: string;
+  discriminator?: string;
+};
+
+/**
+ * The regular "hasOne" relation.
+ *
+ * @example
+ * ```ts
+ * {
+ *   type: 'hasOne',
+ *   model: 'model',
+ *   foreignKey: 'modelId',
+ * }
+ * ```
+ */
+export declare type HasOneDefinition = {
+  type: typeof RelationType.HAS_ONE;
+  model: string;
+  foreignKey: string;
+  polymorphic?: false;
+  discriminator?: undefined;
+};
+
+/**
+ * The polymorphic "hasOne" relation with a target relation name.
+ *
+ * @example
+ * ```ts
+ * {
+ *   type: 'hasOne',
+ *   model: 'model',
+ *   polymorphic: 'reference',
+ * }
+ * ```
+ */
+export declare type PolyHasOneDefinitionWithTargetRelationName = {
+  type: typeof RelationType.HAS_ONE;
+  model: string;
+  polymorphic: string;
+  foreignKey?: undefined;
+  discriminator?: undefined;
+};
+
+/**
+ * The polymorphic "hasOne" relation with target relation keys.
+ *
+ * @example
+ * ```
+ * {
+ *   type: 'hasOne',
+ *   model: 'model',
+ *   polymorphic: true,
+ *   foreignKey: 'referenceId',
+ *   discriminator: 'referenceType',
+ * }
+ * ```
+ */
+export declare type PolyHasOneDefinitionWithTargetKeys = {
+  type: typeof RelationType.HAS_ONE;
+  model: string;
+  polymorphic: true;
+  foreignKey: string;
+  discriminator: string;
+};
+
+/**
+ * The regular "hasMany" relation.
+ *
+ * @example
+ * ```ts
+ * {
+ *   type: 'hasMany',
+ *   model: 'model',
+ *   foreignKey: 'modelId',
+ * }
+ * ```
+ */
+export declare type HasManyDefinition = {
+  type: typeof RelationType.HAS_MANY;
+  model: string;
+  foreignKey: string;
+  polymorphic?: false;
+  discriminator?: undefined;
+};
+
+/**
+ * The polymorphic "hasMany" relation with a target relation name.
+ *
+ * @example
+ * ```ts
+ * {
+ *   type: 'hasMany',
+ *   model: 'model',
+ *   polymorphic: 'reference',
+ * }
+ * ```
+ */
+export declare type PolyHasManyDefinitionWithTargetRelationName = {
+  type: typeof RelationType.HAS_MANY;
+  model: string;
+  polymorphic: string;
+  foreignKey?: undefined;
+  discriminator?: undefined;
+};
+
+/**
+ * The polymorphic "hasMany" relation with target relation keys.
+ *
+ * @example
+ * ```
+ * {
+ *   type: 'hasMany',
+ *   model: 'model',
+ *   polymorphic: true,
+ *   foreignKey: 'referenceId',
+ *   discriminator: 'referenceType',
+ * }
+ * ```
+ */
+export declare type PolyHasManyDefinitionWithTargetKeys = {
+  type: typeof RelationType.HAS_MANY;
+  model: string;
+  polymorphic: true;
+  foreignKey: string;
+  discriminator: string;
+};
+
+/**
+ * The regular "referencesMany" relation.
+ *
+ * @example Required options only.
+ * ```
+ * {
+ *   type: 'referencesMany',
+ *   model: 'model',
+ * }
+ * ```
+ *
+ * @example Verbose definition.
+ * ```
+ * {
+ *   type: 'referencesMany',
+ *   model: 'model',
+ *   foreignKey: 'modelIds',
+ * }
+ * ```
+ */
+export declare type ReferencesManyDefinition = {
+  type: typeof RelationType.REFERENCES_MANY;
+  model: string;
+  foreignKey?: string;
+  discriminator?: undefined;
+};

+ 1 - 0
src/definition/model/relations/relation-definition.js

@@ -0,0 +1 @@
+export {};

+ 14 - 0
src/definition/model/relations/relation-type.d.ts

@@ -0,0 +1,14 @@
+/**
+ * Relation type.
+ */
+export declare const RelationType: {
+  BELONGS_TO: 'belongsTo';
+  HAS_ONE: 'hasOne';
+  HAS_MANY: 'hasMany';
+  REFERENCES_MANY: 'referencesMany';
+};
+
+/**
+ * Type of RelationType.
+ */
+export type RelationType = (typeof RelationType)[keyof typeof RelationType];

+ 15 - 0
src/definition/model/relations/relations-definition-validator.d.ts

@@ -0,0 +1,15 @@
+import {Service} from '@e22m4u/js-service';
+import {RelationDefinitionMap} from '../model-definition.js';
+
+/**
+ * Relations definition validator.
+ */
+export declare class RelationsDefinitionValidator extends Service {
+  /**
+   * Validate.
+   *
+   * @param modelName
+   * @param relDefs
+   */
+  validate(modelName: string, relDefs: RelationDefinitionMap): void;
+}

+ 5 - 4
src/definition/model/relations/relations-definition-validator.js

@@ -1,5 +1,6 @@
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
 import {RelationType} from './relation-type.js';
 import {RelationType} from './relation-type.js';
+import {RelationType as Type} from './relation-type.js';
 import {InvalidArgumentError} from '../../../errors/index.js';
 import {InvalidArgumentError} from '../../../errors/index.js';
 
 
 /**
 /**
@@ -61,13 +62,13 @@ export class RelationsDefinitionValidator extends Service {
         modelName,
         modelName,
         relDef,
         relDef,
       );
       );
-    if (!relDef.type || !Object.values(RelationType).includes(relDef.type))
+    if (!relDef.type || !Object.values(Type).includes(relDef.type))
       throw new InvalidArgumentError(
       throw new InvalidArgumentError(
         'The relation %v of the model %v requires the option "type" ' +
         'The relation %v of the model %v requires the option "type" ' +
           'to have one of relation types: %l, but %v was given.',
           'to have one of relation types: %l, but %v was given.',
         relName,
         relName,
         modelName,
         modelName,
-        Object.values(RelationType),
+        Object.values(Type),
         relDef.type,
         relDef.type,
       );
       );
     this._validateBelongsTo(modelName, relName, relDef);
     this._validateBelongsTo(modelName, relName, relDef);
@@ -104,7 +105,7 @@ export class RelationsDefinitionValidator extends Service {
    * @private
    * @private
    */
    */
   _validateBelongsTo(modelName, relName, relDef) {
   _validateBelongsTo(modelName, relName, relDef) {
-    if (relDef.type !== RelationType.BELONGS_TO) return;
+    if (relDef.type !== Type.BELONGS_TO) return;
     if (relDef.polymorphic) {
     if (relDef.polymorphic) {
       // A polymorphic "belongsTo" relation.
       // A polymorphic "belongsTo" relation.
       if (typeof relDef.polymorphic !== 'boolean')
       if (typeof relDef.polymorphic !== 'boolean')
@@ -418,7 +419,7 @@ export class RelationsDefinitionValidator extends Service {
    * @private
    * @private
    */
    */
   _validateReferencesMany(modelName, relName, relDef) {
   _validateReferencesMany(modelName, relName, relDef) {
-    if (relDef.type !== RelationType.REFERENCES_MANY) return;
+    if (relDef.type !== Type.REFERENCES_MANY) return;
     if (!relDef.model || typeof relDef.model !== 'string')
     if (!relDef.model || typeof relDef.model !== 'string')
       throw new InvalidArgumentError(
       throw new InvalidArgumentError(
         'The relation %v of the model %v has the type "referencesMany", ' +
         'The relation %v of the model %v has the type "referencesMany", ' +

+ 3 - 0
src/errors/index.d.ts

@@ -0,0 +1,3 @@
+export * from './not-implemented-error.js';
+export * from './invalid-argument-error.js';
+export * from './invalid-operator-value-error.js';

+ 6 - 0
src/errors/invalid-argument-error.d.ts

@@ -0,0 +1,6 @@
+import {Errorf} from '@e22m4u/js-format';
+
+/**
+ * Invalid argument error.
+ */
+export declare class InvalidArgumentError extends Errorf {}

+ 13 - 0
src/errors/invalid-operator-value-error.d.ts

@@ -0,0 +1,13 @@
+/**
+ * Invalid operator value error.
+ */
+export declare class InvalidOperatorValueError extends Error {
+  /**
+   * Constructor.
+   *
+   * @param operator
+   * @param expects
+   * @param value
+   */
+  constructor(operator: string, expects: string, value: unknown);
+}

+ 6 - 0
src/errors/not-implemented-error.d.ts

@@ -0,0 +1,6 @@
+import {Errorf} from '@e22m4u/js-format';
+
+/**
+ * Not implemented error.
+ */
+export declare class NotImplementedError extends Errorf {}

+ 38 - 0
src/filter/fields-clause-tool.d.ts

@@ -0,0 +1,38 @@
+import {ModelData} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+import {FieldsClause} from './filter-clause.js';
+import {NormalizedFieldsClause} from './filter-clause.js';
+
+/**
+ * Field clause tool.
+ */
+export declare class FieldsClauseTool extends Service {
+  /**
+   * Filter.
+   *
+   * @param input
+   * @param modelName
+   * @param clause
+   */
+  filter<T extends ModelData | ModelData[]>(
+    input: T,
+    modelName: string,
+    clause: FieldsClause | undefined,
+  ): T;
+
+  /**
+   * Validate fields clause.
+   *
+   * @param clause
+   */
+  static validateFieldsClause(clause: FieldsClause | undefined): void;
+
+  /**
+   * Normalize fields clause.
+   *
+   * @param clause
+   */
+  static normalizeFieldsClause(
+    clause: FieldsClause | undefined,
+  ): NormalizedFieldsClause | undefined;
+}

+ 348 - 0
src/filter/filter-clause.d.ts

@@ -0,0 +1,348 @@
+import {ModelData} from '../types.js';
+
+/**
+ * Filter clause.
+ */
+export declare type FilterClause<M extends object = ModelData> = {
+  where?: WhereClause<M>;
+  order?: OrderClause<M>;
+  limit?: number;
+  skip?: number;
+  fields?: FieldsClause<M>;
+  include?: IncludeClause<M>;
+};
+
+/**
+ * Item filter clause.
+ */
+export declare type ItemFilterClause<M extends object = ModelData> = Pick<
+  FilterClause<M>,
+  'fields' | 'include'
+>;
+
+/**
+ * Where clause.
+ *
+ * @example
+ * ```ts
+ * value => value.featured === true
+ * {foo: 'bar'}
+ * {foo: {eq: 'bar'}}
+ * {foo: {neq: 'bar'}}
+ * {foo: {gt: 5}}
+ * {foo: {lt: 10}}
+ * {foo: {gte: 5}}
+ * {foo: {lte: 10}}
+ * {foo: {inq: ['bar', 'baz']}}
+ * {foo: {nin: ['bar', 'baz']}}
+ * {foo: {between: [5, 10]}}
+ * {foo: {exists: true}}
+ * {foo: {like: 'bar'}}
+ * {foo: {ilike: 'BaR'}}
+ * {foo: {nlike: 'bar'}}
+ * {foo: {nilike: 'BaR'}}
+ * {foo: {regexp: 'ba.+'}}
+ * {foo: {regexp: 'ba.+', flags: 'i'}}
+ * {and: [...]}
+ * {or: [...]}
+ * ```
+ */
+export declare type WhereClause<M extends object = ModelData> =
+  Partial<AndClause<M>> |
+  Partial<OrClause<M>> |
+  PropertiesClause<M>;
+
+/**
+ * Primitive values.
+ */
+export declare type PrimitiveValue =
+  | string
+  | number
+  | boolean
+  | null
+  | undefined;
+
+/**
+ * Properties clause.
+ *
+ * @example
+ * ```ts
+ * {
+ *   name: {inq: ['John', 'Mary']},
+ *   status: 'ACTIVE',
+ *   age: {gte: 40}
+ * }
+ * ```
+ */
+export declare type PropertiesClause<M extends object = ModelData> = {
+  [property in keyof M]?: OperatorClause | PrimitiveValue | RegExp;
+};
+
+/**
+ * Operator clause.
+ *
+ * @example
+ * ```ts
+ * {eq: 'bar'}
+ * {neq: 'bar'}
+ * {gt: 5}
+ * {lt: 10}
+ * {gte: 5}
+ * {lte: 10}
+ * {inq: ['bar', 'baz']}
+ * {nin: ['bar', 'baz']}
+ * {between: [5, 10]}
+ * {exists: true}
+ * {like: 'bar'}
+ * {ilike: 'BaR'}
+ * {nlike: 'bar'}
+ * {nilike: 'BaR'}
+ * {regexp: 'ba.+'}
+ * {regexp: 'ba.+', flags: 'i'}
+ * ```
+ */
+export declare type OperatorClause = {
+  eq?: PrimitiveValue;
+  neq?: PrimitiveValue;
+  gt?: string | number;
+  gte?: string | number;
+  lt?: string | number;
+  lte?: string | number;
+  inq?: PrimitiveValue[];
+  nin?: PrimitiveValue[];
+  between?: readonly [string | number, string | number];
+  exists?: boolean;
+  like?: string;
+  nlike?: string;
+  ilike?: string;
+  nilike?: string;
+  regexp?: string | RegExp;
+  flags?: string;
+};
+
+/**
+ * And clause.
+ *
+ * @example
+ * ```ts
+ * {
+ *   and: [...],
+ * }
+ * ```
+ */
+export interface AndClause<M extends object = ModelData> {
+  and: WhereClause<M>[];
+}
+
+/**
+ * Or clause.
+ *
+ * @example
+ * ```ts
+ * {
+ *   or: [...],
+ * }
+ * ```
+ */
+export interface OrClause<M extends object = ModelData> {
+  or: WhereClause<M>[];
+}
+
+/**
+ * Order clause item.
+ *
+ * @example
+ * ```ts
+ * 'prop'
+ * 'prop ASC'
+ * 'prop DESC';
+ * ```
+ */
+export declare type OrderClauseItem<M extends object = ModelData> = {
+  [prop in keyof M]: prop | `${prop & string} ASC` | `${prop & string} DESC`;
+}[keyof M];
+
+/**
+ * Order clause.
+ *
+ * @example
+ * ```ts
+ * 'prop'
+ * 'prop ASC'
+ * 'prop DESC';
+ * ['prop1', 'prop2'];
+ * ['prop1 ASC', 'prop2 DESC'];
+ * ```
+ */
+export declare type OrderClause<M extends object = ModelData> =
+  | OrderClauseItem<M>
+  | OrderClauseItem<M>[];
+
+/**
+ * Fields.
+ *
+ * @example
+ * ```ts
+ * 'prop'
+ * ['prop1', 'prop2']
+ * ```
+ */
+export declare type FieldsClause<M extends object = ModelData> =
+  | keyof M
+  | NormalizedFieldsClause<M>;
+
+/**
+ * Normalized fields clause.
+ *
+ * @example
+ * ```ts
+ * [
+ *   'prop1',
+ *   'prop2',
+ * ]
+ * ```
+ */
+export declare type NormalizedFieldsClause<M extends object = ModelData> =
+  (keyof M)[];
+
+/**
+ * Include clause.
+ *
+ * @example
+ * ```ts
+ * 'customers'
+ * ```
+ *
+ * @example
+ * ```ts
+ * [
+ *   'customers',
+ *   'orders',
+ * ]
+ * ```
+ *
+ * @example
+ * ```ts
+ * {
+ *   customer: 'orders'
+ * }
+ * ```
+ *
+ * @example
+ * ```ts
+ * {
+ *   customer: {
+ *     address: 'city',
+ *   },
+ * }
+ * ```
+ *
+ * @example
+ * ```ts
+ * {
+ *   customer: [
+ *     'orders',
+ *     {address: 'city'},
+ *   ],
+ * }
+ * ```
+ *
+ * @example
+ * ```ts
+ * {
+ *   relation: 'customer',
+ *   scope: {
+ *     where: {removed: false},
+ *     order: 'createdAt DESC',
+ *     skip: 0,
+ *     limit: 16,
+ *     fields: ['id', 'name', 'removed'],
+ *     include: 'address',
+ *   }
+ * }
+ * ```
+ */
+export declare type IncludeClause<M extends object = ModelData> =
+  | keyof M
+  | (keyof M)[]
+  | NestedIncludeClause<M>
+  | NormalizedIncludeClause<M>
+  | IncludeClause[];
+
+/**
+ * Nested include clause.
+ *
+ * @example
+ * ```ts
+ * {
+ *   customer: 'orders'
+ * }
+ * ```
+ *
+ * @example
+ * ```ts
+ * {
+ *   customer: {
+ *     address: 'city',
+ *   },
+ * }
+ * ```
+ *
+ * @example
+ * ```ts
+ * {
+ *   customer: [
+ *     'orders',
+ *     {address: 'city'},
+ *   ],
+ * }
+ * ```
+ *
+ * @example
+ * ```ts
+ * {
+ *   relation: 'customer',
+ *   scope: {
+ *     where: {removed: false},
+ *     order: 'createdAt DESC',
+ *     skip: 0,
+ *     limit: 16,
+ *     fields: ['id', 'name', 'removed'],
+ *     include: 'address',
+ *   }
+ * }
+ * ```
+ */
+export declare type NestedIncludeClause<M extends object = ModelData> = {
+  [property in keyof M]?: IncludeClause;
+};
+
+/**
+ * Inclusion.
+ *
+ * @example
+ * ```ts
+ * {
+ *   relation: 'customer',
+ * }
+ * ```
+ *
+ * @example
+ * ```ts
+ * {
+ *   relation: 'customer',
+ *   scope: {
+ *     where: {removed: false},
+ *     order: 'createdAt DESC',
+ *     skip: 0,
+ *     limit: 16,
+ *     fields: ['id', 'name', 'removed'],
+ *     include: 'address',
+ *   }
+ * }
+ * ```
+ */
+export declare interface NormalizedIncludeClause<M extends object = ModelData> {
+  relation: keyof M;
+  scope?: FilterClause;
+}

+ 55 - 0
src/filter/include-clause-tool.d.ts

@@ -0,0 +1,55 @@
+import {ModelData} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+import {FilterClause} from './filter-clause.js';
+import {IncludeClause} from './filter-clause.js';
+import {NormalizedIncludeClause} from './filter-clause.js';
+
+/**
+ * Include clause tool.
+ */
+export declare class IncludeClauseTool extends Service {
+  /**
+   * Include to.
+   *
+   * @param entities
+   * @param modelName
+   * @param clause
+   */
+  includeTo(
+    entities: ModelData[],
+    modelName: string,
+    clause: IncludeClause | undefined,
+  ): Promise<void>;
+
+  /**
+   * Validate include clause.
+   *
+   * @param clause
+   */
+  static validateIncludeClause(clause: IncludeClause | undefined): void;
+
+  /**
+   * Validate scope clause.
+   *
+   * @param clause
+   */
+  static validateScopeClause(clause: FilterClause | undefined): void;
+
+  /**
+   * Normalize include clause.
+   *
+   * @param clause
+   */
+  static normalizeIncludeClause(
+    clause: IncludeClause | undefined,
+  ): NormalizedIncludeClause[];
+
+  /**
+   * Normalize scope clause.
+   *
+   * @param clause
+   */
+  static normalizeScopeClause(
+    clause: FilterClause | undefined,
+  ): FilterClause | undefined;
+}

+ 6 - 8
src/filter/include-clause-tool.js

@@ -1,17 +1,15 @@
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
+import {RelationType} from '../definition/index.js';
+import {HasOneResolver} from '../relations/index.js';
+import {HasManyResolver} from '../relations/index.js';
 import {WhereClauseTool} from './where-clause-tool.js';
 import {WhereClauseTool} from './where-clause-tool.js';
 import {OrderClauseTool} from './order-clause-tool.js';
 import {OrderClauseTool} from './order-clause-tool.js';
 import {SliceClauseTool} from './slice-clause-tool.js';
 import {SliceClauseTool} from './slice-clause-tool.js';
 import {InvalidArgumentError} from '../errors/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
+import {BelongsToResolver} from '../relations/index.js';
 import {FieldsClauseTool} from './fields-clause-tool.js';
 import {FieldsClauseTool} from './fields-clause-tool.js';
-import {RelationType, ModelDefinitionUtils} from '../definition/index.js';
-
-import {
-  HasOneResolver,
-  HasManyResolver,
-  BelongsToResolver,
-  ReferencesManyResolver,
-} from '../relations/index.js';
+import {ModelDefinitionUtils} from '../definition/index.js';
+import {ReferencesManyResolver} from '../relations/index.js';
 
 
 /**
 /**
  * Include clause tool.
  * Include clause tool.

+ 7 - 0
src/filter/index.d.ts

@@ -0,0 +1,7 @@
+export * from './filter-clause.js';
+export * from './slice-clause-tool.js';
+export * from './order-clause-tool.js';
+export * from './where-clause-tool.js';
+export * from './fields-clause-tool.js';
+export * from './include-clause-tool.js';
+export * from './operator-clause-tool.js';

+ 224 - 0
src/filter/operator-clause-tool.d.ts

@@ -0,0 +1,224 @@
+import {Service} from '@e22m4u/js-service';
+
+/**
+ * Operator clause tool.
+ */
+export declare class OperatorClauseTool extends Service {
+  /**
+   * Compare.
+   *
+   * @param val1
+   * @param val2
+   * @param noTypeConversion
+   */
+  compare(val1: unknown, val2: unknown, noTypeConversion?: boolean): number;
+
+  /**
+   * Test all operators.
+   *
+   * @param clause
+   * @param value
+   */
+  testAll(clause: object, value: unknown): boolean | undefined;
+
+  /**
+   * Test eq/neq operator.
+   *
+   * @example
+   * ```ts
+   * {
+   *   eq: 'foo',
+   * }
+   * ```
+   *
+   * @example
+   * ```ts
+   * {
+   *   neq: 'foo',
+   * }
+   * ```
+   *
+   * @param clause
+   * @param value
+   */
+  testEqNeq(clause: object, value: unknown): boolean | undefined;
+
+  /**
+   * Test lt/gt/lte/gte operator.
+   *
+   * @example
+   * ```ts
+   * {
+   *   lt: 10,
+   * }
+   * ```
+   *
+   * @example
+   * ```ts
+   * {
+   *   lte: 10,
+   * }
+   * ```
+   *
+   * @example
+   * ```ts
+   * {
+   *   gt: 10,
+   * }
+   * ```
+   *
+   * @example
+   * ```ts
+   * {
+   *   gte: 10,
+   * }
+   * ```
+   *
+   * @param clause
+   * @param value
+   */
+  testGtLt(clause: object, value: unknown): boolean | undefined;
+
+  /**
+   * Test inc operator.
+   *
+   * @example
+   * ```ts
+   * {
+   *   inc: ['foo', 'bar'],
+   * }
+   * ```
+   *
+   * @param clause
+   * @param value
+   */
+  testInq(clause: object, value: unknown): boolean | undefined;
+
+  /**
+   * Test nin operator.
+   *
+   * @example
+   * ```ts
+   * {
+   *   nin: ['foo', 'bar'],
+   * }
+   * ```
+   *
+   * @param clause
+   * @param value
+   */
+  testNin(clause: object, value: unknown): boolean | undefined;
+
+  /**
+   * Test between operator.
+   *
+   * @example
+   * ```ts
+   * {
+   *   between: [10, 20],
+   * }
+   * ```
+   *
+   * @param clause
+   * @param value
+   */
+  testBetween(clause: object, value: unknown): boolean | undefined;
+
+  /**
+   * Test exists operator.
+   *
+   * @example
+   * ```ts
+   * {
+   *   exists: true,
+   * }
+   * ```
+   *
+   * @param clause
+   * @param value
+   */
+  testExists(clause: object, value: unknown): boolean | undefined;
+
+  /**
+   * Test like operator.
+   *
+   * @example
+   * ```ts
+   * {
+   *   like: 'foo',
+   * }
+   * ```
+   *
+   * @param clause
+   * @param value
+   */
+  testLike(clause: object, value: unknown): boolean | undefined;
+
+  /**
+   * Test nlike operator.
+   *
+   * @example
+   * ```ts
+   * {
+   *   nlike: 'foo',
+   * }
+   * ```
+   *
+   * @param clause
+   * @param value
+   */
+  testNlike(clause: object, value: unknown): boolean | undefined;
+
+  /**
+   * Test ilike operator.
+   *
+   * @example
+   * ```ts
+   * {
+   *   ilike: 'foo',
+   * }
+   * ```
+   *
+   * @param clause
+   * @param value
+   */
+  testIlike(clause: object, value: unknown): boolean | undefined;
+
+  /**
+   * Test nilike operator.
+   *
+   * @example
+   * ```ts
+   * {
+   *   nilike: 'foo',
+   * }
+   * ```
+   *
+   * @param clause
+   * @param value
+   */
+  testNilike(clause: object, value: unknown): boolean | undefined;
+
+  /**
+   * Test regexp.
+   *
+   * @example
+   * ```ts
+   * {
+   *   regexp: 'foo.*',
+   * }
+   * ```
+   *
+   * @example
+   * ```ts
+   * {
+   *   regexp: 'foo.*',
+   *   flags: 'i',
+   * }
+   * ```
+   *
+   * @param clause
+   * @param value
+   */
+  testRegexp(clause: object, value: unknown): boolean | undefined;
+}

+ 32 - 0
src/filter/order-clause-tool.d.ts

@@ -0,0 +1,32 @@
+import {ModelData} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+import {OrderClause} from './filter-clause.js';
+
+/**
+ * Order clause tool.
+ */
+export declare class OrderClauseTool extends Service {
+  /**
+   * Sort.
+   *
+   * @param entities
+   * @param clause
+   */
+  sort(entities: ModelData[], clause: OrderClause | undefined): void;
+
+  /**
+   * Validate order clause.
+   *
+   * @param clause
+   */
+  static validateOrderClause(clause: OrderClause | undefined): void;
+
+  /**
+   * Normalize order clause.
+   *
+   * @param clause
+   */
+  static normalizeOrderClause(
+    clause: OrderClause | undefined,
+  ): string[] | undefined;
+}

+ 30 - 0
src/filter/slice-clause-tool.d.ts

@@ -0,0 +1,30 @@
+import {ModelData} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+
+/**
+ * Slice clause tool.
+ */
+export declare class SliceClauseTool extends Service {
+  /**
+   * Slice.
+   *
+   * @param entities
+   * @param skip
+   * @param limit
+   */
+  slice(entities: ModelData[], skip?: number, limit?: number): ModelData[];
+
+  /**
+   * Validate skip clause.
+   *
+   * @param skip
+   */
+  static validateSkipClause(skip: number | undefined): void;
+
+  /**
+   * Validate limit clause.
+   *
+   * @param limit
+   */
+  static validateLimitClause(limit: number | undefined): void;
+}

+ 23 - 0
src/filter/where-clause-tool.d.ts

@@ -0,0 +1,23 @@
+import {ModelData} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+import {WhereClause} from './filter-clause.js';
+
+/**
+ * Where clause tool.
+ */
+export declare class WhereClauseTool extends Service {
+  /**
+   * Filter.
+   *
+   * @param entities
+   * @param where
+   */
+  filter(entities: ModelData[], where: WhereClause | undefined): ModelData[];
+
+  /**
+   * Validate where clause.
+   *
+   * @param clause
+   */
+  static validateWhereClause(clause: WhereClause | undefined): void;
+}

+ 9 - 0
src/index.d.ts

@@ -0,0 +1,9 @@
+export * from './types.js';
+export * from './utils/index.js';
+export * from './errors/index.js';
+export * from './filter/index.js';
+export * from './adapter/index.js';
+export * from './database-schema.js';
+export * from './relations/index.js';
+export * from './definition/index.js';
+export * from './repository/index.js';

+ 1 - 0
src/index.js

@@ -1,3 +1,4 @@
+export * from './types.js';
 export * from './utils/index.js';
 export * from './utils/index.js';
 export * from './errors/index.js';
 export * from './errors/index.js';
 export * from './filter/index.js';
 export * from './filter/index.js';

+ 46 - 0
src/relations/belongs-to-resolver.d.ts

@@ -0,0 +1,46 @@
+import {ModelData} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+import {FilterClause} from '../filter/index.js';
+
+/**
+ * Belongs to resolver.
+ */
+export declare class BelongsToResolver extends Service {
+  /**
+   * Include to.
+   *
+   * @param entities
+   * @param sourceName
+   * @param targetName
+   * @param relationName
+   * @param foreignKey
+   * @param scope
+   */
+  includeTo(
+    entities: ModelData[],
+    sourceName: string,
+    targetName: string,
+    relationName: string,
+    foreignKey?: string,
+    scope?: FilterClause,
+  ): Promise<void>;
+
+  /**
+   * Include polymorphic to.
+   *
+   * @param entities
+   * @param sourceName
+   * @param relationName
+   * @param foreignKey
+   * @param discriminator
+   * @param scope
+   */
+  includePolymorphicTo(
+    entities: ModelData[],
+    sourceName: string,
+    relationName: string,
+    foreignKey?: string,
+    discriminator?: string,
+    scope?: FilterClause,
+  ): Promise<void>;
+}

+ 2 - 1
src/relations/belongs-to-resolver.js

@@ -1,6 +1,7 @@
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
+import {cloneDeep} from '../utils/index.js';
+import {singularize} from '../utils/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
-import {cloneDeep, singularize} from '../utils/index.js';
 import {RepositoryRegistry} from '../repository/index.js';
 import {RepositoryRegistry} from '../repository/index.js';
 import {ModelDefinitionUtils} from '../definition/index.js';
 import {ModelDefinitionUtils} from '../definition/index.js';
 
 

+ 3 - 6
src/relations/belongs-to-resolver.spec.js

@@ -1,13 +1,10 @@
 import {expect} from 'chai';
 import {expect} from 'chai';
 import {format} from '@e22m4u/js-format';
 import {format} from '@e22m4u/js-format';
+import {DataType} from '../definition/index.js';
+import {RelationType} from '../definition/index.js';
 import {DatabaseSchema} from '../database-schema.js';
 import {DatabaseSchema} from '../database-schema.js';
 import {BelongsToResolver} from './belongs-to-resolver.js';
 import {BelongsToResolver} from './belongs-to-resolver.js';
-
-import {
-  DataType,
-  RelationType,
-  DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK,
-} from '../definition/index.js';
+import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '../definition/index.js';
 
 
 describe('BelongsToResolver', function () {
 describe('BelongsToResolver', function () {
   describe('includeTo', function () {
   describe('includeTo', function () {

+ 67 - 0
src/relations/has-many-resolver.d.ts

@@ -0,0 +1,67 @@
+import {ModelData} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+import {FilterClause} from '../filter/index.js';
+
+/**
+ * Has many resolver.
+ */
+export declare class HasManyResolver extends Service {
+  /**
+   * Include to.
+   *
+   * @param entities
+   * @param sourceName
+   * @param targetName
+   * @param relationName
+   * @param foreignKey
+   * @param scope
+   */
+  includeTo(
+    entities: ModelData[],
+    sourceName: string,
+    targetName: string,
+    relationName: string,
+    foreignKey: string,
+    scope?: FilterClause,
+  ): Promise<void>;
+
+  /**
+   * Include polymorphic to.
+   *
+   * @param entities
+   * @param sourceName
+   * @param targetName
+   * @param relationName
+   * @param foreignKey
+   * @param discriminator
+   * @param scope
+   */
+  includePolymorphicTo(
+    entities: ModelData[],
+    sourceName: string,
+    targetName: string,
+    relationName: string,
+    foreignKey: string,
+    discriminator: string,
+    scope?: FilterClause,
+  ): Promise<void>;
+
+  /**
+   * Include polymorphic by relation name.
+   *
+   * @param entities
+   * @param sourceName
+   * @param targetName
+   * @param relationName
+   * @param targetRelationName
+   * @param scope
+   */
+  includePolymorphicByRelationName(
+    entities: ModelData[],
+    sourceName: string,
+    targetName: string,
+    relationName: string,
+    targetRelationName: string,
+    scope?: FilterClause,
+  ): Promise<void>;
+}

+ 2 - 1
src/relations/has-many-resolver.js

@@ -1,8 +1,9 @@
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
 import {cloneDeep} from '../utils/index.js';
 import {cloneDeep} from '../utils/index.js';
+import {RelationType} from '../definition/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
 import {RepositoryRegistry} from '../repository/index.js';
 import {RepositoryRegistry} from '../repository/index.js';
-import {RelationType, ModelDefinitionUtils} from '../definition/index.js';
+import {ModelDefinitionUtils} from '../definition/index.js';
 
 
 /**
 /**
  * Has many resolver.
  * Has many resolver.

+ 3 - 6
src/relations/has-many-resolver.spec.js

@@ -1,13 +1,10 @@
 import {expect} from 'chai';
 import {expect} from 'chai';
 import {format} from '@e22m4u/js-format';
 import {format} from '@e22m4u/js-format';
+import {DataType} from '../definition/index.js';
+import {RelationType} from '../definition/index.js';
 import {DatabaseSchema} from '../database-schema.js';
 import {DatabaseSchema} from '../database-schema.js';
 import {HasManyResolver} from './has-many-resolver.js';
 import {HasManyResolver} from './has-many-resolver.js';
-
-import {
-  DataType,
-  RelationType,
-  DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK,
-} from '../definition/index.js';
+import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '../definition/index.js';
 
 
 describe('HasManyResolver', function () {
 describe('HasManyResolver', function () {
   describe('includeTo', function () {
   describe('includeTo', function () {

+ 67 - 0
src/relations/has-one-resolver.d.ts

@@ -0,0 +1,67 @@
+import {ModelData} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+import {FilterClause} from '../filter/index.js';
+
+/**
+ * Has one resolver.
+ */
+export declare class HasOneResolver extends Service {
+  /**
+   * Include to.
+   *
+   * @param entities
+   * @param sourceName
+   * @param targetName
+   * @param relationName
+   * @param foreignKey
+   * @param scope
+   */
+  includeTo(
+    entities: ModelData[],
+    sourceName: string,
+    targetName: string,
+    relationName: string,
+    foreignKey: string,
+    scope?: FilterClause,
+  ): Promise<void>;
+
+  /**
+   * Include polymorphic to.
+   *
+   * @param entities
+   * @param sourceName
+   * @param targetName
+   * @param relationName
+   * @param foreignKey
+   * @param discriminator
+   * @param scope
+   */
+  includePolymorphicTo(
+    entities: ModelData[],
+    sourceName: string,
+    targetName: string,
+    relationName: string,
+    foreignKey: string,
+    discriminator: string,
+    scope?: FilterClause,
+  ): Promise<void>;
+
+  /**
+   * Include polymorphic by relation name.
+   *
+   * @param entities
+   * @param sourceName
+   * @param targetName
+   * @param relationName
+   * @param targetRelationName
+   * @param scope
+   */
+  includePolymorphicByRelationName(
+    entities: ModelData[],
+    sourceName: string,
+    targetName: string,
+    relationName: string,
+    targetRelationName: string,
+    scope?: FilterClause,
+  ): Promise<void>;
+}

+ 2 - 1
src/relations/has-one-resolver.js

@@ -1,8 +1,9 @@
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
 import {cloneDeep} from '../utils/index.js';
 import {cloneDeep} from '../utils/index.js';
+import {RelationType} from '../definition/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
 import {RepositoryRegistry} from '../repository/index.js';
 import {RepositoryRegistry} from '../repository/index.js';
-import {RelationType, ModelDefinitionUtils} from '../definition/index.js';
+import {ModelDefinitionUtils} from '../definition/index.js';
 
 
 /**
 /**
  * Has one resolver.
  * Has one resolver.

+ 3 - 6
src/relations/has-one-resolver.spec.js

@@ -1,13 +1,10 @@
 import {expect} from 'chai';
 import {expect} from 'chai';
 import {format} from '@e22m4u/js-format';
 import {format} from '@e22m4u/js-format';
+import {DataType} from '../definition/index.js';
+import {RelationType} from '../definition/index.js';
 import {HasOneResolver} from './has-one-resolver.js';
 import {HasOneResolver} from './has-one-resolver.js';
 import {DatabaseSchema} from '../database-schema.js';
 import {DatabaseSchema} from '../database-schema.js';
-
-import {
-  DataType,
-  RelationType,
-  DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK,
-} from '../definition/index.js';
+import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '../definition/index.js';
 
 
 describe('HasOneResolver', function () {
 describe('HasOneResolver', function () {
   describe('includeTo', function () {
   describe('includeTo', function () {

+ 4 - 0
src/relations/index.d.ts

@@ -0,0 +1,4 @@
+export * from './has-one-resolver.js';
+export * from './has-many-resolver.js';
+export * from './belongs-to-resolver.js';
+export * from './references-many-resolver.js';

+ 27 - 0
src/relations/references-many-resolver.d.ts

@@ -0,0 +1,27 @@
+import {ModelData} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+import {FilterClause} from '../filter/index.js';
+
+/**
+ * References many resolver.
+ */
+export declare class ReferencesManyResolver extends Service {
+  /**
+   * Include to.
+   *
+   * @param entities
+   * @param sourceName
+   * @param targetName
+   * @param relationName
+   * @param foreignKey
+   * @param scope
+   */
+  includeTo(
+    entities: ModelData[],
+    sourceName: string,
+    targetName: string,
+    relationName: string,
+    foreignKey?: string,
+    scope?: FilterClause,
+  ): Promise<void>;
+}

+ 2 - 1
src/relations/references-many-resolver.js

@@ -1,6 +1,7 @@
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
+import {cloneDeep} from '../utils/index.js';
+import {singularize} from '../utils/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
-import {cloneDeep, singularize} from '../utils/index.js';
 import {RepositoryRegistry} from '../repository/index.js';
 import {RepositoryRegistry} from '../repository/index.js';
 import {ModelDefinitionUtils} from '../definition/index.js';
 import {ModelDefinitionUtils} from '../definition/index.js';
 
 

+ 3 - 6
src/relations/references-many-resolver.spec.js

@@ -1,13 +1,10 @@
 import {expect} from 'chai';
 import {expect} from 'chai';
 import {format} from '@e22m4u/js-format';
 import {format} from '@e22m4u/js-format';
+import {DataType} from '../definition/index.js';
+import {RelationType} from '../definition/index.js';
 import {DatabaseSchema} from '../database-schema.js';
 import {DatabaseSchema} from '../database-schema.js';
 import {ReferencesManyResolver} from './references-many-resolver.js';
 import {ReferencesManyResolver} from './references-many-resolver.js';
-
-import {
-  DataType,
-  RelationType,
-  DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK,
-} from '../definition/index.js';
+import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '../definition/index.js';
 
 
 describe('ReferencesManyResolver', function () {
 describe('ReferencesManyResolver', function () {
   describe('includeTo', function () {
   describe('includeTo', function () {

+ 2 - 0
src/repository/index.d.ts

@@ -0,0 +1,2 @@
+export * from './repository.js';
+export * from './repository-registry.js';

+ 29 - 0
src/repository/repository-registry.d.ts

@@ -0,0 +1,29 @@
+import {ModelId} from '../types.js';
+import {ModelData} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+import {Repository} from './repository.js';
+import {Constructor} from '@e22m4u/js-service';
+import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME} from '../definition/index.js';
+
+/**
+ * Repository registry.
+ */
+export declare class RepositoryRegistry extends Service {
+  /**
+   * Set repository registry.
+   *
+   * @param ctor
+   */
+  setRepositoryCtor(ctor: Constructor<Repository<any, any, any>>): void;
+
+  /**
+   * Get repository.
+   *
+   * @param modelName
+   */
+  getRepository<
+    Data extends ModelData = ModelData,
+    IdType extends ModelId = ModelId,
+    IdName extends string = typeof DEFAULT_PRIMARY_KEY_PROPERTY_NAME,
+  >(modelName: string): Repository<Data, IdType, IdName>;
+}

+ 183 - 0
src/repository/repository.d.ts

@@ -0,0 +1,183 @@
+import {ModelId} from '../types.js';
+import {Flatten} from '../types.js';
+import {ModelData} from '../types.js';
+import {PartialBy} from '../types.js';
+import {Service} from '@e22m4u/js-service';
+import {Adapter} from '../adapter/index.js';
+import {WhereClause} from '../filter/index.js';
+import {FilterClause} from '../filter/index.js';
+import {ItemFilterClause} from '../filter/index.js';
+import {ServiceContainer} from '@e22m4u/js-service';
+import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME} from '../definition/index.js';
+
+/**
+ * Repository.
+ */
+export declare class Repository<
+  Data extends object = ModelData,
+  IdType extends ModelId = ModelId,
+  IdName extends string = typeof DEFAULT_PRIMARY_KEY_PROPERTY_NAME,
+  FlatData extends object = Flatten<Data>,
+> extends Service {
+  // it fixes unused generic bug
+  private _Data?: Data;
+  private _IdType?: IdType;
+  private _IdName?: IdName;
+  private _FlatData?: FlatData;
+
+  /**
+   * Model name.
+   */
+  get modelName(): string;
+
+  /**
+   * Datasource name.
+   */
+  get datasourceName(): string;
+
+  /**
+   * Constructor.
+   *
+   * @param container
+   * @param modelName
+   */
+  constructor(container: ServiceContainer, modelName: string);
+
+  /**
+   * Get adapter.
+   */
+  getAdapter(): Promise<Adapter>;
+
+  /**
+   * Create.
+   *
+   * @param data
+   * @param filter
+   */
+  create(
+    data: WithOptionalId<FlatData, IdName>,
+    filter?: ItemFilterClause<FlatData>,
+  ): Promise<FlatData>;
+
+  /**
+   * Replace by id.
+   *
+   * @param id
+   * @param data
+   * @param filter
+   */
+  replaceById(
+    id: IdType,
+    data: WithoutId<FlatData, IdName>,
+    filter?: ItemFilterClause<FlatData>,
+  ): Promise<FlatData>;
+
+  /**
+   * Replace or create.
+   *
+   * @param data
+   * @param filter
+   */
+  replaceOrCreate(
+    data: WithOptionalId<FlatData, IdName>,
+    filter?: ItemFilterClause<FlatData>,
+  ): Promise<FlatData>;
+
+  /**
+   * Patch.
+   *
+   * @param data
+   * @param where
+   */
+  patch(
+    data: PartialWithoutId<FlatData, IdName>,
+    where?: WhereClause<FlatData>,
+  ): Promise<number>;
+
+  /**
+   * Patch by id.
+   *
+   * @param id
+   * @param data
+   * @param filter
+   */
+  patchById(
+    id: IdType,
+    data: PartialWithoutId<FlatData, IdName>,
+    filter?: ItemFilterClause<FlatData>,
+  ): Promise<FlatData>;
+
+  /**
+   * Find.
+   *
+   * @param filter
+   */
+  find(filter?: FilterClause<FlatData>): Promise<FlatData[]>;
+
+  /**
+   * Find one.
+   *
+   * @param filter
+   */
+  findOne(filter?: FilterClause<FlatData>): Promise<FlatData | undefined>;
+
+  /**
+   * Find by id.
+   *
+   * @param id
+   * @param filter
+   */
+  findById(id: IdType, filter?: ItemFilterClause<FlatData>): Promise<FlatData>;
+
+  /**
+   * Delete.
+   *
+   * @param where
+   */
+  delete(where?: WhereClause<FlatData>): Promise<number>;
+
+  /**
+   * Delete by id.
+   *
+   * @param id
+   */
+  deleteById(id: IdType): Promise<boolean>;
+
+  /**
+   * Exists.
+   *
+   * @param id
+   */
+  exists(id: IdType): Promise<boolean>;
+
+  /**
+   * Count.
+   *
+   * @param where
+   */
+  count(where?: WhereClause<FlatData>): Promise<number>;
+}
+
+/**
+ * Removes id field.
+ */
+export declare type WithoutId<
+  Data extends object,
+  IdName extends string = 'id',
+> = Flatten<Omit<Data, IdName>>;
+
+/**
+ * Makes fields as optional and remove id field.
+ */
+export declare type PartialWithoutId<
+  Data extends object,
+  IdName extends string = 'id',
+> = Flatten<Partial<Omit<Data, IdName>>>;
+
+/**
+ * Makes the required id field as optional.
+ */
+export declare type WithOptionalId<
+  Data extends object,
+  IdName extends string = 'id',
+> = Flatten<Data extends {[K in IdName]: any} ? PartialBy<Data, IdName> : Data>;

+ 2 - 1
src/repository/repository.js

@@ -1,7 +1,8 @@
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
+import {Adapter} from '../adapter/index.js';
+import {AdapterRegistry} from '../adapter/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
 import {InvalidArgumentError} from '../errors/index.js';
 import {DefinitionRegistry} from '../definition/index.js';
 import {DefinitionRegistry} from '../definition/index.js';
-import {Adapter, AdapterRegistry} from '../adapter/index.js';
 
 
 /**
 /**
  * Repository.
  * Repository.

+ 43 - 0
src/types.d.ts

@@ -0,0 +1,43 @@
+/**
+ * Free-form object with open properties.
+ */
+export declare type AnyObject = {
+  [property: string]: unknown;
+};
+
+/**
+ * Makes specific field as optional.
+ */
+export declare type PartialBy<T, K extends keyof T> = Omit<T, K> &
+  Partial<Pick<T, K>>;
+
+/**
+ * Model data.
+ */
+export declare type ModelData = Record<string, unknown>;
+
+/**
+ * Model id.
+ */
+export declare type ModelId = unknown;
+
+/**
+ * Flatten.
+ */
+type Identity<T> = T;
+export declare type Flatten<T> = Identity<{[k in keyof T]: T[k]}>;
+
+/**
+ * A callable type with the "new" operator
+ * allows class and constructor.
+ */
+export interface Constructor<T = unknown> {
+  new (...args: any[]): T;
+}
+
+/**
+ * Representing a value or promise. This type is used
+ * to represent results of synchronous/asynchronous
+ * resolution of values.
+ */
+export type ValueOrPromise<T> = T | PromiseLike<T>;

+ 1 - 0
src/types.js

@@ -0,0 +1 @@
+export {};

+ 6 - 0
src/utils/capitalize.d.ts

@@ -0,0 +1,6 @@
+/**
+ * Capitalize.
+ *
+ * @param string
+ */
+export declare function capitalize(string: string): string;

+ 6 - 0
src/utils/clone-deep.d.ts

@@ -0,0 +1,6 @@
+/**
+ * Clone deep.
+ *
+ * @param value
+ */
+export declare function cloneDeep<T>(value: T): T;

+ 10 - 0
src/utils/exclude-object-keys.d.ts

@@ -0,0 +1,10 @@
+/**
+ * Exclude object keys.
+ *
+ * @param obj
+ * @param keys
+ */
+export declare function excludeObjectKeys<T extends object>(
+  obj: T,
+  keys: string | string[],
+): Partial<T>;

+ 12 - 0
src/utils/get-value-by-path.d.ts

@@ -0,0 +1,12 @@
+/**
+ * Get value by path.
+ *
+ * @param obj
+ * @param path
+ * @param orElse
+ */
+export declare function getValueByPath(
+  obj: object,
+  path: string,
+  orElse?: unknown,
+): unknown;

+ 12 - 0
src/utils/index.d.ts

@@ -0,0 +1,12 @@
+export * from './is-promise.js';
+export * from './capitalize.js';
+export * from './clone-deep.js';
+export * from './singularize.js';
+export * from './is-deep-equal.js';
+export * from './like-to-regexp.js';
+export * from './is-plain-object.js';
+export * from './string-to-regexp.js';
+export * from './get-value-by-path.js';
+export * from './select-object-keys.js';
+export * from './exclude-object-keys.js';
+export * from './model-name-to-model-key.js';

+ 10 - 0
src/utils/is-deep-equal.d.ts

@@ -0,0 +1,10 @@
+/**
+ * Is deep equal.
+ *
+ * @param firstValue
+ * @param secondValue
+ */
+export declare function isDeepEqual(
+  firstValue: unknown,
+  secondValue: unknown,
+): boolean;

+ 6 - 0
src/utils/is-plain-object.d.ts

@@ -0,0 +1,6 @@
+/**
+ * Is plain object.
+ *
+ * @param value
+ */
+export declare function isPlainObject(value: unknown): boolean;

+ 4 - 4
src/utils/is-plain-object.js

@@ -7,9 +7,9 @@
 export function isPlainObject(value) {
 export function isPlainObject(value) {
   return Boolean(
   return Boolean(
     typeof value === 'object' &&
     typeof value === 'object' &&
-    value &&
-    !Array.isArray(value) &&
-    (!value.constructor ||
-      (value.constructor && value.constructor.name === 'Object')),
+      value &&
+      !Array.isArray(value) &&
+      (!value.constructor ||
+        (value.constructor && value.constructor.name === 'Object')),
   );
   );
 }
 }

+ 10 - 0
src/utils/is-promise.d.ts

@@ -0,0 +1,10 @@
+/**
+ * Check whether a value is a Promise-like
+ * instance. Recognizes both native promises
+ * and third-party promise libraries.
+ *
+ * @param value
+ */
+export declare function isPromise<T>(
+  value: T | PromiseLike<T> | undefined
+): value is PromiseLike<T>;

+ 14 - 0
src/utils/like-to-regexp.d.ts

@@ -0,0 +1,14 @@
+/**
+ * Преобразует SQL LIKE-шаблон в объект RegExp.
+ *
+ * Экранирует специальные символы регулярных выражений,
+ * чтобы они обрабатывались как обычные символы, и преобразует
+ * SQL wildcards (% и _) в их эквиваленты в регулярных выражениях.
+ *
+ * @param pattern
+ * @param isCaseInsensitive
+ */
+export function likeToRegexp(
+  pattern: string,
+  isCaseInsensitive?: boolean,
+): RegExp;

Some files were not shown because too many files changed in this diff