@spinajs/orm-sql 2.0.38 → 2.0.39
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/lib/compilers.d.ts +25 -6
- package/lib/compilers.js +223 -16
- package/lib/compilers.js.map +1 -1
- package/lib/converters.js +4 -7
- package/lib/converters.js.map +1 -1
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -1
- package/lib/orm/src/builders.d.ts +636 -0
- package/lib/orm/src/builders.js +1509 -0
- package/lib/orm/src/builders.js.map +1 -0
- package/lib/orm/src/converters.d.ts +14 -0
- package/lib/orm/src/converters.js +57 -0
- package/lib/orm/src/converters.js.map +1 -0
- package/lib/orm/src/decorators.d.ts +152 -0
- package/lib/orm/src/decorators.js +454 -0
- package/lib/orm/src/decorators.js.map +1 -0
- package/lib/orm/src/dehydrators.d.ts +7 -0
- package/lib/orm/src/dehydrators.js +41 -0
- package/lib/orm/src/dehydrators.js.map +1 -0
- package/lib/orm/src/driver.d.ts +80 -0
- package/lib/orm/src/driver.js +104 -0
- package/lib/orm/src/driver.js.map +1 -0
- package/lib/orm/src/enums.d.ts +115 -0
- package/lib/orm/src/enums.js +125 -0
- package/lib/orm/src/enums.js.map +1 -0
- package/lib/orm/src/exceptions.d.ts +6 -0
- package/lib/orm/src/exceptions.js +11 -0
- package/lib/orm/src/exceptions.js.map +1 -0
- package/lib/orm/src/hydrators.d.ts +19 -0
- package/lib/orm/src/hydrators.js +110 -0
- package/lib/orm/src/hydrators.js.map +1 -0
- package/lib/orm/src/interfaces.d.ts +794 -0
- package/lib/orm/src/interfaces.js +293 -0
- package/lib/orm/src/interfaces.js.map +1 -0
- package/lib/orm/src/model.d.ts +310 -0
- package/lib/orm/src/model.js +779 -0
- package/lib/orm/src/model.js.map +1 -0
- package/lib/orm/src/orm.d.ts +61 -0
- package/lib/orm/src/orm.js +341 -0
- package/lib/orm/src/orm.js.map +1 -0
- package/lib/orm/src/relations.d.ts +150 -0
- package/lib/orm/src/relations.js +681 -0
- package/lib/orm/src/relations.js.map +1 -0
- package/lib/orm/src/statements.d.ts +140 -0
- package/lib/orm/src/statements.js +314 -0
- package/lib/orm/src/statements.js.map +1 -0
- package/lib/orm/src/types.d.ts +11 -0
- package/lib/orm/src/types.js +3 -0
- package/lib/orm/src/types.js.map +1 -0
- package/lib/orm-sql/src/builders.d.ts +11 -0
- package/lib/orm-sql/src/builders.js +42 -0
- package/lib/orm-sql/src/builders.js.map +1 -0
- package/lib/orm-sql/src/compilers.d.ts +226 -0
- package/lib/orm-sql/src/compilers.js +1016 -0
- package/lib/orm-sql/src/compilers.js.map +1 -0
- package/lib/orm-sql/src/converters.d.ts +10 -0
- package/lib/orm-sql/src/converters.js +39 -0
- package/lib/orm-sql/src/converters.js.map +1 -0
- package/lib/orm-sql/src/index.d.ts +6 -0
- package/lib/orm-sql/src/index.js +70 -0
- package/lib/orm-sql/src/index.js.map +1 -0
- package/lib/orm-sql/src/statements.d.ts +46 -0
- package/lib/orm-sql/src/statements.js +268 -0
- package/lib/orm-sql/src/statements.js.map +1 -0
- package/lib/statements.js +22 -4
- package/lib/statements.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,779 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.MODEL_STATIC_MIXINS = exports.createQuery = exports.HistoricalModel = exports.ModelBase = exports.extractModelDescriptor = void 0;
|
|
27
|
+
/* eslint-disable prettier/prettier */
|
|
28
|
+
const relations_1 = require("./relations");
|
|
29
|
+
const enums_1 = require("./enums");
|
|
30
|
+
const decorators_1 = require("./decorators");
|
|
31
|
+
const interfaces_1 = require("./interfaces");
|
|
32
|
+
const builders_1 = require("./builders");
|
|
33
|
+
const di_1 = require("@spinajs/di");
|
|
34
|
+
const orm_1 = require("./orm");
|
|
35
|
+
const hydrators_1 = require("./hydrators");
|
|
36
|
+
const _ = __importStar(require("lodash"));
|
|
37
|
+
const uuid_1 = require("uuid");
|
|
38
|
+
const exceptions_1 = require("./exceptions");
|
|
39
|
+
const dehydrators_1 = require("./dehydrators");
|
|
40
|
+
const luxon_1 = require("luxon");
|
|
41
|
+
function extractModelDescriptor(targetOrForward) {
|
|
42
|
+
const target = !(0, di_1.isConstructor)(targetOrForward) && targetOrForward ? targetOrForward() : targetOrForward;
|
|
43
|
+
if (!target) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
let descriptor = null;
|
|
47
|
+
_reduce(target);
|
|
48
|
+
return descriptor;
|
|
49
|
+
function _reduce(t) {
|
|
50
|
+
if (!t) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (t[decorators_1.MODEL_DESCTRIPTION_SYMBOL]) {
|
|
54
|
+
descriptor = descriptor !== null && descriptor !== void 0 ? descriptor : {};
|
|
55
|
+
_.mergeWith(descriptor, t[decorators_1.MODEL_DESCTRIPTION_SYMBOL], (a, b) => {
|
|
56
|
+
if (!a) {
|
|
57
|
+
return b;
|
|
58
|
+
}
|
|
59
|
+
if (Array.isArray(a)) {
|
|
60
|
+
return a.concat(b);
|
|
61
|
+
}
|
|
62
|
+
return a;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
_reduce(t.prototype);
|
|
66
|
+
_reduce(t.__proto__);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.extractModelDescriptor = extractModelDescriptor;
|
|
70
|
+
class ModelBase {
|
|
71
|
+
constructor(data) {
|
|
72
|
+
/**
|
|
73
|
+
* List of hidden properties from JSON / dehydrations
|
|
74
|
+
* eg. password field of user
|
|
75
|
+
*/
|
|
76
|
+
this._hidden = [];
|
|
77
|
+
this.setDefaults();
|
|
78
|
+
if (data) {
|
|
79
|
+
this.hydrate(data);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Gets descriptor for this model. It contains information about relations, orm driver, connection properties,
|
|
84
|
+
* db table attached, column information and others.
|
|
85
|
+
*/
|
|
86
|
+
get ModelDescriptor() {
|
|
87
|
+
return extractModelDescriptor(this.constructor);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Gets di container associated with this model ( via connection object eg. different drivers have their own implementation of things)
|
|
91
|
+
*/
|
|
92
|
+
get Container() {
|
|
93
|
+
if (!this._container) {
|
|
94
|
+
const orm = di_1.DI.get(orm_1.Orm);
|
|
95
|
+
const driver = orm.Connections.get(this.ModelDescriptor.Connection);
|
|
96
|
+
if (!driver) {
|
|
97
|
+
throw new Error(`model ${this.constructor.name} have invalid connection ${this.ModelDescriptor.Connection}, please check your db config file or model connection name`);
|
|
98
|
+
}
|
|
99
|
+
this._container = driver.Container;
|
|
100
|
+
}
|
|
101
|
+
return this._container;
|
|
102
|
+
}
|
|
103
|
+
get PrimaryKeyName() {
|
|
104
|
+
return this.ModelDescriptor.PrimaryKey;
|
|
105
|
+
}
|
|
106
|
+
get PrimaryKeyValue() {
|
|
107
|
+
return this[this.PrimaryKeyName];
|
|
108
|
+
}
|
|
109
|
+
set PrimaryKeyValue(newVal) {
|
|
110
|
+
this[this.PrimaryKeyName] = newVal;
|
|
111
|
+
this.ModelDescriptor.Relations.forEach((r) => {
|
|
112
|
+
const rel = this[r.Name];
|
|
113
|
+
if (!rel)
|
|
114
|
+
return;
|
|
115
|
+
switch (r.Type) {
|
|
116
|
+
case interfaces_1.RelationType.One:
|
|
117
|
+
rel[r.ForeignKey] = newVal;
|
|
118
|
+
break;
|
|
119
|
+
case interfaces_1.RelationType.Many:
|
|
120
|
+
rel.forEach((rVal) => (rVal[r.ForeignKey] = newVal));
|
|
121
|
+
break;
|
|
122
|
+
case interfaces_1.RelationType.ManyToMany:
|
|
123
|
+
// TODO: rethink this
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
driver() {
|
|
129
|
+
const orm = di_1.DI.get(orm_1.Orm);
|
|
130
|
+
const driver = orm.Connections.get(this.ModelDescriptor.Connection);
|
|
131
|
+
return driver;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Recursivelly takes all relation data and returns as single array
|
|
135
|
+
*/
|
|
136
|
+
getFlattenRelationModels(recursive) {
|
|
137
|
+
const reduceRelations = function (m) {
|
|
138
|
+
const relations = [...m.ModelDescriptor.Relations.values()];
|
|
139
|
+
const models = _.flatMap(relations, (r) => {
|
|
140
|
+
if (r.Type === interfaces_1.RelationType.Many || r.Type === interfaces_1.RelationType.ManyToMany) {
|
|
141
|
+
return m[r.Name];
|
|
142
|
+
}
|
|
143
|
+
if (m[r.Name].Value) {
|
|
144
|
+
return [m[r.Name].Value];
|
|
145
|
+
}
|
|
146
|
+
}).filter((x) => x !== undefined);
|
|
147
|
+
if (recursive) {
|
|
148
|
+
return [...models, ..._.flatMap(models, reduceRelations)];
|
|
149
|
+
}
|
|
150
|
+
return models;
|
|
151
|
+
};
|
|
152
|
+
return reduceRelations(this);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Clears all data in table
|
|
156
|
+
*/
|
|
157
|
+
static truncate() {
|
|
158
|
+
throw new Error('Not implemented');
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get all data from db
|
|
162
|
+
*/
|
|
163
|
+
static all(_page, _perPage) {
|
|
164
|
+
throw new Error('Not implemented');
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Inserts data to DB.
|
|
168
|
+
*
|
|
169
|
+
* @param _data - data to insert
|
|
170
|
+
*/
|
|
171
|
+
static insert(_data, _insertBehaviour = interfaces_1.InsertBehaviour.None) {
|
|
172
|
+
throw new Error('Not implemented');
|
|
173
|
+
}
|
|
174
|
+
static where(_column, _operator, _value) {
|
|
175
|
+
throw new Error('Not implemented');
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Updates single or multiple records at once with provided value based on condition
|
|
179
|
+
*
|
|
180
|
+
* @param _data - data to set
|
|
181
|
+
*/
|
|
182
|
+
static update(_data) {
|
|
183
|
+
throw new Error('Not implemented');
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Tries to find all models with given primary keys
|
|
187
|
+
*/
|
|
188
|
+
static find(_pks) {
|
|
189
|
+
throw new Error('Not implemented');
|
|
190
|
+
}
|
|
191
|
+
static first() {
|
|
192
|
+
throw new Error('Not implemented');
|
|
193
|
+
}
|
|
194
|
+
static last() {
|
|
195
|
+
throw new Error('Not implemented');
|
|
196
|
+
}
|
|
197
|
+
static newest() {
|
|
198
|
+
throw new Error('Not implemented');
|
|
199
|
+
}
|
|
200
|
+
static oldest() {
|
|
201
|
+
throw new Error('Not implemented');
|
|
202
|
+
}
|
|
203
|
+
static count() {
|
|
204
|
+
throw new Error('Not implemented');
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Tries to find all models in db. If not all exists, throws exception
|
|
208
|
+
*/
|
|
209
|
+
static findOrFail(_pks) {
|
|
210
|
+
throw new Error('Not implemented');
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* gets model by specified pk, if not exists, returns null
|
|
214
|
+
*
|
|
215
|
+
*/
|
|
216
|
+
static get(_pk) {
|
|
217
|
+
throw new Error('Not implemented');
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Finds model by specified pk. If model not exists in db throws exception
|
|
221
|
+
*
|
|
222
|
+
*/
|
|
223
|
+
static getOrFail(_pk) {
|
|
224
|
+
throw new Error('Not implemented');
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
*
|
|
228
|
+
* Checks if model with pk key or unique fields exists and if not creates one AND NOT save in db
|
|
229
|
+
* NOTE: it checks for unique fields constraint
|
|
230
|
+
*/
|
|
231
|
+
static getOrNew(_pk, _data) {
|
|
232
|
+
throw new Error('Not implemented');
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Creates query on this model. used for quering db for partial data, to perform some kind of operations
|
|
236
|
+
* that dont need full ORM model to involve, or other non standard operations eg. joins or raw data queries based on this model
|
|
237
|
+
*/
|
|
238
|
+
static query() {
|
|
239
|
+
throw new Error('Not implemented');
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
*
|
|
243
|
+
* Checks if model with pk key / unique fields exists and if not creates one and saves to db
|
|
244
|
+
* NOTE: it checks for unique fields too.
|
|
245
|
+
*
|
|
246
|
+
* @param data - model width data to check
|
|
247
|
+
*/
|
|
248
|
+
static getOrCreate(_pk, _data) {
|
|
249
|
+
throw new Error('Not implemented');
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Creates new model & saves is to db
|
|
253
|
+
*
|
|
254
|
+
* @param data - initial model data
|
|
255
|
+
*/
|
|
256
|
+
static create(_data) {
|
|
257
|
+
throw new Error('Not implemented');
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Deletes model from db
|
|
261
|
+
*
|
|
262
|
+
* @param pk - primary key
|
|
263
|
+
*/
|
|
264
|
+
static destroy(_pk) {
|
|
265
|
+
throw new Error('Not implemented');
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Fills model with data. It only fills properties that exists in database
|
|
269
|
+
*
|
|
270
|
+
* @param data - data to fill
|
|
271
|
+
*/
|
|
272
|
+
hydrate(data) {
|
|
273
|
+
this.Container.resolve(Array.ofType(hydrators_1.ModelHydrator)).forEach((h) => h.hydrate(this, data));
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
*
|
|
277
|
+
* Attachess model to proper relation an sets foreign key
|
|
278
|
+
*
|
|
279
|
+
* @param data - model to attach
|
|
280
|
+
*/
|
|
281
|
+
attach(data) {
|
|
282
|
+
// TODO: refactor this, to not check every time for relation
|
|
283
|
+
// do this as map or smth
|
|
284
|
+
for (const [_, v] of this.ModelDescriptor.Relations.entries()) {
|
|
285
|
+
if (v.TargetModel.name === data.constructor.name) {
|
|
286
|
+
data[v.ForeignKey] = this.PrimaryKeyValue;
|
|
287
|
+
switch (v.Type) {
|
|
288
|
+
case interfaces_1.RelationType.One:
|
|
289
|
+
this[v.Name].attach(data);
|
|
290
|
+
break;
|
|
291
|
+
case interfaces_1.RelationType.Many:
|
|
292
|
+
case interfaces_1.RelationType.ManyToMany:
|
|
293
|
+
this[v.Name].push(data);
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Extracts all data from model. It takes only properties that exists in DB
|
|
301
|
+
*/
|
|
302
|
+
dehydrate(omit) {
|
|
303
|
+
return this.Container.resolve(dehydrators_1.ModelDehydrator).dehydrate(this, [...(omit !== null && omit !== void 0 ? omit : []), ...this._hidden]);
|
|
304
|
+
}
|
|
305
|
+
toSql() {
|
|
306
|
+
var _a;
|
|
307
|
+
const obj = {};
|
|
308
|
+
const relArr = [...this.ModelDescriptor.Relations.values()];
|
|
309
|
+
(_a = this.ModelDescriptor.Columns) === null || _a === void 0 ? void 0 : _a.forEach((c) => {
|
|
310
|
+
const val = this[c.Name];
|
|
311
|
+
if (!c.PrimaryKey && !c.Nullable && (val === null || val === undefined || val === '')) {
|
|
312
|
+
throw new exceptions_1.OrmException(`Field ${c.Name} cannot be null`);
|
|
313
|
+
}
|
|
314
|
+
obj[c.Name] = c.Converter ? c.Converter.toDB(val, this, this.ModelDescriptor.Converters.get(c.Name).Options) : val;
|
|
315
|
+
});
|
|
316
|
+
for (const val of relArr) {
|
|
317
|
+
if (val.Type === interfaces_1.RelationType.One) {
|
|
318
|
+
if (this[val.Name].Value) {
|
|
319
|
+
obj[val.ForeignKey] = this[val.Name].Value.PrimaryKeyValue;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return obj;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* deletes enitt from db. If model have SoftDelete decorator, model is marked as deleted
|
|
327
|
+
*/
|
|
328
|
+
async destroy() {
|
|
329
|
+
if (!this.PrimaryKeyValue) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
await this.constructor.destroy(this.PrimaryKeyValue);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* If model can be in achived state - sets archived at date and saves it to db
|
|
336
|
+
*/
|
|
337
|
+
async archive() {
|
|
338
|
+
const { query } = this.createUpdateQuery();
|
|
339
|
+
if (this.ModelDescriptor.Archived) {
|
|
340
|
+
this[this.ModelDescriptor.Archived.ArchivedAt] = luxon_1.DateTime.now();
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
throw new exceptions_1.OrmException('archived at column not exists in model');
|
|
344
|
+
}
|
|
345
|
+
await query.update(this.toSql()).where(this.PrimaryKeyName, this.PrimaryKeyValue);
|
|
346
|
+
}
|
|
347
|
+
async update() {
|
|
348
|
+
const { query } = this.createUpdateQuery();
|
|
349
|
+
if (this.ModelDescriptor.Timestamps.UpdatedAt) {
|
|
350
|
+
this[this.ModelDescriptor.Timestamps.UpdatedAt] = luxon_1.DateTime.now();
|
|
351
|
+
}
|
|
352
|
+
await query.update(this.toSql()).where(this.PrimaryKeyName, this.PrimaryKeyValue);
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Save all changes to db. It creates new entry id db or updates existing one if
|
|
356
|
+
* primary key exists
|
|
357
|
+
*/
|
|
358
|
+
async insert(insertBehaviour = interfaces_1.InsertBehaviour.None) {
|
|
359
|
+
const { query, description } = this.createInsertQuery();
|
|
360
|
+
switch (insertBehaviour) {
|
|
361
|
+
case interfaces_1.InsertBehaviour.InsertOrIgnore:
|
|
362
|
+
query.orIgnore();
|
|
363
|
+
break;
|
|
364
|
+
case interfaces_1.InsertBehaviour.InsertOrUpdate:
|
|
365
|
+
query.onDuplicate().update(description.Columns.filter((c) => !c.PrimaryKey).map((c) => c.Name));
|
|
366
|
+
break;
|
|
367
|
+
case interfaces_1.InsertBehaviour.InsertOrReplace:
|
|
368
|
+
query.orReplace();
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
const iMidleware = {
|
|
372
|
+
afterQuery: (data) => {
|
|
373
|
+
var _a;
|
|
374
|
+
this.PrimaryKeyValue = (_a = this.PrimaryKeyValue) !== null && _a !== void 0 ? _a : data.LastInsertId;
|
|
375
|
+
return data;
|
|
376
|
+
},
|
|
377
|
+
modelCreation: () => null,
|
|
378
|
+
afterHydration: () => null,
|
|
379
|
+
};
|
|
380
|
+
query.middleware(iMidleware);
|
|
381
|
+
return query.values(this.toSql());
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Gets model data from database and returns as fresh instance.
|
|
385
|
+
*
|
|
386
|
+
* If primary key is not fetched, tries to load by columns with unique constraint.
|
|
387
|
+
* If there is no unique columns or primary key, throws error
|
|
388
|
+
*/
|
|
389
|
+
async fresh() {
|
|
390
|
+
const { query, description } = this.createSelectQuery();
|
|
391
|
+
query.select('*');
|
|
392
|
+
_preparePkWhere(description, query, this);
|
|
393
|
+
_prepareOrderBy(description, query);
|
|
394
|
+
// TODO: rethink all cast of this type?
|
|
395
|
+
return (await query.firstOrFail());
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Refresh model from database.
|
|
399
|
+
*
|
|
400
|
+
* If no primary key is set, tries to fetch data base on columns
|
|
401
|
+
* with unique constraints. If none exists, throws exception
|
|
402
|
+
*/
|
|
403
|
+
async refresh() {
|
|
404
|
+
let model = null;
|
|
405
|
+
model = await this.fresh();
|
|
406
|
+
for (const c of this.ModelDescriptor.Columns) {
|
|
407
|
+
this[c.Name] = model[c.Name];
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
toJSON() {
|
|
411
|
+
return this.dehydrate();
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* sets default values for model. values are taken from DB default column prop
|
|
415
|
+
*/
|
|
416
|
+
setDefaults() {
|
|
417
|
+
var _a;
|
|
418
|
+
(_a = this.ModelDescriptor.Columns) === null || _a === void 0 ? void 0 : _a.forEach((c) => {
|
|
419
|
+
if (c.Uuid) {
|
|
420
|
+
this[c.Name] = (0, uuid_1.v4)();
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
this[c.Name] = c.DefaultValue;
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
if (this.ModelDescriptor.Timestamps.CreatedAt) {
|
|
427
|
+
this[this.ModelDescriptor.Timestamps.CreatedAt] = luxon_1.DateTime.now();
|
|
428
|
+
}
|
|
429
|
+
for (const [, rel] of this.ModelDescriptor.Relations) {
|
|
430
|
+
if (rel.Factory) {
|
|
431
|
+
this[rel.Name] = rel.Factory(this, rel, this.Container);
|
|
432
|
+
}
|
|
433
|
+
else if (rel.RelationClass) {
|
|
434
|
+
this[rel.Name] = this.Container.resolve(rel.RelationClass, [this, rel.TargetModel, rel, []]);
|
|
435
|
+
}
|
|
436
|
+
else if (rel.Type === interfaces_1.RelationType.Many) {
|
|
437
|
+
this[rel.Name] = new relations_1.OneToManyRelationList(this, rel.TargetModel, rel, []);
|
|
438
|
+
}
|
|
439
|
+
else if (rel.Type === interfaces_1.RelationType.ManyToMany) {
|
|
440
|
+
this[rel.Name] = new relations_1.ManyToManyRelationList(this, rel.TargetModel, rel, []);
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
this[rel.Name] = new relations_1.SingleRelation(this, rel.TargetModel, rel, null);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
createSelectQuery() {
|
|
448
|
+
return createQuery(this.constructor, builders_1.SelectQueryBuilder);
|
|
449
|
+
}
|
|
450
|
+
createUpdateQuery() {
|
|
451
|
+
return createQuery(this.constructor, builders_1.UpdateQueryBuilder);
|
|
452
|
+
}
|
|
453
|
+
createInsertQuery() {
|
|
454
|
+
return createQuery(this.constructor, builders_1.InsertQueryBuilder);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
exports.ModelBase = ModelBase;
|
|
458
|
+
function _descriptor(model) {
|
|
459
|
+
return model[decorators_1.MODEL_DESCTRIPTION_SYMBOL];
|
|
460
|
+
}
|
|
461
|
+
function _preparePkWhere(description, query, model) {
|
|
462
|
+
if (description.PrimaryKey) {
|
|
463
|
+
query.where(description.PrimaryKey, model.PrimaryKeyValue);
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
const unique = description.Columns.filter((x) => x.Unique);
|
|
467
|
+
if (unique.length !== 0) {
|
|
468
|
+
for (const c of unique) {
|
|
469
|
+
query.where(c.Name, '=', model[c.Name]);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
throw new exceptions_1.OrmException('Model dont have primary key set or columns with unique constraint, cannot fetch model from database');
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
function _prepareOrderBy(description, query, order) {
|
|
478
|
+
var _a, _b;
|
|
479
|
+
if (description.PrimaryKey) {
|
|
480
|
+
query.order(description.PrimaryKey, order !== null && order !== void 0 ? order : enums_1.SordOrder.DESC);
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
const unique = description.Columns.filter((c) => c.Unique);
|
|
484
|
+
if (unique.length !== 0) {
|
|
485
|
+
unique.forEach((c) => query.order(c.Name, order !== null && order !== void 0 ? order : enums_1.SordOrder.DESC));
|
|
486
|
+
}
|
|
487
|
+
else if ((_a = description.Timestamps) === null || _a === void 0 ? void 0 : _a.CreatedAt) {
|
|
488
|
+
query.order(description.Timestamps.CreatedAt, order !== null && order !== void 0 ? order : enums_1.SordOrder.DESC);
|
|
489
|
+
}
|
|
490
|
+
else if ((_b = description.Timestamps) === null || _b === void 0 ? void 0 : _b.UpdatedAt) {
|
|
491
|
+
query.order(description.Timestamps.UpdatedAt, order !== null && order !== void 0 ? order : enums_1.SordOrder.DESC);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
class HistoricalModel {
|
|
496
|
+
}
|
|
497
|
+
exports.HistoricalModel = HistoricalModel;
|
|
498
|
+
/**
|
|
499
|
+
* Helper function to create query based on model
|
|
500
|
+
*
|
|
501
|
+
* @param model - source model for query
|
|
502
|
+
* @param query - query class
|
|
503
|
+
* @param injectModel - should inject model information into query, if not, query will return raw data
|
|
504
|
+
*
|
|
505
|
+
* @returns
|
|
506
|
+
*/
|
|
507
|
+
function createQuery(model, query, injectModel = true) {
|
|
508
|
+
const dsc = _descriptor(model);
|
|
509
|
+
if (!dsc) {
|
|
510
|
+
throw new Error(`model ${model.name} does not have model descriptor. Use @model decorator on class`);
|
|
511
|
+
}
|
|
512
|
+
const orm = di_1.DI.get(orm_1.Orm);
|
|
513
|
+
const driver = orm.Connections.get(dsc.Connection);
|
|
514
|
+
if (!driver) {
|
|
515
|
+
throw new Error(`model ${model.name} have invalid connection ${dsc.Connection}, please check your db config file or model connection name`);
|
|
516
|
+
}
|
|
517
|
+
const cnt = driver.Container;
|
|
518
|
+
const qr = cnt.resolve(query, [driver, injectModel ? orm.Models.find((x) => x.name === model.name).type : null]);
|
|
519
|
+
if (qr instanceof builders_1.SelectQueryBuilder) {
|
|
520
|
+
const scope = model._queryScopes;
|
|
521
|
+
if (scope) {
|
|
522
|
+
Object.getOwnPropertyNames(scope.__proto__)
|
|
523
|
+
.filter((x) => x !== 'constructor')
|
|
524
|
+
.forEach(function (property) {
|
|
525
|
+
if (typeof scope[property] === 'function') {
|
|
526
|
+
qr[property] = scope[property].bind(qr);
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
qr.middleware(new relations_1.DiscriminationMapMiddleware(dsc));
|
|
532
|
+
qr.setTable(dsc.TableName);
|
|
533
|
+
if (driver.Options.Database) {
|
|
534
|
+
qr.database(driver.Options.Database);
|
|
535
|
+
}
|
|
536
|
+
return {
|
|
537
|
+
query: qr,
|
|
538
|
+
description: dsc,
|
|
539
|
+
model,
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
exports.createQuery = createQuery;
|
|
543
|
+
exports.MODEL_STATIC_MIXINS = {
|
|
544
|
+
truncate() {
|
|
545
|
+
const { query } = createQuery(this, builders_1.TruncateTableQueryBuilder, false);
|
|
546
|
+
return query;
|
|
547
|
+
},
|
|
548
|
+
driver() {
|
|
549
|
+
const dsc = _descriptor(this);
|
|
550
|
+
const orm = di_1.DI.get(orm_1.Orm);
|
|
551
|
+
const driver = orm.Connections.get(dsc.Connection);
|
|
552
|
+
if (!driver) {
|
|
553
|
+
throw new Error(`model ${this.name} have invalid connection ${dsc.Connection}, please check your db config file or model connection name`);
|
|
554
|
+
}
|
|
555
|
+
return driver;
|
|
556
|
+
},
|
|
557
|
+
query() {
|
|
558
|
+
const { query } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
559
|
+
return query;
|
|
560
|
+
},
|
|
561
|
+
where(column, operator, value) {
|
|
562
|
+
const { query } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
563
|
+
query.select('*');
|
|
564
|
+
return query.where(column, operator, value);
|
|
565
|
+
},
|
|
566
|
+
update(data) {
|
|
567
|
+
const { query } = createQuery(this, builders_1.UpdateQueryBuilder);
|
|
568
|
+
return query.update(data);
|
|
569
|
+
},
|
|
570
|
+
all(page, perPage) {
|
|
571
|
+
const { query } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
572
|
+
query.select('*');
|
|
573
|
+
if (page >= 0 && perPage > 0) {
|
|
574
|
+
query.take(perPage).skip(page * perPage);
|
|
575
|
+
}
|
|
576
|
+
return query;
|
|
577
|
+
},
|
|
578
|
+
/**
|
|
579
|
+
* Try to insert new value
|
|
580
|
+
*/
|
|
581
|
+
async insert(data, insertBehaviour = interfaces_1.InsertBehaviour.None) {
|
|
582
|
+
const { query, description } = createQuery(this, builders_1.InsertQueryBuilder);
|
|
583
|
+
if (Array.isArray(data)) {
|
|
584
|
+
if (insertBehaviour !== interfaces_1.InsertBehaviour.None) {
|
|
585
|
+
throw new exceptions_1.OrmException(`insert behaviour is not supported with arrays`);
|
|
586
|
+
}
|
|
587
|
+
query.values(data.map((d) => {
|
|
588
|
+
if (d instanceof ModelBase) {
|
|
589
|
+
return d.toSql();
|
|
590
|
+
}
|
|
591
|
+
return d;
|
|
592
|
+
}));
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
switch (insertBehaviour) {
|
|
596
|
+
case interfaces_1.InsertBehaviour.InsertOrIgnore:
|
|
597
|
+
query.orIgnore();
|
|
598
|
+
break;
|
|
599
|
+
case interfaces_1.InsertBehaviour.InsertOrUpdate:
|
|
600
|
+
query.onDuplicate().update(description.Columns.filter((c) => !c.PrimaryKey).map((c) => c.Name));
|
|
601
|
+
break;
|
|
602
|
+
case interfaces_1.InsertBehaviour.InsertOrReplace:
|
|
603
|
+
query.orReplace();
|
|
604
|
+
break;
|
|
605
|
+
}
|
|
606
|
+
if (data instanceof ModelBase) {
|
|
607
|
+
query.values(data.toSql());
|
|
608
|
+
}
|
|
609
|
+
else {
|
|
610
|
+
query.values(data);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
const iMidleware = {
|
|
614
|
+
afterQuery: (result) => {
|
|
615
|
+
var _a;
|
|
616
|
+
if (Array.isArray(data)) {
|
|
617
|
+
data.forEach((v, idx) => {
|
|
618
|
+
var _a;
|
|
619
|
+
if (v instanceof ModelBase) {
|
|
620
|
+
v.PrimaryKeyValue = (_a = v.PrimaryKeyValue) !== null && _a !== void 0 ? _a : result.LastInsertId - data.length + idx;
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
else if (data instanceof ModelBase) {
|
|
625
|
+
data.PrimaryKeyValue = (_a = data.PrimaryKeyValue) !== null && _a !== void 0 ? _a : result.LastInsertId;
|
|
626
|
+
}
|
|
627
|
+
return result;
|
|
628
|
+
},
|
|
629
|
+
modelCreation: () => null,
|
|
630
|
+
afterHydration: () => null,
|
|
631
|
+
};
|
|
632
|
+
query.middleware(iMidleware);
|
|
633
|
+
return query;
|
|
634
|
+
},
|
|
635
|
+
async find(pks) {
|
|
636
|
+
const { query, description } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
637
|
+
const pkey = description.PrimaryKey;
|
|
638
|
+
query.select('*');
|
|
639
|
+
query.whereIn(pkey, pks);
|
|
640
|
+
return await query;
|
|
641
|
+
},
|
|
642
|
+
async findOrFail(pks) {
|
|
643
|
+
const { query, description, model } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
644
|
+
const pkey = description.PrimaryKey;
|
|
645
|
+
query.select('*');
|
|
646
|
+
query.whereIn(pkey, pks);
|
|
647
|
+
const result = await query;
|
|
648
|
+
if (result.length !== pks.length) {
|
|
649
|
+
throw new Error(`could not find all results for model ${model.name}`);
|
|
650
|
+
}
|
|
651
|
+
return result;
|
|
652
|
+
},
|
|
653
|
+
async get(pk) {
|
|
654
|
+
const { query, description } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
655
|
+
const pkey = description.PrimaryKey;
|
|
656
|
+
query.select('*');
|
|
657
|
+
query.where(pkey, pk);
|
|
658
|
+
_prepareOrderBy(description, query);
|
|
659
|
+
return (await query.first());
|
|
660
|
+
},
|
|
661
|
+
async getOrFail(pk) {
|
|
662
|
+
const { query, description } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
663
|
+
const pkey = description.PrimaryKey;
|
|
664
|
+
query.select('*');
|
|
665
|
+
query.where(pkey, pk);
|
|
666
|
+
_prepareOrderBy(description, query);
|
|
667
|
+
return (await query.firstOrFail());
|
|
668
|
+
},
|
|
669
|
+
destroy(pks) {
|
|
670
|
+
var _a, _b;
|
|
671
|
+
const description = _descriptor(this);
|
|
672
|
+
const data = Array.isArray(pks) ? pks : [pks];
|
|
673
|
+
const { query } = ((_a = description.SoftDelete) === null || _a === void 0 ? void 0 : _a.DeletedAt) ? createQuery(this, builders_1.UpdateQueryBuilder) : createQuery(this, builders_1.DeleteQueryBuilder);
|
|
674
|
+
if ((_b = description.SoftDelete) === null || _b === void 0 ? void 0 : _b.DeletedAt) {
|
|
675
|
+
query.update({
|
|
676
|
+
[description.SoftDelete.DeletedAt]: luxon_1.DateTime.now(),
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
if (pks) {
|
|
680
|
+
query.whereIn(description.PrimaryKey, data);
|
|
681
|
+
}
|
|
682
|
+
return query;
|
|
683
|
+
},
|
|
684
|
+
async create(data) {
|
|
685
|
+
const entity = new (Function.prototype.bind.apply(this))(data);
|
|
686
|
+
await entity.insert();
|
|
687
|
+
return entity;
|
|
688
|
+
},
|
|
689
|
+
async getOrCreate(pk, data) {
|
|
690
|
+
const { query, description } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
691
|
+
// pk constrain
|
|
692
|
+
if (description.PrimaryKey && pk !== null) {
|
|
693
|
+
query.where(description.PrimaryKey, pk);
|
|
694
|
+
}
|
|
695
|
+
// check for all unique columns ( unique constrain )
|
|
696
|
+
description.Columns.filter((c) => c.Unique).forEach((c) => {
|
|
697
|
+
query.andWhere(c, data[c.Name]);
|
|
698
|
+
});
|
|
699
|
+
_prepareOrderBy(description, query);
|
|
700
|
+
let entity = (await query.first());
|
|
701
|
+
if (!entity) {
|
|
702
|
+
entity = new (Function.prototype.bind.apply(this))(data);
|
|
703
|
+
await entity.insert();
|
|
704
|
+
return entity;
|
|
705
|
+
}
|
|
706
|
+
return entity;
|
|
707
|
+
},
|
|
708
|
+
async getOrNew(pk, data) {
|
|
709
|
+
const { query, description } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
710
|
+
// pk constrain
|
|
711
|
+
if (description.PrimaryKey) {
|
|
712
|
+
query.where(description.PrimaryKey, pk);
|
|
713
|
+
}
|
|
714
|
+
// check for all unique columns ( unique constrain )
|
|
715
|
+
description.Columns.filter((c) => c.Unique).forEach((c) => {
|
|
716
|
+
query.andWhere(c, data[c.Name]);
|
|
717
|
+
});
|
|
718
|
+
_prepareOrderBy(description, query);
|
|
719
|
+
let entity = (await query.first());
|
|
720
|
+
if (!entity) {
|
|
721
|
+
entity = new (Function.prototype.bind.apply(this))(data);
|
|
722
|
+
return entity;
|
|
723
|
+
}
|
|
724
|
+
return entity;
|
|
725
|
+
},
|
|
726
|
+
async first(callback) {
|
|
727
|
+
const { query, description } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
728
|
+
_prepareOrderBy(description, query, enums_1.SordOrder.ASC);
|
|
729
|
+
if (callback) {
|
|
730
|
+
callback(query);
|
|
731
|
+
}
|
|
732
|
+
return (await query.first());
|
|
733
|
+
},
|
|
734
|
+
async last(callback) {
|
|
735
|
+
const { query, description } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
736
|
+
_prepareOrderBy(description, query, enums_1.SordOrder.DESC);
|
|
737
|
+
if (callback) {
|
|
738
|
+
callback(query);
|
|
739
|
+
}
|
|
740
|
+
return (await query.first());
|
|
741
|
+
},
|
|
742
|
+
async newest(callback) {
|
|
743
|
+
var _a;
|
|
744
|
+
const { query, description } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
745
|
+
if ((_a = description.Timestamps) === null || _a === void 0 ? void 0 : _a.CreatedAt) {
|
|
746
|
+
query.order(description.Timestamps.CreatedAt, enums_1.SordOrder.DESC);
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
throw new exceptions_1.OrmException('cannot fetch newest entity - CreateAt column not exists in model/db');
|
|
750
|
+
}
|
|
751
|
+
if (callback) {
|
|
752
|
+
callback(query);
|
|
753
|
+
}
|
|
754
|
+
return (await query.first());
|
|
755
|
+
},
|
|
756
|
+
async oldest(callback) {
|
|
757
|
+
var _a;
|
|
758
|
+
const { query, description } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
759
|
+
if ((_a = description.Timestamps) === null || _a === void 0 ? void 0 : _a.CreatedAt) {
|
|
760
|
+
query.order(description.Timestamps.CreatedAt, enums_1.SordOrder.ASC);
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
throw new exceptions_1.OrmException('cannot fetch oldest entity - CreateAt column not exists in model/db');
|
|
764
|
+
}
|
|
765
|
+
if (callback) {
|
|
766
|
+
callback(query);
|
|
767
|
+
}
|
|
768
|
+
return (await query.first());
|
|
769
|
+
},
|
|
770
|
+
async count(callback) {
|
|
771
|
+
const { query } = createQuery(this, builders_1.SelectQueryBuilder);
|
|
772
|
+
query.count('*', 'count');
|
|
773
|
+
if (callback) {
|
|
774
|
+
callback(query);
|
|
775
|
+
}
|
|
776
|
+
return await (await query.asRaw()).count;
|
|
777
|
+
},
|
|
778
|
+
};
|
|
779
|
+
//# sourceMappingURL=model.js.map
|