velocious 1.0.643 → 1.0.645
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 +21 -10
- package/build/authorization/ability.js +36 -13
- package/build/background-jobs/adapter.js +9 -0
- package/build/background-jobs/main.js +35 -10
- package/build/background-jobs/store.js +217 -38
- package/build/background-jobs/types.js +15 -0
- package/build/configuration-types.js +1 -1
- package/build/configuration.js +45 -9
- package/build/database/drivers/base-column.js +8 -0
- package/build/database/drivers/mssql/sql/update.js +1 -3
- package/build/database/drivers/mysql/sql/update.js +1 -3
- package/build/database/drivers/pgsql/column.js +22 -0
- package/build/database/drivers/pgsql/sql/update.js +1 -3
- package/build/database/drivers/sqlite/sql/alter-table.js +11 -1
- package/build/database/drivers/sqlite/sql/update.js +1 -3
- package/build/database/query/index.js +2 -2
- package/build/database/query/model-class-query.js +26 -10
- package/build/database/query/preloader/has-many.js +4 -1
- package/build/database/query/query-data.js +2 -1
- package/build/database/query/update-base.js +14 -0
- package/build/database/query/with-count.js +3 -1
- package/build/database/record/acts-as-list.js +37 -13
- package/build/database/record/attachments/store.js +336 -26
- package/build/database/record/auditing.js +6 -3
- package/build/database/record/index.js +197 -42
- package/build/database/record/instance-relationships/belongs-to.js +2 -1
- package/build/database/record/validators/uniqueness.js +8 -5
- package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +24 -8
- package/build/frontend-model-controller.js +136 -53
- package/build/frontend-model-resource/base-resource.js +87 -37
- package/build/frontend-model-resource/velocious-attachment-resource.js +98 -31
- package/build/frontend-models/base.js +307 -59
- package/build/frontend-models/preloader.js +6 -3
- package/build/frontend-models/query.js +15 -6
- package/build/frontend-models/resource-definition.js +21 -2
- package/build/frontend-models/use-destroyed-event.js +1 -1
- package/build/frontend-models/use-model-class-event.js +2 -2
- package/build/frontend-models/use-updated-event.js +1 -1
- package/build/frontend-models/websocket-channel.js +256 -93
- package/build/frontend-models/websocket-publishers.js +218 -18
- package/build/http-server/client/websocket-session.js +13 -1
- package/build/http-server/websocket-channel.js +15 -2
- package/build/src/authorization/ability.d.ts +9 -3
- package/build/src/authorization/ability.d.ts.map +1 -1
- package/build/src/authorization/ability.js +33 -14
- package/build/src/background-jobs/adapter.d.ts +6 -0
- package/build/src/background-jobs/adapter.d.ts.map +1 -1
- package/build/src/background-jobs/adapter.js +9 -1
- package/build/src/background-jobs/main.d.ts +6 -0
- package/build/src/background-jobs/main.d.ts.map +1 -1
- package/build/src/background-jobs/main.js +34 -11
- package/build/src/background-jobs/store.d.ts +66 -12
- package/build/src/background-jobs/store.d.ts.map +1 -1
- package/build/src/background-jobs/store.js +191 -35
- package/build/src/background-jobs/types.d.ts +55 -0
- package/build/src/background-jobs/types.d.ts.map +1 -1
- package/build/src/background-jobs/types.js +16 -1
- package/build/src/configuration-types.d.ts +3 -3
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +2 -2
- package/build/src/configuration.d.ts +18 -8
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +38 -7
- package/build/src/database/drivers/base-column.d.ts +5 -0
- package/build/src/database/drivers/base-column.d.ts.map +1 -1
- package/build/src/database/drivers/base-column.js +8 -1
- package/build/src/database/drivers/mssql/sql/update.d.ts.map +1 -1
- package/build/src/database/drivers/mssql/sql/update.js +2 -4
- package/build/src/database/drivers/mysql/sql/update.d.ts.map +1 -1
- package/build/src/database/drivers/mysql/sql/update.js +2 -4
- package/build/src/database/drivers/pgsql/column.d.ts +5 -0
- package/build/src/database/drivers/pgsql/column.d.ts.map +1 -1
- package/build/src/database/drivers/pgsql/column.js +19 -1
- package/build/src/database/drivers/pgsql/sql/update.d.ts.map +1 -1
- package/build/src/database/drivers/pgsql/sql/update.js +2 -4
- package/build/src/database/drivers/sqlite/sql/alter-table.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/sql/alter-table.js +6 -2
- package/build/src/database/drivers/sqlite/sql/update.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/sql/update.js +2 -4
- package/build/src/database/query/index.d.ts +4 -4
- package/build/src/database/query/index.d.ts.map +1 -1
- package/build/src/database/query/index.js +3 -3
- package/build/src/database/query/model-class-query.d.ts +8 -2
- package/build/src/database/query/model-class-query.d.ts.map +1 -1
- package/build/src/database/query/model-class-query.js +25 -11
- package/build/src/database/query/preloader/has-many.d.ts.map +1 -1
- package/build/src/database/query/preloader/has-many.js +4 -2
- package/build/src/database/query/query-data.d.ts.map +1 -1
- package/build/src/database/query/query-data.js +3 -2
- package/build/src/database/query/update-base.d.ts +7 -0
- package/build/src/database/query/update-base.d.ts.map +1 -1
- package/build/src/database/query/update-base.js +13 -1
- package/build/src/database/query/with-count.d.ts.map +1 -1
- package/build/src/database/query/with-count.js +3 -2
- package/build/src/database/record/acts-as-list.d.ts.map +1 -1
- package/build/src/database/record/acts-as-list.js +35 -14
- package/build/src/database/record/attachments/store.d.ts +67 -0
- package/build/src/database/record/attachments/store.d.ts.map +1 -1
- package/build/src/database/record/attachments/store.js +301 -25
- package/build/src/database/record/auditing.d.ts.map +1 -1
- package/build/src/database/record/auditing.js +7 -4
- package/build/src/database/record/index.d.ts +78 -26
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +171 -42
- package/build/src/database/record/instance-relationships/belongs-to.d.ts.map +1 -1
- package/build/src/database/record/instance-relationships/belongs-to.js +3 -2
- package/build/src/database/record/validators/uniqueness.d.ts.map +1 -1
- package/build/src/database/record/validators/uniqueness.js +8 -6
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +4 -4
- 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 +24 -12
- package/build/src/frontend-model-controller.d.ts +29 -8
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +122 -51
- package/build/src/frontend-model-resource/base-resource.d.ts +51 -24
- package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
- package/build/src/frontend-model-resource/base-resource.js +83 -37
- package/build/src/frontend-model-resource/velocious-attachment-resource.d.ts +45 -26
- package/build/src/frontend-model-resource/velocious-attachment-resource.d.ts.map +1 -1
- package/build/src/frontend-model-resource/velocious-attachment-resource.js +89 -31
- package/build/src/frontend-models/base.d.ts +53 -20
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +275 -59
- package/build/src/frontend-models/preloader.d.ts.map +1 -1
- package/build/src/frontend-models/preloader.js +6 -4
- package/build/src/frontend-models/query.d.ts +2 -2
- package/build/src/frontend-models/query.d.ts.map +1 -1
- package/build/src/frontend-models/query.js +14 -7
- package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
- package/build/src/frontend-models/resource-definition.js +20 -3
- package/build/src/frontend-models/use-destroyed-event.d.ts +1 -1
- package/build/src/frontend-models/use-destroyed-event.d.ts.map +1 -1
- package/build/src/frontend-models/use-destroyed-event.js +2 -2
- package/build/src/frontend-models/use-model-class-event.d.ts +2 -2
- package/build/src/frontend-models/use-model-class-event.d.ts.map +1 -1
- package/build/src/frontend-models/use-model-class-event.js +3 -3
- package/build/src/frontend-models/use-updated-event.d.ts +1 -1
- package/build/src/frontend-models/use-updated-event.d.ts.map +1 -1
- package/build/src/frontend-models/use-updated-event.js +2 -2
- package/build/src/frontend-models/websocket-channel.d.ts +60 -41
- package/build/src/frontend-models/websocket-channel.d.ts.map +1 -1
- package/build/src/frontend-models/websocket-channel.js +225 -85
- package/build/src/frontend-models/websocket-publishers.d.ts +9 -0
- package/build/src/frontend-models/websocket-publishers.d.ts.map +1 -1
- package/build/src/frontend-models/websocket-publishers.js +190 -19
- package/build/src/http-server/client/websocket-session.d.ts.map +1 -1
- package/build/src/http-server/client/websocket-session.js +11 -2
- package/build/src/http-server/websocket-channel.d.ts +20 -8
- package/build/src/http-server/websocket-channel.d.ts.map +1 -1
- package/build/src/http-server/websocket-channel.js +15 -3
- package/build/src/sync/assets/cache.d.ts +288 -0
- package/build/src/sync/assets/cache.d.ts.map +1 -0
- package/build/src/sync/assets/cache.js +883 -0
- package/build/src/sync/assets/types.d.ts +199 -0
- package/build/src/sync/assets/types.d.ts.map +1 -0
- package/build/src/sync/assets/types.js +56 -0
- package/build/src/sync/sync-api-client.d.ts.map +1 -1
- package/build/src/sync/sync-api-client.js +4 -3
- package/build/src/sync/sync-client.d.ts.map +1 -1
- package/build/src/sync/sync-client.js +3 -2
- package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
- package/build/src/sync/sync-envelope-replay-service.js +6 -5
- package/build/src/sync/sync-publisher.d.ts.map +1 -1
- package/build/src/sync/sync-publisher.js +4 -3
- package/build/src/testing/browser-frontend-model-event-hook-scenarios.d.ts +2 -2
- package/build/src/testing/browser-frontend-model-event-hook-scenarios.d.ts.map +1 -1
- package/build/src/testing/browser-frontend-model-event-hook-scenarios.js +3 -3
- package/build/src/testing/test-profiler.d.ts +4 -4
- package/build/src/testing/test-profiler.d.ts.map +1 -1
- package/build/src/testing/test-profiler.js +3 -3
- package/build/src/testing/test-runner.d.ts +279 -117
- package/build/src/testing/test-runner.d.ts.map +1 -1
- package/build/src/testing/test-runner.js +503 -933
- package/build/src/testing/test.d.ts +11 -72
- package/build/src/testing/test.d.ts.map +1 -1
- package/build/src/testing/test.js +131 -284
- package/build/src/testing/velocious-attempt-executor.d.ts +54 -0
- package/build/src/testing/velocious-attempt-executor.d.ts.map +1 -0
- package/build/src/testing/velocious-attempt-executor.js +408 -0
- package/build/src/testing/velocious-runner-reporter.d.ts +67 -0
- package/build/src/testing/velocious-runner-reporter.d.ts.map +1 -0
- package/build/src/testing/velocious-runner-reporter.js +240 -0
- package/build/src/testing/velocious-suite-hook-executor.d.ts +19 -0
- package/build/src/testing/velocious-suite-hook-executor.d.ts.map +1 -0
- package/build/src/testing/velocious-suite-hook-executor.js +41 -0
- package/build/src/testing/velocious-test-arguments.d.ts +39 -0
- package/build/src/testing/velocious-test-arguments.d.ts.map +1 -0
- package/build/src/testing/velocious-test-arguments.js +55 -0
- package/build/src/utils/model-primary-key.d.ts +73 -0
- package/build/src/utils/model-primary-key.d.ts.map +1 -0
- package/build/src/utils/model-primary-key.js +144 -0
- package/build/src/utils/sha256-bytes-hex.d.ts +7 -0
- package/build/src/utils/sha256-bytes-hex.d.ts.map +1 -0
- package/build/src/utils/sha256-bytes-hex.js +117 -0
- package/build/src/utils/sha256-hex.d.ts +2 -4
- package/build/src/utils/sha256-hex.d.ts.map +1 -1
- package/build/src/utils/sha256-hex.js +6 -120
- package/build/sync/assets/cache.js +998 -0
- package/build/sync/assets/types.js +62 -0
- package/build/sync/sync-api-client.js +3 -2
- package/build/sync/sync-client.js +2 -1
- package/build/sync/sync-envelope-replay-service.js +5 -4
- package/build/sync/sync-publisher.js +3 -2
- package/build/testing/browser-frontend-model-event-hook-scenarios.js +2 -2
- package/build/testing/test-profiler.js +2 -2
- package/build/testing/test-runner.js +496 -990
- package/build/testing/test.js +164 -306
- package/build/testing/velocious-attempt-executor.js +441 -0
- package/build/testing/velocious-runner-reporter.js +264 -0
- package/build/testing/velocious-suite-hook-executor.js +43 -0
- package/build/testing/velocious-test-arguments.js +64 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/utils/model-primary-key.js +171 -0
- package/build/utils/sha256-bytes-hex.js +132 -0
- package/build/utils/sha256-hex.js +7 -135
- package/package.json +5 -4
- package/src/authorization/ability.js +36 -13
- package/src/background-jobs/adapter.js +9 -0
- package/src/background-jobs/main.js +35 -10
- package/src/background-jobs/store.js +217 -38
- package/src/background-jobs/types.js +15 -0
- package/src/configuration-types.js +1 -1
- package/src/configuration.js +45 -9
- package/src/database/drivers/base-column.js +8 -0
- package/src/database/drivers/mssql/sql/update.js +1 -3
- package/src/database/drivers/mysql/sql/update.js +1 -3
- package/src/database/drivers/pgsql/column.js +22 -0
- package/src/database/drivers/pgsql/sql/update.js +1 -3
- package/src/database/drivers/sqlite/sql/alter-table.js +11 -1
- package/src/database/drivers/sqlite/sql/update.js +1 -3
- package/src/database/query/index.js +2 -2
- package/src/database/query/model-class-query.js +26 -10
- package/src/database/query/preloader/has-many.js +4 -1
- package/src/database/query/query-data.js +2 -1
- package/src/database/query/update-base.js +14 -0
- package/src/database/query/with-count.js +3 -1
- package/src/database/record/acts-as-list.js +37 -13
- package/src/database/record/attachments/store.js +336 -26
- package/src/database/record/auditing.js +6 -3
- package/src/database/record/index.js +197 -42
- package/src/database/record/instance-relationships/belongs-to.js +2 -1
- package/src/database/record/validators/uniqueness.js +8 -5
- package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +24 -8
- package/src/frontend-model-controller.js +136 -53
- package/src/frontend-model-resource/base-resource.js +87 -37
- package/src/frontend-model-resource/velocious-attachment-resource.js +98 -31
- package/src/frontend-models/base.js +307 -59
- package/src/frontend-models/preloader.js +6 -3
- package/src/frontend-models/query.js +15 -6
- package/src/frontend-models/resource-definition.js +21 -2
- package/src/frontend-models/use-destroyed-event.js +1 -1
- package/src/frontend-models/use-model-class-event.js +2 -2
- package/src/frontend-models/use-updated-event.js +1 -1
- package/src/frontend-models/websocket-channel.js +256 -93
- package/src/frontend-models/websocket-publishers.js +218 -18
- package/src/http-server/client/websocket-session.js +13 -1
- package/src/http-server/websocket-channel.js +15 -2
- package/src/sync/assets/cache.js +998 -0
- package/src/sync/assets/types.js +62 -0
- package/src/sync/sync-api-client.js +3 -2
- package/src/sync/sync-client.js +2 -1
- package/src/sync/sync-envelope-replay-service.js +5 -4
- package/src/sync/sync-publisher.js +3 -2
- package/src/testing/browser-frontend-model-event-hook-scenarios.js +2 -2
- package/src/testing/test-profiler.js +2 -2
- package/src/testing/test-runner.js +496 -990
- package/src/testing/test.js +164 -306
- package/src/testing/velocious-attempt-executor.js +441 -0
- package/src/testing/velocious-runner-reporter.js +264 -0
- package/src/testing/velocious-suite-hook-executor.js +43 -0
- package/src/testing/velocious-test-arguments.js +64 -0
- package/src/utils/model-primary-key.js +171 -0
- package/src/utils/sha256-bytes-hex.js +132 -0
- package/src/utils/sha256-hex.js +7 -135
- package/build/src/testing/testing-package-adapter.d.ts +0 -9
- package/build/src/testing/testing-package-adapter.d.ts.map +0 -1
- package/build/src/testing/testing-package-adapter.js +0 -69
- package/build/testing/testing-package-adapter.js +0 -76
- package/src/testing/testing-package-adapter.js +0 -76
|
@@ -41,6 +41,7 @@ import HasManyRelationship from "./relationships/has-many.js"
|
|
|
41
41
|
import HasOneInstanceRelationship from "./instance-relationships/has-one.js"
|
|
42
42
|
import HasOneRelationship from "./relationships/has-one.js"
|
|
43
43
|
import RecordAttachmentHandle from "./attachments/handle.js"
|
|
44
|
+
import {recordAttachmentsStoreForModel, recordAttachmentsStoreForModelClass} from "./attachments/store.js"
|
|
44
45
|
import * as inflection from "inflection"
|
|
45
46
|
import deburrColumnName from "../../utils/deburr-column-name.js"
|
|
46
47
|
import ModelClassQuery from "../query/model-class-query.js"
|
|
@@ -52,6 +53,7 @@ import singularizeModelName from "../../utils/singularize-model-name.js"
|
|
|
52
53
|
import {defineModelScope} from "../../utils/model-scope.js"
|
|
53
54
|
import { normalizeDateStringForWrite, normalizeDateValueForRead, normalizeDateValueForWrite } from "../datetime-storage.js"
|
|
54
55
|
import {formatValue} from "../../utils/format-value.js"
|
|
56
|
+
import {modelPrimaryKeyCacheKey, modelPrimaryKeyConditions, readModelPrimaryKeyValue, scalarModelPrimaryKey, scalarModelPrimaryKeyValue} from "../../utils/model-primary-key.js"
|
|
55
57
|
import {captureCreateAuditChanges, captureUpdateAuditChanges, createAudit, createCreateAudit, createDestroyAudit, createUpdateAudit, initializeAuditing, registerAuditCallback, registerAuditing, withoutAudit} from "./auditing.js"
|
|
56
58
|
import {registerMagnitudeCounterCache} from "./counter-cache-magnitude.js"
|
|
57
59
|
import {stateMachine} from "./state-machine.js"
|
|
@@ -519,6 +521,11 @@ class VelociousDatabaseRecord {
|
|
|
519
521
|
* @type {Record<string, ReturnType<typeof JSON.parse>>} */
|
|
520
522
|
_changes = {}
|
|
521
523
|
|
|
524
|
+
/**
|
|
525
|
+
* Whether primary-key reads are pinned to the stored attributes.
|
|
526
|
+
* @type {boolean} */
|
|
527
|
+
_readsPersistedPrimaryKey = false
|
|
528
|
+
|
|
522
529
|
/**
|
|
523
530
|
* Changes captured before a create audit is written.
|
|
524
531
|
* @type {import("./auditing.js").AuditChanges | undefined} */
|
|
@@ -2551,6 +2558,9 @@ class VelociousDatabaseRecord {
|
|
|
2551
2558
|
const primaryKey = this.primaryKey()
|
|
2552
2559
|
const tableName = this.tableName()
|
|
2553
2560
|
const connection = this.connection()
|
|
2561
|
+
|
|
2562
|
+
if (Array.isArray(primaryKey)) throw new Error(`${this.name}.nextPrimaryKey() does not support composite primary keys.`)
|
|
2563
|
+
|
|
2554
2564
|
const newestRecord = await this.order(`${connection.quoteTable(tableName)}.${connection.quoteColumn(primaryKey)}`).last()
|
|
2555
2565
|
|
|
2556
2566
|
if (newestRecord) {
|
|
@@ -2568,10 +2578,25 @@ class VelociousDatabaseRecord {
|
|
|
2568
2578
|
|
|
2569
2579
|
/**
|
|
2570
2580
|
* Runs set primary key.
|
|
2571
|
-
* @param {string} primaryKey - Primary key.
|
|
2581
|
+
* @param {string | string[] | null} primaryKey - Primary key.
|
|
2572
2582
|
* @returns {void} - No return value.
|
|
2573
2583
|
*/
|
|
2574
2584
|
static setPrimaryKey(primaryKey) {
|
|
2585
|
+
if (Array.isArray(primaryKey)) {
|
|
2586
|
+
if (primaryKey.length === 0) throw new TypeError("Composite primary keys require at least one column.")
|
|
2587
|
+
|
|
2588
|
+
const seenColumns = new Set()
|
|
2589
|
+
|
|
2590
|
+
for (const columnName of primaryKey) {
|
|
2591
|
+
if (seenColumns.has(columnName)) throw new TypeError(`Composite primary key has duplicate column: ${columnName}.`)
|
|
2592
|
+
|
|
2593
|
+
seenColumns.add(columnName)
|
|
2594
|
+
}
|
|
2595
|
+
|
|
2596
|
+
this._primaryKey = [...primaryKey]
|
|
2597
|
+
return
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2575
2600
|
this._primaryKey = primaryKey
|
|
2576
2601
|
}
|
|
2577
2602
|
|
|
@@ -2616,7 +2641,7 @@ class VelociousDatabaseRecord {
|
|
|
2616
2641
|
|
|
2617
2642
|
/**
|
|
2618
2643
|
* Runs primary key.
|
|
2619
|
-
* @returns {string} - The primary key.
|
|
2644
|
+
* @returns {string | string[]} - The primary key.
|
|
2620
2645
|
*/
|
|
2621
2646
|
static primaryKey() {
|
|
2622
2647
|
if (this._primaryKey) return this._primaryKey
|
|
@@ -2646,33 +2671,60 @@ class VelociousDatabaseRecord {
|
|
|
2646
2671
|
await this._runLifecycleCallbacks("beforeValidation")
|
|
2647
2672
|
await this._runValidations()
|
|
2648
2673
|
|
|
2674
|
+
if (this._databaseOperation && this.isPersisted() && Object.keys(this.getModelClass().getAttachments()).length > 0) {
|
|
2675
|
+
const connection = this._connection()
|
|
2676
|
+
|
|
2677
|
+
if (!connection.insideTransaction()) {
|
|
2678
|
+
await this.getModelClass()._prepareAttachmentStoreSchema(connection)
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2649
2682
|
const saveInTransaction = async () => {
|
|
2650
|
-
|
|
2683
|
+
/** @type {Record<string, ReturnType<typeof JSON.parse>> | undefined} */
|
|
2684
|
+
let persistedAttributesBeforeUpdate
|
|
2685
|
+
/** @type {Record<string, ReturnType<typeof JSON.parse>> | undefined} */
|
|
2686
|
+
let changesBeforeUpdate
|
|
2687
|
+
let updateReloaded = false
|
|
2688
|
+
|
|
2689
|
+
try {
|
|
2690
|
+
await this._runLifecycleCallbacks("beforeSave")
|
|
2651
2691
|
|
|
2652
|
-
|
|
2653
|
-
|
|
2692
|
+
// If any belongs-to-relationships was saved, then updated-at should still be set on this record.
|
|
2693
|
+
const {savedCount} = await this._autoSaveBelongsToRelationships()
|
|
2654
2694
|
|
|
2655
|
-
|
|
2656
|
-
|
|
2695
|
+
if (this.isPersisted()) {
|
|
2696
|
+
persistedAttributesBeforeUpdate = {...this._attributes}
|
|
2697
|
+
await this._runLifecycleCallbacks("beforeUpdate")
|
|
2698
|
+
changesBeforeUpdate = {...this._changes}
|
|
2657
2699
|
|
|
2658
|
-
|
|
2659
|
-
|
|
2700
|
+
// If any has-many-relationships will be saved, then updated-at should still be set on this record.
|
|
2701
|
+
const autoSaveHasManyrelationships = this._autoSaveHasManyAndHasOneRelationshipsToSave()
|
|
2702
|
+
|
|
2703
|
+
if (this._hasChanges() || savedCount > 0 || autoSaveHasManyrelationships.length > 0) {
|
|
2704
|
+
result = await this._updateRecordWithChanges()
|
|
2705
|
+
updateReloaded = true
|
|
2706
|
+
}
|
|
2660
2707
|
|
|
2661
|
-
|
|
2662
|
-
|
|
2708
|
+
await this._runLifecycleCallbacks("afterUpdate")
|
|
2709
|
+
} else {
|
|
2710
|
+
await this._runLifecycleCallbacks("beforeCreate")
|
|
2711
|
+
result = await this._createNewRecord()
|
|
2712
|
+
await this._runLifecycleCallbacks("afterCreate")
|
|
2663
2713
|
}
|
|
2664
2714
|
|
|
2665
|
-
await this.
|
|
2666
|
-
|
|
2667
|
-
await this._runLifecycleCallbacks("
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2715
|
+
await this._autoSaveHasManyAndHasOneRelationships({isNewRecord})
|
|
2716
|
+
await this._autoSaveAttachments()
|
|
2717
|
+
await this._runLifecycleCallbacks("afterSave")
|
|
2718
|
+
await this._emitRecordChangeAfterCommit(isNewRecord ? "create" : "update")
|
|
2719
|
+
} catch (error) {
|
|
2720
|
+
if (updateReloaded && persistedAttributesBeforeUpdate && changesBeforeUpdate) {
|
|
2721
|
+
this._attributes = persistedAttributesBeforeUpdate
|
|
2722
|
+
this._changes = changesBeforeUpdate
|
|
2723
|
+
this._assignedAttributeNames = undefined
|
|
2724
|
+
}
|
|
2671
2725
|
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
await this._runLifecycleCallbacks("afterSave")
|
|
2675
|
-
await this._emitRecordChangeAfterCommit(isNewRecord ? "create" : "update")
|
|
2726
|
+
throw error
|
|
2727
|
+
}
|
|
2676
2728
|
}
|
|
2677
2729
|
|
|
2678
2730
|
if (this._databaseOperation) {
|
|
@@ -2774,7 +2826,7 @@ class VelociousDatabaseRecord {
|
|
|
2774
2826
|
this.bindRelatedRecord(model)
|
|
2775
2827
|
const foreignKey = model._relationshipForeignKeyAttribute(instanceRelationship)
|
|
2776
2828
|
|
|
2777
|
-
model.setAttribute(foreignKey, this.id())
|
|
2829
|
+
model.setAttribute(foreignKey, scalarModelPrimaryKeyValue(this.id(), `Has-many autosave for ${this.getModelClass().name}`))
|
|
2778
2830
|
|
|
2779
2831
|
if (model.isChanged()) {
|
|
2780
2832
|
useRelationship = true
|
|
@@ -2828,7 +2880,7 @@ class VelociousDatabaseRecord {
|
|
|
2828
2880
|
this.bindRelatedRecord(model)
|
|
2829
2881
|
const foreignKey = model._relationshipForeignKeyAttribute(instanceRelationship)
|
|
2830
2882
|
|
|
2831
|
-
model.setAttribute(foreignKey, this.id())
|
|
2883
|
+
model.setAttribute(foreignKey, scalarModelPrimaryKeyValue(this.id(), `Has-many autosave for ${this.getModelClass().name}`))
|
|
2832
2884
|
|
|
2833
2885
|
if (model.isChanged()) {
|
|
2834
2886
|
await model.save()
|
|
@@ -2882,15 +2934,30 @@ class VelociousDatabaseRecord {
|
|
|
2882
2934
|
static async transaction(callback) {
|
|
2883
2935
|
await this.ensureInitialized()
|
|
2884
2936
|
|
|
2885
|
-
const
|
|
2937
|
+
const connection = this.connection()
|
|
2938
|
+
|
|
2939
|
+
if (!connection.insideTransaction()) {
|
|
2940
|
+
await this._prepareAttachmentStoreSchema(connection)
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2943
|
+
const useTransactions = connection.getArgs().record?.transactions
|
|
2886
2944
|
|
|
2887
2945
|
if (useTransactions !== false) {
|
|
2888
|
-
return await
|
|
2946
|
+
return await connection.transaction(callback)
|
|
2889
2947
|
} else {
|
|
2890
2948
|
return await callback()
|
|
2891
2949
|
}
|
|
2892
2950
|
}
|
|
2893
2951
|
|
|
2952
|
+
/**
|
|
2953
|
+
* Prepares this model's attachment store before opening a model transaction.
|
|
2954
|
+
* @param {import("../drivers/base.js").default} connection - Model connection.
|
|
2955
|
+
* @returns {Promise<void>} - Resolves when the attachment schema is current.
|
|
2956
|
+
*/
|
|
2957
|
+
static async _prepareAttachmentStoreSchema(connection) {
|
|
2958
|
+
await recordAttachmentsStoreForModelClass(this, connection).prepareRecordIdentityMigration({connection})
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2894
2961
|
/**
|
|
2895
2962
|
* Runs the callback while holding a named advisory lock. Calls without
|
|
2896
2963
|
* By default calls use the caller connection. Calls with `dedicatedConnection`
|
|
@@ -3027,7 +3094,7 @@ class VelociousDatabaseRecord {
|
|
|
3027
3094
|
const targetTableSql = driver.quoteTable(query.getTableReferenceForJoin())
|
|
3028
3095
|
const scopeTableSql = driver.quoteTable(scopeTableReference)
|
|
3029
3096
|
const scopeTableFromSql = `${driver.quoteTable(tableName)} AS ${scopeTableSql}`
|
|
3030
|
-
const primaryKeyColumn = translationClass.primaryKey()
|
|
3097
|
+
const primaryKeyColumn = scalarModelPrimaryKey(translationClass.primaryKey(), `Current translation scope for ${translationClass.name}`)
|
|
3031
3098
|
const foreignKeyColumn = relationship.getForeignKey()
|
|
3032
3099
|
const targetPrimaryKeySql = `${targetTableSql}.${driver.quoteColumn(primaryKeyColumn)}`
|
|
3033
3100
|
const targetForeignKeySql = `${targetTableSql}.${driver.quoteColumn(foreignKeyColumn)}`
|
|
@@ -3284,7 +3351,11 @@ class VelociousDatabaseRecord {
|
|
|
3284
3351
|
static orderableColumn() {
|
|
3285
3352
|
// FIXME: Allow to change to 'created_at' if using UUID?
|
|
3286
3353
|
|
|
3287
|
-
|
|
3354
|
+
const primaryKey = this.primaryKey()
|
|
3355
|
+
|
|
3356
|
+
if (Array.isArray(primaryKey)) return primaryKey[0]
|
|
3357
|
+
|
|
3358
|
+
return primaryKey
|
|
3288
3359
|
}
|
|
3289
3360
|
|
|
3290
3361
|
/**
|
|
@@ -3390,7 +3461,7 @@ class VelociousDatabaseRecord {
|
|
|
3390
3461
|
* Runs find.
|
|
3391
3462
|
* @template {typeof VelociousDatabaseRecord} MC
|
|
3392
3463
|
* @this {MC}
|
|
3393
|
-
* @param {
|
|
3464
|
+
* @param {import("../../utils/model-primary-key.js").ModelPrimaryKeyValue} recordId - Record id.
|
|
3394
3465
|
* @returns {Promise<InstanceType<MC>>} - Resolves with the find.
|
|
3395
3466
|
*/
|
|
3396
3467
|
static async find(recordId) {
|
|
@@ -3969,11 +4040,38 @@ class VelociousDatabaseRecord {
|
|
|
3969
4040
|
return tenants
|
|
3970
4041
|
}
|
|
3971
4042
|
|
|
4043
|
+
/**
|
|
4044
|
+
* Runs a callback while primary-key reads resolve to the persisted identity.
|
|
4045
|
+
* @param {() => Promise<void>} callback - Callback that requires the stored identity.
|
|
4046
|
+
* @returns {Promise<void>} - Resolves when the callback completes.
|
|
4047
|
+
*/
|
|
4048
|
+
async _withPersistedPrimaryKey(callback) {
|
|
4049
|
+
const previousReadsPersistedPrimaryKey = this._readsPersistedPrimaryKey
|
|
4050
|
+
|
|
4051
|
+
this._readsPersistedPrimaryKey = true
|
|
4052
|
+
|
|
4053
|
+
try {
|
|
4054
|
+
await callback()
|
|
4055
|
+
} finally {
|
|
4056
|
+
this._readsPersistedPrimaryKey = previousReadsPersistedPrimaryKey
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
|
|
3972
4060
|
/**
|
|
3973
4061
|
* Destroys the record in the database and all of its dependent records.
|
|
3974
4062
|
* @returns {Promise<void>} - Resolves when complete.
|
|
3975
4063
|
*/
|
|
3976
4064
|
async destroy() {
|
|
4065
|
+
await this._withPersistedPrimaryKey(async () => {
|
|
4066
|
+
await this._destroyPersistedRecord()
|
|
4067
|
+
})
|
|
4068
|
+
}
|
|
4069
|
+
|
|
4070
|
+
/**
|
|
4071
|
+
* Runs the destroy lifecycle after the persisted identity has been restored.
|
|
4072
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
4073
|
+
*/
|
|
4074
|
+
async _destroyPersistedRecord() {
|
|
3977
4075
|
await this._runLifecycleCallbacks("beforeDestroy")
|
|
3978
4076
|
|
|
3979
4077
|
for (const relationship of this.getModelClass().getRelationships()) {
|
|
@@ -4053,7 +4151,7 @@ class VelociousDatabaseRecord {
|
|
|
4053
4151
|
* @type {Record<string, ReturnType<typeof JSON.parse>>} */
|
|
4054
4152
|
const conditions = {}
|
|
4055
4153
|
|
|
4056
|
-
conditions
|
|
4154
|
+
Object.assign(conditions, modelPrimaryKeyConditions(this.getModelClass().primaryKey(), this._persistedPrimaryKeyValue()))
|
|
4057
4155
|
|
|
4058
4156
|
const sql = this._connection().deleteSql({
|
|
4059
4157
|
conditions,
|
|
@@ -4416,9 +4514,15 @@ class VelociousDatabaseRecord {
|
|
|
4416
4514
|
readColumn(attributeName) {
|
|
4417
4515
|
this.getModelClass()._assertHasBeenInitialized()
|
|
4418
4516
|
const belongsToChanges = this._belongsToChanges()
|
|
4517
|
+
const primaryKey = this.getModelClass().primaryKey()
|
|
4518
|
+
const readsPersistedPrimaryKey = this._readsPersistedPrimaryKey && (
|
|
4519
|
+
Array.isArray(primaryKey) ? primaryKey.includes(attributeName) : primaryKey == attributeName
|
|
4520
|
+
)
|
|
4419
4521
|
let result
|
|
4420
4522
|
|
|
4421
|
-
if (
|
|
4523
|
+
if (readsPersistedPrimaryKey) {
|
|
4524
|
+
result = this._attributes[attributeName]
|
|
4525
|
+
} else if (attributeName in belongsToChanges) {
|
|
4422
4526
|
result = belongsToChanges[attributeName]
|
|
4423
4527
|
} else if (attributeName in this._changes) {
|
|
4424
4528
|
result = this._changes[attributeName]
|
|
@@ -4551,7 +4655,10 @@ class VelociousDatabaseRecord {
|
|
|
4551
4655
|
|
|
4552
4656
|
const data = Object.assign({}, this._belongsToChanges(), this.rawAttributes())
|
|
4553
4657
|
const primaryKey = this.getModelClass().primaryKey()
|
|
4554
|
-
const
|
|
4658
|
+
const primaryKeyColumns = this.getModelClass().getColumns().filter((column) => {
|
|
4659
|
+
return Array.isArray(primaryKey) ? primaryKey.includes(column.getName()) : column.getName() == primaryKey
|
|
4660
|
+
})
|
|
4661
|
+
const primaryKeyColumn = Array.isArray(primaryKey) ? undefined : primaryKeyColumns[0]
|
|
4555
4662
|
const primaryKeyType = primaryKeyColumn?.getType()?.toLowerCase()
|
|
4556
4663
|
const driverSupportsDefaultUUID = typeof connection.supportsDefaultPrimaryKeyUUID == "function" && connection.supportsDefaultPrimaryKeyUUID()
|
|
4557
4664
|
const isUUIDPrimaryKey = primaryKeyType?.includes("uuid")
|
|
@@ -4559,9 +4666,18 @@ class VelociousDatabaseRecord {
|
|
|
4559
4666
|
this._setDefaultTimestampValues(data)
|
|
4560
4667
|
|
|
4561
4668
|
const columnNames = this.getModelClass().getColumnNames()
|
|
4562
|
-
const hasUserProvidedPrimaryKey =
|
|
4669
|
+
const hasUserProvidedPrimaryKey = Array.isArray(primaryKey)
|
|
4670
|
+
? primaryKey.every((columnName) => data[columnName] !== undefined && data[columnName] !== null && data[columnName] !== "")
|
|
4671
|
+
: data[primaryKey] !== undefined && data[primaryKey] !== null && data[primaryKey] !== ""
|
|
4672
|
+
const hasUserProvidedAutoIncrementPrimaryKey = primaryKeyColumns.some((column) => {
|
|
4673
|
+
const value = data[column.getName()]
|
|
4674
|
+
|
|
4675
|
+
return column.getAutoIncrement() === true && value !== undefined && value !== null && value !== ""
|
|
4676
|
+
})
|
|
4563
4677
|
|
|
4564
4678
|
if (shouldAssignUUIDPrimaryKey && !hasUserProvidedPrimaryKey) {
|
|
4679
|
+
if (Array.isArray(primaryKey)) throw new Error("Composite UUID primary keys must be provided explicitly.")
|
|
4680
|
+
|
|
4565
4681
|
data[primaryKey] = new UUID(4).format()
|
|
4566
4682
|
}
|
|
4567
4683
|
|
|
@@ -4576,7 +4692,7 @@ class VelociousDatabaseRecord {
|
|
|
4576
4692
|
// Explicit primary-key inserts into auto-increment columns go through the
|
|
4577
4693
|
// driver's explicit-primary-key insert (MSSQL wraps it in IDENTITY_INSERT);
|
|
4578
4694
|
// everything else uses the plain query path.
|
|
4579
|
-
const insertResult =
|
|
4695
|
+
const insertResult = hasUserProvidedAutoIncrementPrimaryKey
|
|
4580
4696
|
? await connection.insertWithExplicitPrimaryKey({options: insertOptions, sql, tableName: this._tableName()})
|
|
4581
4697
|
: await connection.query(sql, insertOptions)
|
|
4582
4698
|
|
|
@@ -4606,10 +4722,17 @@ class VelociousDatabaseRecord {
|
|
|
4606
4722
|
|
|
4607
4723
|
/**
|
|
4608
4724
|
* Applies the database insert response to this record.
|
|
4609
|
-
* @param {{connection: import("../drivers/base.js").default, data: Record<string, string | number | boolean | Date | null | undefined>, insertResult: Array<Record<string, string | number | boolean | Date | null | undefined>> | null | undefined, primaryKey: string}} options - Pinned insert connection, inserted data, connection result, and primary key column name.
|
|
4725
|
+
* @param {{connection: import("../drivers/base.js").default, data: Record<string, string | number | boolean | Date | null | undefined>, insertResult: Array<Record<string, string | number | boolean | Date | null | undefined>> | null | undefined, primaryKey: string | string[]}} options - Pinned insert connection, inserted data, connection result, and primary key column name.
|
|
4610
4726
|
* @returns {Promise<void>} - Resolves when complete.
|
|
4611
4727
|
*/
|
|
4612
4728
|
async _applyInsertResult({connection, data, insertResult, primaryKey}) {
|
|
4729
|
+
if (Array.isArray(primaryKey)) {
|
|
4730
|
+
const insertedRow = Array.isArray(insertResult) ? insertResult[0] : undefined
|
|
4731
|
+
|
|
4732
|
+
await this._reloadWithId(readModelPrimaryKeyValue(primaryKey, (columnName) => insertedRow?.[columnName] ?? data[columnName]))
|
|
4733
|
+
return
|
|
4734
|
+
}
|
|
4735
|
+
|
|
4613
4736
|
if (Array.isArray(insertResult) && insertResult[0] && insertResult[0][primaryKey]) {
|
|
4614
4737
|
this._attributes = insertResult[0]
|
|
4615
4738
|
this._changes = {}
|
|
@@ -4671,12 +4794,16 @@ class VelociousDatabaseRecord {
|
|
|
4671
4794
|
* @returns {Promise<void>} - Resolves when complete.
|
|
4672
4795
|
*/
|
|
4673
4796
|
async _updateRecordWithChanges() {
|
|
4797
|
+
const connection = this._connection()
|
|
4798
|
+
const primaryKey = this.getModelClass().primaryKey()
|
|
4799
|
+
const persistedPrimaryKeyValue = this._persistedPrimaryKeyValue()
|
|
4800
|
+
const nextPrimaryKeyValue = this.id()
|
|
4674
4801
|
/**
|
|
4675
4802
|
* Conditions.
|
|
4676
4803
|
* @type {Record<string, ReturnType<typeof JSON.parse>>} */
|
|
4677
4804
|
const conditions = {}
|
|
4678
4805
|
|
|
4679
|
-
|
|
4806
|
+
Object.assign(conditions, modelPrimaryKeyConditions(primaryKey, persistedPrimaryKeyValue))
|
|
4680
4807
|
|
|
4681
4808
|
const changes = Object.assign({}, this._belongsToChanges(), this._changes)
|
|
4682
4809
|
const updatedAtColumn = this.getModelClass().getColumns().find((column) => column.getName() == "updated_at")
|
|
@@ -4688,19 +4815,32 @@ class VelociousDatabaseRecord {
|
|
|
4688
4815
|
|
|
4689
4816
|
if (Object.keys(changes).length > 0) {
|
|
4690
4817
|
this._normalizeDateValuesForWrite(changes)
|
|
4691
|
-
const sql =
|
|
4818
|
+
const sql = connection.updateSql({
|
|
4692
4819
|
tableName: this._tableName(),
|
|
4693
4820
|
data: changes,
|
|
4694
4821
|
conditions
|
|
4695
4822
|
})
|
|
4696
|
-
await
|
|
4697
|
-
await this._reloadWithId(
|
|
4823
|
+
await connection.query(sql, {logName: `${this.getModelClass().name} Update`})
|
|
4824
|
+
await this._reloadWithId(nextPrimaryKeyValue)
|
|
4825
|
+
const reloadedPrimaryKeyValue = this.id()
|
|
4826
|
+
|
|
4827
|
+
if (
|
|
4828
|
+
Object.keys(this.getModelClass().getAttachments()).length > 0
|
|
4829
|
+
&& modelPrimaryKeyCacheKey(primaryKey, persistedPrimaryKeyValue) !== modelPrimaryKeyCacheKey(primaryKey, reloadedPrimaryKeyValue)
|
|
4830
|
+
) {
|
|
4831
|
+
await recordAttachmentsStoreForModel(this).migrateRecordIdentity({
|
|
4832
|
+
connection,
|
|
4833
|
+
model: this,
|
|
4834
|
+
nextIdentity: reloadedPrimaryKeyValue,
|
|
4835
|
+
previousIdentity: persistedPrimaryKeyValue
|
|
4836
|
+
})
|
|
4837
|
+
}
|
|
4698
4838
|
}
|
|
4699
4839
|
}
|
|
4700
4840
|
|
|
4701
4841
|
/**
|
|
4702
4842
|
* Runs id.
|
|
4703
|
-
* @returns {
|
|
4843
|
+
* @returns {import("../../utils/model-primary-key.js").ModelPrimaryKeyValue} - The id.
|
|
4704
4844
|
*/
|
|
4705
4845
|
id() {
|
|
4706
4846
|
if (!this.getModelClass()._columnNameToAttributeName) {
|
|
@@ -4708,6 +4848,11 @@ class VelociousDatabaseRecord {
|
|
|
4708
4848
|
}
|
|
4709
4849
|
|
|
4710
4850
|
const primaryKey = this.getModelClass().primaryKey()
|
|
4851
|
+
|
|
4852
|
+
if (Array.isArray(primaryKey)) {
|
|
4853
|
+
return readModelPrimaryKeyValue(primaryKey, (columnName) => this.readColumn(columnName))
|
|
4854
|
+
}
|
|
4855
|
+
|
|
4711
4856
|
const attributeName = this.getModelClass().getColumnNameToAttributeNameMap()[primaryKey]
|
|
4712
4857
|
|
|
4713
4858
|
if (attributeName === undefined) {
|
|
@@ -4717,6 +4862,16 @@ class VelociousDatabaseRecord {
|
|
|
4717
4862
|
return /** @type {number | string} */ (this.readAttribute(attributeName))
|
|
4718
4863
|
}
|
|
4719
4864
|
|
|
4865
|
+
/**
|
|
4866
|
+
* Returns the identity represented by the last persisted database attributes.
|
|
4867
|
+
* @returns {import("../../utils/model-primary-key.js").ModelPrimaryKeyValue} - Persisted identity.
|
|
4868
|
+
*/
|
|
4869
|
+
_persistedPrimaryKeyValue() {
|
|
4870
|
+
const primaryKey = this.getModelClass().primaryKey()
|
|
4871
|
+
|
|
4872
|
+
return readModelPrimaryKeyValue(primaryKey, (columnName) => this._attributes[columnName])
|
|
4873
|
+
}
|
|
4874
|
+
|
|
4720
4875
|
/**
|
|
4721
4876
|
* Runs is persisted.
|
|
4722
4877
|
* @returns {boolean} - Whether persisted.
|
|
@@ -4741,7 +4896,7 @@ class VelociousDatabaseRecord {
|
|
|
4741
4896
|
/**
|
|
4742
4897
|
* Runs reload with id.
|
|
4743
4898
|
* @template {typeof VelociousDatabaseRecord} MC
|
|
4744
|
-
* @param {
|
|
4899
|
+
* @param {import("../../utils/model-primary-key.js").ModelPrimaryKeyValue} id - Record identifier.
|
|
4745
4900
|
* @returns {Promise<void>} - Resolves when complete.
|
|
4746
4901
|
*/
|
|
4747
4902
|
async _reloadWithId(id) {
|
|
@@ -4752,7 +4907,7 @@ class VelociousDatabaseRecord {
|
|
|
4752
4907
|
* @type {Record<string, ReturnType<typeof JSON.parse>>} */
|
|
4753
4908
|
const whereObject = {}
|
|
4754
4909
|
|
|
4755
|
-
whereObject
|
|
4910
|
+
Object.assign(whereObject, modelPrimaryKeyConditions(primaryKey, id))
|
|
4756
4911
|
|
|
4757
4912
|
const query = /** @type {import("../query/model-class-query.js").default<MC>} */ (
|
|
4758
4913
|
this
|
|
@@ -4773,7 +4928,7 @@ class VelociousDatabaseRecord {
|
|
|
4773
4928
|
* @returns {Promise<void>} - Resolves when complete.
|
|
4774
4929
|
*/
|
|
4775
4930
|
async reload() {
|
|
4776
|
-
const recordId =
|
|
4931
|
+
const recordId = this._persistedPrimaryKeyValue()
|
|
4777
4932
|
await this._reloadWithId(recordId)
|
|
4778
4933
|
}
|
|
4779
4934
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import BaseInstanceRelationship from "./base.js"
|
|
4
|
+
import {scalarModelPrimaryKey} from "../../../utils/model-primary-key.js"
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* A generic query over some model type.
|
|
@@ -79,7 +80,7 @@ export default class VelociousDatabaseRecordBelongsToInstanceRelationship extend
|
|
|
79
80
|
* @returns {Promise<InstanceType<TMC> | undefined>} - Loaded foreign model.
|
|
80
81
|
*/
|
|
81
82
|
async _loadForeignModel({foreignModelID, TargetModelClass}) {
|
|
82
|
-
const primaryKey = TargetModelClass.primaryKey()
|
|
83
|
+
const primaryKey = scalarModelPrimaryKey(TargetModelClass.primaryKey(), `Belongs-to relationship load for ${TargetModelClass.name}`)
|
|
83
84
|
/**
|
|
84
85
|
* Where args.
|
|
85
86
|
* @type {Record<string, string | number | null | undefined>} */
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import Base from "./base.js"
|
|
4
4
|
import * as inflection from "inflection"
|
|
5
|
+
import {modelPrimaryKeyConditions, scalarModelPrimaryKeyValue} from "../../../utils/model-primary-key.js"
|
|
5
6
|
import validationMessage from "../validation-messages.js"
|
|
6
7
|
|
|
7
8
|
export default class VelociousDatabaseRecordValidatorsUniqueness extends Base {
|
|
@@ -15,8 +16,6 @@ export default class VelociousDatabaseRecordValidatorsUniqueness extends Base {
|
|
|
15
16
|
async validate({model, attributeName}) {
|
|
16
17
|
const modelClass = /** @type {typeof import("../index.js").default} */ (model.constructor)
|
|
17
18
|
|
|
18
|
-
const connection = model.connection()
|
|
19
|
-
const tableName = modelClass._getTable().getName()
|
|
20
19
|
const attributeValue = /** @type {string | number} */ (model.readAttribute(attributeName))
|
|
21
20
|
const attributeNameUnderscore = inflection.underscore(attributeName)
|
|
22
21
|
|
|
@@ -55,7 +54,7 @@ export default class VelociousDatabaseRecordValidatorsUniqueness extends Base {
|
|
|
55
54
|
.where(whereArgs)
|
|
56
55
|
|
|
57
56
|
if (model.isPersisted()) {
|
|
58
|
-
existingRecordQuery.
|
|
57
|
+
existingRecordQuery.whereNot(modelPrimaryKeyConditions(modelClass.primaryKey(), model._persistedPrimaryKeyValue()))
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
const existingRecord = await existingRecordQuery.first()
|
|
@@ -95,8 +94,12 @@ export default class VelociousDatabaseRecordValidatorsUniqueness extends Base {
|
|
|
95
94
|
const instanceRelationship = model.getRelationshipByName(relationshipName)
|
|
96
95
|
const loaded = instanceRelationship.loaded()
|
|
97
96
|
|
|
98
|
-
if (loaded && !Array.isArray(loaded)
|
|
99
|
-
|
|
97
|
+
if (loaded && !Array.isArray(loaded)) {
|
|
98
|
+
const loadedId = loaded.id()
|
|
99
|
+
|
|
100
|
+
if (loadedId == null) return null
|
|
101
|
+
|
|
102
|
+
return scalarModelPrimaryKeyValue(loadedId, `Uniqueness scope relationship for ${modelClass.name}`)
|
|
100
103
|
}
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -543,7 +543,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
543
543
|
fileContent += ` return /** @type {${signature.returnType}} */ (await ${className}.executeCustomCommand({\n`
|
|
544
544
|
fileContent += ` commandName: ${JSON.stringify(memberCommands[methodName])},\n`
|
|
545
545
|
fileContent += ` commandType: ${JSON.stringify(memberCommands[methodName])},\n`
|
|
546
|
-
fileContent +=
|
|
546
|
+
fileContent += ` memberId: this.scalarPrimaryKeyValue(${JSON.stringify(`Custom member command ${className}#${methodName}`)}),\n`
|
|
547
547
|
fileContent += ` payload: ${className}.normalizeCustomCommandPayloadArguments(${signature.payloadArguments}),\n`
|
|
548
548
|
fileContent += ` resourcePath: ${className}.resourcePath()\n`
|
|
549
549
|
fileContent += " }))\n"
|
|
@@ -1179,10 +1179,12 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1179
1179
|
|
|
1180
1180
|
const primaryKey = modelClass.primaryKey()
|
|
1181
1181
|
|
|
1182
|
-
|
|
1183
|
-
|
|
1182
|
+
for (const columnName of Array.isArray(primaryKey) ? primaryKey : [primaryKey]) {
|
|
1183
|
+
if (attributeName === columnName) return true
|
|
1184
|
+
if (modelClass.resolveAttributeName(columnName) === attributeName) return true
|
|
1185
|
+
}
|
|
1184
1186
|
|
|
1185
|
-
return
|
|
1187
|
+
return false
|
|
1186
1188
|
}
|
|
1187
1189
|
|
|
1188
1190
|
/**
|
|
@@ -1202,13 +1204,27 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1202
1204
|
|
|
1203
1205
|
/**
|
|
1204
1206
|
* Validates an explicitly configured frontend-model primary key.
|
|
1205
|
-
* @param {{attributeNames: Array<string>, primaryKey: string}} args - Configured primary key args.
|
|
1206
|
-
* @returns {string} - Configured primary key.
|
|
1207
|
+
* @param {{attributeNames: Array<string>, primaryKey: string | string[]}} args - Configured primary key args.
|
|
1208
|
+
* @returns {string | string[]} - Configured primary key.
|
|
1207
1209
|
*/
|
|
1208
1210
|
validatedConfiguredPrimaryKey({attributeNames, primaryKey}) {
|
|
1209
|
-
|
|
1211
|
+
const primaryKeyAttributes = Array.isArray(primaryKey) ? primaryKey : [primaryKey]
|
|
1212
|
+
|
|
1213
|
+
if (primaryKeyAttributes.length < 1) {
|
|
1214
|
+
throw new Error("Configured frontend model composite primary key must contain at least one attribute.")
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
if (new Set(primaryKeyAttributes).size !== primaryKeyAttributes.length) {
|
|
1218
|
+
throw new Error("Configured frontend model composite primary key attributes must be unique.")
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
for (const attributeName of primaryKeyAttributes) {
|
|
1222
|
+
if (!attributeNames.includes(attributeName)) {
|
|
1223
|
+
throw new Error(`Configured frontend model primary key "${attributeName}" is not a generated frontend model attribute.`)
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1210
1226
|
|
|
1211
|
-
|
|
1227
|
+
return primaryKey
|
|
1212
1228
|
}
|
|
1213
1229
|
|
|
1214
1230
|
/**
|