velocious 1.0.85 → 1.0.87
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/bin/velocious.js +10 -1
- package/eslint.config.js +33 -0
- package/package.json +7 -2
- package/peak_flow.yml +6 -0
- package/spec/cli/commands/db/create-spec.js +4 -0
- package/spec/cli/commands/db/migrate-spec.js +4 -2
- package/spec/cli/commands/db/rollback-spec.js +179 -0
- package/spec/cli/commands/destroy/migration-spec.js +4 -0
- package/spec/cli/commands/generate/migration-spec.js +4 -0
- package/spec/cli/commands/init-spec.js +4 -0
- package/spec/dummy/index.js +7 -4
- package/spec/dummy/src/config/configuration.example.js +2 -0
- package/spec/dummy/src/config/configuration.peakflow.mariadb.js +2 -0
- package/spec/dummy/src/config/configuration.peakflow.mssql.js +2 -0
- package/spec/dummy/src/config/configuration.peakflow.pgsql.js +2 -0
- package/spec/dummy/src/config/configuration.peakflow.sqlite.js +2 -0
- package/spec/dummy/src/database/migrations/20250921121002-create-project-details.js +3 -1
- package/src/application.js +12 -0
- package/src/cli/base-command.js +9 -5
- package/src/cli/browser-cli.js +37 -0
- package/src/cli/commands/db/create.js +5 -5
- package/src/cli/commands/db/drop.js +4 -5
- package/src/cli/commands/db/migrate.js +6 -10
- package/src/cli/commands/db/reset.js +8 -12
- package/src/cli/commands/db/rollback.js +15 -0
- package/src/cli/commands/destroy/migration.js +2 -2
- package/src/cli/commands/generate/migration.js +3 -6
- package/src/cli/commands/generate/model.js +3 -6
- package/src/cli/commands/init.js +5 -8
- package/src/cli/commands/server.js +3 -3
- package/src/cli/commands/test.js +1 -1
- package/src/cli/index.js +15 -63
- package/src/cli/use-browser-cli.js +25 -0
- package/src/configuration-resolver.js +1 -1
- package/src/configuration.js +118 -9
- package/src/controller.js +29 -0
- package/src/database/drivers/base-column.js +14 -0
- package/src/database/drivers/base-columns-index.js +3 -0
- package/src/database/drivers/base-foreign-key.js +3 -0
- package/src/database/drivers/base-table.js +3 -0
- package/src/database/drivers/base.js +55 -1
- package/src/database/drivers/mssql/index.js +64 -1
- package/src/database/drivers/mysql/columns-index.js +0 -1
- package/src/database/drivers/sqlite/base.js +39 -0
- package/src/database/drivers/sqlite/connection-remote.js +1 -1
- package/src/database/drivers/sqlite/sql/alter-table.js +1 -1
- package/src/database/drivers/sqlite/sql/delete.js +15 -10
- package/src/database/migration/index.js +122 -1
- package/src/database/migrator/files-finder.js +13 -1
- package/src/database/migrator.js +125 -24
- package/src/database/pool/single-multi-use.js +1 -1
- package/src/database/query/alter-table-base.js +11 -0
- package/src/database/query/base.js +7 -0
- package/src/database/query/create-database-base.js +3 -0
- package/src/database/query/create-index-base.js +3 -1
- package/src/database/query/create-table-base.js +3 -0
- package/src/database/query/drop-table-base.js +4 -1
- package/src/database/query/from-base.js +7 -0
- package/src/database/query/index.js +96 -6
- package/src/database/query/insert-base.js +6 -0
- package/src/database/query/join-base.js +3 -0
- package/src/database/query/order-base.js +3 -0
- package/src/database/query/select-base.js +3 -0
- package/src/database/query/update-base.js +3 -0
- package/src/database/query/where-base.js +3 -0
- package/src/database/record/index.js +272 -19
- package/src/database/record/instance-relationships/base.js +66 -1
- package/src/database/record/relationships/base.js +41 -1
- package/src/database/record/validators/base.js +10 -0
- package/src/database/record/validators/presence.js +1 -1
- package/src/database/table-data/table-column.js +37 -3
- package/src/database/table-data/table-index.js +1 -1
- package/src/database/use-database.js +2 -2
- package/src/environment-handlers/base.js +53 -0
- package/src/environment-handlers/browser.js +171 -0
- package/src/environment-handlers/node.js +162 -0
- package/src/http-server/client/request-buffer/index.js +9 -9
- package/src/http-server/index.js +6 -0
- package/src/http-server/worker-handler/index.js +20 -19
- package/src/initializer.js +17 -1
- package/src/logger.js +3 -0
- package/src/routes/app-routes.js +6 -2
- package/src/routes/base-route.js +1 -1
- package/src/routes/get-route.js +1 -1
- package/src/routes/namespace-route.js +1 -1
- package/src/routes/post-route.js +1 -1
- package/src/routes/resolver.js +1 -1
- package/src/routes/resource-route.js +1 -1
- package/src/templates/configuration.js +4 -0
- package/src/testing/request-client.js +26 -3
- package/src/testing/test-files-finder.js +2 -2
- package/src/testing/test-runner.js +74 -28
- package/src/testing/test.js +62 -0
- package/src/utils/file-exists.js +7 -5
- package/src/utils/rest-args-error.js +5 -3
|
@@ -9,18 +9,30 @@ import HasOneRelationship from "./relationships/has-one.js"
|
|
|
9
9
|
import HasOneInstanceRelationship from "./instance-relationships/has-one.js"
|
|
10
10
|
import * as inflection from "inflection"
|
|
11
11
|
import Query from "../query/index.js"
|
|
12
|
+
import restArgsError from "../../utils/rest-args-error.js"
|
|
12
13
|
import ValidatorsPresence from "./validators/presence.js"
|
|
13
14
|
import ValidatorsUniqueness from "./validators/uniqueness.js"
|
|
14
15
|
|
|
15
16
|
class ValidationError extends Error {
|
|
17
|
+
/**
|
|
18
|
+
* @template T extends VelociousDatabaseRecord
|
|
19
|
+
* @returns {T}
|
|
20
|
+
*/
|
|
16
21
|
getModel() {
|
|
17
22
|
return this._model
|
|
18
23
|
}
|
|
19
24
|
|
|
25
|
+
/**
|
|
26
|
+
* @template T extends VelociousDatabaseRecord
|
|
27
|
+
* @param {T} model
|
|
28
|
+
*/
|
|
20
29
|
setModel(model) {
|
|
21
30
|
this._model = model
|
|
22
31
|
}
|
|
23
32
|
|
|
33
|
+
/**
|
|
34
|
+
* @returns {Array}
|
|
35
|
+
*/
|
|
24
36
|
getValidationErrors() {
|
|
25
37
|
return this._validationErrors
|
|
26
38
|
}
|
|
@@ -31,22 +43,38 @@ class ValidationError extends Error {
|
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
class VelociousDatabaseRecord {
|
|
46
|
+
/**
|
|
47
|
+
* @template T extends import("./validators/base.js").default
|
|
48
|
+
* @returns {Record<string, T>}
|
|
49
|
+
*/
|
|
34
50
|
static validatorTypes() {
|
|
35
51
|
if (!this._validatorTypes) this._validatorTypes = {}
|
|
36
52
|
|
|
37
53
|
return this._validatorTypes
|
|
38
54
|
}
|
|
39
55
|
|
|
56
|
+
/**
|
|
57
|
+
* @param {string} name
|
|
58
|
+
* @template T extends import("./validators/base.js").default
|
|
59
|
+
* @param {T} validatorClass
|
|
60
|
+
*/
|
|
40
61
|
static registerValidatorType(name, validatorClass) {
|
|
41
62
|
this.validatorTypes()[name] = validatorClass
|
|
42
63
|
}
|
|
43
64
|
|
|
65
|
+
/**
|
|
66
|
+
* @template T extends import("./validators/base.js").default
|
|
67
|
+
* @returns {T}
|
|
68
|
+
*/
|
|
44
69
|
static getValidatorType(validatorName) {
|
|
45
70
|
if (!(validatorName in this.validatorTypes())) throw new Error(`Validator type ${validatorName} not found`)
|
|
46
71
|
|
|
47
72
|
return this.validatorTypes()[validatorName]
|
|
48
73
|
}
|
|
49
74
|
|
|
75
|
+
/**
|
|
76
|
+
* @returns {boolean}
|
|
77
|
+
*/
|
|
50
78
|
static _relationshipExists(relationshipName) {
|
|
51
79
|
if (this._relationships && relationshipName in this._relationships) {
|
|
52
80
|
return true
|
|
@@ -160,6 +188,10 @@ class VelociousDatabaseRecord {
|
|
|
160
188
|
this._relationships[relationshipName] = relationship
|
|
161
189
|
}
|
|
162
190
|
|
|
191
|
+
/**
|
|
192
|
+
* @template T extends import("./relationships/index.js").default
|
|
193
|
+
* @returns {T}
|
|
194
|
+
*/
|
|
163
195
|
static getRelationshipByName(relationshipName) {
|
|
164
196
|
if (!this._relationships) this._relationships = {}
|
|
165
197
|
|
|
@@ -170,16 +202,26 @@ class VelociousDatabaseRecord {
|
|
|
170
202
|
return relationship
|
|
171
203
|
}
|
|
172
204
|
|
|
205
|
+
/**
|
|
206
|
+
* @returns {Array}
|
|
207
|
+
*/
|
|
173
208
|
static getRelationships() {
|
|
174
209
|
if (this._relationships) return Object.values(this._relationships)
|
|
175
210
|
|
|
176
211
|
return []
|
|
177
212
|
}
|
|
178
213
|
|
|
214
|
+
/**
|
|
215
|
+
* @returns {Array<string>}
|
|
216
|
+
*/
|
|
179
217
|
static getRelationshipNames() {
|
|
180
218
|
return this.getRelationships().map((relationship) => relationship.getRelationshipName())
|
|
181
219
|
}
|
|
182
220
|
|
|
221
|
+
/**
|
|
222
|
+
* @template T extends import("./instance-relationships/index.js").default
|
|
223
|
+
* @returns {T}
|
|
224
|
+
*/
|
|
183
225
|
getRelationshipByName(relationshipName) {
|
|
184
226
|
if (!this._instanceRelationships) this._instanceRelationships = {}
|
|
185
227
|
|
|
@@ -206,7 +248,6 @@ class VelociousDatabaseRecord {
|
|
|
206
248
|
|
|
207
249
|
/**
|
|
208
250
|
* Adds a belongs-to-relationship to the model.
|
|
209
|
-
*
|
|
210
251
|
* @param {string} relationshipName The name of the relationship.
|
|
211
252
|
* @param {object} options The options for the relationship.
|
|
212
253
|
*/
|
|
@@ -214,6 +255,10 @@ class VelociousDatabaseRecord {
|
|
|
214
255
|
this._defineRelationship(relationshipName, Object.assign({type: "belongsTo"}, options))
|
|
215
256
|
}
|
|
216
257
|
|
|
258
|
+
/**
|
|
259
|
+
* @template T extends import("./database/drivers/base").default
|
|
260
|
+
* @returns {T}
|
|
261
|
+
*/
|
|
217
262
|
static connection() {
|
|
218
263
|
const databasePool = this._getConfiguration().getDatabasePool(this.getDatabaseIdentifier())
|
|
219
264
|
const connection = databasePool.getCurrentConnection()
|
|
@@ -223,6 +268,10 @@ class VelociousDatabaseRecord {
|
|
|
223
268
|
return connection
|
|
224
269
|
}
|
|
225
270
|
|
|
271
|
+
/**
|
|
272
|
+
* @param {object} attributes
|
|
273
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
274
|
+
*/
|
|
226
275
|
static async create(attributes) {
|
|
227
276
|
const record = new this(attributes)
|
|
228
277
|
|
|
@@ -231,6 +280,9 @@ class VelociousDatabaseRecord {
|
|
|
231
280
|
return record
|
|
232
281
|
}
|
|
233
282
|
|
|
283
|
+
/**
|
|
284
|
+
* @returns {import("../../configuration.js").default}
|
|
285
|
+
*/
|
|
234
286
|
static _getConfiguration() {
|
|
235
287
|
if (!this._configuration) {
|
|
236
288
|
this._configuration = Configuration.current()
|
|
@@ -243,13 +295,15 @@ class VelociousDatabaseRecord {
|
|
|
243
295
|
return this._configuration
|
|
244
296
|
}
|
|
245
297
|
|
|
298
|
+
/**
|
|
299
|
+
* @returns {import("../../configuration.js").default}
|
|
300
|
+
*/
|
|
246
301
|
_getConfiguration() {
|
|
247
302
|
return this.constructor._getConfiguration()
|
|
248
303
|
}
|
|
249
304
|
|
|
250
305
|
/**
|
|
251
306
|
* Adds a has-many-relationship to the model class.
|
|
252
|
-
*
|
|
253
307
|
* @param {string} relationshipName The name of the relationship (e.g. "posts")
|
|
254
308
|
* @param {object} options The options for the relationship (e.g. {className: "Post"})
|
|
255
309
|
*/
|
|
@@ -259,7 +313,6 @@ class VelociousDatabaseRecord {
|
|
|
259
313
|
|
|
260
314
|
/**
|
|
261
315
|
* Adds a has-one-relationship to the model class.
|
|
262
|
-
*
|
|
263
316
|
* @param {string} relationshipName The name of the relationship (e.g. "post")
|
|
264
317
|
* @param {object} options The options for the relationship (e.g. {className: "Post"})
|
|
265
318
|
*/
|
|
@@ -267,15 +320,29 @@ class VelociousDatabaseRecord {
|
|
|
267
320
|
return this._defineRelationship(relationshipName, Object.assign({type: "hasOne"}, options))
|
|
268
321
|
}
|
|
269
322
|
|
|
323
|
+
/**
|
|
324
|
+
* @param {string} attributeName
|
|
325
|
+
* @returns {string}
|
|
326
|
+
*/
|
|
270
327
|
static humanAttributeName(attributeName) {
|
|
271
328
|
const modelNameKey = inflection.underscore(this.constructor.name)
|
|
272
329
|
|
|
273
330
|
return this._getConfiguration().getTranslator()(`velocious.database.record.attributes.${modelNameKey}.${attributeName}`, {defaultValue: inflection.camelize(attributeName)})
|
|
274
331
|
}
|
|
275
332
|
|
|
333
|
+
/**
|
|
334
|
+
* @returns {string}
|
|
335
|
+
*/
|
|
276
336
|
static getDatabaseType() { return this._databaseType }
|
|
277
337
|
|
|
278
|
-
|
|
338
|
+
/**
|
|
339
|
+
* @param {object} args
|
|
340
|
+
* @param {import("../configuration.js").default} args.configuration
|
|
341
|
+
* @returns {void}
|
|
342
|
+
*/
|
|
343
|
+
static async initializeRecord({configuration, ...restArgs}) {
|
|
344
|
+
restArgsError(restArgs)
|
|
345
|
+
|
|
279
346
|
if (!configuration) throw new Error(`No configuration given for ${this.name}`)
|
|
280
347
|
|
|
281
348
|
this._configuration = configuration
|
|
@@ -316,6 +383,9 @@ class VelociousDatabaseRecord {
|
|
|
316
383
|
this._initialized = true
|
|
317
384
|
}
|
|
318
385
|
|
|
386
|
+
/**
|
|
387
|
+
* @returns {boolean}
|
|
388
|
+
*/
|
|
319
389
|
_hasAttribute(value) {
|
|
320
390
|
if (typeof value == "string") {
|
|
321
391
|
value = value.trim()
|
|
@@ -328,6 +398,9 @@ class VelociousDatabaseRecord {
|
|
|
328
398
|
return false
|
|
329
399
|
}
|
|
330
400
|
|
|
401
|
+
/**
|
|
402
|
+
* @returns {boolean}
|
|
403
|
+
*/
|
|
331
404
|
static isInitialized() {
|
|
332
405
|
if (this._initialized) return true
|
|
333
406
|
|
|
@@ -381,14 +454,25 @@ class VelociousDatabaseRecord {
|
|
|
381
454
|
}
|
|
382
455
|
}
|
|
383
456
|
|
|
457
|
+
/**
|
|
458
|
+
* @returns {string}
|
|
459
|
+
*/
|
|
384
460
|
static getDatabaseIdentifier() {
|
|
385
461
|
return this._databaseIdentifier || "default"
|
|
386
462
|
}
|
|
387
463
|
|
|
464
|
+
/**
|
|
465
|
+
* @param {string} databaseIdentifier
|
|
466
|
+
* @returns {void}
|
|
467
|
+
*/
|
|
388
468
|
static setDatabaseIdentifier(databaseIdentifier) {
|
|
389
469
|
this._databaseIdentifier = databaseIdentifier
|
|
390
470
|
}
|
|
391
471
|
|
|
472
|
+
/**
|
|
473
|
+
* @param {string} name
|
|
474
|
+
* @returns {*}
|
|
475
|
+
*/
|
|
392
476
|
getAttribute(name) {
|
|
393
477
|
const columnName = inflection.underscore(name)
|
|
394
478
|
|
|
@@ -399,6 +483,11 @@ class VelociousDatabaseRecord {
|
|
|
399
483
|
return this._attributes[columnName]
|
|
400
484
|
}
|
|
401
485
|
|
|
486
|
+
/**
|
|
487
|
+
* @param {string} name
|
|
488
|
+
* @param {*} newValue
|
|
489
|
+
* @returns {void}
|
|
490
|
+
*/
|
|
402
491
|
setAttribute(name, newValue) {
|
|
403
492
|
const setterName = `set${inflection.camelize(name)}`
|
|
404
493
|
|
|
@@ -413,7 +502,7 @@ class VelociousDatabaseRecord {
|
|
|
413
502
|
|
|
414
503
|
const columnName = this.constructor._attributeNameToColumnName[name]
|
|
415
504
|
|
|
416
|
-
if (!columnName) throw new Error(`Couldn't figure out column name for attribute: ${
|
|
505
|
+
if (!columnName) throw new Error(`Couldn't figure out column name for attribute: ${name}`)
|
|
417
506
|
|
|
418
507
|
if (this._attributes[columnName] != newValue) {
|
|
419
508
|
this._changes[columnName] = newValue
|
|
@@ -426,6 +515,9 @@ class VelociousDatabaseRecord {
|
|
|
426
515
|
return this._columns
|
|
427
516
|
}
|
|
428
517
|
|
|
518
|
+
/**
|
|
519
|
+
* @returns {Array<string>}
|
|
520
|
+
*/
|
|
429
521
|
static getColumnNames() {
|
|
430
522
|
if (!this._columnNames) {
|
|
431
523
|
this._columnNames = this.getColumns().map((column) => column.getName())
|
|
@@ -440,10 +532,18 @@ class VelociousDatabaseRecord {
|
|
|
440
532
|
return this._table
|
|
441
533
|
}
|
|
442
534
|
|
|
535
|
+
/**
|
|
536
|
+
* @param {Array<string>} columns
|
|
537
|
+
* @param {Array<Array<string>>} rows
|
|
538
|
+
* @returns {void}
|
|
539
|
+
*/
|
|
443
540
|
static async insertMultiple(columns, rows) {
|
|
444
541
|
return await this.connection().insertMultiple(this.tableName(), columns, rows)
|
|
445
542
|
}
|
|
446
543
|
|
|
544
|
+
/**
|
|
545
|
+
* @returns {number}
|
|
546
|
+
*/
|
|
447
547
|
static async nextPrimaryKey() {
|
|
448
548
|
const primaryKey = this.primaryKey()
|
|
449
549
|
const tableName = this.tableName()
|
|
@@ -457,16 +557,26 @@ class VelociousDatabaseRecord {
|
|
|
457
557
|
}
|
|
458
558
|
}
|
|
459
559
|
|
|
560
|
+
/**
|
|
561
|
+
* @param {string} primaryKey
|
|
562
|
+
* @returns {void}
|
|
563
|
+
*/
|
|
460
564
|
static setPrimaryKey(primaryKey) {
|
|
461
565
|
this._primaryKey = primaryKey
|
|
462
566
|
}
|
|
463
567
|
|
|
568
|
+
/**
|
|
569
|
+
* @returns {string}
|
|
570
|
+
*/
|
|
464
571
|
static primaryKey() {
|
|
465
572
|
if (this._primaryKey) return this._primaryKey
|
|
466
573
|
|
|
467
574
|
return "id"
|
|
468
575
|
}
|
|
469
576
|
|
|
577
|
+
/**
|
|
578
|
+
* @returns {boolean}
|
|
579
|
+
*/
|
|
470
580
|
async save() {
|
|
471
581
|
const isNewRecord = this.isNewRecord()
|
|
472
582
|
let result
|
|
@@ -600,26 +710,40 @@ class VelociousDatabaseRecord {
|
|
|
600
710
|
}
|
|
601
711
|
}
|
|
602
712
|
|
|
713
|
+
/**
|
|
714
|
+
* @returns {string}
|
|
715
|
+
*/
|
|
603
716
|
static tableName() {
|
|
604
717
|
if (!this._tableName) this._tableName = inflection.underscore(inflection.pluralize(this.name))
|
|
605
718
|
|
|
606
719
|
return this._tableName
|
|
607
720
|
}
|
|
608
721
|
|
|
722
|
+
/**
|
|
723
|
+
* @param {string} tableName
|
|
724
|
+
* @returns {void}
|
|
725
|
+
*/
|
|
609
726
|
static setTableName(tableName) {
|
|
610
727
|
this._tableName = tableName
|
|
611
728
|
}
|
|
612
729
|
|
|
730
|
+
/**
|
|
731
|
+
* @param {function() : void} callback
|
|
732
|
+
* @returns {*}
|
|
733
|
+
*/
|
|
613
734
|
static async transaction(callback) {
|
|
614
735
|
const useTransactions = this.connection().getArgs().record?.transactions
|
|
615
736
|
|
|
616
737
|
if (useTransactions !== false) {
|
|
617
|
-
await this.connection().transaction(callback)
|
|
738
|
+
return await this.connection().transaction(callback)
|
|
618
739
|
} else {
|
|
619
740
|
return await callback()
|
|
620
741
|
}
|
|
621
742
|
}
|
|
622
743
|
|
|
744
|
+
/**
|
|
745
|
+
* @returns {void}
|
|
746
|
+
*/
|
|
623
747
|
static translates(...names) {
|
|
624
748
|
for (const name of names) {
|
|
625
749
|
if (!this._translations) this._translations = {}
|
|
@@ -633,6 +757,9 @@ class VelociousDatabaseRecord {
|
|
|
633
757
|
}
|
|
634
758
|
}
|
|
635
759
|
|
|
760
|
+
/**
|
|
761
|
+
* @returns {VelociousDatabaseRecord}
|
|
762
|
+
*/
|
|
636
763
|
static getTranslationClass() {
|
|
637
764
|
if (this._translationClass) return this._translationClass
|
|
638
765
|
if (this.tableName().endsWith("_translations")) throw new Error("Trying to define a translations class for a translation class")
|
|
@@ -650,6 +777,9 @@ class VelociousDatabaseRecord {
|
|
|
650
777
|
return this._translationClass
|
|
651
778
|
}
|
|
652
779
|
|
|
780
|
+
/**
|
|
781
|
+
* @returns {string}
|
|
782
|
+
*/
|
|
653
783
|
static getTranslationsTableName() {
|
|
654
784
|
const tableNameParts = this.tableName().split("_")
|
|
655
785
|
|
|
@@ -658,6 +788,9 @@ class VelociousDatabaseRecord {
|
|
|
658
788
|
return `${tableNameParts.join("_")}_translations`
|
|
659
789
|
}
|
|
660
790
|
|
|
791
|
+
/**
|
|
792
|
+
* @returns {Promise<boolean>}
|
|
793
|
+
*/
|
|
661
794
|
static async hasTranslationsTable() {
|
|
662
795
|
try {
|
|
663
796
|
await this.connection().getTableByName(this.getTranslationsTableName())
|
|
@@ -670,7 +803,6 @@ class VelociousDatabaseRecord {
|
|
|
670
803
|
|
|
671
804
|
/**
|
|
672
805
|
* Adds a validation to an attribute.
|
|
673
|
-
*
|
|
674
806
|
* @param {string} attributeName The name of the attribute to validate.
|
|
675
807
|
* @param {object} validators The validators to add. Key is the validator name, value is the validator arguments.
|
|
676
808
|
*/
|
|
@@ -687,6 +819,11 @@ class VelociousDatabaseRecord {
|
|
|
687
819
|
}
|
|
688
820
|
}
|
|
689
821
|
|
|
822
|
+
/**
|
|
823
|
+
* @param {string} name
|
|
824
|
+
* @param {string} locale
|
|
825
|
+
* @returns {*}
|
|
826
|
+
*/
|
|
690
827
|
_getTranslatedAttribute(name, locale) {
|
|
691
828
|
const translation = this.translations().loaded().find((translation) => translation.locale() == locale)
|
|
692
829
|
|
|
@@ -695,6 +832,11 @@ class VelociousDatabaseRecord {
|
|
|
695
832
|
}
|
|
696
833
|
}
|
|
697
834
|
|
|
835
|
+
/**
|
|
836
|
+
* @param {string} name
|
|
837
|
+
* @param {string} locale
|
|
838
|
+
* @returns {*}
|
|
839
|
+
*/
|
|
698
840
|
_getTranslatedAttributeWithFallback(name, locale) {
|
|
699
841
|
let localesInOrder
|
|
700
842
|
const fallbacks = this._getConfiguration().getLocaleFallbacks()
|
|
@@ -714,6 +856,12 @@ class VelociousDatabaseRecord {
|
|
|
714
856
|
}
|
|
715
857
|
}
|
|
716
858
|
|
|
859
|
+
/**
|
|
860
|
+
* @param {string} name
|
|
861
|
+
* @param {string} locale
|
|
862
|
+
* @param {*} newValue
|
|
863
|
+
* @returns {void}
|
|
864
|
+
*/
|
|
717
865
|
_setTranslatedAttribute(name, locale, newValue) {
|
|
718
866
|
let translation = this.translations().loaded()?.find((translation) => translation.locale() == locale)
|
|
719
867
|
|
|
@@ -728,6 +876,9 @@ class VelociousDatabaseRecord {
|
|
|
728
876
|
translation.assign(assignments)
|
|
729
877
|
}
|
|
730
878
|
|
|
879
|
+
/**
|
|
880
|
+
* @returns {Query}
|
|
881
|
+
*/
|
|
731
882
|
static _newQuery() {
|
|
732
883
|
const handler = new Handler()
|
|
733
884
|
const query = new Query({
|
|
@@ -739,80 +890,139 @@ class VelociousDatabaseRecord {
|
|
|
739
890
|
return query.from(new FromTable({driver: this.connection(), tableName: this.tableName()}))
|
|
740
891
|
}
|
|
741
892
|
|
|
893
|
+
/**
|
|
894
|
+
* @returns {string}
|
|
895
|
+
*/
|
|
742
896
|
static orderableColumn() {
|
|
743
897
|
// FIXME: Allow to change to 'created_at' if using UUID?
|
|
744
898
|
|
|
745
899
|
return this.primaryKey()
|
|
746
900
|
}
|
|
747
901
|
|
|
902
|
+
/**
|
|
903
|
+
* @returns {Query}
|
|
904
|
+
*/
|
|
748
905
|
static all() {
|
|
749
906
|
return this._newQuery()
|
|
750
907
|
}
|
|
751
908
|
|
|
909
|
+
/**
|
|
910
|
+
* @returns {number}
|
|
911
|
+
*/
|
|
752
912
|
static async count() {
|
|
753
|
-
return this._newQuery().count()
|
|
913
|
+
return await this._newQuery().count()
|
|
754
914
|
}
|
|
755
915
|
|
|
756
916
|
static async destroyAll(...args) {
|
|
757
|
-
return this._newQuery().destroyAll(...args)
|
|
917
|
+
return await this._newQuery().destroyAll(...args)
|
|
758
918
|
}
|
|
759
919
|
|
|
920
|
+
/**
|
|
921
|
+
* @param {...Parameters<Query["find"]>} args
|
|
922
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
923
|
+
*/
|
|
760
924
|
static async find(...args) {
|
|
761
|
-
return this._newQuery().find(...args)
|
|
925
|
+
return await this._newQuery().find(...args)
|
|
762
926
|
}
|
|
763
927
|
|
|
928
|
+
/**
|
|
929
|
+
* @param {...Parameters<Query["findBy"]>} args
|
|
930
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
931
|
+
*/
|
|
764
932
|
static async findBy(...args) {
|
|
765
|
-
return this._newQuery().findBy(...args)
|
|
933
|
+
return await this._newQuery().findBy(...args)
|
|
766
934
|
}
|
|
767
935
|
|
|
936
|
+
/**
|
|
937
|
+
* @param {...Parameters<Query["findByOrFail"]>} args
|
|
938
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
939
|
+
*/
|
|
768
940
|
static async findByOrFail(...args) {
|
|
769
|
-
return this._newQuery().findByOrFail(...args)
|
|
941
|
+
return await this._newQuery().findByOrFail(...args)
|
|
770
942
|
}
|
|
771
943
|
|
|
944
|
+
/**
|
|
945
|
+
* @param {...Parameters<Query["findOrCreateBy"]>} args
|
|
946
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
947
|
+
*/
|
|
772
948
|
static async findOrCreateBy(...args) {
|
|
773
|
-
return this._newQuery().findOrCreateBy(...args)
|
|
949
|
+
return await this._newQuery().findOrCreateBy(...args)
|
|
774
950
|
}
|
|
775
951
|
|
|
952
|
+
/**
|
|
953
|
+
* @param {...Parameters<Query["findOrInitializeBy"]>} args
|
|
954
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
955
|
+
*/
|
|
776
956
|
static async findOrInitializeBy(...args) {
|
|
777
|
-
return this._newQuery().findOrInitializeBy(...args)
|
|
957
|
+
return await this._newQuery().findOrInitializeBy(...args)
|
|
778
958
|
}
|
|
779
959
|
|
|
960
|
+
/**
|
|
961
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
962
|
+
*/
|
|
780
963
|
static async first() {
|
|
781
|
-
return this._newQuery().first()
|
|
964
|
+
return await this._newQuery().first()
|
|
782
965
|
}
|
|
783
966
|
|
|
967
|
+
/**
|
|
968
|
+
* @returns {Query}
|
|
969
|
+
*/
|
|
784
970
|
static joins(...args) {
|
|
785
971
|
return this._newQuery().joins(...args)
|
|
786
972
|
}
|
|
787
973
|
|
|
974
|
+
/**
|
|
975
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
976
|
+
*/
|
|
788
977
|
static async last(...args) {
|
|
789
978
|
return await this._newQuery().last(...args)
|
|
790
979
|
}
|
|
791
980
|
|
|
981
|
+
/**
|
|
982
|
+
* @returns {Query}
|
|
983
|
+
*/
|
|
792
984
|
static limit(...args) {
|
|
793
985
|
return this._newQuery().limit(...args)
|
|
794
986
|
}
|
|
795
987
|
|
|
988
|
+
/**
|
|
989
|
+
* @returns {Query}
|
|
990
|
+
*/
|
|
796
991
|
static order(...args) {
|
|
797
992
|
return this._newQuery().order(...args)
|
|
798
993
|
}
|
|
799
994
|
|
|
995
|
+
/**
|
|
996
|
+
* @returns {Query}
|
|
997
|
+
*/
|
|
800
998
|
static preload(...args) {
|
|
801
999
|
return this._newQuery().preload(...args)
|
|
802
1000
|
}
|
|
803
1001
|
|
|
1002
|
+
/**
|
|
1003
|
+
* @returns {Query}
|
|
1004
|
+
*/
|
|
804
1005
|
static select(...args) {
|
|
805
1006
|
return this._newQuery().select(...args)
|
|
806
1007
|
}
|
|
807
1008
|
|
|
1009
|
+
/**
|
|
1010
|
+
* @returns {Query}
|
|
1011
|
+
*/
|
|
808
1012
|
static toArray(...args) {
|
|
809
1013
|
return this._newQuery().toArray(...args)
|
|
810
1014
|
}
|
|
811
1015
|
|
|
1016
|
+
/**
|
|
1017
|
+
* @returns {Query}
|
|
1018
|
+
*/
|
|
812
1019
|
static where(...args) {
|
|
813
1020
|
return this._newQuery().where(...args)
|
|
814
1021
|
}
|
|
815
1022
|
|
|
1023
|
+
/**
|
|
1024
|
+
* @param {object} changes
|
|
1025
|
+
*/
|
|
816
1026
|
constructor(changes = {}) {
|
|
817
1027
|
this._attributes = {}
|
|
818
1028
|
this._changes = {}
|
|
@@ -824,6 +1034,10 @@ class VelociousDatabaseRecord {
|
|
|
824
1034
|
}
|
|
825
1035
|
}
|
|
826
1036
|
|
|
1037
|
+
/**
|
|
1038
|
+
* @param {object} attributes
|
|
1039
|
+
* @returns {void}
|
|
1040
|
+
*/
|
|
827
1041
|
loadExistingRecord(attributes) {
|
|
828
1042
|
this._attributes = attributes
|
|
829
1043
|
this._isNewRecord = false
|
|
@@ -831,6 +1045,8 @@ class VelociousDatabaseRecord {
|
|
|
831
1045
|
|
|
832
1046
|
/**
|
|
833
1047
|
* Assigns the given attributes to the record.
|
|
1048
|
+
* @param {object} attributesToAssign
|
|
1049
|
+
* @returns {void}
|
|
834
1050
|
*/
|
|
835
1051
|
assign(attributesToAssign) {
|
|
836
1052
|
for (const attributeToAssign in attributesToAssign) {
|
|
@@ -840,11 +1056,15 @@ class VelociousDatabaseRecord {
|
|
|
840
1056
|
|
|
841
1057
|
/**
|
|
842
1058
|
* Returns a the current attributes of the record (original attributes from database plus changes)
|
|
1059
|
+
* @returns {void}
|
|
843
1060
|
*/
|
|
844
1061
|
attributes() {
|
|
845
1062
|
return Object.assign({}, this._attributes, this._changes)
|
|
846
1063
|
}
|
|
847
1064
|
|
|
1065
|
+
/**
|
|
1066
|
+
* @returns {import("../drivers/base.js").default}
|
|
1067
|
+
*/
|
|
848
1068
|
_connection() {
|
|
849
1069
|
if (this.__connection) return this.__connection
|
|
850
1070
|
|
|
@@ -853,6 +1073,7 @@ class VelociousDatabaseRecord {
|
|
|
853
1073
|
|
|
854
1074
|
/**
|
|
855
1075
|
* Destroys the record in the database and all of its dependent records.
|
|
1076
|
+
* @returns {void}
|
|
856
1077
|
*/
|
|
857
1078
|
async destroy() {
|
|
858
1079
|
for (const relationship of this.constructor.getRelationships()) {
|
|
@@ -900,10 +1121,14 @@ class VelociousDatabaseRecord {
|
|
|
900
1121
|
await this._connection().query(sql)
|
|
901
1122
|
}
|
|
902
1123
|
|
|
1124
|
+
/**
|
|
1125
|
+
* @returns {boolean}
|
|
1126
|
+
*/
|
|
903
1127
|
_hasChanges() { return Object.keys(this._changes).length > 0 }
|
|
904
1128
|
|
|
905
1129
|
/**
|
|
906
1130
|
* Returns true if the model has been changed since it was loaded from the database.
|
|
1131
|
+
* @returns {boolean}
|
|
907
1132
|
*/
|
|
908
1133
|
isChanged() {
|
|
909
1134
|
if (this.isNewRecord() || this._hasChanges()){
|
|
@@ -936,6 +1161,7 @@ class VelociousDatabaseRecord {
|
|
|
936
1161
|
|
|
937
1162
|
/**
|
|
938
1163
|
* Returns the changes that have been made to this record since it was loaded from the database.
|
|
1164
|
+
* @returns {object}
|
|
939
1165
|
*/
|
|
940
1166
|
changes() {
|
|
941
1167
|
const changes = {}
|
|
@@ -949,6 +1175,9 @@ class VelociousDatabaseRecord {
|
|
|
949
1175
|
return changes
|
|
950
1176
|
}
|
|
951
1177
|
|
|
1178
|
+
/**
|
|
1179
|
+
* @returns {string}
|
|
1180
|
+
*/
|
|
952
1181
|
_tableName() {
|
|
953
1182
|
if (this.__tableName) return this.__tableName
|
|
954
1183
|
|
|
@@ -957,8 +1186,8 @@ class VelociousDatabaseRecord {
|
|
|
957
1186
|
|
|
958
1187
|
/**
|
|
959
1188
|
* Reads an attribute value from the record.
|
|
960
|
-
*
|
|
961
1189
|
* @param {string} attributeName The name of the attribute to read. This is the attribute name, not the column name.
|
|
1190
|
+
* @returns {void}
|
|
962
1191
|
*/
|
|
963
1192
|
readAttribute(attributeName) {
|
|
964
1193
|
const columnName = this.constructor._attributeNameToColumnName[attributeName]
|
|
@@ -970,7 +1199,6 @@ class VelociousDatabaseRecord {
|
|
|
970
1199
|
|
|
971
1200
|
/**
|
|
972
1201
|
* Reads a column value from the record.
|
|
973
|
-
*
|
|
974
1202
|
* @param {string} attributeName The name of the column to read. This is the column name, not the attribute name.
|
|
975
1203
|
*/
|
|
976
1204
|
readColumn(attributeName) {
|
|
@@ -1010,6 +1238,9 @@ class VelociousDatabaseRecord {
|
|
|
1010
1238
|
return belongsToChanges
|
|
1011
1239
|
}
|
|
1012
1240
|
|
|
1241
|
+
/**
|
|
1242
|
+
* @returns {void}
|
|
1243
|
+
*/
|
|
1013
1244
|
async _createNewRecord() {
|
|
1014
1245
|
if (!this.constructor.connection()["insertSql"]) {
|
|
1015
1246
|
throw new Error(`No insertSql on ${this.constructor.connection().constructor.name}`)
|
|
@@ -1055,6 +1286,9 @@ class VelociousDatabaseRecord {
|
|
|
1055
1286
|
}
|
|
1056
1287
|
}
|
|
1057
1288
|
|
|
1289
|
+
/**
|
|
1290
|
+
* @returns {void}
|
|
1291
|
+
*/
|
|
1058
1292
|
async _updateRecordWithChanges() {
|
|
1059
1293
|
const conditions = {}
|
|
1060
1294
|
|
|
@@ -1077,6 +1311,9 @@ class VelociousDatabaseRecord {
|
|
|
1077
1311
|
}
|
|
1078
1312
|
}
|
|
1079
1313
|
|
|
1314
|
+
/**
|
|
1315
|
+
* @returns {number|string}
|
|
1316
|
+
*/
|
|
1080
1317
|
id() {
|
|
1081
1318
|
if (!this.constructor._columnNameToAttributeName) {
|
|
1082
1319
|
throw new Error(`Column names mapping hasn't been set on ${this.constructor.name}. Has the model been initialized?`)
|
|
@@ -1092,9 +1329,20 @@ class VelociousDatabaseRecord {
|
|
|
1092
1329
|
return this.readAttribute(attributeName)
|
|
1093
1330
|
}
|
|
1094
1331
|
|
|
1332
|
+
/**
|
|
1333
|
+
* @returns {boolean}
|
|
1334
|
+
*/
|
|
1095
1335
|
isPersisted() { return !this._isNewRecord }
|
|
1336
|
+
|
|
1337
|
+
/**
|
|
1338
|
+
* @returns {boolean}
|
|
1339
|
+
*/
|
|
1096
1340
|
isNewRecord() { return this._isNewRecord }
|
|
1097
1341
|
|
|
1342
|
+
/**
|
|
1343
|
+
* @param {boolean} newIsNewRecord
|
|
1344
|
+
* @returns {void}
|
|
1345
|
+
*/
|
|
1098
1346
|
setIsNewRecord(newIsNewRecord) {
|
|
1099
1347
|
this._isNewRecord = newIsNewRecord
|
|
1100
1348
|
}
|
|
@@ -1114,6 +1362,9 @@ class VelociousDatabaseRecord {
|
|
|
1114
1362
|
this._changes = {}
|
|
1115
1363
|
}
|
|
1116
1364
|
|
|
1365
|
+
/**
|
|
1366
|
+
* @returns {void}
|
|
1367
|
+
*/
|
|
1117
1368
|
async reload() {
|
|
1118
1369
|
this._reloadWithId(this.readAttribute("id"))
|
|
1119
1370
|
}
|
|
@@ -1143,6 +1394,9 @@ class VelociousDatabaseRecord {
|
|
|
1143
1394
|
}
|
|
1144
1395
|
}
|
|
1145
1396
|
|
|
1397
|
+
/**
|
|
1398
|
+
* @returns {Array<string>}
|
|
1399
|
+
*/
|
|
1146
1400
|
fullErrorMessages() {
|
|
1147
1401
|
const validationErrorMessages = []
|
|
1148
1402
|
|
|
@@ -1161,8 +1415,7 @@ class VelociousDatabaseRecord {
|
|
|
1161
1415
|
|
|
1162
1416
|
/**
|
|
1163
1417
|
* Assigns the attributes to the record and saves it.
|
|
1164
|
-
*
|
|
1165
|
-
* @param {Object} attributesToAssign - The attributes to assign to the record.
|
|
1418
|
+
* @param {object} attributesToAssign - The attributes to assign to the record.
|
|
1166
1419
|
*/
|
|
1167
1420
|
async update(attributesToAssign) {
|
|
1168
1421
|
if (attributesToAssign) this.assign(attributesToAssign)
|