velocious 1.0.567 → 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 +49 -1
- package/build/configuration.js +36 -0
- package/build/database/drivers/base-table.js +4 -3
- package/build/database/drivers/base.js +195 -54
- package/build/database/drivers/index-metadata.js +28 -0
- package/build/database/drivers/mssql/column.js +2 -34
- package/build/database/drivers/mssql/columns-index.js +37 -0
- package/build/database/drivers/mssql/index.js +10 -7
- package/build/database/drivers/mssql/table.js +55 -11
- package/build/database/drivers/mysql/index.js +10 -5
- package/build/database/drivers/mysql/sql/alter-table.js +13 -0
- package/build/database/drivers/pgsql/column.js +2 -27
- package/build/database/drivers/pgsql/columns-index.js +37 -0
- package/build/database/drivers/pgsql/index.js +4 -4
- package/build/database/drivers/pgsql/table.js +61 -10
- 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/drivers/sqlite/sql/alter-table.js +18 -0
- package/build/database/migration/index.js +92 -3
- 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/alter-table-base.js +20 -1
- 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/normalize-input.js +38 -10
- package/build/database/record/attachments/storage-drivers/filesystem.js +33 -2
- package/build/database/record/attachments/storage-drivers/native.js +17 -2
- package/build/database/record/attachments/storage-drivers/s3.js +27 -7
- package/build/database/record/attachments/store.js +173 -53
- 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/database/table-data/table-foreign-key.js +9 -1
- package/build/environment-handlers/base.js +1 -1
- package/build/environment-handlers/node/attachment-path-source.js +144 -0
- package/build/environment-handlers/node.js +28 -3
- 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-table.d.ts.map +1 -1
- package/build/src/database/drivers/base-table.js +4 -3
- package/build/src/database/drivers/base.d.ts +73 -20
- package/build/src/database/drivers/base.d.ts.map +1 -1
- package/build/src/database/drivers/base.js +181 -54
- package/build/src/database/drivers/index-metadata.d.ts +41 -0
- package/build/src/database/drivers/index-metadata.d.ts.map +1 -0
- package/build/src/database/drivers/index-metadata.js +26 -0
- package/build/src/database/drivers/mssql/column.d.ts.map +1 -1
- package/build/src/database/drivers/mssql/column.js +3 -31
- package/build/src/database/drivers/mssql/columns-index.d.ts +41 -0
- package/build/src/database/drivers/mssql/columns-index.d.ts.map +1 -1
- package/build/src/database/drivers/mssql/columns-index.js +35 -1
- 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/mssql/table.d.ts +42 -0
- package/build/src/database/drivers/mssql/table.d.ts.map +1 -1
- package/build/src/database/drivers/mssql/table.js +49 -12
- 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/mysql/sql/alter-table.d.ts.map +1 -1
- package/build/src/database/drivers/mysql/sql/alter-table.js +12 -1
- package/build/src/database/drivers/pgsql/column.d.ts.map +1 -1
- package/build/src/database/drivers/pgsql/column.js +3 -24
- package/build/src/database/drivers/pgsql/columns-index.d.ts +41 -0
- package/build/src/database/drivers/pgsql/columns-index.d.ts.map +1 -1
- package/build/src/database/drivers/pgsql/columns-index.js +35 -1
- 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/pgsql/table.d.ts +42 -0
- package/build/src/database/drivers/pgsql/table.d.ts.map +1 -1
- package/build/src/database/drivers/pgsql/table.js +54 -11
- 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/drivers/sqlite/sql/alter-table.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/sql/alter-table.js +15 -1
- package/build/src/database/migration/index.d.ts +35 -1
- package/build/src/database/migration/index.d.ts.map +1 -1
- package/build/src/database/migration/index.js +78 -4
- 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/alter-table-base.d.ts +6 -0
- package/build/src/database/query/alter-table-base.d.ts.map +1 -1
- package/build/src/database/query/alter-table-base.js +18 -2
- 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/normalize-input.d.ts +33 -4
- package/build/src/database/record/attachments/normalize-input.d.ts.map +1 -1
- package/build/src/database/record/attachments/normalize-input.js +39 -11
- package/build/src/database/record/attachments/storage-drivers/filesystem.d.ts +2 -5
- package/build/src/database/record/attachments/storage-drivers/filesystem.d.ts.map +1 -1
- package/build/src/database/record/attachments/storage-drivers/filesystem.js +28 -3
- package/build/src/database/record/attachments/storage-drivers/native.d.ts +2 -6
- package/build/src/database/record/attachments/storage-drivers/native.d.ts.map +1 -1
- package/build/src/database/record/attachments/storage-drivers/native.js +14 -3
- package/build/src/database/record/attachments/storage-drivers/s3.d.ts +2 -6
- package/build/src/database/record/attachments/storage-drivers/s3.d.ts.map +1 -1
- package/build/src/database/record/attachments/storage-drivers/s3.js +29 -8
- package/build/src/database/record/attachments/store.d.ts +31 -2
- package/build/src/database/record/attachments/store.d.ts.map +1 -1
- package/build/src/database/record/attachments/store.js +158 -54
- 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/database/table-data/table-foreign-key.d.ts +9 -1
- package/build/src/database/table-data/table-foreign-key.d.ts.map +1 -1
- package/build/src/database/table-data/table-foreign-key.js +9 -2
- package/build/src/environment-handlers/base.d.ts +2 -5
- package/build/src/environment-handlers/base.d.ts.map +1 -1
- package/build/src/environment-handlers/base.js +2 -2
- package/build/src/environment-handlers/node/attachment-path-source.d.ts +64 -0
- package/build/src/environment-handlers/node/attachment-path-source.d.ts.map +1 -0
- package/build/src/environment-handlers/node/attachment-path-source.js +116 -0
- package/build/src/environment-handlers/node.d.ts +12 -0
- package/build/src/environment-handlers/node.d.ts.map +1 -1
- package/build/src/environment-handlers/node.js +24 -4
- 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-table.js +4 -3
- package/src/database/drivers/base.js +195 -54
- package/src/database/drivers/index-metadata.js +28 -0
- package/src/database/drivers/mssql/column.js +2 -34
- package/src/database/drivers/mssql/columns-index.js +37 -0
- package/src/database/drivers/mssql/index.js +10 -7
- package/src/database/drivers/mssql/table.js +55 -11
- package/src/database/drivers/mysql/index.js +10 -5
- package/src/database/drivers/mysql/sql/alter-table.js +13 -0
- package/src/database/drivers/pgsql/column.js +2 -27
- package/src/database/drivers/pgsql/columns-index.js +37 -0
- package/src/database/drivers/pgsql/index.js +4 -4
- package/src/database/drivers/pgsql/table.js +61 -10
- 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/drivers/sqlite/sql/alter-table.js +18 -0
- package/src/database/migration/index.js +92 -3
- 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/alter-table-base.js +20 -1
- 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/normalize-input.js +38 -10
- package/src/database/record/attachments/storage-drivers/filesystem.js +33 -2
- package/src/database/record/attachments/storage-drivers/native.js +17 -2
- package/src/database/record/attachments/storage-drivers/s3.js +27 -7
- package/src/database/record/attachments/store.js +173 -53
- 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/database/table-data/table-foreign-key.js +9 -1
- package/src/environment-handlers/base.js +1 -1
- package/src/environment-handlers/node/attachment-path-source.js +144 -0
- package/src/environment-handlers/node.js +28 -3
- 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
|
@@ -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)
|
|
@@ -156,65 +157,181 @@ export default class RecordAttachmentsStore {
|
|
|
156
157
|
allowedPathPrefixes,
|
|
157
158
|
environmentHandler: this.configuration.getEnvironmentHandler()
|
|
158
159
|
})
|
|
160
|
+
/**
|
|
161
|
+
* Attachment persistence error.
|
|
162
|
+
* This stays opaque so any JavaScript thrown value is preserved exactly.
|
|
163
|
+
* @type {unknown} */
|
|
164
|
+
let persistenceError = null
|
|
165
|
+
let persistenceFailed = false
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const persistenceInput = await this.persistenceInputFor(normalizedInput)
|
|
169
|
+
|
|
170
|
+
await this.persistNormalizedAttachment({
|
|
171
|
+
model,
|
|
172
|
+
name,
|
|
173
|
+
normalizedInput: persistenceInput,
|
|
174
|
+
replace
|
|
175
|
+
})
|
|
176
|
+
} catch (error) {
|
|
177
|
+
persistenceFailed = true
|
|
178
|
+
persistenceError = error
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (normalizedInput.pathSource) {
|
|
182
|
+
try {
|
|
183
|
+
await normalizedInput.pathSource.close()
|
|
184
|
+
} catch (closeError) {
|
|
185
|
+
if (persistenceFailed) {
|
|
186
|
+
throw new AggregateError(
|
|
187
|
+
[persistenceError, closeError],
|
|
188
|
+
`Attachment persistence and path-source close both failed for ${model.getModelClass().getModelName()}#${String(model.id())} (${name})`,
|
|
189
|
+
{cause: closeError}
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
throw closeError
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (persistenceFailed) throw persistenceError
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Materializes path content once when a legacy schema requires Base64.
|
|
202
|
+
* @param {import("./normalize-input.js").NormalizedAttachmentInput} normalizedInput - Normalized attachment input.
|
|
203
|
+
* @returns {Promise<import("./normalize-input.js").NormalizedAttachmentInput>} - Input used by the driver and database.
|
|
204
|
+
*/
|
|
205
|
+
async persistenceInputFor(normalizedInput) {
|
|
206
|
+
if (this._contentBase64Nullable || !normalizedInput.pathSource) return normalizedInput
|
|
207
|
+
|
|
208
|
+
const contentBuffer = await normalizedInput.pathSource.readBuffer()
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
...normalizedInput,
|
|
212
|
+
contentBase64: contentBuffer.toString("base64"),
|
|
213
|
+
contentBuffer,
|
|
214
|
+
pathSource: null
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Persists one normalized attachment while its path source remains open.
|
|
220
|
+
* @param {object} args - Options.
|
|
221
|
+
* @param {import("../index.js").default} args.model - Model instance.
|
|
222
|
+
* @param {string} args.name - Attachment name.
|
|
223
|
+
* @param {import("./normalize-input.js").NormalizedAttachmentInput} args.normalizedInput - Normalized attachment.
|
|
224
|
+
* @param {boolean} args.replace - Whether to replace existing attachments.
|
|
225
|
+
* @returns {Promise<void>} - Resolves after persistence.
|
|
226
|
+
*/
|
|
227
|
+
async persistNormalizedAttachment({model, name, normalizedInput, replace}) {
|
|
159
228
|
const attachmentDriver = await this.resolveAttachmentDriver({model, name})
|
|
160
229
|
const attachmentDriverName = this._attachmentDriverNameFor({model, name})
|
|
161
230
|
const now = Date.now()
|
|
162
231
|
const recordType = model.getModelClass().getModelName()
|
|
163
232
|
const recordId = String(model.id())
|
|
164
233
|
const attachmentId = generateUUID()
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Written storage key.
|
|
236
|
+
* @type {string | null} */
|
|
237
|
+
let storageKey = null
|
|
238
|
+
let rowPersisted = false
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
const writeResult = await attachmentDriver.write({
|
|
242
|
+
attachmentId,
|
|
243
|
+
input: normalizedInput,
|
|
244
|
+
model,
|
|
245
|
+
name
|
|
246
|
+
})
|
|
171
247
|
|
|
172
|
-
|
|
173
|
-
if (replace) {
|
|
174
|
-
const existingRows = await db
|
|
175
|
-
.newQuery()
|
|
176
|
-
.from(ATTACHMENTS_TABLE)
|
|
177
|
-
.where({name, record_id: recordId, record_type: recordType})
|
|
178
|
-
.results()
|
|
248
|
+
storageKey = writeResult.storageKey
|
|
179
249
|
|
|
180
|
-
|
|
181
|
-
|
|
250
|
+
// Current schemas keep content_base64 nullable and avoid duplicating
|
|
251
|
+
// driver-backed content. Legacy path input was materialized once before
|
|
252
|
+
// the driver write so this value describes those exact persisted bytes.
|
|
253
|
+
const databaseContentBase64 = await this.databaseContentBase64For(normalizedInput)
|
|
254
|
+
|
|
255
|
+
await this._withDb(async (db) => {
|
|
256
|
+
if (replace) {
|
|
257
|
+
const existingRows = await db
|
|
258
|
+
.newQuery()
|
|
259
|
+
.from(ATTACHMENTS_TABLE)
|
|
260
|
+
.where({name, record_id: recordId, record_type: recordType})
|
|
261
|
+
.results()
|
|
262
|
+
|
|
263
|
+
for (const existingRow of existingRows) {
|
|
264
|
+
await this.deleteAttachmentRowStorage({model, name, row: existingRow})
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
await db.delete({
|
|
268
|
+
conditions: {name, record_id: recordId, record_type: recordType},
|
|
269
|
+
tableName: ATTACHMENTS_TABLE
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const position = replace ? 0 : await this._nextPosition({db, name, recordId, recordType})
|
|
274
|
+
/**
|
|
275
|
+
* Insert data.
|
|
276
|
+
* @type {Record<string, ?>} */
|
|
277
|
+
const insertData = {
|
|
278
|
+
byte_size: normalizedInput.byteSize,
|
|
279
|
+
content_base64: databaseContentBase64,
|
|
280
|
+
content_type: normalizedInput.contentType,
|
|
281
|
+
created_at_ms: now,
|
|
282
|
+
filename: normalizedInput.filename,
|
|
283
|
+
id: attachmentId,
|
|
284
|
+
name,
|
|
285
|
+
position,
|
|
286
|
+
record_id: recordId,
|
|
287
|
+
record_type: recordType,
|
|
288
|
+
updated_at_ms: now
|
|
182
289
|
}
|
|
183
290
|
|
|
184
|
-
|
|
185
|
-
|
|
291
|
+
if (this._driverColumnsAvailable) {
|
|
292
|
+
insertData.driver = attachmentDriverName
|
|
293
|
+
insertData.storage_key = storageKey
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
await db.insert({
|
|
297
|
+
data: insertData,
|
|
186
298
|
tableName: ATTACHMENTS_TABLE
|
|
187
299
|
})
|
|
188
|
-
}
|
|
189
300
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
301
|
+
rowPersisted = true
|
|
302
|
+
}, model)
|
|
303
|
+
} catch (error) {
|
|
304
|
+
if (!rowPersisted && storageKey && typeof attachmentDriver.delete === "function") {
|
|
305
|
+
try {
|
|
306
|
+
await attachmentDriver.delete({
|
|
307
|
+
model,
|
|
308
|
+
name,
|
|
309
|
+
row: {id: attachmentId, storage_key: storageKey},
|
|
310
|
+
storageKey
|
|
311
|
+
})
|
|
312
|
+
} catch (cleanupError) {
|
|
313
|
+
throw new AggregateError(
|
|
314
|
+
[error, cleanupError],
|
|
315
|
+
`Attachment write finalization and new-storage cleanup both failed for ${recordType}#${recordId} (${name})`,
|
|
316
|
+
{cause: cleanupError}
|
|
317
|
+
)
|
|
318
|
+
}
|
|
206
319
|
}
|
|
207
320
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
321
|
+
throw error
|
|
322
|
+
}
|
|
323
|
+
}
|
|
212
324
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
325
|
+
/**
|
|
326
|
+
* Resolves the database content_base64 value for current and legacy schemas.
|
|
327
|
+
* @param {import("./normalize-input.js").NormalizedAttachmentInput} normalizedInput - Normalized attachment input.
|
|
328
|
+
* @returns {Promise<string | null>} - Nullable or legacy Base64 database value.
|
|
329
|
+
*/
|
|
330
|
+
async databaseContentBase64For(normalizedInput) {
|
|
331
|
+
if (this._contentBase64Nullable) return null
|
|
332
|
+
if (normalizedInput.contentBase64 !== null) return normalizedInput.contentBase64
|
|
333
|
+
|
|
334
|
+
throw new Error("Legacy attachment schema requires materialized content bytes")
|
|
218
335
|
}
|
|
219
336
|
|
|
220
337
|
/**
|
|
@@ -319,7 +436,7 @@ export default class RecordAttachmentsStore {
|
|
|
319
436
|
* @returns {Promise<Record<string, ?> | null>} - Attachment row.
|
|
320
437
|
*/
|
|
321
438
|
async findOne({id, model, name}) {
|
|
322
|
-
await this.ensureReady()
|
|
439
|
+
await this.ensureReady(model)
|
|
323
440
|
|
|
324
441
|
return await this._withDb(async (db) => {
|
|
325
442
|
const recordType = model.getModelClass().getModelName()
|
|
@@ -339,7 +456,7 @@ export default class RecordAttachmentsStore {
|
|
|
339
456
|
const rows = await query.results()
|
|
340
457
|
|
|
341
458
|
return rows[0] || null
|
|
342
|
-
})
|
|
459
|
+
}, model)
|
|
343
460
|
}
|
|
344
461
|
|
|
345
462
|
/**
|
|
@@ -350,7 +467,7 @@ export default class RecordAttachmentsStore {
|
|
|
350
467
|
* @returns {Promise<Array<Record<string, ?>>>} - Attachment rows.
|
|
351
468
|
*/
|
|
352
469
|
async findMany({model, name}) {
|
|
353
|
-
await this.ensureReady()
|
|
470
|
+
await this.ensureReady(model)
|
|
354
471
|
|
|
355
472
|
return await this._withDb(async (db) => {
|
|
356
473
|
const recordType = model.getModelClass().getModelName()
|
|
@@ -363,7 +480,7 @@ export default class RecordAttachmentsStore {
|
|
|
363
480
|
.order("created_at_ms ASC")
|
|
364
481
|
|
|
365
482
|
return await query.results()
|
|
366
|
-
})
|
|
483
|
+
}, model)
|
|
367
484
|
}
|
|
368
485
|
|
|
369
486
|
/**
|
|
@@ -401,7 +518,7 @@ export default class RecordAttachmentsStore {
|
|
|
401
518
|
* @returns {Promise<number>} - Number of attachments purged.
|
|
402
519
|
*/
|
|
403
520
|
async purgeAll({model, name}) {
|
|
404
|
-
await this.ensureReady()
|
|
521
|
+
await this.ensureReady(model)
|
|
405
522
|
|
|
406
523
|
return await this._withDb(async (db) => {
|
|
407
524
|
const recordType = model.getModelClass().getModelName()
|
|
@@ -433,7 +550,7 @@ export default class RecordAttachmentsStore {
|
|
|
433
550
|
}
|
|
434
551
|
|
|
435
552
|
return rows.length
|
|
436
|
-
})
|
|
553
|
+
}, model)
|
|
437
554
|
}
|
|
438
555
|
|
|
439
556
|
/**
|
|
@@ -616,9 +733,12 @@ export default class RecordAttachmentsStore {
|
|
|
616
733
|
* Runs with db.
|
|
617
734
|
* @template T
|
|
618
735
|
* @param {(db: import("../../../database/drivers/base.js").default) => Promise<T>} callback - Callback.
|
|
736
|
+
* @param {import("../index.js").default} [model] - Operation-owning model.
|
|
619
737
|
* @returns {Promise<T>} - Callback result.
|
|
620
738
|
*/
|
|
621
|
-
async _withDb(callback) {
|
|
739
|
+
async _withDb(callback, model) {
|
|
740
|
+
if (model && model.databaseOperation()) return await callback(model.connection())
|
|
741
|
+
|
|
622
742
|
const pool = this.configuration.getDatabasePool(this.databaseIdentifier)
|
|
623
743
|
/**
|
|
624
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`)
|
|
@@ -27,7 +27,9 @@ export default class VelociousDatabaseRecordBelongsToInstanceRelationship extend
|
|
|
27
27
|
|
|
28
28
|
if (!TargetModelClass) throw new Error("Can't build a new record without a target model")
|
|
29
29
|
|
|
30
|
-
const newInstance =
|
|
30
|
+
const newInstance = this.getModel().bindRelatedRecord(
|
|
31
|
+
/** @type {InstanceType<TMC>} */ (new TargetModelClass(data))
|
|
32
|
+
)
|
|
31
33
|
|
|
32
34
|
this._loaded = newInstance
|
|
33
35
|
|
|
@@ -85,7 +87,7 @@ export default class VelociousDatabaseRecordBelongsToInstanceRelationship extend
|
|
|
85
87
|
|
|
86
88
|
whereArgs[primaryKey] = foreignModelID
|
|
87
89
|
|
|
88
|
-
const query = this.applyScope(TargetModelClass.where(whereArgs))
|
|
90
|
+
const query = this.applyScope(this.getModel().queryForModel(TargetModelClass).where(whereArgs))
|
|
89
91
|
|
|
90
92
|
const foreignModel = await query.first()
|
|
91
93
|
|