velocious 1.0.84 → 1.0.86
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 +4 -3
- package/src/cli/commands/test.js +1 -1
- package/src/cli/index.js +15 -40
- 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 +105 -1
- 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 +321 -14
- 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
|
|
|
@@ -204,10 +246,19 @@ class VelociousDatabaseRecord {
|
|
|
204
246
|
return this._instanceRelationships[relationshipName]
|
|
205
247
|
}
|
|
206
248
|
|
|
249
|
+
/**
|
|
250
|
+
* Adds a belongs-to-relationship to the model.
|
|
251
|
+
* @param {string} relationshipName The name of the relationship.
|
|
252
|
+
* @param {object} options The options for the relationship.
|
|
253
|
+
*/
|
|
207
254
|
static belongsTo(relationshipName, options) {
|
|
208
255
|
this._defineRelationship(relationshipName, Object.assign({type: "belongsTo"}, options))
|
|
209
256
|
}
|
|
210
257
|
|
|
258
|
+
/**
|
|
259
|
+
* @template T extends import("./database/drivers/base").default
|
|
260
|
+
* @returns {T}
|
|
261
|
+
*/
|
|
211
262
|
static connection() {
|
|
212
263
|
const databasePool = this._getConfiguration().getDatabasePool(this.getDatabaseIdentifier())
|
|
213
264
|
const connection = databasePool.getCurrentConnection()
|
|
@@ -217,6 +268,10 @@ class VelociousDatabaseRecord {
|
|
|
217
268
|
return connection
|
|
218
269
|
}
|
|
219
270
|
|
|
271
|
+
/**
|
|
272
|
+
* @param {object} attributes
|
|
273
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
274
|
+
*/
|
|
220
275
|
static async create(attributes) {
|
|
221
276
|
const record = new this(attributes)
|
|
222
277
|
|
|
@@ -225,6 +280,9 @@ class VelociousDatabaseRecord {
|
|
|
225
280
|
return record
|
|
226
281
|
}
|
|
227
282
|
|
|
283
|
+
/**
|
|
284
|
+
* @returns {import("../../configuration.js").default}
|
|
285
|
+
*/
|
|
228
286
|
static _getConfiguration() {
|
|
229
287
|
if (!this._configuration) {
|
|
230
288
|
this._configuration = Configuration.current()
|
|
@@ -237,27 +295,54 @@ class VelociousDatabaseRecord {
|
|
|
237
295
|
return this._configuration
|
|
238
296
|
}
|
|
239
297
|
|
|
298
|
+
/**
|
|
299
|
+
* @returns {import("../../configuration.js").default}
|
|
300
|
+
*/
|
|
240
301
|
_getConfiguration() {
|
|
241
302
|
return this.constructor._getConfiguration()
|
|
242
303
|
}
|
|
243
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Adds a has-many-relationship to the model class.
|
|
307
|
+
* @param {string} relationshipName The name of the relationship (e.g. "posts")
|
|
308
|
+
* @param {object} options The options for the relationship (e.g. {className: "Post"})
|
|
309
|
+
*/
|
|
244
310
|
static hasMany(relationshipName, options = {}) {
|
|
245
311
|
return this._defineRelationship(relationshipName, Object.assign({type: "hasMany"}, options))
|
|
246
312
|
}
|
|
247
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Adds a has-one-relationship to the model class.
|
|
316
|
+
* @param {string} relationshipName The name of the relationship (e.g. "post")
|
|
317
|
+
* @param {object} options The options for the relationship (e.g. {className: "Post"})
|
|
318
|
+
*/
|
|
248
319
|
static hasOne(relationshipName, options = {}) {
|
|
249
320
|
return this._defineRelationship(relationshipName, Object.assign({type: "hasOne"}, options))
|
|
250
321
|
}
|
|
251
322
|
|
|
323
|
+
/**
|
|
324
|
+
* @param {string} attributeName
|
|
325
|
+
* @returns {string}
|
|
326
|
+
*/
|
|
252
327
|
static humanAttributeName(attributeName) {
|
|
253
328
|
const modelNameKey = inflection.underscore(this.constructor.name)
|
|
254
329
|
|
|
255
330
|
return this._getConfiguration().getTranslator()(`velocious.database.record.attributes.${modelNameKey}.${attributeName}`, {defaultValue: inflection.camelize(attributeName)})
|
|
256
331
|
}
|
|
257
332
|
|
|
333
|
+
/**
|
|
334
|
+
* @returns {string}
|
|
335
|
+
*/
|
|
258
336
|
static getDatabaseType() { return this._databaseType }
|
|
259
337
|
|
|
260
|
-
|
|
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
|
+
|
|
261
346
|
if (!configuration) throw new Error(`No configuration given for ${this.name}`)
|
|
262
347
|
|
|
263
348
|
this._configuration = configuration
|
|
@@ -298,6 +383,9 @@ class VelociousDatabaseRecord {
|
|
|
298
383
|
this._initialized = true
|
|
299
384
|
}
|
|
300
385
|
|
|
386
|
+
/**
|
|
387
|
+
* @returns {boolean}
|
|
388
|
+
*/
|
|
301
389
|
_hasAttribute(value) {
|
|
302
390
|
if (typeof value == "string") {
|
|
303
391
|
value = value.trim()
|
|
@@ -310,6 +398,9 @@ class VelociousDatabaseRecord {
|
|
|
310
398
|
return false
|
|
311
399
|
}
|
|
312
400
|
|
|
401
|
+
/**
|
|
402
|
+
* @returns {boolean}
|
|
403
|
+
*/
|
|
313
404
|
static isInitialized() {
|
|
314
405
|
if (this._initialized) return true
|
|
315
406
|
|
|
@@ -363,14 +454,25 @@ class VelociousDatabaseRecord {
|
|
|
363
454
|
}
|
|
364
455
|
}
|
|
365
456
|
|
|
457
|
+
/**
|
|
458
|
+
* @returns {string}
|
|
459
|
+
*/
|
|
366
460
|
static getDatabaseIdentifier() {
|
|
367
461
|
return this._databaseIdentifier || "default"
|
|
368
462
|
}
|
|
369
463
|
|
|
464
|
+
/**
|
|
465
|
+
* @param {string} databaseIdentifier
|
|
466
|
+
* @returns {void}
|
|
467
|
+
*/
|
|
370
468
|
static setDatabaseIdentifier(databaseIdentifier) {
|
|
371
469
|
this._databaseIdentifier = databaseIdentifier
|
|
372
470
|
}
|
|
373
471
|
|
|
472
|
+
/**
|
|
473
|
+
* @param {string} name
|
|
474
|
+
* @returns {*}
|
|
475
|
+
*/
|
|
374
476
|
getAttribute(name) {
|
|
375
477
|
const columnName = inflection.underscore(name)
|
|
376
478
|
|
|
@@ -381,6 +483,11 @@ class VelociousDatabaseRecord {
|
|
|
381
483
|
return this._attributes[columnName]
|
|
382
484
|
}
|
|
383
485
|
|
|
486
|
+
/**
|
|
487
|
+
* @param {string} name
|
|
488
|
+
* @param {*} newValue
|
|
489
|
+
* @returns {void}
|
|
490
|
+
*/
|
|
384
491
|
setAttribute(name, newValue) {
|
|
385
492
|
const setterName = `set${inflection.camelize(name)}`
|
|
386
493
|
|
|
@@ -395,7 +502,7 @@ class VelociousDatabaseRecord {
|
|
|
395
502
|
|
|
396
503
|
const columnName = this.constructor._attributeNameToColumnName[name]
|
|
397
504
|
|
|
398
|
-
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}`)
|
|
399
506
|
|
|
400
507
|
if (this._attributes[columnName] != newValue) {
|
|
401
508
|
this._changes[columnName] = newValue
|
|
@@ -408,6 +515,9 @@ class VelociousDatabaseRecord {
|
|
|
408
515
|
return this._columns
|
|
409
516
|
}
|
|
410
517
|
|
|
518
|
+
/**
|
|
519
|
+
* @returns {Array<string>}
|
|
520
|
+
*/
|
|
411
521
|
static getColumnNames() {
|
|
412
522
|
if (!this._columnNames) {
|
|
413
523
|
this._columnNames = this.getColumns().map((column) => column.getName())
|
|
@@ -422,10 +532,18 @@ class VelociousDatabaseRecord {
|
|
|
422
532
|
return this._table
|
|
423
533
|
}
|
|
424
534
|
|
|
535
|
+
/**
|
|
536
|
+
* @param {Array<string>} columns
|
|
537
|
+
* @param {Array<Array<string>>} rows
|
|
538
|
+
* @returns {void}
|
|
539
|
+
*/
|
|
425
540
|
static async insertMultiple(columns, rows) {
|
|
426
541
|
return await this.connection().insertMultiple(this.tableName(), columns, rows)
|
|
427
542
|
}
|
|
428
543
|
|
|
544
|
+
/**
|
|
545
|
+
* @returns {number}
|
|
546
|
+
*/
|
|
429
547
|
static async nextPrimaryKey() {
|
|
430
548
|
const primaryKey = this.primaryKey()
|
|
431
549
|
const tableName = this.tableName()
|
|
@@ -439,16 +557,26 @@ class VelociousDatabaseRecord {
|
|
|
439
557
|
}
|
|
440
558
|
}
|
|
441
559
|
|
|
560
|
+
/**
|
|
561
|
+
* @param {string} primaryKey
|
|
562
|
+
* @returns {void}
|
|
563
|
+
*/
|
|
442
564
|
static setPrimaryKey(primaryKey) {
|
|
443
565
|
this._primaryKey = primaryKey
|
|
444
566
|
}
|
|
445
567
|
|
|
568
|
+
/**
|
|
569
|
+
* @returns {string}
|
|
570
|
+
*/
|
|
446
571
|
static primaryKey() {
|
|
447
572
|
if (this._primaryKey) return this._primaryKey
|
|
448
573
|
|
|
449
574
|
return "id"
|
|
450
575
|
}
|
|
451
576
|
|
|
577
|
+
/**
|
|
578
|
+
* @returns {boolean}
|
|
579
|
+
*/
|
|
452
580
|
async save() {
|
|
453
581
|
const isNewRecord = this.isNewRecord()
|
|
454
582
|
let result
|
|
@@ -582,26 +710,40 @@ class VelociousDatabaseRecord {
|
|
|
582
710
|
}
|
|
583
711
|
}
|
|
584
712
|
|
|
713
|
+
/**
|
|
714
|
+
* @returns {string}
|
|
715
|
+
*/
|
|
585
716
|
static tableName() {
|
|
586
717
|
if (!this._tableName) this._tableName = inflection.underscore(inflection.pluralize(this.name))
|
|
587
718
|
|
|
588
719
|
return this._tableName
|
|
589
720
|
}
|
|
590
721
|
|
|
722
|
+
/**
|
|
723
|
+
* @param {string} tableName
|
|
724
|
+
* @returns {void}
|
|
725
|
+
*/
|
|
591
726
|
static setTableName(tableName) {
|
|
592
727
|
this._tableName = tableName
|
|
593
728
|
}
|
|
594
729
|
|
|
730
|
+
/**
|
|
731
|
+
* @param {function() : void} callback
|
|
732
|
+
* @returns {*}
|
|
733
|
+
*/
|
|
595
734
|
static async transaction(callback) {
|
|
596
735
|
const useTransactions = this.connection().getArgs().record?.transactions
|
|
597
736
|
|
|
598
737
|
if (useTransactions !== false) {
|
|
599
|
-
await this.connection().transaction(callback)
|
|
738
|
+
return await this.connection().transaction(callback)
|
|
600
739
|
} else {
|
|
601
740
|
return await callback()
|
|
602
741
|
}
|
|
603
742
|
}
|
|
604
743
|
|
|
744
|
+
/**
|
|
745
|
+
* @returns {void}
|
|
746
|
+
*/
|
|
605
747
|
static translates(...names) {
|
|
606
748
|
for (const name of names) {
|
|
607
749
|
if (!this._translations) this._translations = {}
|
|
@@ -615,6 +757,9 @@ class VelociousDatabaseRecord {
|
|
|
615
757
|
}
|
|
616
758
|
}
|
|
617
759
|
|
|
760
|
+
/**
|
|
761
|
+
* @returns {VelociousDatabaseRecord}
|
|
762
|
+
*/
|
|
618
763
|
static getTranslationClass() {
|
|
619
764
|
if (this._translationClass) return this._translationClass
|
|
620
765
|
if (this.tableName().endsWith("_translations")) throw new Error("Trying to define a translations class for a translation class")
|
|
@@ -632,6 +777,9 @@ class VelociousDatabaseRecord {
|
|
|
632
777
|
return this._translationClass
|
|
633
778
|
}
|
|
634
779
|
|
|
780
|
+
/**
|
|
781
|
+
* @returns {string}
|
|
782
|
+
*/
|
|
635
783
|
static getTranslationsTableName() {
|
|
636
784
|
const tableNameParts = this.tableName().split("_")
|
|
637
785
|
|
|
@@ -640,6 +788,9 @@ class VelociousDatabaseRecord {
|
|
|
640
788
|
return `${tableNameParts.join("_")}_translations`
|
|
641
789
|
}
|
|
642
790
|
|
|
791
|
+
/**
|
|
792
|
+
* @returns {Promise<boolean>}
|
|
793
|
+
*/
|
|
643
794
|
static async hasTranslationsTable() {
|
|
644
795
|
try {
|
|
645
796
|
await this.connection().getTableByName(this.getTranslationsTableName())
|
|
@@ -650,6 +801,11 @@ class VelociousDatabaseRecord {
|
|
|
650
801
|
}
|
|
651
802
|
}
|
|
652
803
|
|
|
804
|
+
/**
|
|
805
|
+
* Adds a validation to an attribute.
|
|
806
|
+
* @param {string} attributeName The name of the attribute to validate.
|
|
807
|
+
* @param {object} validators The validators to add. Key is the validator name, value is the validator arguments.
|
|
808
|
+
*/
|
|
653
809
|
static async validates(attributeName, validators) {
|
|
654
810
|
for (const validatorName in validators) {
|
|
655
811
|
const validatorArgs = validators[validatorName]
|
|
@@ -663,6 +819,11 @@ class VelociousDatabaseRecord {
|
|
|
663
819
|
}
|
|
664
820
|
}
|
|
665
821
|
|
|
822
|
+
/**
|
|
823
|
+
* @param {string} name
|
|
824
|
+
* @param {string} locale
|
|
825
|
+
* @returns {*}
|
|
826
|
+
*/
|
|
666
827
|
_getTranslatedAttribute(name, locale) {
|
|
667
828
|
const translation = this.translations().loaded().find((translation) => translation.locale() == locale)
|
|
668
829
|
|
|
@@ -671,6 +832,11 @@ class VelociousDatabaseRecord {
|
|
|
671
832
|
}
|
|
672
833
|
}
|
|
673
834
|
|
|
835
|
+
/**
|
|
836
|
+
* @param {string} name
|
|
837
|
+
* @param {string} locale
|
|
838
|
+
* @returns {*}
|
|
839
|
+
*/
|
|
674
840
|
_getTranslatedAttributeWithFallback(name, locale) {
|
|
675
841
|
let localesInOrder
|
|
676
842
|
const fallbacks = this._getConfiguration().getLocaleFallbacks()
|
|
@@ -690,6 +856,12 @@ class VelociousDatabaseRecord {
|
|
|
690
856
|
}
|
|
691
857
|
}
|
|
692
858
|
|
|
859
|
+
/**
|
|
860
|
+
* @param {string} name
|
|
861
|
+
* @param {string} locale
|
|
862
|
+
* @param {*} newValue
|
|
863
|
+
* @returns {void}
|
|
864
|
+
*/
|
|
693
865
|
_setTranslatedAttribute(name, locale, newValue) {
|
|
694
866
|
let translation = this.translations().loaded()?.find((translation) => translation.locale() == locale)
|
|
695
867
|
|
|
@@ -704,6 +876,9 @@ class VelociousDatabaseRecord {
|
|
|
704
876
|
translation.assign(assignments)
|
|
705
877
|
}
|
|
706
878
|
|
|
879
|
+
/**
|
|
880
|
+
* @returns {Query}
|
|
881
|
+
*/
|
|
707
882
|
static _newQuery() {
|
|
708
883
|
const handler = new Handler()
|
|
709
884
|
const query = new Query({
|
|
@@ -715,80 +890,139 @@ class VelociousDatabaseRecord {
|
|
|
715
890
|
return query.from(new FromTable({driver: this.connection(), tableName: this.tableName()}))
|
|
716
891
|
}
|
|
717
892
|
|
|
893
|
+
/**
|
|
894
|
+
* @returns {string}
|
|
895
|
+
*/
|
|
718
896
|
static orderableColumn() {
|
|
719
897
|
// FIXME: Allow to change to 'created_at' if using UUID?
|
|
720
898
|
|
|
721
899
|
return this.primaryKey()
|
|
722
900
|
}
|
|
723
901
|
|
|
724
|
-
|
|
725
|
-
|
|
902
|
+
/**
|
|
903
|
+
* @returns {Promise<Array<InstanceType<typeof this>>>}
|
|
904
|
+
*/
|
|
905
|
+
static async all() {
|
|
906
|
+
return await this._newQuery()
|
|
726
907
|
}
|
|
727
908
|
|
|
909
|
+
/**
|
|
910
|
+
* @returns {number}
|
|
911
|
+
*/
|
|
728
912
|
static async count() {
|
|
729
|
-
return this._newQuery().count()
|
|
913
|
+
return await this._newQuery().count()
|
|
730
914
|
}
|
|
731
915
|
|
|
732
916
|
static async destroyAll(...args) {
|
|
733
|
-
return this._newQuery().destroyAll(...args)
|
|
917
|
+
return await this._newQuery().destroyAll(...args)
|
|
734
918
|
}
|
|
735
919
|
|
|
920
|
+
/**
|
|
921
|
+
* @param {...Parameters<Query["find"]>} args
|
|
922
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
923
|
+
*/
|
|
736
924
|
static async find(...args) {
|
|
737
|
-
return this._newQuery().find(...args)
|
|
925
|
+
return await this._newQuery().find(...args)
|
|
738
926
|
}
|
|
739
927
|
|
|
928
|
+
/**
|
|
929
|
+
* @param {...Parameters<Query["findBy"]>} args
|
|
930
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
931
|
+
*/
|
|
740
932
|
static async findBy(...args) {
|
|
741
|
-
return this._newQuery().findBy(...args)
|
|
933
|
+
return await this._newQuery().findBy(...args)
|
|
742
934
|
}
|
|
743
935
|
|
|
936
|
+
/**
|
|
937
|
+
* @param {...Parameters<Query["findByOrFail"]>} args
|
|
938
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
939
|
+
*/
|
|
744
940
|
static async findByOrFail(...args) {
|
|
745
|
-
return this._newQuery().findByOrFail(...args)
|
|
941
|
+
return await this._newQuery().findByOrFail(...args)
|
|
746
942
|
}
|
|
747
943
|
|
|
944
|
+
/**
|
|
945
|
+
* @param {...Parameters<Query["findOrCreateBy"]>} args
|
|
946
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
947
|
+
*/
|
|
748
948
|
static async findOrCreateBy(...args) {
|
|
749
|
-
return this._newQuery().findOrCreateBy(...args)
|
|
949
|
+
return await this._newQuery().findOrCreateBy(...args)
|
|
750
950
|
}
|
|
751
951
|
|
|
952
|
+
/**
|
|
953
|
+
* @param {...Parameters<Query["findOrInitializeBy"]>} args
|
|
954
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
955
|
+
*/
|
|
752
956
|
static async findOrInitializeBy(...args) {
|
|
753
|
-
return this._newQuery().findOrInitializeBy(...args)
|
|
957
|
+
return await this._newQuery().findOrInitializeBy(...args)
|
|
754
958
|
}
|
|
755
959
|
|
|
960
|
+
/**
|
|
961
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
962
|
+
*/
|
|
756
963
|
static async first() {
|
|
757
|
-
return this._newQuery().first()
|
|
964
|
+
return await this._newQuery().first()
|
|
758
965
|
}
|
|
759
966
|
|
|
967
|
+
/**
|
|
968
|
+
* @returns {Query}
|
|
969
|
+
*/
|
|
760
970
|
static joins(...args) {
|
|
761
971
|
return this._newQuery().joins(...args)
|
|
762
972
|
}
|
|
763
973
|
|
|
974
|
+
/**
|
|
975
|
+
* @returns {Promise<InstanceType<typeof this>>}
|
|
976
|
+
*/
|
|
764
977
|
static async last(...args) {
|
|
765
978
|
return await this._newQuery().last(...args)
|
|
766
979
|
}
|
|
767
980
|
|
|
981
|
+
/**
|
|
982
|
+
* @returns {Query}
|
|
983
|
+
*/
|
|
768
984
|
static limit(...args) {
|
|
769
985
|
return this._newQuery().limit(...args)
|
|
770
986
|
}
|
|
771
987
|
|
|
988
|
+
/**
|
|
989
|
+
* @returns {Query}
|
|
990
|
+
*/
|
|
772
991
|
static order(...args) {
|
|
773
992
|
return this._newQuery().order(...args)
|
|
774
993
|
}
|
|
775
994
|
|
|
995
|
+
/**
|
|
996
|
+
* @returns {Query}
|
|
997
|
+
*/
|
|
776
998
|
static preload(...args) {
|
|
777
999
|
return this._newQuery().preload(...args)
|
|
778
1000
|
}
|
|
779
1001
|
|
|
1002
|
+
/**
|
|
1003
|
+
* @returns {Query}
|
|
1004
|
+
*/
|
|
780
1005
|
static select(...args) {
|
|
781
1006
|
return this._newQuery().select(...args)
|
|
782
1007
|
}
|
|
783
1008
|
|
|
1009
|
+
/**
|
|
1010
|
+
* @returns {Query}
|
|
1011
|
+
*/
|
|
784
1012
|
static toArray(...args) {
|
|
785
1013
|
return this._newQuery().toArray(...args)
|
|
786
1014
|
}
|
|
787
1015
|
|
|
1016
|
+
/**
|
|
1017
|
+
* @returns {Query}
|
|
1018
|
+
*/
|
|
788
1019
|
static where(...args) {
|
|
789
1020
|
return this._newQuery().where(...args)
|
|
790
1021
|
}
|
|
791
1022
|
|
|
1023
|
+
/**
|
|
1024
|
+
* @param {object} changes
|
|
1025
|
+
*/
|
|
792
1026
|
constructor(changes = {}) {
|
|
793
1027
|
this._attributes = {}
|
|
794
1028
|
this._changes = {}
|
|
@@ -800,27 +1034,47 @@ class VelociousDatabaseRecord {
|
|
|
800
1034
|
}
|
|
801
1035
|
}
|
|
802
1036
|
|
|
1037
|
+
/**
|
|
1038
|
+
* @param {object} attributes
|
|
1039
|
+
* @returns {void}
|
|
1040
|
+
*/
|
|
803
1041
|
loadExistingRecord(attributes) {
|
|
804
1042
|
this._attributes = attributes
|
|
805
1043
|
this._isNewRecord = false
|
|
806
1044
|
}
|
|
807
1045
|
|
|
1046
|
+
/**
|
|
1047
|
+
* Assigns the given attributes to the record.
|
|
1048
|
+
* @param {object} attributesToAssign
|
|
1049
|
+
* @returns {void}
|
|
1050
|
+
*/
|
|
808
1051
|
assign(attributesToAssign) {
|
|
809
1052
|
for (const attributeToAssign in attributesToAssign) {
|
|
810
1053
|
this.setAttribute(attributeToAssign, attributesToAssign[attributeToAssign])
|
|
811
1054
|
}
|
|
812
1055
|
}
|
|
813
1056
|
|
|
1057
|
+
/**
|
|
1058
|
+
* Returns a the current attributes of the record (original attributes from database plus changes)
|
|
1059
|
+
* @returns {void}
|
|
1060
|
+
*/
|
|
814
1061
|
attributes() {
|
|
815
1062
|
return Object.assign({}, this._attributes, this._changes)
|
|
816
1063
|
}
|
|
817
1064
|
|
|
1065
|
+
/**
|
|
1066
|
+
* @returns {import("../drivers/base.js").default}
|
|
1067
|
+
*/
|
|
818
1068
|
_connection() {
|
|
819
1069
|
if (this.__connection) return this.__connection
|
|
820
1070
|
|
|
821
1071
|
return this.constructor.connection()
|
|
822
1072
|
}
|
|
823
1073
|
|
|
1074
|
+
/**
|
|
1075
|
+
* Destroys the record in the database and all of its dependent records.
|
|
1076
|
+
* @returns {void}
|
|
1077
|
+
*/
|
|
824
1078
|
async destroy() {
|
|
825
1079
|
for (const relationship of this.constructor.getRelationships()) {
|
|
826
1080
|
if (relationship.getDependent() != "destroy") {
|
|
@@ -867,8 +1121,15 @@ class VelociousDatabaseRecord {
|
|
|
867
1121
|
await this._connection().query(sql)
|
|
868
1122
|
}
|
|
869
1123
|
|
|
870
|
-
|
|
1124
|
+
/**
|
|
1125
|
+
* @returns {boolean}
|
|
1126
|
+
*/
|
|
1127
|
+
_hasChanges() { return Object.keys(this._changes).length > 0 }
|
|
871
1128
|
|
|
1129
|
+
/**
|
|
1130
|
+
* Returns true if the model has been changed since it was loaded from the database.
|
|
1131
|
+
* @returns {boolean}
|
|
1132
|
+
*/
|
|
872
1133
|
isChanged() {
|
|
873
1134
|
if (this.isNewRecord() || this._hasChanges()){
|
|
874
1135
|
return true
|
|
@@ -898,6 +1159,10 @@ class VelociousDatabaseRecord {
|
|
|
898
1159
|
return false
|
|
899
1160
|
}
|
|
900
1161
|
|
|
1162
|
+
/**
|
|
1163
|
+
* Returns the changes that have been made to this record since it was loaded from the database.
|
|
1164
|
+
* @returns {object}
|
|
1165
|
+
*/
|
|
901
1166
|
changes() {
|
|
902
1167
|
const changes = {}
|
|
903
1168
|
|
|
@@ -910,12 +1175,20 @@ class VelociousDatabaseRecord {
|
|
|
910
1175
|
return changes
|
|
911
1176
|
}
|
|
912
1177
|
|
|
1178
|
+
/**
|
|
1179
|
+
* @returns {string}
|
|
1180
|
+
*/
|
|
913
1181
|
_tableName() {
|
|
914
1182
|
if (this.__tableName) return this.__tableName
|
|
915
1183
|
|
|
916
1184
|
return this.constructor.tableName()
|
|
917
1185
|
}
|
|
918
1186
|
|
|
1187
|
+
/**
|
|
1188
|
+
* Reads an attribute value from the record.
|
|
1189
|
+
* @param {string} attributeName The name of the attribute to read. This is the attribute name, not the column name.
|
|
1190
|
+
* @returns {void}
|
|
1191
|
+
*/
|
|
919
1192
|
readAttribute(attributeName) {
|
|
920
1193
|
const columnName = this.constructor._attributeNameToColumnName[attributeName]
|
|
921
1194
|
|
|
@@ -924,6 +1197,10 @@ class VelociousDatabaseRecord {
|
|
|
924
1197
|
return this.readColumn(columnName)
|
|
925
1198
|
}
|
|
926
1199
|
|
|
1200
|
+
/**
|
|
1201
|
+
* Reads a column value from the record.
|
|
1202
|
+
* @param {string} attributeName The name of the column to read. This is the column name, not the attribute name.
|
|
1203
|
+
*/
|
|
927
1204
|
readColumn(attributeName) {
|
|
928
1205
|
const column = this.constructor.getColumns().find((column) => column.getName() == attributeName)
|
|
929
1206
|
let result
|
|
@@ -961,6 +1238,9 @@ class VelociousDatabaseRecord {
|
|
|
961
1238
|
return belongsToChanges
|
|
962
1239
|
}
|
|
963
1240
|
|
|
1241
|
+
/**
|
|
1242
|
+
* @returns {void}
|
|
1243
|
+
*/
|
|
964
1244
|
async _createNewRecord() {
|
|
965
1245
|
if (!this.constructor.connection()["insertSql"]) {
|
|
966
1246
|
throw new Error(`No insertSql on ${this.constructor.connection().constructor.name}`)
|
|
@@ -1006,6 +1286,9 @@ class VelociousDatabaseRecord {
|
|
|
1006
1286
|
}
|
|
1007
1287
|
}
|
|
1008
1288
|
|
|
1289
|
+
/**
|
|
1290
|
+
* @returns {void}
|
|
1291
|
+
*/
|
|
1009
1292
|
async _updateRecordWithChanges() {
|
|
1010
1293
|
const conditions = {}
|
|
1011
1294
|
|
|
@@ -1028,6 +1311,9 @@ class VelociousDatabaseRecord {
|
|
|
1028
1311
|
}
|
|
1029
1312
|
}
|
|
1030
1313
|
|
|
1314
|
+
/**
|
|
1315
|
+
* @returns {number|string}
|
|
1316
|
+
*/
|
|
1031
1317
|
id() {
|
|
1032
1318
|
if (!this.constructor._columnNameToAttributeName) {
|
|
1033
1319
|
throw new Error(`Column names mapping hasn't been set on ${this.constructor.name}. Has the model been initialized?`)
|
|
@@ -1043,9 +1329,20 @@ class VelociousDatabaseRecord {
|
|
|
1043
1329
|
return this.readAttribute(attributeName)
|
|
1044
1330
|
}
|
|
1045
1331
|
|
|
1332
|
+
/**
|
|
1333
|
+
* @returns {boolean}
|
|
1334
|
+
*/
|
|
1046
1335
|
isPersisted() { return !this._isNewRecord }
|
|
1336
|
+
|
|
1337
|
+
/**
|
|
1338
|
+
* @returns {boolean}
|
|
1339
|
+
*/
|
|
1047
1340
|
isNewRecord() { return this._isNewRecord }
|
|
1048
1341
|
|
|
1342
|
+
/**
|
|
1343
|
+
* @param {boolean} newIsNewRecord
|
|
1344
|
+
* @returns {void}
|
|
1345
|
+
*/
|
|
1049
1346
|
setIsNewRecord(newIsNewRecord) {
|
|
1050
1347
|
this._isNewRecord = newIsNewRecord
|
|
1051
1348
|
}
|
|
@@ -1065,6 +1362,9 @@ class VelociousDatabaseRecord {
|
|
|
1065
1362
|
this._changes = {}
|
|
1066
1363
|
}
|
|
1067
1364
|
|
|
1365
|
+
/**
|
|
1366
|
+
* @returns {void}
|
|
1367
|
+
*/
|
|
1068
1368
|
async reload() {
|
|
1069
1369
|
this._reloadWithId(this.readAttribute("id"))
|
|
1070
1370
|
}
|
|
@@ -1094,6 +1394,9 @@ class VelociousDatabaseRecord {
|
|
|
1094
1394
|
}
|
|
1095
1395
|
}
|
|
1096
1396
|
|
|
1397
|
+
/**
|
|
1398
|
+
* @returns {Array<string>}
|
|
1399
|
+
*/
|
|
1097
1400
|
fullErrorMessages() {
|
|
1098
1401
|
const validationErrorMessages = []
|
|
1099
1402
|
|
|
@@ -1110,6 +1413,10 @@ class VelociousDatabaseRecord {
|
|
|
1110
1413
|
return validationErrorMessages
|
|
1111
1414
|
}
|
|
1112
1415
|
|
|
1416
|
+
/**
|
|
1417
|
+
* Assigns the attributes to the record and saves it.
|
|
1418
|
+
* @param {object} attributesToAssign - The attributes to assign to the record.
|
|
1419
|
+
*/
|
|
1113
1420
|
async update(attributesToAssign) {
|
|
1114
1421
|
if (attributesToAssign) this.assign(attributesToAssign)
|
|
1115
1422
|
|