velocious 1.0.568 → 1.0.570
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 +30 -0
- package/build/configuration.js +36 -0
- package/build/database/drivers/base.js +244 -93
- package/build/database/drivers/mssql/index.js +10 -7
- package/build/database/drivers/mysql/index.js +10 -5
- package/build/database/drivers/pgsql/index.js +4 -4
- package/build/database/drivers/sqlite/base.js +2 -2
- package/build/database/drivers/sqlite/connection-sql-js.js +62 -2
- package/build/database/drivers/sqlite/index.web.js +74 -0
- package/build/database/operation-connection.js +121 -0
- package/build/database/operation-lease.js +47 -0
- package/build/database/operation.js +150 -0
- package/build/database/pool/base.js +26 -1
- package/build/database/pool/single-multi-use.js +49 -0
- package/build/database/query/model-class-query.js +38 -7
- package/build/database/query/preloader/belongs-to.js +3 -2
- package/build/database/query/preloader/has-many.js +4 -3
- package/build/database/query/preloader/has-one.js +2 -1
- package/build/database/query/preloader/query-for-model.js +17 -0
- package/build/database/query/query-data.js +12 -3
- package/build/database/query/with-count.js +5 -3
- package/build/database/record/acts-as-list.js +11 -8
- package/build/database/record/attachments/store.js +15 -11
- package/build/database/record/auditing.js +12 -9
- package/build/database/record/counter-cache-magnitude.js +5 -3
- package/build/database/record/index.js +95 -14
- package/build/database/record/instance-relationships/belongs-to.js +4 -2
- package/build/database/record/instance-relationships/has-many.js +7 -5
- package/build/database/record/instance-relationships/has-one.js +4 -2
- package/build/database/record/validators/uniqueness.js +3 -2
- package/build/frontend-models/websocket-publishers.js +2 -2
- package/build/src/configuration.d.ts +12 -0
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +35 -1
- package/build/src/database/drivers/base.d.ts +96 -23
- package/build/src/database/drivers/base.d.ts.map +1 -1
- package/build/src/database/drivers/base.js +230 -90
- package/build/src/database/drivers/mssql/index.d.ts +4 -1
- package/build/src/database/drivers/mssql/index.d.ts.map +1 -1
- package/build/src/database/drivers/mssql/index.js +11 -8
- package/build/src/database/drivers/mysql/index.d.ts +2 -1
- package/build/src/database/drivers/mysql/index.d.ts.map +1 -1
- package/build/src/database/drivers/mysql/index.js +10 -6
- package/build/src/database/drivers/pgsql/index.d.ts +2 -1
- package/build/src/database/drivers/pgsql/index.d.ts.map +1 -1
- package/build/src/database/drivers/pgsql/index.js +5 -5
- package/build/src/database/drivers/sqlite/base.d.ts +1 -1
- package/build/src/database/drivers/sqlite/base.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/base.js +3 -3
- package/build/src/database/drivers/sqlite/connection-sql-js.d.ts +20 -0
- package/build/src/database/drivers/sqlite/connection-sql-js.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/connection-sql-js.js +56 -3
- package/build/src/database/drivers/sqlite/index.web.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/index.web.js +64 -1
- package/build/src/database/operation-connection.d.ts +67 -0
- package/build/src/database/operation-connection.d.ts.map +1 -0
- package/build/src/database/operation-connection.js +102 -0
- package/build/src/database/operation-lease.d.ts +27 -0
- package/build/src/database/operation-lease.d.ts.map +1 -0
- package/build/src/database/operation-lease.js +44 -0
- package/build/src/database/operation.d.ts +85 -0
- package/build/src/database/operation.d.ts.map +1 -0
- package/build/src/database/operation.js +132 -0
- package/build/src/database/pool/base.d.ts +14 -0
- package/build/src/database/pool/base.d.ts.map +1 -1
- package/build/src/database/pool/base.js +24 -2
- package/build/src/database/pool/single-multi-use.d.ts +1 -0
- package/build/src/database/pool/single-multi-use.d.ts.map +1 -1
- package/build/src/database/pool/single-multi-use.js +49 -1
- package/build/src/database/query/model-class-query.d.ts +14 -0
- package/build/src/database/query/model-class-query.d.ts.map +1 -1
- package/build/src/database/query/model-class-query.js +32 -8
- package/build/src/database/query/preloader/belongs-to.d.ts.map +1 -1
- package/build/src/database/query/preloader/belongs-to.js +4 -3
- package/build/src/database/query/preloader/has-many.d.ts.map +1 -1
- package/build/src/database/query/preloader/has-many.js +5 -4
- package/build/src/database/query/preloader/has-one.d.ts.map +1 -1
- package/build/src/database/query/preloader/has-one.js +3 -2
- package/build/src/database/query/preloader/query-for-model.d.ts +10 -0
- package/build/src/database/query/preloader/query-for-model.d.ts.map +1 -0
- package/build/src/database/query/preloader/query-for-model.js +16 -0
- package/build/src/database/query/query-data.d.ts.map +1 -1
- package/build/src/database/query/query-data.js +13 -4
- package/build/src/database/query/with-count.d.ts.map +1 -1
- package/build/src/database/query/with-count.js +6 -4
- package/build/src/database/record/acts-as-list.js +12 -9
- package/build/src/database/record/attachments/attachment-record.d.ts +9 -0
- package/build/src/database/record/attachments/attachment-record.d.ts.map +1 -1
- package/build/src/database/record/attachments/store.d.ts +4 -2
- package/build/src/database/record/attachments/store.d.ts.map +1 -1
- package/build/src/database/record/attachments/store.js +16 -12
- package/build/src/database/record/auditing.d.ts.map +1 -1
- package/build/src/database/record/auditing.js +13 -10
- package/build/src/database/record/counter-cache-magnitude.js +6 -4
- package/build/src/database/record/index.d.ts +42 -2
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +87 -15
- package/build/src/database/record/instance-relationships/belongs-to.d.ts.map +1 -1
- package/build/src/database/record/instance-relationships/belongs-to.js +4 -3
- package/build/src/database/record/instance-relationships/has-many.d.ts.map +1 -1
- package/build/src/database/record/instance-relationships/has-many.js +7 -5
- package/build/src/database/record/instance-relationships/has-one.d.ts.map +1 -1
- package/build/src/database/record/instance-relationships/has-one.js +4 -3
- package/build/src/database/record/validators/uniqueness.d.ts.map +1 -1
- package/build/src/database/record/validators/uniqueness.js +4 -3
- package/build/src/frontend-models/websocket-publishers.js +3 -3
- package/build/src/sync/server-sequence-allocator.d.ts +16 -4
- package/build/src/sync/server-sequence-allocator.d.ts.map +1 -1
- package/build/src/sync/server-sequence-allocator.js +37 -11
- package/build/src/sync/sync-client.d.ts.map +1 -1
- package/build/src/sync/sync-client.js +7 -3
- package/build/src/sync/sync-publisher.d.ts +2 -1
- package/build/src/sync/sync-publisher.d.ts.map +1 -1
- package/build/src/sync/sync-publisher.js +11 -6
- package/build/sync/server-sequence-allocator.js +43 -10
- package/build/sync/sync-client.js +6 -2
- package/build/sync/sync-publisher.js +10 -5
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/configuration.js +36 -0
- package/src/database/drivers/base.js +244 -93
- package/src/database/drivers/mssql/index.js +10 -7
- package/src/database/drivers/mysql/index.js +10 -5
- package/src/database/drivers/pgsql/index.js +4 -4
- package/src/database/drivers/sqlite/base.js +2 -2
- package/src/database/drivers/sqlite/connection-sql-js.js +62 -2
- package/src/database/drivers/sqlite/index.web.js +74 -0
- package/src/database/operation-connection.js +121 -0
- package/src/database/operation-lease.js +47 -0
- package/src/database/operation.js +150 -0
- package/src/database/pool/base.js +26 -1
- package/src/database/pool/single-multi-use.js +49 -0
- package/src/database/query/model-class-query.js +38 -7
- package/src/database/query/preloader/belongs-to.js +3 -2
- package/src/database/query/preloader/has-many.js +4 -3
- package/src/database/query/preloader/has-one.js +2 -1
- package/src/database/query/preloader/query-for-model.js +17 -0
- package/src/database/query/query-data.js +12 -3
- package/src/database/query/with-count.js +5 -3
- package/src/database/record/acts-as-list.js +11 -8
- package/src/database/record/attachments/store.js +15 -11
- package/src/database/record/auditing.js +12 -9
- package/src/database/record/counter-cache-magnitude.js +5 -3
- package/src/database/record/index.js +95 -14
- package/src/database/record/instance-relationships/belongs-to.js +4 -2
- package/src/database/record/instance-relationships/has-many.js +7 -5
- package/src/database/record/instance-relationships/has-one.js +4 -2
- package/src/database/record/validators/uniqueness.js +3 -2
- package/src/frontend-models/websocket-publishers.js +2 -2
- package/src/sync/server-sequence-allocator.js +43 -10
- package/src/sync/sync-client.js +6 -2
- package/src/sync/sync-publisher.js +10 -5
|
@@ -24,7 +24,7 @@ import WhereParser from "../query-parser/where-parser.js"
|
|
|
24
24
|
/**
|
|
25
25
|
* Defines this typedef.
|
|
26
26
|
* @template {typeof import("../record/index.js").default} [MC=typeof import("../record/index.js").default]
|
|
27
|
-
* @typedef {import("./index.js").QueryArgsType & {modelClass: MC, joinBasePath?: string[], joinTracker?: import("./join-tracker.js").default, forceQualifyBaseTable?: boolean, withCount?: import("./with-count.js").WithCountEntry[], queryData?: import("./query-data.js").QueryDataEntry[]}} ModelClassQueryArgsType
|
|
27
|
+
* @typedef {import("./index.js").QueryArgsType & {modelClass: MC, joinBasePath?: string[], joinTracker?: import("./join-tracker.js").default, forceQualifyBaseTable?: boolean, withCount?: import("./with-count.js").WithCountEntry[], queryData?: import("./query-data.js").QueryDataEntry[], operation?: import("../operation.js").default}} ModelClassQueryArgsType
|
|
28
28
|
*/
|
|
29
29
|
/**
|
|
30
30
|
* Runs unquote sql identifier.
|
|
@@ -200,6 +200,7 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
200
200
|
this._joinBasePath = args.joinBasePath || []
|
|
201
201
|
this._joinTracker = args.joinTracker || new JoinTracker({modelClass: this.modelClass})
|
|
202
202
|
this._forceQualifyBaseTable = Boolean(args.forceQualifyBaseTable)
|
|
203
|
+
this._operation = args.operation
|
|
203
204
|
|
|
204
205
|
/**
|
|
205
206
|
* Narrows the runtime value to the documented type.
|
|
@@ -240,7 +241,8 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
240
241
|
joinTracker: this._joinTracker.clone(),
|
|
241
242
|
forceQualifyBaseTable: this._forceQualifyBaseTable,
|
|
242
243
|
withCount: [...this._withCount],
|
|
243
|
-
queryData: [...this._queryData]
|
|
244
|
+
queryData: [...this._queryData],
|
|
245
|
+
operation: this._operation
|
|
244
246
|
}))
|
|
245
247
|
|
|
246
248
|
// @ts-expect-error
|
|
@@ -723,7 +725,11 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
723
725
|
* @returns {VelociousDatabaseQueryModelClassQuery<MC>} - The scoped join query.
|
|
724
726
|
*/
|
|
725
727
|
buildJoinScopeQuery(targetModelClass, joinPath) {
|
|
726
|
-
const scopedQuery = /** @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (
|
|
728
|
+
const scopedQuery = /** @type {VelociousDatabaseQueryModelClassQuery<MC>} */ (
|
|
729
|
+
this._operation
|
|
730
|
+
? this._operation.forModel(targetModelClass)
|
|
731
|
+
: targetModelClass._newQuery()
|
|
732
|
+
)
|
|
727
733
|
|
|
728
734
|
scopedQuery._joinTracker = this._joinTracker
|
|
729
735
|
scopedQuery._joinBasePath = joinPath
|
|
@@ -864,8 +870,7 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
864
870
|
|
|
865
871
|
if (record) return record
|
|
866
872
|
|
|
867
|
-
const
|
|
868
|
-
const newRecord = /** @type {InstanceType<MC>} */ (new ModelClass(conditions))
|
|
873
|
+
const newRecord = this.build(conditions)
|
|
869
874
|
|
|
870
875
|
if (callback) {
|
|
871
876
|
callback(newRecord)
|
|
@@ -874,6 +879,33 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
874
879
|
return newRecord
|
|
875
880
|
}
|
|
876
881
|
|
|
882
|
+
/**
|
|
883
|
+
* Builds a record owned by the query's operation, when present.
|
|
884
|
+
* @param {Record<string, ?>} [attributes] - Initial attributes.
|
|
885
|
+
* @returns {InstanceType<MC>} - Built record.
|
|
886
|
+
*/
|
|
887
|
+
build(attributes = {}) {
|
|
888
|
+
const ModelClass = this.getModelClass()
|
|
889
|
+
const record = /** @type {InstanceType<MC>} */ (new ModelClass(attributes))
|
|
890
|
+
|
|
891
|
+
if (this._operation) this._operation.bindRecord(record)
|
|
892
|
+
|
|
893
|
+
return record
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* Creates a record owned by the query's operation, when present.
|
|
898
|
+
* @param {Record<string, ?>} [attributes] - Initial attributes.
|
|
899
|
+
* @returns {Promise<InstanceType<MC>>} - Created record.
|
|
900
|
+
*/
|
|
901
|
+
async create(attributes = {}) {
|
|
902
|
+
const record = this.build(attributes)
|
|
903
|
+
|
|
904
|
+
await record.save()
|
|
905
|
+
|
|
906
|
+
return record
|
|
907
|
+
}
|
|
908
|
+
|
|
877
909
|
/**
|
|
878
910
|
* Runs first.
|
|
879
911
|
* @returns {Promise<InstanceType<MC> | null>} - Resolves with the first.
|
|
@@ -917,8 +949,7 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
|
|
|
917
949
|
const results = await this.results()
|
|
918
950
|
|
|
919
951
|
for (const result of results) {
|
|
920
|
-
const
|
|
921
|
-
const model = /** @type {InstanceType<MC>} */ (new ModelClass())
|
|
952
|
+
const model = this.build()
|
|
922
953
|
|
|
923
954
|
model.loadExistingRecord(result)
|
|
924
955
|
models.push(model)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import ensureModelClassInitialized from "./ensure-model-class-initialized.js"
|
|
4
4
|
import PreloaderSelection from "./selection.js"
|
|
5
|
+
import preloadQueryForModel from "./query-for-model.js"
|
|
5
6
|
import restArgsError from "../../../utils/rest-args-error.js"
|
|
6
7
|
|
|
7
8
|
export default class VelociousDatabaseQueryPreloaderBelongsTo {
|
|
@@ -94,7 +95,7 @@ export default class VelociousDatabaseQueryPreloaderBelongsTo {
|
|
|
94
95
|
whereArgs[primaryKey] = [...foreignKeyValues]
|
|
95
96
|
|
|
96
97
|
// Load target models to be preloaded on the given models
|
|
97
|
-
let query = targetModelClass.where(whereArgs)
|
|
98
|
+
let query = preloadQueryForModel(modelsToLoad, targetModelClass).where(whereArgs)
|
|
98
99
|
|
|
99
100
|
query = this.relationship.applyScope(query)
|
|
100
101
|
query = this.selection.applyToQuery({query, targetModelClass, mappingColumns: [primaryKey]})
|
|
@@ -211,7 +212,7 @@ export default class VelociousDatabaseQueryPreloaderBelongsTo {
|
|
|
211
212
|
|
|
212
213
|
whereArgs[primaryKey] = [...foreignKeyValuesByType[targetType]]
|
|
213
214
|
|
|
214
|
-
let query = targetModelClass.where(whereArgs)
|
|
215
|
+
let query = preloadQueryForModel(this.models, targetModelClass).where(whereArgs)
|
|
215
216
|
|
|
216
217
|
query = this.relationship.applyScope(query)
|
|
217
218
|
query = this.selection.applyToQuery({query, targetModelClass, mappingColumns: [primaryKey]})
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import ensureModelClassInitialized from "./ensure-model-class-initialized.js"
|
|
4
4
|
import PreloaderSelection from "./selection.js"
|
|
5
|
+
import preloadQueryForModel from "./query-for-model.js"
|
|
5
6
|
import restArgsError from "../../../utils/rest-args-error.js"
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -155,7 +156,7 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
|
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
// Step 1: Query the through table to build parent→target ID mapping
|
|
158
|
-
const throughModels = await throughModelClass
|
|
159
|
+
const throughModels = await preloadQueryForModel(modelsToLoad, throughModelClass)
|
|
159
160
|
.where({[throughForeignKey]: [...modelsPrimaryKeyValues]})
|
|
160
161
|
.toArray()
|
|
161
162
|
|
|
@@ -186,7 +187,7 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
|
|
|
186
187
|
let targetModels = []
|
|
187
188
|
|
|
188
189
|
if (allTargetIds.size > 0) {
|
|
189
|
-
let query = targetModelClass.where({[targetForeignKey]: [...allTargetIds]})
|
|
190
|
+
let query = preloadQueryForModel(modelsToLoad, targetModelClass).where({[targetForeignKey]: [...allTargetIds]})
|
|
190
191
|
|
|
191
192
|
query = this.relationship.applyScope(query)
|
|
192
193
|
query = this.selection.applyToQuery({query, targetModelClass, mappingColumns: [targetForeignKey]})
|
|
@@ -299,7 +300,7 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
|
|
|
299
300
|
|
|
300
301
|
await ensureModelClassInitialized(targetModelClass, this.relationship.getConfiguration())
|
|
301
302
|
|
|
302
|
-
let query = targetModelClass.where(whereArgs)
|
|
303
|
+
let query = preloadQueryForModel(modelsToLoad, targetModelClass).where(whereArgs)
|
|
303
304
|
|
|
304
305
|
query = this.relationship.applyScope(query)
|
|
305
306
|
query = this.selection.applyToQuery({query, targetModelClass, mappingColumns: [foreignKey]})
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import ensureModelClassInitialized from "./ensure-model-class-initialized.js"
|
|
4
4
|
import PreloaderSelection from "./selection.js"
|
|
5
|
+
import preloadQueryForModel from "./query-for-model.js"
|
|
5
6
|
import restArgsError from "../../../utils/rest-args-error.js"
|
|
6
7
|
|
|
7
8
|
export default class VelociousDatabaseQueryPreloaderHasOne {
|
|
@@ -87,7 +88,7 @@ export default class VelociousDatabaseQueryPreloaderHasOne {
|
|
|
87
88
|
await ensureModelClassInitialized(targetModelClass, this.relationship.getConfiguration())
|
|
88
89
|
|
|
89
90
|
// Load target models to be preloaded on the given models
|
|
90
|
-
let query = targetModelClass.where(whereArgs)
|
|
91
|
+
let query = preloadQueryForModel(this.models, targetModelClass).where(whereArgs)
|
|
91
92
|
|
|
92
93
|
query = this.relationship.applyScope(query)
|
|
93
94
|
query = this.selection.applyToQuery({query, targetModelClass, mappingColumns: [foreignKey]})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Builds a target query preserving the explicit database operation owned by
|
|
5
|
+
* the source records.
|
|
6
|
+
* @template {typeof import("../../record/index.js").default} MC
|
|
7
|
+
* @param {import("../../record/index.js").default[]} models - Source records.
|
|
8
|
+
* @param {MC} ModelClass - Target model class.
|
|
9
|
+
* @returns {import("../model-class-query.js").default<MC>} - Target query.
|
|
10
|
+
*/
|
|
11
|
+
export default function preloadQueryForModel(models, ModelClass) {
|
|
12
|
+
const sourceModel = models[0]
|
|
13
|
+
|
|
14
|
+
if (!sourceModel) throw new Error("Cannot build a preload query without source records")
|
|
15
|
+
|
|
16
|
+
return sourceModel.queryForModel(ModelClass)
|
|
17
|
+
}
|
|
@@ -190,7 +190,15 @@ export async function runQueryData({rootModelClass, rootModels, entries}) {
|
|
|
190
190
|
|
|
191
191
|
const primaryKey = rootModelClass.primaryKey()
|
|
192
192
|
const rootIds = rootModels.map((model) => /** @type {string | number} */ (model.readColumn(primaryKey)))
|
|
193
|
-
const
|
|
193
|
+
const sourceModel = rootModels[0]
|
|
194
|
+
const preparedEntries = entries.map((entry, entryIndex) => prepareEntry({
|
|
195
|
+
entry,
|
|
196
|
+
entryIndex,
|
|
197
|
+
primaryKey,
|
|
198
|
+
rootIds,
|
|
199
|
+
rootModelClass,
|
|
200
|
+
sourceModel
|
|
201
|
+
}))
|
|
194
202
|
/**
|
|
195
203
|
* Compatible query groups.
|
|
196
204
|
* @type {Array<{aliases: Set<string>, query: import("./model-class-query.js").default, signature: string}>} */
|
|
@@ -231,9 +239,10 @@ export async function runQueryData({rootModelClass, rootModels, entries}) {
|
|
|
231
239
|
* @param {string} args.primaryKey - Root model primary key column.
|
|
232
240
|
* @param {Array<string | number>} args.rootIds - Root primary-key values.
|
|
233
241
|
* @param {typeof import("../record/index.js").default} args.rootModelClass - Root model class.
|
|
242
|
+
* @param {import("../record/index.js").default} args.sourceModel - Loaded operation owner.
|
|
234
243
|
* @returns {{aliases: string[], query: import("./model-class-query.js").default, signature: string}} - Prepared entry.
|
|
235
244
|
*/
|
|
236
|
-
function prepareEntry({entry, entryIndex, primaryKey, rootIds, rootModelClass}) {
|
|
245
|
+
function prepareEntry({entry, entryIndex, primaryKey, rootIds, rootModelClass, sourceModel}) {
|
|
237
246
|
const targetModelClass = resolveTargetModelClass(rootModelClass, entry.chain)
|
|
238
247
|
const fn = targetModelClass.getQueryDataByName(entry.fnName)
|
|
239
248
|
|
|
@@ -242,7 +251,7 @@ function prepareEntry({entry, entryIndex, primaryKey, rootIds, rootModelClass})
|
|
|
242
251
|
`Declare it with ${targetModelClass.name}.queryData(${JSON.stringify(entry.fnName)}, ({query, tableName}) => query.select(...))`)
|
|
243
252
|
}
|
|
244
253
|
|
|
245
|
-
const query =
|
|
254
|
+
const query = sourceModel.queryForModel(rootModelClass)
|
|
246
255
|
|
|
247
256
|
// Empty out any defaults the query factory added — queryData runs
|
|
248
257
|
// a bare aggregate, not a full model load.
|
|
@@ -111,10 +111,11 @@ export async function runWithCount({models, modelClass, entries}) {
|
|
|
111
111
|
|
|
112
112
|
const primaryKey = modelClass.primaryKey()
|
|
113
113
|
const parentIds = models.map((model) => /** @type {string | number} */ (model.readColumn(primaryKey)))
|
|
114
|
+
const sourceModel = models[0]
|
|
114
115
|
const queryGroups = new Map()
|
|
115
116
|
|
|
116
117
|
for (const entry of entries) {
|
|
117
|
-
const countQuery = queryForEntry({entry, modelClass, parentIds})
|
|
118
|
+
const countQuery = queryForEntry({entry, modelClass, parentIds, sourceModel})
|
|
118
119
|
const sql = countQuery.toSql()
|
|
119
120
|
const existingGroup = queryGroups.get(sql)
|
|
120
121
|
|
|
@@ -138,9 +139,10 @@ export async function runWithCount({models, modelClass, entries}) {
|
|
|
138
139
|
* @param {WithCountEntry} args.entry - Entry being evaluated.
|
|
139
140
|
* @param {typeof import("../record/index.js").default} args.modelClass - Parent model class.
|
|
140
141
|
* @param {Array<string | number>} args.parentIds - Primary keys of the loaded parents.
|
|
142
|
+
* @param {import("../record/index.js").default} args.sourceModel - Loaded operation owner.
|
|
141
143
|
* @returns {import("./model-class-query.js").default} - Prepared count query.
|
|
142
144
|
*/
|
|
143
|
-
function queryForEntry({entry, modelClass, parentIds}) {
|
|
145
|
+
function queryForEntry({entry, modelClass, parentIds, sourceModel}) {
|
|
144
146
|
const relationship = modelClass.getRelationshipByName(entry.relationshipName)
|
|
145
147
|
|
|
146
148
|
if (!relationship) {
|
|
@@ -172,7 +174,7 @@ function queryForEntry({entry, modelClass, parentIds}) {
|
|
|
172
174
|
Object.assign(whereConditions, entry.where)
|
|
173
175
|
}
|
|
174
176
|
|
|
175
|
-
const baseQuery =
|
|
177
|
+
const baseQuery = sourceModel.queryForModel(targetModelClass)
|
|
176
178
|
baseQuery._forceQualifyBaseTable = true
|
|
177
179
|
baseQuery.where(whereConditions)
|
|
178
180
|
|
|
@@ -173,7 +173,7 @@ function assertPositivePosition({position, positionColumn, persisted = false}) {
|
|
|
173
173
|
*/
|
|
174
174
|
async function placeMovedRecord({record, positionColumn, scope, scopeValue, position}) {
|
|
175
175
|
const modelClass = /** @type {typeof import("./index.js").default} */ (record.constructor)
|
|
176
|
-
const connection =
|
|
176
|
+
const connection = record.connection()
|
|
177
177
|
const tableSql = connection.quoteTable(modelClass._getTable().getName())
|
|
178
178
|
const scopeCol = modelClass.getColumnNameForAttributeName(scope)
|
|
179
179
|
const posCol = modelClass.getColumnNameForAttributeName(positionColumn)
|
|
@@ -224,7 +224,7 @@ function clearBelongsToChangeForScope(record) {
|
|
|
224
224
|
*/
|
|
225
225
|
async function shiftPositionsUp({record, positionColumn, scope, fromPosition, toPosition, scopeValue, excludeRecordId}) {
|
|
226
226
|
const modelClass = /** @type {typeof import("./index.js").default} */ (record.constructor)
|
|
227
|
-
const connection =
|
|
227
|
+
const connection = record.connection()
|
|
228
228
|
const tableName = modelClass._getTable().getName()
|
|
229
229
|
const resolvedScopeValue = scopeValue != null ? scopeValue : resolveScopeValue(record, scope)
|
|
230
230
|
const scopeColumnName = modelClass.getColumnNameForAttributeName(scope)
|
|
@@ -239,7 +239,8 @@ async function shiftPositionsUp({record, positionColumn, scope, fromPosition, to
|
|
|
239
239
|
const quotedScope = connection.quote(resolvedScopeValue)
|
|
240
240
|
|
|
241
241
|
// Load rows in descending order so we bump the highest first
|
|
242
|
-
let query =
|
|
242
|
+
let query = record
|
|
243
|
+
.queryForModel(modelClass)
|
|
243
244
|
.select(modelClass.primaryKey())
|
|
244
245
|
.select(positionColumn)
|
|
245
246
|
.where({[scopeColumnName]: resolvedScopeValue})
|
|
@@ -289,7 +290,7 @@ async function shiftPositionsUp({record, positionColumn, scope, fromPosition, to
|
|
|
289
290
|
*/
|
|
290
291
|
async function shiftPositionsDown({record, positionColumn, scope, fromPosition, toPosition, scopeValue}) {
|
|
291
292
|
const modelClass = /** @type {typeof import("./index.js").default} */ (record.constructor)
|
|
292
|
-
const connection =
|
|
293
|
+
const connection = record.connection()
|
|
293
294
|
const tableName = modelClass._getTable().getName()
|
|
294
295
|
const resolvedScopeValue = scopeValue != null ? scopeValue : resolveScopeValue(record, scope)
|
|
295
296
|
const scopeColumnName = modelClass.getColumnNameForAttributeName(scope)
|
|
@@ -304,7 +305,8 @@ async function shiftPositionsDown({record, positionColumn, scope, fromPosition,
|
|
|
304
305
|
const quotedScope = connection.quote(resolvedScopeValue)
|
|
305
306
|
|
|
306
307
|
// Load rows in ascending order so we shift the lowest gap first
|
|
307
|
-
let query =
|
|
308
|
+
let query = record
|
|
309
|
+
.queryForModel(modelClass)
|
|
308
310
|
.select(modelClass.primaryKey())
|
|
309
311
|
.select(positionColumn)
|
|
310
312
|
.where({[scopeColumnName]: resolvedScopeValue})
|
|
@@ -345,7 +347,7 @@ async function shiftPositionsDown({record, positionColumn, scope, fromPosition,
|
|
|
345
347
|
*/
|
|
346
348
|
async function highestPositionInScope({record, positionColumn, scope, scopeValue}) {
|
|
347
349
|
const modelClass = /** @type {typeof import("./index.js").default} */ (record.constructor)
|
|
348
|
-
const connection =
|
|
350
|
+
const connection = record.connection()
|
|
349
351
|
const scopeColumnName = modelClass.getColumnNameForAttributeName(scope)
|
|
350
352
|
const positionColumnName = modelClass.getColumnNameForAttributeName(positionColumn)
|
|
351
353
|
const positionColumnSql = connection.quoteColumn(positionColumnName)
|
|
@@ -353,7 +355,8 @@ async function highestPositionInScope({record, positionColumn, scope, scopeValue
|
|
|
353
355
|
|
|
354
356
|
if (resolvedScopeValue == null) return 0
|
|
355
357
|
|
|
356
|
-
const rows = await
|
|
358
|
+
const rows = await record
|
|
359
|
+
.queryForModel(modelClass)
|
|
357
360
|
.select(positionColumn)
|
|
358
361
|
.where({[scopeColumnName]: resolvedScopeValue})
|
|
359
362
|
.order(`${positionColumnSql} DESC`)
|
|
@@ -415,7 +418,7 @@ function resolveScopeValue(record, scope) {
|
|
|
415
418
|
*/
|
|
416
419
|
async function moveOutOfWay({record, positionColumn, scope, scopeValue}) {
|
|
417
420
|
const modelClass = /** @type {typeof import("./index.js").default} */ (record.constructor)
|
|
418
|
-
const connection =
|
|
421
|
+
const connection = record.connection()
|
|
419
422
|
const tableName = modelClass._getTable().getName()
|
|
420
423
|
const resolvedScopeValue = scopeValue != null ? scopeValue : resolveScopeValue(record, scope)
|
|
421
424
|
|
|
@@ -88,9 +88,10 @@ export default class RecordAttachmentsStore {
|
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
90
|
* Runs ensure ready.
|
|
91
|
+
* @param {import("../index.js").default} [model] - Operation-owning model.
|
|
91
92
|
* @returns {Promise<void>} - Resolves when schema is ready.
|
|
92
93
|
*/
|
|
93
|
-
async ensureReady() {
|
|
94
|
+
async ensureReady(model) {
|
|
94
95
|
if (this._readyPromise) {
|
|
95
96
|
await this._readyPromise
|
|
96
97
|
return
|
|
@@ -124,7 +125,7 @@ export default class RecordAttachmentsStore {
|
|
|
124
125
|
await db.createTable(table)
|
|
125
126
|
this._driverColumnsAvailable = true
|
|
126
127
|
this._contentBase64Nullable = true
|
|
127
|
-
})
|
|
128
|
+
}, model)
|
|
128
129
|
})()
|
|
129
130
|
|
|
130
131
|
try {
|
|
@@ -144,7 +145,7 @@ export default class RecordAttachmentsStore {
|
|
|
144
145
|
* @returns {Promise<void>} - Resolves when complete.
|
|
145
146
|
*/
|
|
146
147
|
async attach({input, model, name, replace}) {
|
|
147
|
-
await this.ensureReady()
|
|
148
|
+
await this.ensureReady(model)
|
|
148
149
|
const attachmentsConfiguration = this.configuration.getAttachmentsConfiguration?.() || {}
|
|
149
150
|
const allowPathInput = attachmentsConfiguration.allowPathInput === true
|
|
150
151
|
const allowedPathPrefixes = Array.isArray(attachmentsConfiguration.allowedPathPrefixes)
|
|
@@ -298,7 +299,7 @@ export default class RecordAttachmentsStore {
|
|
|
298
299
|
})
|
|
299
300
|
|
|
300
301
|
rowPersisted = true
|
|
301
|
-
})
|
|
302
|
+
}, model)
|
|
302
303
|
} catch (error) {
|
|
303
304
|
if (!rowPersisted && storageKey && typeof attachmentDriver.delete === "function") {
|
|
304
305
|
try {
|
|
@@ -435,7 +436,7 @@ export default class RecordAttachmentsStore {
|
|
|
435
436
|
* @returns {Promise<Record<string, ?> | null>} - Attachment row.
|
|
436
437
|
*/
|
|
437
438
|
async findOne({id, model, name}) {
|
|
438
|
-
await this.ensureReady()
|
|
439
|
+
await this.ensureReady(model)
|
|
439
440
|
|
|
440
441
|
return await this._withDb(async (db) => {
|
|
441
442
|
const recordType = model.getModelClass().getModelName()
|
|
@@ -455,7 +456,7 @@ export default class RecordAttachmentsStore {
|
|
|
455
456
|
const rows = await query.results()
|
|
456
457
|
|
|
457
458
|
return rows[0] || null
|
|
458
|
-
})
|
|
459
|
+
}, model)
|
|
459
460
|
}
|
|
460
461
|
|
|
461
462
|
/**
|
|
@@ -466,7 +467,7 @@ export default class RecordAttachmentsStore {
|
|
|
466
467
|
* @returns {Promise<Array<Record<string, ?>>>} - Attachment rows.
|
|
467
468
|
*/
|
|
468
469
|
async findMany({model, name}) {
|
|
469
|
-
await this.ensureReady()
|
|
470
|
+
await this.ensureReady(model)
|
|
470
471
|
|
|
471
472
|
return await this._withDb(async (db) => {
|
|
472
473
|
const recordType = model.getModelClass().getModelName()
|
|
@@ -479,7 +480,7 @@ export default class RecordAttachmentsStore {
|
|
|
479
480
|
.order("created_at_ms ASC")
|
|
480
481
|
|
|
481
482
|
return await query.results()
|
|
482
|
-
})
|
|
483
|
+
}, model)
|
|
483
484
|
}
|
|
484
485
|
|
|
485
486
|
/**
|
|
@@ -517,7 +518,7 @@ export default class RecordAttachmentsStore {
|
|
|
517
518
|
* @returns {Promise<number>} - Number of attachments purged.
|
|
518
519
|
*/
|
|
519
520
|
async purgeAll({model, name}) {
|
|
520
|
-
await this.ensureReady()
|
|
521
|
+
await this.ensureReady(model)
|
|
521
522
|
|
|
522
523
|
return await this._withDb(async (db) => {
|
|
523
524
|
const recordType = model.getModelClass().getModelName()
|
|
@@ -549,7 +550,7 @@ export default class RecordAttachmentsStore {
|
|
|
549
550
|
}
|
|
550
551
|
|
|
551
552
|
return rows.length
|
|
552
|
-
})
|
|
553
|
+
}, model)
|
|
553
554
|
}
|
|
554
555
|
|
|
555
556
|
/**
|
|
@@ -732,9 +733,12 @@ export default class RecordAttachmentsStore {
|
|
|
732
733
|
* Runs with db.
|
|
733
734
|
* @template T
|
|
734
735
|
* @param {(db: import("../../../database/drivers/base.js").default) => Promise<T>} callback - Callback.
|
|
736
|
+
* @param {import("../index.js").default} [model] - Operation-owning model.
|
|
735
737
|
* @returns {Promise<T>} - Callback result.
|
|
736
738
|
*/
|
|
737
|
-
async _withDb(callback) {
|
|
739
|
+
async _withDb(callback, model) {
|
|
740
|
+
if (model && model.databaseOperation()) return await callback(model.connection())
|
|
741
|
+
|
|
738
742
|
const pool = this.configuration.getDatabasePool(this.databaseIdentifier)
|
|
739
743
|
/**
|
|
740
744
|
* Defines result.
|
|
@@ -148,18 +148,20 @@ function dedicatedAuditTableName(modelClass) {
|
|
|
148
148
|
* Resolves audit table data for a model class. Cached per model.
|
|
149
149
|
* Called lazily on first createAudit / withoutAudit / relationship usage.
|
|
150
150
|
* @param {AuditedModelClass} modelClass - Audited model class.
|
|
151
|
+
* @param {import("../drivers/base.js").default} [connection] - Explicit record-owned connection.
|
|
151
152
|
* @returns {Promise<AuditTableData>} Resolved audit table metadata.
|
|
152
153
|
*/
|
|
153
|
-
async function resolveAuditTableData(modelClass) {
|
|
154
|
+
async function resolveAuditTableData(modelClass, connection) {
|
|
154
155
|
if (modelClass._auditTableResolved && modelClass._auditTableData) {
|
|
155
156
|
return modelClass._auditTableData
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
const
|
|
159
|
+
const resolvedConnection = connection || modelClass.connection()
|
|
160
|
+
const tableData = await buildAuditTableData(modelClass, resolvedConnection)
|
|
159
161
|
const configuration = modelClass._getConfiguration()
|
|
160
162
|
|
|
161
163
|
tableData.auditClass.registerRecordClass({configuration})
|
|
162
|
-
await tableData.auditClass.initializeRecord({configuration})
|
|
164
|
+
await tableData.auditClass.initializeRecord({configuration, connection: resolvedConnection})
|
|
163
165
|
|
|
164
166
|
modelClass._auditTableData = tableData
|
|
165
167
|
modelClass._auditTableResolved = true
|
|
@@ -174,11 +176,12 @@ async function resolveAuditTableData(modelClass) {
|
|
|
174
176
|
* registered Audit model for shared tables; falls back to a framework-owned
|
|
175
177
|
* dynamic class.
|
|
176
178
|
* @param {AuditedModelClass} modelClass - Audited model class.
|
|
179
|
+
* @param {import("../drivers/base.js").default} connection - Explicit record-owned connection.
|
|
177
180
|
* @returns {Promise<AuditTableData>} Audit table metadata.
|
|
178
181
|
*/
|
|
179
|
-
async function buildAuditTableData(modelClass) {
|
|
182
|
+
async function buildAuditTableData(modelClass, connection) {
|
|
180
183
|
const dedicatedTable = dedicatedAuditTableName(modelClass)
|
|
181
|
-
const dedicatedExists = await dedicatedTableExistsForConnection(modelClass, dedicatedTable)
|
|
184
|
+
const dedicatedExists = await dedicatedTableExistsForConnection(modelClass, dedicatedTable, connection)
|
|
182
185
|
|
|
183
186
|
if (dedicatedExists) {
|
|
184
187
|
const auditClass = dedicatedAuditClass(modelClass, dedicatedTable)
|
|
@@ -217,9 +220,10 @@ async function buildAuditTableData(modelClass) {
|
|
|
217
220
|
* Checks whether a dedicated audit table exists for a model's connection.
|
|
218
221
|
* @param {AuditedModelClass} modelClass - Audited model class.
|
|
219
222
|
* @param {string} tableName - Dedicated audit table name to check.
|
|
223
|
+
* @param {import("../drivers/base.js").default} connection - Explicit record-owned connection.
|
|
220
224
|
* @returns {Promise<boolean>} Whether the table exists.
|
|
221
225
|
*/
|
|
222
|
-
async function dedicatedTableExistsForConnection(modelClass, tableName) {
|
|
226
|
+
async function dedicatedTableExistsForConnection(modelClass, tableName, connection) {
|
|
223
227
|
const databaseIdentifier = modelClass.getDatabaseIdentifier()
|
|
224
228
|
const cacheKey = `${databaseIdentifier}:${tableName}`
|
|
225
229
|
const cached = dedicatedTableCache.get(cacheKey)
|
|
@@ -228,7 +232,6 @@ async function dedicatedTableExistsForConnection(modelClass, tableName) {
|
|
|
228
232
|
return cached
|
|
229
233
|
}
|
|
230
234
|
|
|
231
|
-
const connection = modelClass.connection()
|
|
232
235
|
const table = await connection.getTableByName(tableName, {throwError: false})
|
|
233
236
|
const exists = Boolean(table)
|
|
234
237
|
|
|
@@ -546,11 +549,11 @@ async function createAudit(record, args) {
|
|
|
546
549
|
async function createAuditWithCurrentConnection(record, args, modelClass) {
|
|
547
550
|
if (!record.isPersisted()) throw new Error(`Cannot audit unpersisted ${modelClass.getModelName()} record`)
|
|
548
551
|
|
|
549
|
-
const
|
|
552
|
+
const db = record.connection()
|
|
553
|
+
const tableData = await resolveAuditTableData(modelClass, db)
|
|
550
554
|
const action = normalizeAction(args.action)
|
|
551
555
|
const auditedChanges = args.auditedChanges === undefined ? null : args.auditedChanges
|
|
552
556
|
const params = args.params === undefined ? null : args.params
|
|
553
|
-
const db = modelClass.connection()
|
|
554
557
|
const currentDate = new Date()
|
|
555
558
|
|
|
556
559
|
const auditActionId = await findOrCreateLookupId({
|
|
@@ -204,9 +204,11 @@ async function incrementParentCounter(record, definition, parentId, amount) {
|
|
|
204
204
|
throw new Error(`magnitudeCounterCache on ${modelClass.getModelName()} could not resolve the "${definition.belongsTo}" parent model class`)
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
const db =
|
|
207
|
+
// Resolve through the record so an operation both owns the parent write and
|
|
208
|
+
// rejects a relationship whose parent routes to another database.
|
|
209
|
+
const db = record
|
|
210
|
+
.queryForModel(parentModelClass)
|
|
211
|
+
.driver
|
|
210
212
|
const counterColumnSql = db.quoteColumn(definition.counterColumn)
|
|
211
213
|
const truncatedAmount = Math.trunc(amount)
|
|
212
214
|
|