@e22m4u/js-repository 0.2.5 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +394 -394
- package/dist/cjs/index.cjs +3 -3
- package/package.json +32 -33
- package/src/chai.js +0 -2
- package/README-ru.md +0 -962
package/README.md
CHANGED
|
@@ -1,44 +1,42 @@
|
|
|
1
1
|
## @e22m4u/js-repository
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- [
|
|
8
|
-
- [
|
|
9
|
-
- [
|
|
10
|
-
- [
|
|
11
|
-
- [
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
14
|
-
- [
|
|
15
|
-
- [
|
|
16
|
-
- [
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [Relations](#Relations)
|
|
21
|
-
- [Extension](#Extension)
|
|
3
|
+
Реализация паттерна «Репозиторий» для работы с базами данных в Node.js
|
|
4
|
+
|
|
5
|
+
- [Установка](#Установка)
|
|
6
|
+
- [Импорт](#Импорт)
|
|
7
|
+
- [Описание](#Описание)
|
|
8
|
+
- [Пример](#Пример)
|
|
9
|
+
- [Схема](#Схема)
|
|
10
|
+
- [Источник данных](#Источник-данных)
|
|
11
|
+
- [Модель](#Модель)
|
|
12
|
+
- [Свойства](#Свойства)
|
|
13
|
+
- [Валидаторы](#Валидаторы)
|
|
14
|
+
- [Трансформеры](#Трансформеры)
|
|
15
|
+
- [Пустые значения](#Пустые-значения)
|
|
16
|
+
- [Репозиторий](#Репозиторий)
|
|
17
|
+
- [Фильтрация](#Фильтрация)
|
|
18
|
+
- [Связи](#Связи)
|
|
19
|
+
- [Расширение](#Расширение)
|
|
22
20
|
- [TypeScript](#TypeScript)
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
21
|
+
- [Тесты](#Тесты)
|
|
22
|
+
- [Лицензия](#Лицензия)
|
|
25
23
|
|
|
26
|
-
##
|
|
24
|
+
## Установка
|
|
27
25
|
|
|
28
26
|
```bash
|
|
29
27
|
npm install @e22m4u/js-repository
|
|
30
28
|
```
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
Опционально устанавливаем адаптер.
|
|
33
31
|
|
|
34
|
-
| |
|
|
35
|
-
|
|
36
|
-
| `memory` |
|
|
37
|
-
| `mongodb` | MongoDB -
|
|
32
|
+
| | описание |
|
|
33
|
+
|-----------|--------------------------------------------------------------------------------------------------------------------------------|
|
|
34
|
+
| `memory` | виртуальная база в памяти процесса (не требует установки) |
|
|
35
|
+
| `mongodb` | MongoDB - система управления NoSQL базами (*[установка](https://www.npmjs.com/package/@e22m4u/js-repository-mongodb-adapter))* |
|
|
38
36
|
|
|
39
|
-
##
|
|
37
|
+
## Импорт
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
Модуль поддерживает ESM и CommonJS стандарты.
|
|
42
40
|
|
|
43
41
|
*ESM*
|
|
44
42
|
|
|
@@ -52,97 +50,95 @@ import {Schema} from '@e22m4u/js-repository';
|
|
|
52
50
|
const {Schema} = require('@e22m4u/js-repository');
|
|
53
51
|
```
|
|
54
52
|
|
|
55
|
-
##
|
|
53
|
+
## Описание
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"one-to-one", "one-to-many" and others between models.
|
|
55
|
+
Модуль позволяет абстрагироваться от различных интерфейсов баз данных,
|
|
56
|
+
представляя их как именованные *источники данных*, подключаемые к *моделям*.
|
|
57
|
+
*Модель* же описывает таблицу базы, колонки которой являются свойствами
|
|
58
|
+
модели. Свойства модели могут иметь определенный *тип* допустимого значения,
|
|
59
|
+
набор *валидаторов* и *трансформеров*, через которые проходят данные перед
|
|
60
|
+
записью в базу. Кроме того, *модель* может определять классические связи
|
|
61
|
+
«один к одному», «один ко многим» и другие типы отношений между моделями.
|
|
65
62
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
- *Data Source* - defines database connection settings
|
|
72
|
-
- *Model* - describes document structure and relationships with other models
|
|
73
|
-
- *Repository* - handles read and write operations for model documents
|
|
63
|
+
Непосредственно чтение и запись данных производится с помощью *репозитория*,
|
|
64
|
+
который имеет каждая модель с объявленным *источником данных*. Репозиторий
|
|
65
|
+
может фильтровать запрашиваемые документы, выполнять валидацию свойств
|
|
66
|
+
согласно определению модели, и встраивать связанные данные в результат
|
|
67
|
+
выборки.
|
|
74
68
|
|
|
69
|
+
- *Источник данных* - определяет способ подключения к базе
|
|
70
|
+
- *Модель* - описывает структуру документа и связи к другим моделям
|
|
71
|
+
- *Репозиторий* - выполняет операции чтения и записи документов модели
|
|
75
72
|
|
|
76
73
|
```mermaid
|
|
77
74
|
flowchart TD
|
|
78
75
|
|
|
79
|
-
A[
|
|
80
|
-
subgraph
|
|
81
|
-
B[
|
|
82
|
-
C[
|
|
76
|
+
A[Схема]
|
|
77
|
+
subgraph Базы данных
|
|
78
|
+
B[Источник данных 1]
|
|
79
|
+
C[Источник данных 2]
|
|
83
80
|
end
|
|
84
81
|
A-->B
|
|
85
82
|
A-->C
|
|
86
83
|
|
|
87
|
-
subgraph
|
|
88
|
-
D[
|
|
89
|
-
E[
|
|
90
|
-
F[
|
|
91
|
-
G[
|
|
84
|
+
subgraph Коллекции
|
|
85
|
+
D[Модель A]
|
|
86
|
+
E[Модель Б]
|
|
87
|
+
F[Модель В]
|
|
88
|
+
G[Модель Г]
|
|
92
89
|
end
|
|
93
90
|
B-->D
|
|
94
91
|
B-->E
|
|
95
92
|
C-->F
|
|
96
93
|
C-->G
|
|
97
94
|
|
|
98
|
-
H[
|
|
99
|
-
I[
|
|
100
|
-
J[
|
|
101
|
-
K[
|
|
95
|
+
H[Репозиторий A]
|
|
96
|
+
I[Репозиторий Б]
|
|
97
|
+
J[Репозиторий В]
|
|
98
|
+
K[Репозиторий Г]
|
|
102
99
|
D-->H
|
|
103
100
|
E-->I
|
|
104
101
|
F-->J
|
|
105
102
|
G-->K
|
|
106
103
|
```
|
|
107
104
|
|
|
108
|
-
##
|
|
105
|
+
## Пример
|
|
109
106
|
|
|
110
|
-
|
|
111
|
-
a new document to the collection.
|
|
107
|
+
Объявление источника данных, модели и добавление нового документа в коллекцию.
|
|
112
108
|
|
|
113
109
|
```js
|
|
114
110
|
import {Schema} from '@e22m4u/js-repository';
|
|
115
111
|
import {DataType} from '@e22m4u/js-repository';
|
|
116
112
|
|
|
117
|
-
//
|
|
113
|
+
// создание экземпляра Schema
|
|
118
114
|
const schema = new Schema();
|
|
119
115
|
|
|
120
|
-
//
|
|
116
|
+
// объявление источника "myMemory"
|
|
121
117
|
schema.defineDatasource({
|
|
122
|
-
name: 'myMemory', //
|
|
123
|
-
adapter: 'memory', //
|
|
118
|
+
name: 'myMemory', // название нового источника
|
|
119
|
+
adapter: 'memory', // выбранный адаптер
|
|
124
120
|
});
|
|
125
121
|
|
|
126
|
-
//
|
|
122
|
+
// объявление модели "country"
|
|
127
123
|
schema.defineModel({
|
|
128
|
-
name: 'country', //
|
|
129
|
-
datasource: 'myMemory', //
|
|
130
|
-
properties: { //
|
|
131
|
-
name: DataType.STRING, // "string"
|
|
132
|
-
population: DataType.NUMBER, // "number"
|
|
124
|
+
name: 'country', // название новой модели
|
|
125
|
+
datasource: 'myMemory', // выбранный источник
|
|
126
|
+
properties: { // свойства модели
|
|
127
|
+
name: DataType.STRING, // тип "string"
|
|
128
|
+
population: DataType.NUMBER, // тип "number"
|
|
133
129
|
},
|
|
134
130
|
})
|
|
135
131
|
|
|
136
|
-
//
|
|
132
|
+
// получение репозитория модели "country"
|
|
137
133
|
const countryRep = schema.getRepository('country');
|
|
138
134
|
|
|
139
|
-
//
|
|
135
|
+
// добавление нового документа в коллекцию "country"
|
|
140
136
|
const country = await countryRep.create({
|
|
141
137
|
name: 'Russia',
|
|
142
138
|
population: 143400000,
|
|
143
139
|
});
|
|
144
140
|
|
|
145
|
-
//
|
|
141
|
+
// вывод нового документа
|
|
146
142
|
console.log(country);
|
|
147
143
|
// {
|
|
148
144
|
// "id": 1,
|
|
@@ -151,19 +147,19 @@ console.log(country);
|
|
|
151
147
|
// }
|
|
152
148
|
```
|
|
153
149
|
|
|
154
|
-
##
|
|
150
|
+
## Схема
|
|
155
151
|
|
|
156
|
-
|
|
152
|
+
Экземпляр класса `Schema` хранит определения источников данных и моделей.
|
|
157
153
|
|
|
158
|
-
|
|
154
|
+
**Методы**
|
|
159
155
|
|
|
160
|
-
- `defineDatasource(datasourceDef: object): this` -
|
|
161
|
-
- `defineModel(modelDef: object): this` -
|
|
162
|
-
- `getRepository(modelName: string): Repository` -
|
|
156
|
+
- `defineDatasource(datasourceDef: object): this` - добавить источник
|
|
157
|
+
- `defineModel(modelDef: object): this` - добавить модель
|
|
158
|
+
- `getRepository(modelName: string): Repository` - получить репозиторий
|
|
163
159
|
|
|
164
|
-
|
|
160
|
+
**Примеры**
|
|
165
161
|
|
|
166
|
-
|
|
162
|
+
Импорт класса и создание экземпляра схемы.
|
|
167
163
|
|
|
168
164
|
```js
|
|
169
165
|
import {Schema} from '@e22m4u/js-repository';
|
|
@@ -171,221 +167,219 @@ import {Schema} from '@e22m4u/js-repository';
|
|
|
171
167
|
const schema = new Schema();
|
|
172
168
|
```
|
|
173
169
|
|
|
174
|
-
|
|
170
|
+
Определение нового источника.
|
|
175
171
|
|
|
176
172
|
```js
|
|
177
173
|
schema.defineDatasource({
|
|
178
|
-
name: 'myMemory', //
|
|
179
|
-
adapter: 'memory', //
|
|
174
|
+
name: 'myMemory', // название нового источника
|
|
175
|
+
adapter: 'memory', // выбранный адаптер
|
|
180
176
|
});
|
|
181
177
|
```
|
|
182
178
|
|
|
183
|
-
|
|
179
|
+
Определение новой модели.
|
|
184
180
|
|
|
185
181
|
```js
|
|
186
182
|
schema.defineModel({
|
|
187
|
-
name: 'product', //
|
|
188
|
-
datasource: 'myMemory', //
|
|
189
|
-
properties: { //
|
|
183
|
+
name: 'product', // название новой модели
|
|
184
|
+
datasource: 'myMemory', // выбранный источник
|
|
185
|
+
properties: { // свойства модели
|
|
190
186
|
name: DataType.STRING,
|
|
191
187
|
weight: DataType.NUMBER,
|
|
192
188
|
},
|
|
193
189
|
});
|
|
194
190
|
```
|
|
195
191
|
|
|
196
|
-
|
|
192
|
+
Получение репозитория по названию модели.
|
|
197
193
|
|
|
198
194
|
```js
|
|
199
195
|
const productRep = schema.getRepository('product');
|
|
200
196
|
```
|
|
201
197
|
|
|
202
|
-
##
|
|
198
|
+
## Источник данных
|
|
203
199
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
method of a schema instance.
|
|
200
|
+
Источник хранит название выбранного адаптера и его настройки. Определение
|
|
201
|
+
нового источника выполняется методом `defineDatasource` экземпляра схемы.
|
|
207
202
|
|
|
208
|
-
|
|
203
|
+
**Параметры**
|
|
209
204
|
|
|
210
|
-
- `name: string`
|
|
211
|
-
- `adapter: string`
|
|
212
|
-
-
|
|
205
|
+
- `name: string` уникальное название
|
|
206
|
+
- `adapter: string` выбранный адаптер
|
|
207
|
+
- параметры адаптера (если имеются)
|
|
213
208
|
|
|
214
|
-
|
|
209
|
+
**Примеры**
|
|
215
210
|
|
|
216
|
-
|
|
211
|
+
Определение нового источника.
|
|
217
212
|
|
|
218
213
|
```js
|
|
219
214
|
schema.defineDatasource({
|
|
220
|
-
name: 'myMemory', //
|
|
221
|
-
adapter: 'memory', //
|
|
215
|
+
name: 'myMemory', // название нового источника
|
|
216
|
+
adapter: 'memory', // выбранный адаптер
|
|
222
217
|
});
|
|
223
218
|
```
|
|
224
219
|
|
|
225
|
-
|
|
220
|
+
Передача дополнительных параметров адаптера.
|
|
226
221
|
|
|
227
222
|
```js
|
|
228
223
|
schema.defineDatasource({
|
|
229
224
|
name: 'myMongodb',
|
|
230
225
|
adapter: 'mongodb',
|
|
231
|
-
//
|
|
226
|
+
// параметры адаптера "mongodb"
|
|
232
227
|
host: '127.0.0.1',
|
|
233
228
|
port: 27017,
|
|
234
229
|
database: 'myDatabase',
|
|
235
230
|
});
|
|
236
231
|
```
|
|
237
232
|
|
|
238
|
-
##
|
|
233
|
+
## Модель
|
|
239
234
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
the `defineModel` method of a schema instance.
|
|
235
|
+
Описывает структуру документа коллекции и связи к другим моделям. Определение
|
|
236
|
+
новой модели выполняется методом `defineModel` экземпляра схемы.
|
|
243
237
|
|
|
244
|
-
|
|
238
|
+
**Параметры**
|
|
245
239
|
|
|
246
|
-
- `name: string`
|
|
247
|
-
- `base: string`
|
|
248
|
-
- `tableName: string`
|
|
249
|
-
- `datasource: string`
|
|
250
|
-
- `properties: object`
|
|
251
|
-
- `relations: object`
|
|
240
|
+
- `name: string` название модели (обязательно)
|
|
241
|
+
- `base: string` название наследуемой модели
|
|
242
|
+
- `tableName: string` название коллекции в базе
|
|
243
|
+
- `datasource: string` выбранный источник данных
|
|
244
|
+
- `properties: object` определения свойств (см. [Свойства](#Свойства))
|
|
245
|
+
- `relations: object` определения связей (см. [Связи](#Связи))
|
|
252
246
|
|
|
253
|
-
|
|
247
|
+
**Примеры**
|
|
254
248
|
|
|
255
|
-
|
|
249
|
+
Определение модели со свойствами указанного типа.
|
|
256
250
|
|
|
257
251
|
```js
|
|
258
252
|
schema.defineModel({
|
|
259
|
-
name: 'user', //
|
|
260
|
-
properties: { //
|
|
253
|
+
name: 'user', // название новой модели
|
|
254
|
+
properties: { // свойства модели
|
|
261
255
|
name: DataType.STRING,
|
|
262
256
|
age: DataType.NUMBER,
|
|
263
257
|
},
|
|
264
258
|
});
|
|
265
259
|
```
|
|
266
260
|
|
|
267
|
-
##
|
|
261
|
+
## Свойства
|
|
268
262
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
263
|
+
Параметр `properties` находится в определении модели и принимает объект, ключи
|
|
264
|
+
которого являются свойствами этой модели, а значением тип свойства или объект
|
|
265
|
+
с дополнительными параметрами.
|
|
272
266
|
|
|
273
|
-
|
|
267
|
+
**Тип данных**
|
|
274
268
|
|
|
275
|
-
- `DataType.ANY`
|
|
276
|
-
- `DataType.STRING`
|
|
277
|
-
- `DataType.NUMBER`
|
|
278
|
-
- `DataType.BOOLEAN`
|
|
279
|
-
- `DataType.ARRAY`
|
|
280
|
-
- `DataType.OBJECT`
|
|
269
|
+
- `DataType.ANY` разрешено любое значение
|
|
270
|
+
- `DataType.STRING` только значение типа `string`
|
|
271
|
+
- `DataType.NUMBER` только значение типа `number`
|
|
272
|
+
- `DataType.BOOLEAN` только значение типа `boolean`
|
|
273
|
+
- `DataType.ARRAY` только значение типа `array`
|
|
274
|
+
- `DataType.OBJECT` только значение типа `object`
|
|
281
275
|
|
|
282
|
-
|
|
276
|
+
**Параметры**
|
|
283
277
|
|
|
284
|
-
- `type: string`
|
|
285
|
-
- `itemType: string`
|
|
286
|
-
- `model: string`
|
|
287
|
-
- `primaryKey: boolean`
|
|
288
|
-
- `columnName: string`
|
|
289
|
-
- `columnType: string`
|
|
290
|
-
- `required: boolean`
|
|
291
|
-
- `default: any`
|
|
292
|
-
- `validate: string | array | object`
|
|
293
|
-
- `unique: boolean | string`
|
|
278
|
+
- `type: string` тип допустимого значения (обязательно)
|
|
279
|
+
- `itemType: string` тип элемента массива (для `type: 'array'`)
|
|
280
|
+
- `model: string` модель объекта (для `type: 'object'`)
|
|
281
|
+
- `primaryKey: boolean` объявить свойство первичным ключом
|
|
282
|
+
- `columnName: string` переопределение названия колонки
|
|
283
|
+
- `columnType: string` тип колонки (определяется адаптером)
|
|
284
|
+
- `required: boolean` объявить свойство обязательным
|
|
285
|
+
- `default: any` значение по умолчанию
|
|
286
|
+
- `validate: string | array | object` см. [Валидаторы](#Валидаторы)
|
|
287
|
+
- `unique: boolean | string` проверять значение на уникальность
|
|
294
288
|
|
|
295
|
-
|
|
289
|
+
**Параметр `unique`**
|
|
296
290
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
291
|
+
Если значением параметра `unique` является `true` или `'strict'`, то выполняется
|
|
292
|
+
строгая проверка на уникальность. В этом режиме [пустые значения](#Пустые-значения)
|
|
293
|
+
так же подлежат проверке, где `null` и `undefined` не могут повторяться более одного
|
|
294
|
+
раза.
|
|
301
295
|
|
|
302
|
-
|
|
303
|
-
[
|
|
304
|
-
|
|
305
|
-
`null`
|
|
296
|
+
Режим `'sparse'` проверяет только значения с полезной нагрузкой, исключая
|
|
297
|
+
[пустые значения](#Пустые-значения), список которых отличается в зависимости
|
|
298
|
+
от типа свойства. Например, для типа `string` пустым значением будет `undefined`,
|
|
299
|
+
`null` и `''` (пустая строка).
|
|
306
300
|
|
|
307
|
-
- `unique: true | 'strict'`
|
|
308
|
-
- `unique: 'sparse'`
|
|
309
|
-
- `unique: false | 'nonUnique'`
|
|
301
|
+
- `unique: true | 'strict'` строгая проверка на уникальность
|
|
302
|
+
- `unique: 'sparse'` исключить из проверки [пустые значения](#Пустые-значения)
|
|
303
|
+
- `unique: false | 'nonUnique'` не проверять на уникальность (по умолчанию)
|
|
310
304
|
|
|
311
|
-
|
|
312
|
-
|
|
305
|
+
В качестве значений параметра `unique` можно использовать предопределенные
|
|
306
|
+
константы как эквивалент строковых значений `strict`, `sparse` и `nonUnique`.
|
|
313
307
|
|
|
314
308
|
- `PropertyUniqueness.STRICT`
|
|
315
309
|
- `PropertyUniqueness.SPARSE`
|
|
316
310
|
- `PropertyUniqueness.NON_UNIQUE`
|
|
317
311
|
|
|
318
|
-
|
|
312
|
+
**Примеры**
|
|
319
313
|
|
|
320
|
-
|
|
314
|
+
Краткое определение свойств модели.
|
|
321
315
|
|
|
322
316
|
```js
|
|
323
317
|
schema.defineModel({
|
|
324
318
|
name: 'city',
|
|
325
|
-
properties: { //
|
|
326
|
-
name: DataType.STRING, // "string"
|
|
327
|
-
population: DataType.NUMBER, // "number"
|
|
319
|
+
properties: { // свойства модели
|
|
320
|
+
name: DataType.STRING, // тип свойства "string"
|
|
321
|
+
population: DataType.NUMBER, // тип свойства "number"
|
|
328
322
|
},
|
|
329
323
|
});
|
|
330
324
|
```
|
|
331
325
|
|
|
332
|
-
|
|
326
|
+
Расширенное определение свойств модели.
|
|
333
327
|
|
|
334
328
|
```js
|
|
335
329
|
schema.defineModel({
|
|
336
330
|
name: 'city',
|
|
337
|
-
properties: { //
|
|
331
|
+
properties: { // свойства модели
|
|
338
332
|
name: {
|
|
339
|
-
type: DataType.STRING, // "string"
|
|
340
|
-
required: true, //
|
|
333
|
+
type: DataType.STRING, // тип свойства "string" (обязательно)
|
|
334
|
+
required: true, // исключение значений undefined и null
|
|
341
335
|
},
|
|
342
336
|
population: {
|
|
343
|
-
type: DataType.NUMBER, // "number"
|
|
344
|
-
default: 0, //
|
|
337
|
+
type: DataType.NUMBER, // тип свойства "number" (обязательно)
|
|
338
|
+
default: 0, // значение по умолчанию
|
|
345
339
|
},
|
|
346
340
|
code: {
|
|
347
|
-
type: DataType.NUMBER, // "number"
|
|
348
|
-
unique: PropertyUniqueness.UNIQUE, //
|
|
341
|
+
type: DataType.NUMBER, // тип свойства "number" (обязательно)
|
|
342
|
+
unique: PropertyUniqueness.UNIQUE, // проверять уникальность
|
|
349
343
|
},
|
|
350
344
|
},
|
|
351
345
|
});
|
|
352
346
|
```
|
|
353
347
|
|
|
354
|
-
|
|
355
|
-
|
|
348
|
+
Фабричное значение по умолчанию. Возвращаемое значение функции будет
|
|
349
|
+
определено в момент записи документа.
|
|
356
350
|
|
|
357
351
|
```js
|
|
358
352
|
schema.defineModel({
|
|
359
353
|
name: 'article',
|
|
360
|
-
properties: { //
|
|
354
|
+
properties: { // свойства модели
|
|
361
355
|
tags: {
|
|
362
|
-
type: DataType.ARRAY, // "array"
|
|
363
|
-
itemType: DataType.STRING, // "string"
|
|
364
|
-
default: () => [], //
|
|
356
|
+
type: DataType.ARRAY, // тип свойства "array" (обязательно)
|
|
357
|
+
itemType: DataType.STRING, // тип элемента "string"
|
|
358
|
+
default: () => [], // фабричное значение
|
|
365
359
|
},
|
|
366
360
|
createdAt: {
|
|
367
|
-
type: DataType.STRING, // "string"
|
|
368
|
-
default: () => new Date().toISOString(), //
|
|
361
|
+
type: DataType.STRING, // тип свойства "string" (обязательно)
|
|
362
|
+
default: () => new Date().toISOString(), // фабричное значение
|
|
369
363
|
},
|
|
370
364
|
},
|
|
371
365
|
});
|
|
372
366
|
```
|
|
373
367
|
|
|
374
|
-
##
|
|
368
|
+
## Валидаторы
|
|
375
369
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
[
|
|
370
|
+
Кроме проверки типа, дополнительные условия можно задать с помощью
|
|
371
|
+
валидаторов, через которые будет проходить значение свойства перед
|
|
372
|
+
записью в базу. Исключением являются [пустые значения](#Пустые-значения),
|
|
373
|
+
которые не подлежат проверке.
|
|
379
374
|
|
|
380
|
-
- `minLength: number`
|
|
381
|
-
- `maxLength: number`
|
|
382
|
-
- `regexp: string | RegExp`
|
|
375
|
+
- `minLength: number` минимальная длинна строки или массива
|
|
376
|
+
- `maxLength: number` максимальная длинна строки или массива
|
|
377
|
+
- `regexp: string | RegExp` проверка по регулярному выражению
|
|
383
378
|
|
|
384
|
-
|
|
379
|
+
**Пример**
|
|
385
380
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
names and settings.
|
|
381
|
+
Валидаторы указываются в объявлении свойства модели параметром
|
|
382
|
+
`validate`, который принимает объект с их названиями и настройками.
|
|
389
383
|
|
|
390
384
|
```js
|
|
391
385
|
schema.defineModel({
|
|
@@ -393,42 +387,42 @@ schema.defineModel({
|
|
|
393
387
|
properties: {
|
|
394
388
|
name: {
|
|
395
389
|
type: DataType.STRING,
|
|
396
|
-
validate: { //
|
|
397
|
-
minLength: 2, //
|
|
398
|
-
maxLength: 24, //
|
|
390
|
+
validate: { // валидаторы свойства "name"
|
|
391
|
+
minLength: 2, // минимальная длинна строки
|
|
392
|
+
maxLength: 24, // максимальная длинна строки
|
|
399
393
|
},
|
|
400
394
|
},
|
|
401
395
|
},
|
|
402
396
|
});
|
|
403
397
|
```
|
|
404
398
|
|
|
405
|
-
###
|
|
399
|
+
### Пользовательские валидаторы
|
|
406
400
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
401
|
+
Валидатором является функция, в которую передается значение соответствующего
|
|
402
|
+
поля перед записью в базу. Если во время проверки функция возвращает `false`,
|
|
403
|
+
то выбрасывается стандартная ошибка. Подмена стандартной ошибки возможна
|
|
404
|
+
с помощью выброса пользовательской ошибки непосредственно внутри функции.
|
|
411
405
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
406
|
+
Регистрация пользовательского валидатора выполняется методом `addValidator`
|
|
407
|
+
сервиса `PropertyValidatorRegistry`, который принимает новое название
|
|
408
|
+
и функцию для проверки значения.
|
|
415
409
|
|
|
416
|
-
|
|
410
|
+
**Пример**
|
|
417
411
|
|
|
418
412
|
```js
|
|
419
|
-
//
|
|
420
|
-
//
|
|
413
|
+
// создание валидатора для запрета
|
|
414
|
+
// всех символов кроме чисел
|
|
421
415
|
const numericValidator = (input) => {
|
|
422
416
|
return /^[0-9]+$/.test(String(input));
|
|
423
417
|
}
|
|
424
418
|
|
|
425
|
-
//
|
|
419
|
+
// регистрация валидатора "numeric"
|
|
426
420
|
schema
|
|
427
421
|
.get(PropertyValidatorRegistry)
|
|
428
422
|
.addValidator('numeric', numericValidator);
|
|
429
423
|
|
|
430
|
-
//
|
|
431
|
-
//
|
|
424
|
+
// использование валидатора в определении
|
|
425
|
+
// свойства "code" для новой модели
|
|
432
426
|
schema.defineModel({
|
|
433
427
|
name: 'document',
|
|
434
428
|
properties: {
|
|
@@ -440,24 +434,25 @@ schema.defineModel({
|
|
|
440
434
|
});
|
|
441
435
|
```
|
|
442
436
|
|
|
443
|
-
##
|
|
437
|
+
## Трансформеры
|
|
444
438
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
439
|
+
С помощью трансформеров производится модификация значений определенных
|
|
440
|
+
полей перед записью в базу. Трансформеры позволяют указать какие изменения
|
|
441
|
+
нужно производить с входящими данными. Исключением являются
|
|
442
|
+
[пустые значения](#Пустые-значения), которые не подлежат трансформации.
|
|
448
443
|
|
|
449
|
-
- `trim`
|
|
450
|
-
- `toUpperCase`
|
|
451
|
-
- `toLowerCase`
|
|
452
|
-
- `toTitleCase`
|
|
444
|
+
- `trim` удаление пробельных символов с начала и конца строки
|
|
445
|
+
- `toUpperCase` перевод строки в верхний регистр
|
|
446
|
+
- `toLowerCase` перевод строки в нижний регистр
|
|
447
|
+
- `toTitleCase` перевод строки в регистр заголовка
|
|
453
448
|
|
|
454
|
-
|
|
449
|
+
**Пример**
|
|
455
450
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
451
|
+
Трансформеры указываются в объявлении свойства модели параметром
|
|
452
|
+
`transform`, который принимает название трансформера. Если требуется
|
|
453
|
+
указать несколько названий, то используется массив. Если трансформер
|
|
454
|
+
имеет настройки, то используется объект, где ключом является название
|
|
455
|
+
трансформера, а значением его параметры.
|
|
461
456
|
|
|
462
457
|
```js
|
|
463
458
|
schema.defineModel({
|
|
@@ -465,25 +460,26 @@ schema.defineModel({
|
|
|
465
460
|
properties: {
|
|
466
461
|
name: {
|
|
467
462
|
type: DataType.STRING,
|
|
468
|
-
transform: [ //
|
|
469
|
-
'trim', //
|
|
470
|
-
'toTitleCase', //
|
|
463
|
+
transform: [ // трансформеры свойства "name"
|
|
464
|
+
'trim', // удалить пробелы в начале и конце строки
|
|
465
|
+
'toTitleCase', // перевод строки в регистр заголовка
|
|
471
466
|
],
|
|
472
467
|
},
|
|
473
468
|
},
|
|
474
469
|
});
|
|
475
470
|
```
|
|
476
471
|
|
|
477
|
-
##
|
|
472
|
+
## Пустые значения
|
|
478
473
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
474
|
+
Разные типы свойств имеют свои наборы пустых значений. Эти наборы
|
|
475
|
+
используются для определения наличия полезной нагрузки в значении
|
|
476
|
+
свойства. Например, параметр `default` в определении свойства
|
|
477
|
+
устанавливает значение по умолчанию, только если входящее значение
|
|
478
|
+
является пустым. Параметр `required` исключает пустые значения
|
|
479
|
+
выбрасывая ошибку. А параметр `unique` в режиме `sparse` наоборот
|
|
480
|
+
допускает дублирование пустых значений уникального свойства.
|
|
485
481
|
|
|
486
|
-
|
|
|
482
|
+
| тип | пустые значения |
|
|
487
483
|
|-------------|---------------------------|
|
|
488
484
|
| `'any'` | `undefined`, `null` |
|
|
489
485
|
| `'string'` | `undefined`, `null`, `''` |
|
|
@@ -492,43 +488,42 @@ mode allows duplicate empty values for a unique property.
|
|
|
492
488
|
| `'array'` | `undefined`, `null`, `[]` |
|
|
493
489
|
| `'object'` | `undefined`, `null`, `{}` |
|
|
494
490
|
|
|
495
|
-
##
|
|
491
|
+
## Репозиторий
|
|
496
492
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
instance's `getRepository` method.
|
|
493
|
+
Выполняет операции чтения и записи документов определенной модели.
|
|
494
|
+
Получить репозиторий можно методом `getRepository` экземпляра схемы.
|
|
500
495
|
|
|
501
|
-
|
|
496
|
+
**Методы**
|
|
502
497
|
|
|
503
|
-
- `create(data, filter = undefined)`
|
|
504
|
-
- `replaceById(id, data, filter = undefined)`
|
|
505
|
-
- `replaceOrCreate(data, filter = undefined)`
|
|
506
|
-
- `patchById(id, data, filter = undefined)`
|
|
507
|
-
- `patch(data, where = undefined)`
|
|
508
|
-
- `find(filter = undefined)`
|
|
509
|
-
- `findOne(filter = undefined)`
|
|
510
|
-
- `findById(id, filter = undefined)`
|
|
511
|
-
- `delete(where = undefined)`
|
|
512
|
-
- `deleteById(id)`
|
|
513
|
-
- `exists(id)`
|
|
514
|
-
- `count(where = undefined)`
|
|
498
|
+
- `create(data, filter = undefined)` добавить новый документ
|
|
499
|
+
- `replaceById(id, data, filter = undefined)` заменить весь документ
|
|
500
|
+
- `replaceOrCreate(data, filter = undefined)` заменить или создать новый
|
|
501
|
+
- `patchById(id, data, filter = undefined)` частично обновить документ
|
|
502
|
+
- `patch(data, where = undefined)` обновить все документы или по условию
|
|
503
|
+
- `find(filter = undefined)` найти все документы или по условию
|
|
504
|
+
- `findOne(filter = undefined)` найти первый документ или по условию
|
|
505
|
+
- `findById(id, filter = undefined)` найти документ по идентификатору
|
|
506
|
+
- `delete(where = undefined)` удалить все документы или по условию
|
|
507
|
+
- `deleteById(id)` удалить документ по идентификатору
|
|
508
|
+
- `exists(id)` проверить существование по идентификатору
|
|
509
|
+
- `count(where = undefined)` подсчет всех документов или по условию
|
|
515
510
|
|
|
516
|
-
|
|
511
|
+
**Аргументы**
|
|
517
512
|
|
|
518
|
-
- `id: number|string`
|
|
519
|
-
- `data: object`
|
|
520
|
-
- `where: object`
|
|
521
|
-
- `filter: object`
|
|
513
|
+
- `id: number|string` идентификатор (первичный ключ)
|
|
514
|
+
- `data: object` объект отражающий состав документа
|
|
515
|
+
- `where: object` параметры выборки (см. [Фильтрация](#Фильтрация))
|
|
516
|
+
- `filter: object` параметры возвращаемого результата (см. [Фильтрация](#Фильтрация))
|
|
522
517
|
|
|
523
|
-
|
|
518
|
+
**Примеры**
|
|
524
519
|
|
|
525
|
-
|
|
520
|
+
Получение репозитория по названию модели.
|
|
526
521
|
|
|
527
522
|
```js
|
|
528
523
|
const countryRep = schema.getRepository('country');
|
|
529
524
|
```
|
|
530
525
|
|
|
531
|
-
|
|
526
|
+
Добавление нового документа в коллекцию.
|
|
532
527
|
|
|
533
528
|
```js
|
|
534
529
|
const res = await countryRep.create({
|
|
@@ -544,7 +539,7 @@ console.log(res);
|
|
|
544
539
|
// }
|
|
545
540
|
```
|
|
546
541
|
|
|
547
|
-
|
|
542
|
+
Поиск документа по идентификатору.
|
|
548
543
|
|
|
549
544
|
```js
|
|
550
545
|
const res = await countryRep.findById(1);
|
|
@@ -557,7 +552,7 @@ console.log(res);
|
|
|
557
552
|
// }
|
|
558
553
|
```
|
|
559
554
|
|
|
560
|
-
|
|
555
|
+
Удаление документа по идентификатору.
|
|
561
556
|
|
|
562
557
|
```js
|
|
563
558
|
const res = await countryRep.deleteById(1);
|
|
@@ -565,47 +560,48 @@ const res = await countryRep.deleteById(1);
|
|
|
565
560
|
console.log(res); // true
|
|
566
561
|
```
|
|
567
562
|
|
|
568
|
-
##
|
|
563
|
+
## Фильтрация
|
|
569
564
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
565
|
+
Некоторые методы репозитория принимают объект настроек влияющий
|
|
566
|
+
на возвращаемый результат. Максимально широкий набор таких настроек
|
|
567
|
+
имеет первый параметр метода `find`, где ожидается объект содержащий
|
|
568
|
+
набор опций указанных ниже.
|
|
573
569
|
|
|
574
|
-
- `where: object`
|
|
575
|
-
- `order: string[]`
|
|
576
|
-
- `limit: number`
|
|
577
|
-
- `skip: number`
|
|
578
|
-
- `fields: string[]`
|
|
579
|
-
- `include: object`
|
|
570
|
+
- `where: object` объект выборки
|
|
571
|
+
- `order: string[]` указание порядка
|
|
572
|
+
- `limit: number` ограничение количества документов
|
|
573
|
+
- `skip: number` пропуск документов
|
|
574
|
+
- `fields: string[]` выбор необходимых свойств модели
|
|
575
|
+
- `include: object` включение связанных данных в результат
|
|
580
576
|
|
|
581
577
|
### where
|
|
582
578
|
|
|
583
|
-
|
|
584
|
-
|
|
579
|
+
Параметр принимает объект с условиями выборки и поддерживает широкий
|
|
580
|
+
набор операторов сравнения.
|
|
585
581
|
|
|
586
|
-
`{foo: 'bar'}`
|
|
587
|
-
`{foo: {eq: 'bar'}}`
|
|
588
|
-
`{foo: {neq: 'bar'}}`
|
|
589
|
-
`{foo: {gt: 5}}`
|
|
590
|
-
`{foo: {lt: 10}}`
|
|
591
|
-
`{foo: {gte: 5}}` "
|
|
592
|
-
`{foo: {lte: 10}}` "
|
|
593
|
-
`{foo: {inq: ['bar', 'baz']}}`
|
|
594
|
-
`{foo: {nin: ['bar', 'baz']}}`
|
|
595
|
-
`{foo: {between: [5, 10]}}`
|
|
596
|
-
`{foo: {exists: true}}`
|
|
597
|
-
`{foo: {like: 'bar'}}`
|
|
598
|
-
`{foo: {ilike: 'BaR'}}`
|
|
599
|
-
`{foo: {nlike: 'bar'}}`
|
|
600
|
-
`{foo: {nilike: 'BaR'}}`
|
|
601
|
-
`{foo: {regexp: 'ba.+'}}`
|
|
602
|
-
`{foo: {regexp: 'ba.+', flags: 'i'}}`
|
|
582
|
+
`{foo: 'bar'}` поиск по значению свойства `foo`
|
|
583
|
+
`{foo: {eq: 'bar'}}` оператор равенства `eq`
|
|
584
|
+
`{foo: {neq: 'bar'}}` оператор неравенства `neq`
|
|
585
|
+
`{foo: {gt: 5}}` оператор "больше" `gt`
|
|
586
|
+
`{foo: {lt: 10}}` оператор "меньше" `lt`
|
|
587
|
+
`{foo: {gte: 5}}` оператор "больше или равно" `gte`
|
|
588
|
+
`{foo: {lte: 10}}` оператор "меньше или равно" `lte`
|
|
589
|
+
`{foo: {inq: ['bar', 'baz']}}` равенство одного из значений `inq`
|
|
590
|
+
`{foo: {nin: ['bar', 'baz']}}` исключение значений массива `nin`
|
|
591
|
+
`{foo: {between: [5, 10]}}` оператор диапазона `between`
|
|
592
|
+
`{foo: {exists: true}}` оператор наличия значения `exists`
|
|
593
|
+
`{foo: {like: 'bar'}}` оператор поиска подстроки `like`
|
|
594
|
+
`{foo: {ilike: 'BaR'}}` регистронезависимая версия `ilike`
|
|
595
|
+
`{foo: {nlike: 'bar'}}` оператор исключения подстроки `nlike`
|
|
596
|
+
`{foo: {nilike: 'BaR'}}` регистронезависимая версия `nilike`
|
|
597
|
+
`{foo: {regexp: 'ba.+'}}` оператор регулярного выражения `regexp`
|
|
598
|
+
`{foo: {regexp: 'ba.+', flags: 'i'}}` флаги регулярного выражения
|
|
603
599
|
|
|
604
|
-
*
|
|
600
|
+
*i. Условия можно объединять операторами `and`, `or` и `nor`.*
|
|
605
601
|
|
|
606
|
-
|
|
602
|
+
**Примеры**
|
|
607
603
|
|
|
608
|
-
|
|
604
|
+
Применение условий выборки при подсчете документов.
|
|
609
605
|
|
|
610
606
|
```js
|
|
611
607
|
const res = await rep.count({
|
|
@@ -616,7 +612,7 @@ const res = await rep.count({
|
|
|
616
612
|
});
|
|
617
613
|
```
|
|
618
614
|
|
|
619
|
-
|
|
615
|
+
Применение оператора `or` при удалении документов.
|
|
620
616
|
|
|
621
617
|
```js
|
|
622
618
|
const res = await rep.delete({
|
|
@@ -629,13 +625,12 @@ const res = await rep.delete({
|
|
|
629
625
|
|
|
630
626
|
### order
|
|
631
627
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
the property name.
|
|
628
|
+
Параметр упорядочивает выборку по указанным свойствам модели. Обратное
|
|
629
|
+
направление порядка можно задать постфиксом `DESC` в названии свойства.
|
|
635
630
|
|
|
636
|
-
|
|
631
|
+
**Примеры**
|
|
637
632
|
|
|
638
|
-
|
|
633
|
+
Упорядочить по полю `createdAt`
|
|
639
634
|
|
|
640
635
|
```js
|
|
641
636
|
const res = await rep.find({
|
|
@@ -643,7 +638,7 @@ const res = await rep.find({
|
|
|
643
638
|
});
|
|
644
639
|
```
|
|
645
640
|
|
|
646
|
-
|
|
641
|
+
Упорядочить по полю `createdAt` в обратном порядке.
|
|
647
642
|
|
|
648
643
|
```js
|
|
649
644
|
const res = await rep.find({
|
|
@@ -651,7 +646,7 @@ const res = await rep.find({
|
|
|
651
646
|
});
|
|
652
647
|
```
|
|
653
648
|
|
|
654
|
-
|
|
649
|
+
Упорядочить по нескольким свойствам в разных направлениях.
|
|
655
650
|
|
|
656
651
|
```js
|
|
657
652
|
const res = await rep.find({
|
|
@@ -663,17 +658,17 @@ const res = await rep.find({
|
|
|
663
658
|
});
|
|
664
659
|
```
|
|
665
660
|
|
|
666
|
-
*
|
|
661
|
+
*i. Направление порядка `ASC` указывать необязательно.*
|
|
667
662
|
|
|
668
663
|
### include
|
|
669
664
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
(
|
|
665
|
+
Параметр включает связанные документы в результат вызываемого метода.
|
|
666
|
+
Названия включаемых связей должны быть определены в текущей модели.
|
|
667
|
+
(см. [Связи](#Связи))
|
|
673
668
|
|
|
674
|
-
|
|
669
|
+
**Примеры**
|
|
675
670
|
|
|
676
|
-
|
|
671
|
+
Включение связи по названию.
|
|
677
672
|
|
|
678
673
|
```js
|
|
679
674
|
const res = await rep.find({
|
|
@@ -681,7 +676,7 @@ const res = await rep.find({
|
|
|
681
676
|
});
|
|
682
677
|
```
|
|
683
678
|
|
|
684
|
-
|
|
679
|
+
Включение вложенных связей.
|
|
685
680
|
|
|
686
681
|
```js
|
|
687
682
|
const res = await rep.find({
|
|
@@ -691,7 +686,7 @@ const res = await rep.find({
|
|
|
691
686
|
});
|
|
692
687
|
```
|
|
693
688
|
|
|
694
|
-
|
|
689
|
+
Включение нескольких связей массивом.
|
|
695
690
|
|
|
696
691
|
```js
|
|
697
692
|
const res = await rep.find({
|
|
@@ -703,171 +698,174 @@ const res = await rep.find({
|
|
|
703
698
|
});
|
|
704
699
|
```
|
|
705
700
|
|
|
706
|
-
|
|
701
|
+
Использование фильтрации включаемых документов.
|
|
707
702
|
|
|
708
703
|
```js
|
|
709
704
|
const res = await rep.find({
|
|
710
705
|
include: {
|
|
711
|
-
relation: 'employees', //
|
|
712
|
-
scope: { //
|
|
713
|
-
where: {hidden: false}, //
|
|
714
|
-
order: 'id', //
|
|
715
|
-
limit: 10, //
|
|
716
|
-
skip: 5, //
|
|
717
|
-
fields: ['name', 'surname'], //
|
|
718
|
-
include: 'city', //
|
|
706
|
+
relation: 'employees', // название связи
|
|
707
|
+
scope: { // фильтрация документов "employees"
|
|
708
|
+
where: {hidden: false}, // условия выборки
|
|
709
|
+
order: 'id', // порядок документов
|
|
710
|
+
limit: 10, // ограничение количества
|
|
711
|
+
skip: 5, // пропуск документов
|
|
712
|
+
fields: ['name', 'surname'], // только указанные поля
|
|
713
|
+
include: 'city', // включение связей для "employees"
|
|
719
714
|
},
|
|
720
715
|
},
|
|
721
716
|
});
|
|
722
717
|
```
|
|
723
718
|
|
|
724
|
-
##
|
|
719
|
+
## Связи
|
|
725
720
|
|
|
726
|
-
|
|
727
|
-
|
|
721
|
+
Параметр `relations` находится в определении модели и принимает
|
|
722
|
+
объект, ключ которого является названием связи, а значением объект
|
|
723
|
+
с параметрами.
|
|
728
724
|
|
|
729
|
-
|
|
725
|
+
**Параметры**
|
|
730
726
|
|
|
731
|
-
- `type: string`
|
|
732
|
-
- `model: string`
|
|
733
|
-
- `foreignKey: string`
|
|
734
|
-
- `polymorphic: boolean|string`
|
|
735
|
-
- `discriminator: string`
|
|
727
|
+
- `type: string` тип связи
|
|
728
|
+
- `model: string` название целевой модели
|
|
729
|
+
- `foreignKey: string` свойство текущей модели для идентификатора цели
|
|
730
|
+
- `polymorphic: boolean|string` объявить связь полиморфной*
|
|
731
|
+
- `discriminator: string` свойство текущей модели для названия целевой*
|
|
736
732
|
|
|
737
|
-
*
|
|
738
|
-
|
|
733
|
+
*i. Полиморфный режим позволяет динамически определять целевую модель
|
|
734
|
+
по ее названию, которое хранит документ в свойстве-дискриминаторе.*
|
|
739
735
|
|
|
740
|
-
|
|
736
|
+
**Тип связи**
|
|
741
737
|
|
|
742
|
-
- `belongsTo` -
|
|
743
|
-
- `hasOne` -
|
|
744
|
-
- `hasMany` -
|
|
745
|
-
- `referencesMany` -
|
|
738
|
+
- `belongsTo` - текущая модель содержит свойство для идентификатора цели
|
|
739
|
+
- `hasOne` - обратная сторона `belongsTo` по принципу "один к одному"
|
|
740
|
+
- `hasMany` - обратная сторона `belongsTo` по принципу "один ко многим"
|
|
741
|
+
- `referencesMany` - документ содержит массив с идентификаторами целевой модели
|
|
746
742
|
|
|
747
|
-
|
|
743
|
+
**Примеры**
|
|
748
744
|
|
|
749
|
-
|
|
745
|
+
Объявление связи `belongsTo`
|
|
750
746
|
|
|
751
747
|
```js
|
|
752
748
|
schema.defineModel({
|
|
753
749
|
name: 'user',
|
|
754
750
|
relations: {
|
|
755
|
-
role: { //
|
|
756
|
-
type: RelationType.BELONGS_TO, //
|
|
757
|
-
model: 'role', //
|
|
758
|
-
foreignKey: 'roleId', //
|
|
759
|
-
//
|
|
760
|
-
//
|
|
751
|
+
role: { // название связи
|
|
752
|
+
type: RelationType.BELONGS_TO, // текущая модель ссылается на целевую
|
|
753
|
+
model: 'role', // название целевой модели
|
|
754
|
+
foreignKey: 'roleId', // внешний ключ (необязательно)
|
|
755
|
+
// если "foreignKey" не указан, то свойство внешнего
|
|
756
|
+
// ключа формируется согласно названию связи
|
|
757
|
+
// с добавлением постфикса "Id"
|
|
761
758
|
},
|
|
762
759
|
},
|
|
763
760
|
});
|
|
764
761
|
```
|
|
765
762
|
|
|
766
|
-
|
|
763
|
+
Объявление связи `hasMany`
|
|
767
764
|
|
|
768
765
|
```js
|
|
769
766
|
schema.defineModel({
|
|
770
767
|
name: 'role',
|
|
771
768
|
relations: {
|
|
772
|
-
users: { //
|
|
773
|
-
type: RelationType.HAS_MANY, //
|
|
774
|
-
model: 'user', //
|
|
775
|
-
foreignKey: 'roleId', //
|
|
769
|
+
users: { // название связи
|
|
770
|
+
type: RelationType.HAS_MANY, // целевая модель ссылается на текущую
|
|
771
|
+
model: 'user', // название целевой модели
|
|
772
|
+
foreignKey: 'roleId', // внешний ключ из целевой модели на текущую
|
|
776
773
|
},
|
|
777
774
|
},
|
|
778
775
|
});
|
|
779
776
|
```
|
|
780
777
|
|
|
781
|
-
|
|
778
|
+
Объявление связи `referencesMany`
|
|
782
779
|
|
|
783
780
|
```js
|
|
784
781
|
schema.defineModel({
|
|
785
782
|
name: 'article',
|
|
786
783
|
relations: {
|
|
787
|
-
categories: { //
|
|
788
|
-
type: RelationType.REFERENCES_MANY, //
|
|
789
|
-
model: 'category', //
|
|
790
|
-
foreignKey: 'categoryIds', //
|
|
791
|
-
//
|
|
792
|
-
//
|
|
784
|
+
categories: { // название связи
|
|
785
|
+
type: RelationType.REFERENCES_MANY, // связь через массив идентификаторов
|
|
786
|
+
model: 'category', // название целевой модели
|
|
787
|
+
foreignKey: 'categoryIds', // внешний ключ (необязательно)
|
|
788
|
+
// если "foreignKey" не указан, то свойство внешнего
|
|
789
|
+
// ключа формируется согласно названию связи
|
|
790
|
+
// с добавлением постфикса "Ids"
|
|
793
791
|
},
|
|
794
792
|
},
|
|
795
793
|
});
|
|
796
794
|
```
|
|
797
795
|
|
|
798
|
-
|
|
796
|
+
Полиморфная версия `belongsTo`
|
|
799
797
|
|
|
800
798
|
```js
|
|
801
799
|
schema.defineModel({
|
|
802
800
|
name: 'file',
|
|
803
801
|
relations: {
|
|
804
|
-
reference: { //
|
|
805
|
-
type: RelationType.BELONGS_TO, //
|
|
806
|
-
//
|
|
807
|
-
//
|
|
808
|
-
//
|
|
809
|
-
//
|
|
810
|
-
//
|
|
802
|
+
reference: { // название связи
|
|
803
|
+
type: RelationType.BELONGS_TO, // текущая модель ссылается на целевую
|
|
804
|
+
// полиморфный режим позволяет хранить название целевой модели
|
|
805
|
+
// в свойстве-дискриминаторе, которое формируется согласно
|
|
806
|
+
// названию связи с постфиксом "Type", и в данном случае
|
|
807
|
+
// название целевой модели хранит "referenceType",
|
|
808
|
+
// а идентификатор документа "referenceId"
|
|
811
809
|
polymorphic: true,
|
|
812
810
|
},
|
|
813
811
|
},
|
|
814
812
|
});
|
|
815
813
|
```
|
|
816
814
|
|
|
817
|
-
|
|
815
|
+
Полиморфная версия `belongsTo` с указанием свойств.
|
|
818
816
|
|
|
819
817
|
```js
|
|
820
818
|
schema.defineModel({
|
|
821
819
|
name: 'file',
|
|
822
820
|
relations: {
|
|
823
|
-
reference: { //
|
|
824
|
-
type: RelationType.BELONGS_TO, //
|
|
825
|
-
polymorphic: true, //
|
|
826
|
-
foreignKey: 'referenceId', //
|
|
827
|
-
discriminator: 'referenceType', //
|
|
821
|
+
reference: { // название связи
|
|
822
|
+
type: RelationType.BELONGS_TO, // текущая модель ссылается на целевую
|
|
823
|
+
polymorphic: true, // название целевой модели хранит дискриминатор
|
|
824
|
+
foreignKey: 'referenceId', // свойство для идентификатора цели
|
|
825
|
+
discriminator: 'referenceType', // свойство для названия целевой модели
|
|
828
826
|
},
|
|
829
827
|
},
|
|
830
828
|
});
|
|
831
829
|
```
|
|
832
830
|
|
|
833
|
-
|
|
831
|
+
Полиморфная версия `hasMany` с указанием названия связи целевой модели.
|
|
834
832
|
|
|
835
833
|
```js
|
|
836
834
|
schema.defineModel({
|
|
837
835
|
name: 'letter',
|
|
838
836
|
relations: {
|
|
839
|
-
attachments: { //
|
|
840
|
-
type: RelationType.HAS_MANY, //
|
|
841
|
-
model: 'file', //
|
|
842
|
-
polymorphic: 'reference', //
|
|
837
|
+
attachments: { // название связи
|
|
838
|
+
type: RelationType.HAS_MANY, // целевая модель ссылается на текущую
|
|
839
|
+
model: 'file', // название целевой модели
|
|
840
|
+
polymorphic: 'reference', // название полиморфной связи целевой модели
|
|
843
841
|
},
|
|
844
842
|
},
|
|
845
843
|
});
|
|
846
844
|
```
|
|
847
845
|
|
|
848
|
-
|
|
846
|
+
Полиморфная версия `hasMany` с указанием свойств целевой модели.
|
|
849
847
|
|
|
850
848
|
```js
|
|
851
849
|
schema.defineModel({
|
|
852
850
|
name: 'letter',
|
|
853
851
|
relations: {
|
|
854
|
-
attachments: { //
|
|
855
|
-
type: RelationType.HAS_MANY, //
|
|
856
|
-
model: 'file', //
|
|
857
|
-
polymorphic: true, //
|
|
858
|
-
foreignKey: 'referenceId', //
|
|
859
|
-
discriminator: 'referenceType', //
|
|
852
|
+
attachments: { // название связи
|
|
853
|
+
type: RelationType.HAS_MANY, // целевая модель ссылается на текущую
|
|
854
|
+
model: 'file', // название целевой модели
|
|
855
|
+
polymorphic: true, // название текущей модели находится в дискриминаторе
|
|
856
|
+
foreignKey: 'referenceId', // свойство целевой модели для идентификатора
|
|
857
|
+
discriminator: 'referenceType', // свойство целевой модели для названия текущей
|
|
860
858
|
},
|
|
861
859
|
},
|
|
862
860
|
});
|
|
863
861
|
```
|
|
864
862
|
|
|
865
|
-
##
|
|
863
|
+
## Расширение
|
|
866
864
|
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
865
|
+
Метод `getRepository` экземпляра схемы проверяет наличие существующего
|
|
866
|
+
репозитория для указанной модели и возвращает его. В противном случае
|
|
867
|
+
создается новый экземпляр, который будет сохранен для последующих
|
|
868
|
+
обращений к методу.
|
|
871
869
|
|
|
872
870
|
```js
|
|
873
871
|
import {Schema} from '@e22m4u/js-repository';
|
|
@@ -882,10 +880,10 @@ const rep2 = schema.getRepository('model');
|
|
|
882
880
|
console.log(rep1 === rep2); // true
|
|
883
881
|
```
|
|
884
882
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
883
|
+
Подмена стандартного конструктора репозитория выполняется методом
|
|
884
|
+
`setRepositoryCtor` сервиса `RepositoryRegistry`, который находится
|
|
885
|
+
в контейнере экземпляра схемы. После чего все новые репозитории будут
|
|
886
|
+
создаваться указанным конструктором вместо стандартного.
|
|
889
887
|
|
|
890
888
|
```js
|
|
891
889
|
import {Schema} from '@e22m4u/js-repository';
|
|
@@ -905,12 +903,12 @@ const rep = schema.getRepository('model');
|
|
|
905
903
|
console.log(rep instanceof MyRepository); // true
|
|
906
904
|
```
|
|
907
905
|
|
|
908
|
-
*
|
|
909
|
-
|
|
906
|
+
*i. Так как экземпляры репозитория кэшируется, то замену конструктора
|
|
907
|
+
следует выполнять до обращения к методу `getRepository`.*
|
|
910
908
|
|
|
911
909
|
## TypeScript
|
|
912
910
|
|
|
913
|
-
|
|
911
|
+
Получение типизированного репозитория с указанием интерфейса модели.
|
|
914
912
|
|
|
915
913
|
```ts
|
|
916
914
|
import {Schema} from '@e22m4u/js-repository';
|
|
@@ -921,7 +919,7 @@ import {RelationType} from '@e22m4u/js-repository';
|
|
|
921
919
|
// schema.defineDatasource ...
|
|
922
920
|
// schema.defineModel ...
|
|
923
921
|
|
|
924
|
-
//
|
|
922
|
+
// определение модели "city"
|
|
925
923
|
schema.defineModel({
|
|
926
924
|
name: 'city',
|
|
927
925
|
datasource: 'myDatasource',
|
|
@@ -937,7 +935,7 @@ schema.defineModel({
|
|
|
937
935
|
},
|
|
938
936
|
});
|
|
939
937
|
|
|
940
|
-
//
|
|
938
|
+
// определение интерфейса "city"
|
|
941
939
|
interface City {
|
|
942
940
|
id: number;
|
|
943
941
|
title?: string;
|
|
@@ -946,15 +944,17 @@ interface City {
|
|
|
946
944
|
country?: Country;
|
|
947
945
|
}
|
|
948
946
|
|
|
949
|
-
//
|
|
950
|
-
//
|
|
947
|
+
// получаем репозиторий по названию модели
|
|
948
|
+
// указывая ее тип и тип идентификатора
|
|
951
949
|
const cityRep = schema.getRepository<City, number>('city');
|
|
952
950
|
```
|
|
953
951
|
|
|
954
|
-
##
|
|
952
|
+
## Тесты
|
|
955
953
|
|
|
954
|
+
```bash
|
|
956
955
|
npm run test
|
|
956
|
+
```
|
|
957
957
|
|
|
958
|
-
##
|
|
958
|
+
## Лицензия
|
|
959
959
|
|
|
960
960
|
MIT
|