velocious 1.0.447 → 1.0.449
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/build/configuration-types.js +2 -0
- package/build/database/pool/async-tracked-multi-connection.js +123 -8
- package/build/database/pool/base.js +14 -1
- package/build/database/record/index.js +13 -8
- package/build/environment-handlers/node/cli/commands/generate/base-models.js +1 -16
- package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +125 -73
- package/build/frontend-model-controller.js +9 -0
- package/build/frontend-model-resource/base-resource.js +266 -53
- package/build/frontend-models/base.js +241 -97
- package/build/frontend-models/preloader.js +3 -2
- package/build/src/background-jobs/job-record.d.ts +2 -1
- package/build/src/background-jobs/job-record.d.ts.map +1 -1
- package/build/src/configuration-types.d.ts +10 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +3 -1
- package/build/src/database/pool/async-tracked-multi-connection.d.ts +60 -4
- package/build/src/database/pool/async-tracked-multi-connection.d.ts.map +1 -1
- package/build/src/database/pool/async-tracked-multi-connection.js +113 -9
- package/build/src/database/pool/base.d.ts +38 -1
- package/build/src/database/pool/base.d.ts.map +1 -1
- package/build/src/database/pool/base.js +14 -2
- package/build/src/database/query/preloader/belongs-to.d.ts +2 -2
- package/build/src/database/query/preloader/belongs-to.d.ts.map +1 -1
- package/build/src/database/query/preloader/has-many.d.ts +1 -1
- package/build/src/database/query/preloader/has-many.d.ts.map +1 -1
- package/build/src/database/query/preloader/has-one.d.ts +2 -2
- package/build/src/database/query/preloader/has-one.d.ts.map +1 -1
- package/build/src/database/query/preloader.d.ts +1 -1
- package/build/src/database/query/preloader.d.ts.map +1 -1
- package/build/src/database/record/attachments/handle.d.ts +1 -1
- package/build/src/database/record/attachments/handle.d.ts.map +1 -1
- package/build/src/database/record/index.d.ts +23 -13
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +14 -9
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +2 -15
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +89 -32
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +123 -72
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +8 -1
- package/build/src/frontend-model-resource/base-resource.d.ts +203 -64
- package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
- package/build/src/frontend-model-resource/base-resource.js +237 -54
- package/build/src/frontend-models/base.d.ts +173 -110
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +218 -102
- package/build/src/frontend-models/preloader.d.ts.map +1 -1
- package/build/src/frontend-models/preloader.js +4 -3
- package/build/src/testing/browser-frontend-model-event-hook-scenarios.js +2 -2
- package/build/src/testing/expect.d.ts +6 -0
- package/build/src/testing/expect.d.ts.map +1 -1
- package/build/src/testing/expect.js +9 -1
- package/build/testing/browser-frontend-model-event-hook-scenarios.js +1 -1
- package/build/testing/expect.js +9 -0
- package/package.json +1 -1
- package/src/configuration-types.js +2 -0
- package/src/database/pool/async-tracked-multi-connection.js +123 -8
- package/src/database/pool/base.js +14 -1
- package/src/database/record/index.js +13 -8
- package/src/environment-handlers/node/cli/commands/generate/base-models.js +1 -16
- package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +125 -73
- package/src/frontend-model-controller.js +9 -0
- package/src/frontend-model-resource/base-resource.js +266 -53
- package/src/frontend-models/base.js +241 -97
- package/src/frontend-models/preloader.js +3 -2
- package/src/testing/browser-frontend-model-event-hook-scenarios.js +1 -1
- package/src/testing/expect.js +9 -0
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* EJS-backed mailers with delivery, queueing, and payload rendering support (see [docs/mailers.md](docs/mailers.md))
|
|
23
23
|
* Trusted reverse proxy handling for `request.remoteAddress()` (see [docs/trusted-proxies.md](docs/trusted-proxies.md))
|
|
24
24
|
* In-process driver schema metadata caching (see [docs/schema-metadata-cache.md](docs/schema-metadata-cache.md))
|
|
25
|
-
* Named database connection checkouts
|
|
25
|
+
* Named database connection checkouts, bounded pool waits, and debugging held connections (see [docs/database-connections.md](docs/database-connections.md))
|
|
26
26
|
* Optional built-in debug endpoint for inspecting server and database connection state (see [docs/debug-endpoint.md](docs/debug-endpoint.md))
|
|
27
27
|
|
|
28
28
|
# Setup
|
|
@@ -47,12 +47,14 @@
|
|
|
47
47
|
* @property {number | null} [pool.max] - Maximum number of connections. Set null to disable the cap.
|
|
48
48
|
* @property {number} [pool.min] - Minimum number of connections.
|
|
49
49
|
* @property {number} [pool.idleTimeoutMillis] - Idle timeout before releasing a connection.
|
|
50
|
+
* @property {number | null} [pool.checkoutTimeoutMillis] - Timeout while waiting for an available connection after the max connection cap is reached. Set null to wait indefinitely.
|
|
50
51
|
* @property {string} [server] - SQL server hostname.
|
|
51
52
|
* @property {string} [user] - SQL username.
|
|
52
53
|
*/
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
56
|
* @typedef {object} DatabasePoolConfiguration
|
|
57
|
+
* @property {number | null} [checkoutTimeoutMillis] - Timeout while a checkout waits for an available async-tracked connection after the max live connection cap is reached. Set null to wait indefinitely. Default: 10000.
|
|
56
58
|
* @property {number | null} [idleTimeoutMillis] - Idle timeout before closing a checked-in async-tracked connection. Set null to disable idle reaping. Default: 5000.
|
|
57
59
|
* @property {number | null} [max] - Maximum live async-tracked connections for this pool. Defaults to 10. Extra checkouts wait until a matching connection is checked in or capacity is freed. Set null to disable the cap.
|
|
58
60
|
*/
|
|
@@ -8,6 +8,7 @@ const IDLE_CONNECTION_CHECKED_IN_AT = Symbol("velociousIdleConnectionCheckedInAt
|
|
|
8
8
|
const CONNECTION_CHECKED_OUT_AT = Symbol("velociousConnectionCheckedOutAt")
|
|
9
9
|
const DEFAULT_MAX_CONNECTIONS = 10
|
|
10
10
|
const DEFAULT_IDLE_TIMEOUT_MILLIS = 5000
|
|
11
|
+
const DEFAULT_CHECKOUT_TIMEOUT_MILLIS = 10000
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* PendingCheckout type.
|
|
@@ -18,6 +19,9 @@ const DEFAULT_IDLE_TIMEOUT_MILLIS = 5000
|
|
|
18
19
|
* @property {string} reuseKey - Database configuration reuse key needed by the checkout.
|
|
19
20
|
* @property {(connection: import("../drivers/base.js").default) => void} resolve - Resolves with an activated connection.
|
|
20
21
|
* @property {(error: Error) => void} reject - Rejects when checkout cannot complete.
|
|
22
|
+
* @property {number | null} timeoutAt - Timestamp when the checkout will time out, or null when disabled.
|
|
23
|
+
* @property {number | null} timeoutMillis - Milliseconds to wait before rejecting, or null when disabled.
|
|
24
|
+
* @property {ReturnType<typeof setTimeout> | undefined} timeoutTimer - Timer that rejects the pending checkout.
|
|
21
25
|
*/
|
|
22
26
|
|
|
23
27
|
export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends BasePool {
|
|
@@ -281,17 +285,39 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
|
|
|
281
285
|
|
|
282
286
|
/**
|
|
283
287
|
* Runs max connections.
|
|
284
|
-
* @returns {number |
|
|
288
|
+
* @returns {number | null} - Configured max live connections.
|
|
285
289
|
*/
|
|
286
290
|
maxConnections() {
|
|
287
291
|
const value = this.getConfiguration().pool?.max
|
|
288
292
|
|
|
289
|
-
if (value === null) return
|
|
293
|
+
if (value === null) return null
|
|
290
294
|
if (this.validMaxConnections(value)) return value
|
|
291
295
|
|
|
292
296
|
return DEFAULT_MAX_CONNECTIONS
|
|
293
297
|
}
|
|
294
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Runs checkout timeout millis.
|
|
301
|
+
* @returns {number | null} - Pending checkout timeout in milliseconds, or null when disabled.
|
|
302
|
+
*/
|
|
303
|
+
checkoutTimeoutMillis() {
|
|
304
|
+
const value = this.getConfiguration().pool?.checkoutTimeoutMillis
|
|
305
|
+
|
|
306
|
+
if (value === null) return null
|
|
307
|
+
if (this.validCheckoutTimeoutMillis(value)) return value
|
|
308
|
+
|
|
309
|
+
return DEFAULT_CHECKOUT_TIMEOUT_MILLIS
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Runs valid checkout timeout millis.
|
|
314
|
+
* @param {?} value - Candidate checkout timeout.
|
|
315
|
+
* @returns {value is number} - Whether the value is a valid timeout.
|
|
316
|
+
*/
|
|
317
|
+
validCheckoutTimeoutMillis(value) {
|
|
318
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0
|
|
319
|
+
}
|
|
320
|
+
|
|
295
321
|
/**
|
|
296
322
|
* Runs valid max connections.
|
|
297
323
|
* @param {?} value - Candidate max connection count.
|
|
@@ -322,7 +348,7 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
|
|
|
322
348
|
canSpawnConnection() {
|
|
323
349
|
const maxConnections = this.maxConnections()
|
|
324
350
|
|
|
325
|
-
return maxConnections ===
|
|
351
|
+
return maxConnections === null || this.liveConnectionCount() < maxConnections
|
|
326
352
|
}
|
|
327
353
|
|
|
328
354
|
/**
|
|
@@ -361,7 +387,23 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
|
|
|
361
387
|
*/
|
|
362
388
|
async waitForCheckout(databaseConfig, reuseKey, options = {}) {
|
|
363
389
|
return await new Promise((resolve, reject) => {
|
|
364
|
-
|
|
390
|
+
const enqueuedAt = Date.now()
|
|
391
|
+
const timeoutMillis = this.checkoutTimeoutMillis()
|
|
392
|
+
/** @type {PendingCheckout} */
|
|
393
|
+
const checkout = {
|
|
394
|
+
databaseConfig,
|
|
395
|
+
enqueuedAt,
|
|
396
|
+
options,
|
|
397
|
+
reject,
|
|
398
|
+
resolve,
|
|
399
|
+
reuseKey,
|
|
400
|
+
timeoutAt: timeoutMillis === null ? null : enqueuedAt + timeoutMillis,
|
|
401
|
+
timeoutMillis,
|
|
402
|
+
timeoutTimer: undefined
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
checkout.timeoutTimer = this.startPendingCheckoutTimeout(checkout)
|
|
406
|
+
this.pendingCheckouts.push(checkout)
|
|
365
407
|
void this.drainPendingCheckouts().catch((error) => {
|
|
366
408
|
const checkoutError = error instanceof Error ? error : new Error("Failed to drain pending database connection checkouts.", {cause: error})
|
|
367
409
|
|
|
@@ -400,17 +442,19 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
|
|
|
400
442
|
const checkout = this.pendingCheckouts[0]
|
|
401
443
|
|
|
402
444
|
if (await this.closeIdleConnectionForPendingCheckoutCapacity(checkout)) continue
|
|
445
|
+
if (!this.pendingCheckouts.includes(checkout)) continue
|
|
403
446
|
if (this.canSpawnConnection()) {
|
|
404
|
-
this.
|
|
447
|
+
this.removePendingCheckoutAt(0)
|
|
405
448
|
await this.spawnAndResolvePendingCheckout(checkout)
|
|
406
449
|
continue
|
|
407
450
|
}
|
|
408
451
|
|
|
409
452
|
const reapedConnection = await this.idleConnectionForPendingCheckout(checkout)
|
|
410
453
|
|
|
454
|
+
if (!this.pendingCheckouts.includes(checkout)) continue
|
|
411
455
|
if (!reapedConnection) return
|
|
412
456
|
|
|
413
|
-
this.
|
|
457
|
+
this.removePendingCheckoutAt(0)
|
|
414
458
|
await this.resolvePendingCheckout(checkout, reapedConnection)
|
|
415
459
|
}
|
|
416
460
|
}
|
|
@@ -426,7 +470,7 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
|
|
|
426
470
|
|
|
427
471
|
if (!connection) continue
|
|
428
472
|
|
|
429
|
-
this.
|
|
473
|
+
this.removePendingCheckoutAt(index)
|
|
430
474
|
await this.resolvePendingCheckout(checkout, connection)
|
|
431
475
|
|
|
432
476
|
return true
|
|
@@ -435,6 +479,71 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
|
|
|
435
479
|
return false
|
|
436
480
|
}
|
|
437
481
|
|
|
482
|
+
/**
|
|
483
|
+
* Runs remove pending checkout at.
|
|
484
|
+
* @param {number} index - Pending checkout index.
|
|
485
|
+
* @returns {PendingCheckout} - Removed checkout.
|
|
486
|
+
*/
|
|
487
|
+
removePendingCheckoutAt(index) {
|
|
488
|
+
const checkout = this.pendingCheckouts.splice(index, 1)[0]
|
|
489
|
+
|
|
490
|
+
this.clearPendingCheckoutTimeout(checkout)
|
|
491
|
+
|
|
492
|
+
return checkout
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Runs start pending checkout timeout.
|
|
497
|
+
* @param {PendingCheckout} checkout - Pending checkout to time out.
|
|
498
|
+
* @returns {ReturnType<typeof setTimeout> | undefined} - Timer, if timeout is enabled.
|
|
499
|
+
*/
|
|
500
|
+
startPendingCheckoutTimeout(checkout) {
|
|
501
|
+
if (checkout.timeoutMillis === null) return undefined
|
|
502
|
+
|
|
503
|
+
const timer = setTimeout(() => {
|
|
504
|
+
this.timeoutPendingCheckout(checkout)
|
|
505
|
+
}, checkout.timeoutMillis)
|
|
506
|
+
|
|
507
|
+
return timer
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Runs timeout pending checkout.
|
|
512
|
+
* @param {PendingCheckout} checkout - Pending checkout to reject.
|
|
513
|
+
* @returns {void}
|
|
514
|
+
*/
|
|
515
|
+
timeoutPendingCheckout(checkout) {
|
|
516
|
+
const index = this.pendingCheckouts.indexOf(checkout)
|
|
517
|
+
|
|
518
|
+
if (index === -1) return
|
|
519
|
+
|
|
520
|
+
this.removePendingCheckoutAt(index)
|
|
521
|
+
checkout.reject(this.pendingCheckoutTimeoutError(checkout))
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Runs pending checkout timeout error.
|
|
526
|
+
* @param {PendingCheckout} checkout - Timed-out checkout.
|
|
527
|
+
* @returns {Error} - Timeout error.
|
|
528
|
+
*/
|
|
529
|
+
pendingCheckoutTimeoutError(checkout) {
|
|
530
|
+
const checkoutName = checkout.options.name ? ` Checkout name: ${JSON.stringify(checkout.options.name)}.` : ""
|
|
531
|
+
|
|
532
|
+
return new Error(`Timed out after ${checkout.timeoutMillis}ms waiting for database connection checkout from pool "${this.identifier}".${checkoutName}`)
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Runs clear pending checkout timeout.
|
|
537
|
+
* @param {PendingCheckout} checkout - Pending checkout.
|
|
538
|
+
* @returns {void}
|
|
539
|
+
*/
|
|
540
|
+
clearPendingCheckoutTimeout(checkout) {
|
|
541
|
+
if (!checkout.timeoutTimer) return
|
|
542
|
+
|
|
543
|
+
clearTimeout(checkout.timeoutTimer)
|
|
544
|
+
checkout.timeoutTimer = undefined
|
|
545
|
+
}
|
|
546
|
+
|
|
438
547
|
/**
|
|
439
548
|
* Runs close idle connection for pending checkout capacity.
|
|
440
549
|
* @param {PendingCheckout} checkout - Checkout waiting for a connection.
|
|
@@ -472,6 +581,8 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
|
|
|
472
581
|
if (connection) return connection
|
|
473
582
|
|
|
474
583
|
await this.reapIdleConnections()
|
|
584
|
+
if (!this.pendingCheckouts.includes(checkout)) return
|
|
585
|
+
|
|
475
586
|
connection = this.takeIdleConnectionForReuseKey(checkout.reuseKey, {includeOpenTransactions: false})
|
|
476
587
|
|
|
477
588
|
return connection
|
|
@@ -762,14 +873,17 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
|
|
|
762
873
|
/**
|
|
763
874
|
* Runs pending checkout debug snapshots.
|
|
764
875
|
* @param {number} now - Current timestamp.
|
|
765
|
-
* @returns {
|
|
876
|
+
* @returns {import("./base.js").DatabasePoolPendingCheckoutDebugSnapshot[]} - Pending checkout snapshots.
|
|
766
877
|
*/
|
|
767
878
|
pendingCheckoutDebugSnapshots(now) {
|
|
768
879
|
return this.pendingCheckouts.map((checkout, index) => ({
|
|
769
880
|
checkoutName: checkout.options.name,
|
|
770
881
|
enqueuedAt: checkout.enqueuedAt,
|
|
771
882
|
index,
|
|
883
|
+
remainingTimeoutMs: checkout.timeoutAt === null ? null : Math.max(0, checkout.timeoutAt - now),
|
|
772
884
|
reuseKey: checkout.reuseKey,
|
|
885
|
+
timeoutAt: checkout.timeoutAt,
|
|
886
|
+
timeoutMillis: checkout.timeoutMillis,
|
|
773
887
|
waitingForMs: Math.max(0, now - checkout.enqueuedAt)
|
|
774
888
|
}))
|
|
775
889
|
}
|
|
@@ -1131,6 +1245,7 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
|
|
|
1131
1245
|
this.pendingCheckouts = []
|
|
1132
1246
|
|
|
1133
1247
|
for (const checkout of pendingCheckouts) {
|
|
1248
|
+
this.clearPendingCheckoutTimeout(checkout)
|
|
1134
1249
|
checkout.reject(error)
|
|
1135
1250
|
}
|
|
1136
1251
|
}
|
|
@@ -12,6 +12,19 @@ export const POOL_CONFIGURATION_KEY = Symbol("velociousPoolConfigurationKey")
|
|
|
12
12
|
* @property {string} [name] - Human-readable name for the checked-out connection.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* DatabasePoolPendingCheckoutDebugSnapshot type.
|
|
17
|
+
* @typedef {object} DatabasePoolPendingCheckoutDebugSnapshot
|
|
18
|
+
* @property {string | undefined} checkoutName - Human-readable checkout name.
|
|
19
|
+
* @property {number} enqueuedAt - Timestamp when the checkout started waiting.
|
|
20
|
+
* @property {number} index - Pending checkout queue index.
|
|
21
|
+
* @property {number | null} remainingTimeoutMs - Milliseconds before the checkout times out, or null when disabled.
|
|
22
|
+
* @property {string} reuseKey - Database configuration reuse key needed by the checkout.
|
|
23
|
+
* @property {number | null} timeoutAt - Timestamp when the checkout will time out, or null when disabled.
|
|
24
|
+
* @property {number | null} timeoutMillis - Timeout configured for the checkout, or null when disabled.
|
|
25
|
+
* @property {number} waitingForMs - Milliseconds already spent waiting.
|
|
26
|
+
*/
|
|
27
|
+
|
|
15
28
|
/**
|
|
16
29
|
* DatabasePoolDebugSnapshot type.
|
|
17
30
|
* @typedef {object} DatabasePoolDebugSnapshot
|
|
@@ -21,7 +34,7 @@ export const POOL_CONFIGURATION_KEY = Symbol("velociousPoolConfigurationKey")
|
|
|
21
34
|
* @property {number} idleCount - Number of idle connections.
|
|
22
35
|
* @property {string} identifier - Database identifier.
|
|
23
36
|
* @property {number} inUseCount - Number of checked-out connections.
|
|
24
|
-
* @property {Array<
|
|
37
|
+
* @property {Array<DatabasePoolPendingCheckoutDebugSnapshot>} [pendingCheckouts] - Waiting checkout snapshots.
|
|
25
38
|
* @property {number} pendingCheckoutCount - Number of queued checkout requests.
|
|
26
39
|
* @property {string} poolClass - Pool class name.
|
|
27
40
|
*/
|
|
@@ -222,6 +222,10 @@ class TenantDatabaseScopeError extends Error {
|
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Base database record.
|
|
227
|
+
* @template {Record<string, ?>} [WriteAttributes=Record<string, ?>]
|
|
228
|
+
*/
|
|
225
229
|
class VelociousDatabaseRecord {
|
|
226
230
|
/**
|
|
227
231
|
* Narrows the runtime value to the documented type.
|
|
@@ -1150,17 +1154,18 @@ class VelociousDatabaseRecord {
|
|
|
1150
1154
|
|
|
1151
1155
|
/**
|
|
1152
1156
|
* Runs create.
|
|
1153
|
-
* @template {
|
|
1154
|
-
* @
|
|
1155
|
-
* @
|
|
1156
|
-
* @
|
|
1157
|
+
* @template {Record<string, ?>} CreateAttributes
|
|
1158
|
+
* @template {VelociousDatabaseRecord<CreateAttributes>} Model
|
|
1159
|
+
* @this {{new (changes?: CreateAttributes): Model} & typeof VelociousDatabaseRecord}
|
|
1160
|
+
* @param {CreateAttributes} [attributes] - Attributes.
|
|
1161
|
+
* @returns {Promise<Model>} - Resolves with the create.
|
|
1157
1162
|
*/
|
|
1158
1163
|
static async create(attributes) {
|
|
1159
1164
|
await this.ensureInitialized()
|
|
1160
1165
|
|
|
1161
1166
|
const record = /**
|
|
1162
1167
|
* Narrows the runtime value to the documented type.
|
|
1163
|
-
@type {
|
|
1168
|
+
@type {Model} */ (new this(attributes))
|
|
1164
1169
|
|
|
1165
1170
|
await record.save()
|
|
1166
1171
|
|
|
@@ -3353,9 +3358,9 @@ class VelociousDatabaseRecord {
|
|
|
3353
3358
|
|
|
3354
3359
|
/**
|
|
3355
3360
|
* Runs constructor.
|
|
3356
|
-
* @param {
|
|
3361
|
+
* @param {WriteAttributes} changes - Changes.
|
|
3357
3362
|
*/
|
|
3358
|
-
constructor(changes = {}) {
|
|
3363
|
+
constructor(changes = /** @type {WriteAttributes} */ ({})) {
|
|
3359
3364
|
this.getModelClass()._assertHasBeenInitialized()
|
|
3360
3365
|
this._attributes = {}
|
|
3361
3366
|
this._changes = {}
|
|
@@ -4256,7 +4261,7 @@ class VelociousDatabaseRecord {
|
|
|
4256
4261
|
|
|
4257
4262
|
/**
|
|
4258
4263
|
* Assigns the attributes to the record and saves it.
|
|
4259
|
-
* @param {
|
|
4264
|
+
* @param {WriteAttributes} attributesToAssign - The attributes to assign to the record.
|
|
4260
4265
|
*/
|
|
4261
4266
|
async update(attributesToAssign) {
|
|
4262
4267
|
if (attributesToAssign) this.assign(attributesToAssign)
|
|
@@ -139,24 +139,9 @@ export default class DbGenerateModel extends BaseCommand {
|
|
|
139
139
|
|
|
140
140
|
const hasManyRelationFilePath = `${velociousPath}/database/record/instance-relationships/has-many.js`
|
|
141
141
|
|
|
142
|
+
fileContent += `/** @augments {DatabaseRecord<${writeAttributeTypeName}>} */\n`
|
|
142
143
|
fileContent += `export default class ${modelNameCamelized}Base extends DatabaseRecord {\n`
|
|
143
144
|
|
|
144
|
-
fileContent += " /**\n"
|
|
145
|
-
fileContent += ` * Creates a ${modelNameCamelized} record.\n`
|
|
146
|
-
fileContent += ` * @template {typeof ${modelNameCamelized}Base} T\n`
|
|
147
|
-
fileContent += " * @this {T}\n"
|
|
148
|
-
fileContent += ` * @param {${writeAttributeTypeName}} [attributes] - Attributes for the new record.\n`
|
|
149
|
-
fileContent += " * @returns {Promise<InstanceType<T>>} - Persisted record.\n"
|
|
150
|
-
fileContent += " */\n"
|
|
151
|
-
fileContent += " static async create(attributes) { return /** @type {Promise<InstanceType<T>>} */ (super.create(attributes)) }\n\n"
|
|
152
|
-
|
|
153
|
-
fileContent += " /**\n"
|
|
154
|
-
fileContent += ` * Updates this ${modelNameCamelized} record.\n`
|
|
155
|
-
fileContent += ` * @param {${writeAttributeTypeName}} attributes - Attributes to assign before saving.\n`
|
|
156
|
-
fileContent += " * @returns {Promise<void>} - Resolves when the record is saved.\n"
|
|
157
|
-
fileContent += " */\n"
|
|
158
|
-
fileContent += " async update(attributes) { return await super.update(attributes) }\n\n"
|
|
159
|
-
|
|
160
145
|
// --- getModelClass() override (fixes polymorphic typing in JS/JSDoc) ---
|
|
161
146
|
if (await fileExists(sourceModelFullFilePath)) {
|
|
162
147
|
// Model file exists (e.g. src/models/ticket.js) → return typeof Ticket
|