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
|
@@ -22,9 +22,7 @@ export default class VelociousDatabaseConnectionDriversMysqlSqlUpdate extends Up
|
|
|
22
22
|
for (let columnName in this.conditions) {
|
|
23
23
|
if (count > 0) sql += " AND "
|
|
24
24
|
|
|
25
|
-
sql += this.
|
|
26
|
-
sql += " = "
|
|
27
|
-
sql += this.formatValue(this.conditions[columnName])
|
|
25
|
+
sql += this.formatCondition(columnName, this.conditions[columnName])
|
|
28
26
|
count++
|
|
29
27
|
}
|
|
30
28
|
|
|
@@ -481,7 +481,7 @@ export default class VelociousDatabaseQuery {
|
|
|
481
481
|
* Runs execute query.
|
|
482
482
|
* @param {object} [args] - Options object.
|
|
483
483
|
* @param {string} [args.logName] - Query log name.
|
|
484
|
-
* @returns {Promise<
|
|
484
|
+
* @returns {Promise<import("../drivers/base.js").QueryResultType>} Array of results from the database
|
|
485
485
|
*/
|
|
486
486
|
async _executeQuery({logName = this.queryLogName("Load")} = {}) {
|
|
487
487
|
const sql = this.toSql()
|
|
@@ -503,7 +503,7 @@ export default class VelociousDatabaseQuery {
|
|
|
503
503
|
|
|
504
504
|
/**
|
|
505
505
|
* Runs results.
|
|
506
|
-
* @returns {Promise<
|
|
506
|
+
* @returns {Promise<import("../drivers/base.js").QueryResultType>} Array of results from the database
|
|
507
507
|
*/
|
|
508
508
|
async results() {
|
|
509
509
|
return await this._executeQuery()
|
|
@@ -15,6 +15,7 @@ import JoinTracker from "./join-tracker.js"
|
|
|
15
15
|
import RecordNotFoundError from "../record/record-not-found-error.js"
|
|
16
16
|
import {normalizeRansackGroup, parseRansackSort} from "../../utils/ransack.js"
|
|
17
17
|
import {isModelScopeDescriptor} from "../../utils/model-scope.js"
|
|
18
|
+
import {modelPrimaryKeyConditions, scalarModelPrimaryKey} from "../../utils/model-primary-key.js"
|
|
18
19
|
import WhereCombinator from "./where-combinator.js"
|
|
19
20
|
import WhereModelClassHash from "./where-model-class-hash.js"
|
|
20
21
|
import WhereNot from "./where-not.js"
|
|
@@ -323,7 +324,8 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
323
324
|
// setPrimaryKey([...]) on legacy tables — has no column COUNT can reference (an array primary key
|
|
324
325
|
// cannot be quoted as a single COUNT(column), and primaryKey() falls back to "id" for the no-pk
|
|
325
326
|
// case, so hasPrimaryKey() detects that one).
|
|
326
|
-
const
|
|
327
|
+
const primaryKey = this.getModelClass().primaryKey()
|
|
328
|
+
const hasSingleColumnPrimaryKey = this.getModelClass().hasPrimaryKey() && !Array.isArray(primaryKey)
|
|
327
329
|
|
|
328
330
|
// Pagination, or an ungrouped query on a model with no single primary-key column, counts via the
|
|
329
331
|
// subquery form. It references no primary-key column and preserves DISTINCT over joins — which a
|
|
@@ -340,7 +342,7 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
340
342
|
|
|
341
343
|
const distinctPrefix = this._distinct ? "DISTINCT " : ""
|
|
342
344
|
const countExpression = hasSingleColumnPrimaryKey
|
|
343
|
-
? `${this.driver.quoteTable(this.getModelClass().tableName())}.${this.driver.quoteColumn(
|
|
345
|
+
? `${this.driver.quoteTable(this.getModelClass().tableName())}.${this.driver.quoteColumn(/** @type {string} */ (primaryKey))}`
|
|
344
346
|
: "*"
|
|
345
347
|
let sql = `COUNT(${distinctPrefix}${countExpression})`
|
|
346
348
|
|
|
@@ -807,7 +809,8 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
807
809
|
if (joinsSql.length > 0) {
|
|
808
810
|
// Use a subquery for cross-driver compatibility (SQLite
|
|
809
811
|
// doesn't support UPDATE ... JOIN).
|
|
810
|
-
const
|
|
812
|
+
const primaryKey = scalarModelPrimaryKey(this.getModelClass().primaryKey(), `${this.getModelClass().name}.updateAll() with joins`)
|
|
813
|
+
const pk = driver.quoteColumn(primaryKey)
|
|
811
814
|
const qt = driver.quoteTable(tableName)
|
|
812
815
|
|
|
813
816
|
sql = `UPDATE ${qt} SET ${setCols} WHERE ${pk} IN (SELECT ${qt}.${pk} FROM ${qt}${joinsSql}${whereSql})`
|
|
@@ -820,7 +823,7 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
820
823
|
|
|
821
824
|
/**
|
|
822
825
|
* Runs find.
|
|
823
|
-
* @param {
|
|
826
|
+
* @param {import("../../utils/model-primary-key.js").ModelPrimaryKeyValue} recordId - Record id.
|
|
824
827
|
* @returns {Promise<InstanceType<MC>>} - Resolves with the find.
|
|
825
828
|
*/
|
|
826
829
|
async find(recordId) {
|
|
@@ -829,7 +832,7 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
829
832
|
* @type {{[key: string]: number | string}} */
|
|
830
833
|
const conditions = {}
|
|
831
834
|
|
|
832
|
-
conditions
|
|
835
|
+
Object.assign(conditions, modelPrimaryKeyConditions(this.getModelClass().primaryKey(), recordId))
|
|
833
836
|
|
|
834
837
|
const newQuery = /** @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone())
|
|
835
838
|
|
|
@@ -838,7 +841,7 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
838
841
|
const record = (await newQuery.first())
|
|
839
842
|
|
|
840
843
|
if (!record) {
|
|
841
|
-
throw new RecordNotFoundError(`Couldn't find ${this.getModelClass().name} with '${this.getModelClass().primaryKey()}'=${recordId}`)
|
|
844
|
+
throw new RecordNotFoundError(`Couldn't find ${this.getModelClass().name} with '${this.getModelClass().primaryKey()}'=${JSON.stringify(recordId)}`)
|
|
842
845
|
}
|
|
843
846
|
|
|
844
847
|
return record
|
|
@@ -940,7 +943,7 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
940
943
|
* @returns {Promise<InstanceType<MC> | null>} - Resolves with the first.
|
|
941
944
|
*/
|
|
942
945
|
async first() {
|
|
943
|
-
const newQuery = this.clone().limit(1).reorder(
|
|
946
|
+
const newQuery = this.clone().limit(1).reorder(this._defaultIdentityOrder("ASC"))
|
|
944
947
|
const results = await newQuery.toArray()
|
|
945
948
|
|
|
946
949
|
return results[0] || null
|
|
@@ -951,13 +954,26 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
951
954
|
* @returns {Promise<InstanceType<MC> | null>} - Resolves with the last.
|
|
952
955
|
*/
|
|
953
956
|
async last() {
|
|
954
|
-
const
|
|
955
|
-
const tableName = this.getModelClass().tableName()
|
|
956
|
-
const results = await this.clone().reorder(`${this.driver.quoteTable(tableName)}.${this.driver.quoteColumn(primaryKey)} DESC`).limit(1).toArray()
|
|
957
|
+
const results = await this.clone().reorder(this._defaultIdentityOrder("DESC")).limit(1).toArray()
|
|
957
958
|
|
|
958
959
|
return results[0] || null
|
|
959
960
|
}
|
|
960
961
|
|
|
962
|
+
/**
|
|
963
|
+
* Builds the deterministic default order for the model identity.
|
|
964
|
+
* @param {"ASC" | "DESC"} direction - Sort direction.
|
|
965
|
+
* @returns {string} - SQL order expression.
|
|
966
|
+
*/
|
|
967
|
+
_defaultIdentityOrder(direction) {
|
|
968
|
+
const ModelClass = this.getModelClass()
|
|
969
|
+
const primaryKey = ModelClass.primaryKey()
|
|
970
|
+
const orderableColumns = Array.isArray(primaryKey) ? primaryKey : [ModelClass.orderableColumn()]
|
|
971
|
+
|
|
972
|
+
return orderableColumns
|
|
973
|
+
.map((column) => `${this.driver.quoteTable(ModelClass.tableName())}.${this.driver.quoteColumn(column)} ${direction}`)
|
|
974
|
+
.join(", ")
|
|
975
|
+
}
|
|
976
|
+
|
|
961
977
|
/**
|
|
962
978
|
* Runs preload.
|
|
963
979
|
* @param {import("./index.js").NestedPreloadRecord | string | Array<string | import("./index.js").NestedPreloadRecord>} data - Data payload.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import {scalarModelPrimaryKey} from "../../../utils/model-primary-key.js"
|
|
4
|
+
|
|
3
5
|
import ensureModelClassInitialized from "./ensure-model-class-initialized.js"
|
|
4
6
|
import PreloaderSelection from "./selection.js"
|
|
5
7
|
import preloadQueryForModel, { bindPreloadModelClass } from "./query-for-model.js"
|
|
@@ -185,7 +187,8 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
|
|
|
185
187
|
|
|
186
188
|
for (const throughModel of throughModels) {
|
|
187
189
|
const parentId = /** @type {string | number} */ (throughModel.readColumn(throughForeignKey))
|
|
188
|
-
const
|
|
190
|
+
const throughPrimaryKey = scalarModelPrimaryKey(throughModelClass.primaryKey(), `Has-many-through preload for ${throughModelClass.name}`)
|
|
191
|
+
const throughId = /** @type {string | number} */ (throughModel.readColumn(throughPrimaryKey))
|
|
189
192
|
|
|
190
193
|
if (!(parentId in parentToTargetIds)) parentToTargetIds[parentId] = []
|
|
191
194
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import {isPlainObject} from "is-plain-object"
|
|
4
|
+
import {scalarModelPrimaryKey} from "../../utils/model-primary-key.js"
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* QueryDataEntry type.
|
|
@@ -188,7 +189,7 @@ function resolveTargetModelClass(rootModelClass, chain) {
|
|
|
188
189
|
export async function runQueryData({rootModelClass, rootModels, entries}) {
|
|
189
190
|
if (rootModels.length === 0 || entries.length === 0) return
|
|
190
191
|
|
|
191
|
-
const primaryKey = rootModelClass.primaryKey()
|
|
192
|
+
const primaryKey = scalarModelPrimaryKey(rootModelClass.primaryKey(), `queryData for ${rootModelClass.name}`)
|
|
192
193
|
const rootIds = rootModels.map((model) => /** @type {string | number} */ (model.readColumn(primaryKey)))
|
|
193
194
|
const sourceModel = rootModels[0]
|
|
194
195
|
const preparedEntries = entries.map((entry, entryIndex) => prepareEntry({
|
|
@@ -35,6 +35,20 @@ export default class VelociousDatabaseQueryUpdateBase {
|
|
|
35
35
|
return this.getOptions().quote(value)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Formats one hash condition with SQL null semantics.
|
|
40
|
+
* @param {string} columnName - Column name.
|
|
41
|
+
* @param {ReturnType<typeof JSON.parse>} value - Condition value.
|
|
42
|
+
* @returns {string} - SQL condition.
|
|
43
|
+
*/
|
|
44
|
+
formatCondition(columnName, value) {
|
|
45
|
+
const column = this.getOptions().quoteColumnName(columnName)
|
|
46
|
+
|
|
47
|
+
if (value === null) return `${column} IS NULL`
|
|
48
|
+
|
|
49
|
+
return `${column} = ${this.formatValue(value)}`
|
|
50
|
+
}
|
|
51
|
+
|
|
38
52
|
toSql() {
|
|
39
53
|
throw new Error("'toSql' wasn't implemented")
|
|
40
54
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import {scalarModelPrimaryKey} from "../../utils/model-primary-key.js"
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* WithCountEntry type.
|
|
5
7
|
* @typedef {object} WithCountEntry
|
|
@@ -109,7 +111,7 @@ function entryFromName(name) {
|
|
|
109
111
|
export async function runWithCount({models, modelClass, entries}) {
|
|
110
112
|
if (models.length === 0 || entries.length === 0) return
|
|
111
113
|
|
|
112
|
-
const primaryKey = modelClass.primaryKey()
|
|
114
|
+
const primaryKey = scalarModelPrimaryKey(modelClass.primaryKey(), `withCount for ${modelClass.name}`)
|
|
113
115
|
const parentIds = models.map((model) => /** @type {string | number} */ (model.readColumn(primaryKey)))
|
|
114
116
|
const sourceModel = models[0]
|
|
115
117
|
const queryGroups = new Map()
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import {scalarModelPrimaryKey, scalarModelPrimaryKeyValue} from "../../utils/model-primary-key.js"
|
|
4
|
+
|
|
3
5
|
/** @file Registers gap-less positional list callbacks on a model class. */
|
|
4
6
|
|
|
5
7
|
/**
|
|
@@ -8,6 +10,24 @@
|
|
|
8
10
|
*/
|
|
9
11
|
const ACTS_AS_LIST_SHIFTING = Symbol("actsAsListShifting")
|
|
10
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Returns the scalar primary-key column required by acts-as-list SQL.
|
|
15
|
+
* @param {typeof import("./index.js").default} modelClass - List model class.
|
|
16
|
+
* @returns {string} - Scalar primary-key column.
|
|
17
|
+
*/
|
|
18
|
+
function actsAsListPrimaryKey(modelClass) {
|
|
19
|
+
return scalarModelPrimaryKey(modelClass.primaryKey(), `actsAsList for ${modelClass.name}`)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Returns the scalar record id required by acts-as-list SQL.
|
|
24
|
+
* @param {import("./index.js").default} record - List record.
|
|
25
|
+
* @returns {string | number} - Scalar record id.
|
|
26
|
+
*/
|
|
27
|
+
function actsAsListRecordId(record) {
|
|
28
|
+
return scalarModelPrimaryKeyValue(record.id(), `actsAsList for ${record.getModelClass().name}`)
|
|
29
|
+
}
|
|
30
|
+
|
|
11
31
|
/**
|
|
12
32
|
* Runs set shifting flag.
|
|
13
33
|
* @param {import("./index.js").default} record - Model instance.
|
|
@@ -111,7 +131,7 @@ export default function registerActsAsListCallbacks(modelClass, positionColumn,
|
|
|
111
131
|
await moveOutOfWay({record, positionColumn, scope, scopeValue: oldScopeValue})
|
|
112
132
|
setShiftingFlag(record, false)
|
|
113
133
|
await shiftPositionsDown({record, positionColumn, scope, scopeValue: oldScopeValue, fromPosition: oldPosition + 1})
|
|
114
|
-
await shiftPositionsUp({record, positionColumn, scope, scopeValue: newScopeValue, fromPosition: newPosition, excludeRecordId: record
|
|
134
|
+
await shiftPositionsUp({record, positionColumn, scope, scopeValue: newScopeValue, fromPosition: newPosition, excludeRecordId: actsAsListRecordId(record)})
|
|
115
135
|
await placeMovedRecord({record, positionColumn, scope, scopeValue: newScopeValue, position: newPosition})
|
|
116
136
|
return
|
|
117
137
|
}
|
|
@@ -180,15 +200,17 @@ async function placeMovedRecord({record, positionColumn, scope, scopeValue, posi
|
|
|
180
200
|
const preservedChanges = {...record._changes}
|
|
181
201
|
const scopeColumnSql = connection.quoteColumn(scopeCol)
|
|
182
202
|
const positionColumnSql = connection.quoteColumn(posCol)
|
|
183
|
-
const
|
|
203
|
+
const primaryKey = actsAsListPrimaryKey(modelClass)
|
|
204
|
+
const primaryKeySql = connection.quoteColumn(primaryKey)
|
|
205
|
+
const recordId = actsAsListRecordId(record)
|
|
184
206
|
|
|
185
207
|
delete preservedChanges[scopeCol]
|
|
186
208
|
delete preservedChanges[posCol]
|
|
187
209
|
|
|
188
210
|
await connection.query(
|
|
189
|
-
`UPDATE ${tableSql} SET ${scopeColumnSql} = ${connection.quote(scopeValue)}, ${positionColumnSql} = ${connection.quote(position)} WHERE ${primaryKeySql} = ${connection.quote(
|
|
211
|
+
`UPDATE ${tableSql} SET ${scopeColumnSql} = ${connection.quote(scopeValue)}, ${positionColumnSql} = ${connection.quote(position)} WHERE ${primaryKeySql} = ${connection.quote(recordId)}`
|
|
190
212
|
)
|
|
191
|
-
await record._reloadWithId(
|
|
213
|
+
await record._reloadWithId(recordId)
|
|
192
214
|
record._changes = preservedChanges
|
|
193
215
|
clearBelongsToChangeForScope(record)
|
|
194
216
|
}
|
|
@@ -234,21 +256,22 @@ async function shiftPositionsUp({record, positionColumn, scope, fromPosition, to
|
|
|
234
256
|
const positionColumnName = modelClass.getColumnNameForAttributeName(positionColumn)
|
|
235
257
|
const positionColumnSql = connection.quoteColumn(positionColumnName)
|
|
236
258
|
const scopeColumnSql = connection.quoteColumn(scopeColumnName)
|
|
237
|
-
const
|
|
259
|
+
const primaryKey = actsAsListPrimaryKey(modelClass)
|
|
260
|
+
const primaryKeySql = connection.quoteColumn(primaryKey)
|
|
238
261
|
const tableSql = connection.quoteTable(tableName)
|
|
239
262
|
const quotedScope = connection.quote(resolvedScopeValue)
|
|
240
263
|
|
|
241
264
|
// Load rows in descending order so we bump the highest first
|
|
242
265
|
let query = record
|
|
243
266
|
.queryForModel(modelClass)
|
|
244
|
-
.select(
|
|
267
|
+
.select(primaryKey)
|
|
245
268
|
.select(positionColumn)
|
|
246
269
|
.where({[scopeColumnName]: resolvedScopeValue})
|
|
247
270
|
.where(`${positionColumnSql} >= ${connection.quote(fromPosition)}`)
|
|
248
271
|
.where(`${positionColumnSql} > 0`)
|
|
249
272
|
.order(`${positionColumnSql} DESC`)
|
|
250
273
|
|
|
251
|
-
const recordIdToExclude = excludeRecordId || (record.isPersisted() ? record
|
|
274
|
+
const recordIdToExclude = excludeRecordId || (record.isPersisted() ? actsAsListRecordId(record) : null)
|
|
252
275
|
|
|
253
276
|
if (recordIdToExclude != null) {
|
|
254
277
|
query = query.where(`${primaryKeySql} != ${connection.quote(recordIdToExclude)}`)
|
|
@@ -300,19 +323,20 @@ async function shiftPositionsDown({record, positionColumn, scope, fromPosition,
|
|
|
300
323
|
const positionColumnName = modelClass.getColumnNameForAttributeName(positionColumn)
|
|
301
324
|
const positionColumnSql = connection.quoteColumn(positionColumnName)
|
|
302
325
|
const scopeColumnSql = connection.quoteColumn(scopeColumnName)
|
|
303
|
-
const
|
|
326
|
+
const primaryKey = actsAsListPrimaryKey(modelClass)
|
|
327
|
+
const primaryKeySql = connection.quoteColumn(primaryKey)
|
|
304
328
|
const tableSql = connection.quoteTable(tableName)
|
|
305
329
|
const quotedScope = connection.quote(resolvedScopeValue)
|
|
306
330
|
|
|
307
331
|
// Load rows in ascending order so we shift the lowest gap first
|
|
308
332
|
let query = record
|
|
309
333
|
.queryForModel(modelClass)
|
|
310
|
-
.select(
|
|
334
|
+
.select(primaryKey)
|
|
311
335
|
.select(positionColumn)
|
|
312
336
|
.where({[scopeColumnName]: resolvedScopeValue})
|
|
313
337
|
.where(`${positionColumnSql} >= ${connection.quote(fromPosition)}`)
|
|
314
338
|
.where(`${positionColumnSql} > 0`)
|
|
315
|
-
.where(`${primaryKeySql} != ${connection.quote(record
|
|
339
|
+
.where(`${primaryKeySql} != ${connection.quote(actsAsListRecordId(record))}`)
|
|
316
340
|
.order({column: positionColumnName, direction: "ASC"})
|
|
317
341
|
|
|
318
342
|
if (toPosition != null) {
|
|
@@ -399,7 +423,7 @@ function resolveScopeValue(record, scope) {
|
|
|
399
423
|
const loaded = instanceRelationship.loaded()
|
|
400
424
|
|
|
401
425
|
if (loaded && !Array.isArray(loaded) && typeof loaded.id === "function") {
|
|
402
|
-
return loaded.id()
|
|
426
|
+
return scalarModelPrimaryKeyValue(loaded.id(), `actsAsList scope relationship for ${modelClass.name}`)
|
|
403
427
|
}
|
|
404
428
|
}
|
|
405
429
|
|
|
@@ -427,13 +451,13 @@ async function moveOutOfWay({record, positionColumn, scope, scopeValue}) {
|
|
|
427
451
|
const positionColumnSql = connection.quoteColumn(modelClass.getColumnNameForAttributeName(positionColumn))
|
|
428
452
|
const scopeColumnSql = connection.quoteColumn(modelClass.getColumnNameForAttributeName(scope))
|
|
429
453
|
const tableSql = connection.quoteTable(tableName)
|
|
430
|
-
const pkSql = connection.quoteColumn(modelClass
|
|
454
|
+
const pkSql = connection.quoteColumn(actsAsListPrimaryKey(modelClass))
|
|
431
455
|
|
|
432
456
|
setShiftingFlag(record, true)
|
|
433
457
|
|
|
434
458
|
try {
|
|
435
459
|
await connection.query(
|
|
436
|
-
`UPDATE ${tableSql} SET ${positionColumnSql} = -${positionColumnSql} WHERE ${scopeColumnSql} = ${connection.quote(resolvedScopeValue)} AND ${pkSql} = ${connection.quote(record
|
|
460
|
+
`UPDATE ${tableSql} SET ${positionColumnSql} = -${positionColumnSql} WHERE ${scopeColumnSql} = ${connection.quote(resolvedScopeValue)} AND ${pkSql} = ${connection.quote(actsAsListRecordId(record))}`
|
|
437
461
|
)
|
|
438
462
|
} finally {
|
|
439
463
|
// Don't clear the flag here — the caller will do that after shifts
|