velocious 1.0.568 → 1.0.569
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 +20 -0
- package/build/configuration.js +36 -0
- package/build/database/drivers/base.js +167 -54
- 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 +110 -0
- package/build/database/operation-lease.js +47 -0
- package/build/database/operation.js +140 -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 +66 -20
- package/build/src/database/drivers/base.d.ts.map +1 -1
- package/build/src/database/drivers/base.js +158 -54
- 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 +61 -0
- package/build/src/database/operation-connection.d.ts.map +1 -0
- package/build/src/database/operation-connection.js +93 -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 +77 -0
- package/build/src/database/operation.d.ts.map +1 -0
- package/build/src/database/operation.js +123 -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 +167 -54
- 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 +110 -0
- package/src/database/operation-lease.js +47 -0
- package/src/database/operation.js +140 -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
|
@@ -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
|
|
|
@@ -444,6 +444,11 @@ class VelociousDatabaseRecord {
|
|
|
444
444
|
* @type {import("../drivers/base.js").default | undefined} */
|
|
445
445
|
__connection = undefined
|
|
446
446
|
|
|
447
|
+
/**
|
|
448
|
+
* Explicit operation owning this record's database work.
|
|
449
|
+
* @type {import("../operation.js").default | undefined} */
|
|
450
|
+
_databaseOperation = undefined
|
|
451
|
+
|
|
447
452
|
/**
|
|
448
453
|
* Instance relationships.
|
|
449
454
|
* @type {Record<string, import("./instance-relationships/base.js").default>} */
|
|
@@ -863,9 +868,10 @@ class VelociousDatabaseRecord {
|
|
|
863
868
|
* single UPDATE ... SET col = (SELECT COUNT(*)) so concurrent
|
|
864
869
|
* creates/destroys cannot race into a stale count.
|
|
865
870
|
* @param {number | string | null} parentId - Parent primary-key value.
|
|
871
|
+
* @param {VelociousDatabaseRecord} record - Child record owning the connection.
|
|
866
872
|
* @returns {Promise<void>} - Resolves when the counter cache has been synced.
|
|
867
873
|
*/
|
|
868
|
-
async function syncCounter(parentId) {
|
|
874
|
+
async function syncCounter(parentId, record) {
|
|
869
875
|
if (!parentId) return
|
|
870
876
|
|
|
871
877
|
const relationship = ChildModel.getRelationshipByName(relationshipName)
|
|
@@ -880,7 +886,9 @@ class VelociousDatabaseRecord {
|
|
|
880
886
|
const parentTable = ParentModel.tableName()
|
|
881
887
|
const childTable = ChildModel.tableName()
|
|
882
888
|
const pkColumn = inflection.underscore(primaryKey)
|
|
883
|
-
const connection =
|
|
889
|
+
const connection = record
|
|
890
|
+
.queryForModel(ParentModel)
|
|
891
|
+
.driver
|
|
884
892
|
const quoted = connection.quote(parentId)
|
|
885
893
|
|
|
886
894
|
const sql = `UPDATE ${connection.quoteTable(parentTable)} SET ${connection.quoteColumn(counterColumn)} = (SELECT COUNT(*) FROM ${connection.quoteTable(childTable)} WHERE ${connection.quoteColumn(fk)} = ${quoted}) WHERE ${connection.quoteColumn(pkColumn)} = ${quoted}`
|
|
@@ -901,11 +909,11 @@ class VelociousDatabaseRecord {
|
|
|
901
909
|
}
|
|
902
910
|
|
|
903
911
|
ChildModel.afterCreate(async (record) => {
|
|
904
|
-
await syncCounter(readFkAttribute(record))
|
|
912
|
+
await syncCounter(readFkAttribute(record), record)
|
|
905
913
|
})
|
|
906
914
|
|
|
907
915
|
ChildModel.afterDestroy(async (record) => {
|
|
908
|
-
await syncCounter(readFkAttribute(record))
|
|
916
|
+
await syncCounter(readFkAttribute(record), record)
|
|
909
917
|
})
|
|
910
918
|
|
|
911
919
|
ChildModel.beforeSave(async (record) => {
|
|
@@ -932,8 +940,8 @@ class VelociousDatabaseRecord {
|
|
|
932
940
|
|
|
933
941
|
if (previousParentId !== undefined) {
|
|
934
942
|
delete model[prevKey]
|
|
935
|
-
await syncCounter(previousParentId)
|
|
936
|
-
await syncCounter(readFkAttribute(model))
|
|
943
|
+
await syncCounter(previousParentId, record)
|
|
944
|
+
await syncCounter(readFkAttribute(model), record)
|
|
937
945
|
}
|
|
938
946
|
})
|
|
939
947
|
}
|
|
@@ -1452,15 +1460,16 @@ class VelociousDatabaseRecord {
|
|
|
1452
1460
|
* Runs initialize record.
|
|
1453
1461
|
* @param {object} args - Options object.
|
|
1454
1462
|
* @param {import("../../configuration.js").default} args.configuration - Configuration instance.
|
|
1463
|
+
* @param {import("../drivers/base.js").default} [args.connection] - Explicit metadata connection.
|
|
1455
1464
|
* @returns {Promise<void>} - Resolves when complete.
|
|
1456
1465
|
*/
|
|
1457
|
-
static async initializeRecord({configuration, ...restArgs}) {
|
|
1466
|
+
static async initializeRecord({configuration, connection: explicitConnection, ...restArgs}) {
|
|
1458
1467
|
restArgsError(restArgs)
|
|
1459
1468
|
|
|
1460
1469
|
if (!configuration) throw new Error(`No configuration given for ${this.name}`)
|
|
1461
1470
|
|
|
1462
1471
|
this.registerRecordClass({configuration})
|
|
1463
|
-
const connection = this.connection({enforceTenantDatabaseScope: false})
|
|
1472
|
+
const connection = explicitConnection || this.connection({enforceTenantDatabaseScope: false})
|
|
1464
1473
|
|
|
1465
1474
|
this._databaseType = connection.getType()
|
|
1466
1475
|
|
|
@@ -2427,7 +2436,7 @@ class VelociousDatabaseRecord {
|
|
|
2427
2436
|
await this._runLifecycleCallbacks("beforeValidation")
|
|
2428
2437
|
await this._runValidations()
|
|
2429
2438
|
|
|
2430
|
-
|
|
2439
|
+
const saveInTransaction = async () => {
|
|
2431
2440
|
await this._runLifecycleCallbacks("beforeSave")
|
|
2432
2441
|
|
|
2433
2442
|
// If any belongs-to-relationships was saved, then updated-at should still be set on this record.
|
|
@@ -2454,7 +2463,13 @@ class VelociousDatabaseRecord {
|
|
|
2454
2463
|
await this._autoSaveAttachments()
|
|
2455
2464
|
await this._runLifecycleCallbacks("afterSave")
|
|
2456
2465
|
await this._emitRecordChangeAfterCommit(isNewRecord ? "create" : "update")
|
|
2457
|
-
}
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
if (this._databaseOperation) {
|
|
2469
|
+
await this._databaseOperation.transaction(saveInTransaction)
|
|
2470
|
+
} else {
|
|
2471
|
+
await this.getModelClass().transaction(saveInTransaction)
|
|
2472
|
+
}
|
|
2458
2473
|
})
|
|
2459
2474
|
|
|
2460
2475
|
this._assignedAttributeNames = undefined
|
|
@@ -2481,6 +2496,7 @@ class VelociousDatabaseRecord {
|
|
|
2481
2496
|
if (model) {
|
|
2482
2497
|
if (model instanceof VelociousDatabaseRecord) {
|
|
2483
2498
|
if (model.isChanged()) {
|
|
2499
|
+
this.bindRelatedRecord(model)
|
|
2484
2500
|
await model.save()
|
|
2485
2501
|
|
|
2486
2502
|
const foreignKey = this._relationshipForeignKeyAttribute(instanceRelationship)
|
|
@@ -2539,6 +2555,7 @@ class VelociousDatabaseRecord {
|
|
|
2539
2555
|
|
|
2540
2556
|
if (loaded) {
|
|
2541
2557
|
for (const model of loaded) {
|
|
2558
|
+
this.bindRelatedRecord(model)
|
|
2542
2559
|
const foreignKey = model._relationshipForeignKeyAttribute(instanceRelationship)
|
|
2543
2560
|
|
|
2544
2561
|
model.setAttribute(foreignKey, this.id())
|
|
@@ -2592,6 +2609,7 @@ class VelociousDatabaseRecord {
|
|
|
2592
2609
|
}
|
|
2593
2610
|
|
|
2594
2611
|
for (const model of loaded) {
|
|
2612
|
+
this.bindRelatedRecord(model)
|
|
2595
2613
|
const foreignKey = model._relationshipForeignKeyAttribute(instanceRelationship)
|
|
2596
2614
|
|
|
2597
2615
|
model.setAttribute(foreignKey, this.id())
|
|
@@ -3021,15 +3039,18 @@ class VelociousDatabaseRecord {
|
|
|
3021
3039
|
* Runs new query.
|
|
3022
3040
|
* @template {typeof VelociousDatabaseRecord} MC
|
|
3023
3041
|
* @this {MC}
|
|
3042
|
+
* @param {{driver?: import("../drivers/base.js").default | (() => import("../drivers/base.js").default), operation?: import("../operation.js").default}} [args] - Explicit query ownership.
|
|
3024
3043
|
* @returns {ModelClassQuery<MC>} - The new query.
|
|
3025
3044
|
*/
|
|
3026
|
-
static _newQuery() {
|
|
3045
|
+
static _newQuery({driver = () => this.connection(), operation, ...restArgs} = {}) {
|
|
3046
|
+
restArgsError(restArgs)
|
|
3027
3047
|
this._assertHasBeenInitialized()
|
|
3028
3048
|
const handler = new Handler()
|
|
3029
3049
|
const query = new ModelClassQuery({
|
|
3030
|
-
driver
|
|
3050
|
+
driver,
|
|
3031
3051
|
handler,
|
|
3032
|
-
modelClass: this
|
|
3052
|
+
modelClass: this,
|
|
3053
|
+
operation
|
|
3033
3054
|
})
|
|
3034
3055
|
|
|
3035
3056
|
return query.from(new FromTable(this.tableName()))
|
|
@@ -3416,6 +3437,53 @@ class VelociousDatabaseRecord {
|
|
|
3416
3437
|
}
|
|
3417
3438
|
}
|
|
3418
3439
|
|
|
3440
|
+
/**
|
|
3441
|
+
* Binds future query, lifecycle, relationship, and persistence work to an operation.
|
|
3442
|
+
* @param {import("../operation.js").default} operation - Owning operation.
|
|
3443
|
+
* @returns {this} - Bound record.
|
|
3444
|
+
*/
|
|
3445
|
+
bindDatabaseOperation(operation) {
|
|
3446
|
+
if (this._databaseOperation && this._databaseOperation !== operation) {
|
|
3447
|
+
throw new Error("Record is already bound to another database operation")
|
|
3448
|
+
}
|
|
3449
|
+
|
|
3450
|
+
this._databaseOperation = operation
|
|
3451
|
+
|
|
3452
|
+
return this
|
|
3453
|
+
}
|
|
3454
|
+
|
|
3455
|
+
/**
|
|
3456
|
+
* Returns the explicit operation owning this record, if any.
|
|
3457
|
+
* @returns {import("../operation.js").default | undefined} - Owning operation.
|
|
3458
|
+
*/
|
|
3459
|
+
databaseOperation() {
|
|
3460
|
+
return this._databaseOperation
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
/**
|
|
3464
|
+
* Binds a related record to the same operation as this record.
|
|
3465
|
+
* @template {VelociousDatabaseRecord} Model
|
|
3466
|
+
* @param {Model} record - Related record.
|
|
3467
|
+
* @returns {Model} - Related record.
|
|
3468
|
+
*/
|
|
3469
|
+
bindRelatedRecord(record) {
|
|
3470
|
+
if (this._databaseOperation) this._databaseOperation.bindRecord(record)
|
|
3471
|
+
|
|
3472
|
+
return record
|
|
3473
|
+
}
|
|
3474
|
+
|
|
3475
|
+
/**
|
|
3476
|
+
* Builds a model query preserving this record's operation ownership.
|
|
3477
|
+
* @template {typeof VelociousDatabaseRecord} MC
|
|
3478
|
+
* @param {MC} ModelClass - Target model class.
|
|
3479
|
+
* @returns {ModelClassQuery<MC>} - Target query.
|
|
3480
|
+
*/
|
|
3481
|
+
queryForModel(ModelClass) {
|
|
3482
|
+
if (this._databaseOperation) return this._databaseOperation.forModel(ModelClass)
|
|
3483
|
+
|
|
3484
|
+
return ModelClass._newQuery()
|
|
3485
|
+
}
|
|
3486
|
+
|
|
3419
3487
|
/**
|
|
3420
3488
|
* Runs load existing record.
|
|
3421
3489
|
* @param {object} attributes - Attributes.
|
|
@@ -3473,11 +3541,20 @@ class VelociousDatabaseRecord {
|
|
|
3473
3541
|
* @returns {import("../drivers/base.js").default} - The connection.
|
|
3474
3542
|
*/
|
|
3475
3543
|
_connection() {
|
|
3544
|
+
if (this._databaseOperation) return this._databaseOperation.connection()
|
|
3476
3545
|
if (this.__connection) return this.__connection
|
|
3477
3546
|
|
|
3478
3547
|
return this.getModelClass().connection()
|
|
3479
3548
|
}
|
|
3480
3549
|
|
|
3550
|
+
/**
|
|
3551
|
+
* Returns the connection that owns this record's database work.
|
|
3552
|
+
* @returns {import("../drivers/base.js").default} - Connection.
|
|
3553
|
+
*/
|
|
3554
|
+
connection() {
|
|
3555
|
+
return this._connection()
|
|
3556
|
+
}
|
|
3557
|
+
|
|
3481
3558
|
/**
|
|
3482
3559
|
* Counts dependent records for a `dependent: "restrict"` relationship.
|
|
3483
3560
|
* @param {RestrictInstanceRelationship} instanceRelationship - Relationship instance to count.
|
|
@@ -4374,7 +4451,11 @@ class VelociousDatabaseRecord {
|
|
|
4374
4451
|
|
|
4375
4452
|
whereObject[primaryKey] = id
|
|
4376
4453
|
|
|
4377
|
-
const query = /** @type {import("../query/model-class-query.js").default<MC>} */ (
|
|
4454
|
+
const query = /** @type {import("../query/model-class-query.js").default<MC>} */ (
|
|
4455
|
+
this
|
|
4456
|
+
.queryForModel(this.getModelClass())
|
|
4457
|
+
.where(whereObject)
|
|
4458
|
+
)
|
|
4378
4459
|
const reloadedModel = await query.first()
|
|
4379
4460
|
|
|
4380
4461
|
if (!reloadedModel) throw new Error(`${this.constructor.name}#${id} couldn't be reloaded - record didn't exist`)
|