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
|
@@ -64,6 +64,80 @@ export default class VelociousDatabaseDriversSqliteWeb extends Base {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Starts an outer transaction after draining SQL.js persistence admission.
|
|
69
|
+
* @param {Pick<import("../base.js").QueryOptions, "operationOwner">} [options] - Transaction ownership.
|
|
70
|
+
* @returns {Promise<void>} - Resolves when the transaction starts.
|
|
71
|
+
*/
|
|
72
|
+
async startTransaction(options = {}) {
|
|
73
|
+
if (!this.args?.getConnection) {
|
|
74
|
+
if (!this._connection) throw new Error("SQLite web connection has not been initialized")
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
await super.startTransaction(options)
|
|
78
|
+
} finally {
|
|
79
|
+
this._connection.completeTransactionStart()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
await super.startTransaction(options)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Coordinates SQL BEGIN with active and queued persistence exports.
|
|
90
|
+
* @param {Pick<import("../base.js").QueryOptions, "operationOwner">} [options] - Transaction ownership.
|
|
91
|
+
* @returns {Promise<void>} - Resolves when the transaction starts.
|
|
92
|
+
*/
|
|
93
|
+
async _startTransactionAction(options = {}) {
|
|
94
|
+
if (!this.args?.getConnection) {
|
|
95
|
+
if (!this._connection) throw new Error("SQLite web connection has not been initialized")
|
|
96
|
+
|
|
97
|
+
await this._connection.withTransactionStart(async () => {
|
|
98
|
+
await super._startTransactionAction(options)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
await super._startTransactionAction(options)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Commits and persists bytes after the outermost SQL.js transaction closes.
|
|
109
|
+
* @param {Pick<import("../base.js").QueryOptions, "operationOwner">} [options] - Transaction ownership.
|
|
110
|
+
* @returns {Promise<void>} - Resolves when committed bytes are persisted.
|
|
111
|
+
*/
|
|
112
|
+
async commitTransaction(options = {}) {
|
|
113
|
+
const outermostTransaction = this._transactionsCount === 1
|
|
114
|
+
|
|
115
|
+
await super.commitTransaction(options)
|
|
116
|
+
|
|
117
|
+
if (outermostTransaction && !this.args?.getConnection) {
|
|
118
|
+
if (!this._connection) throw new Error("SQLite web connection has not been initialized")
|
|
119
|
+
|
|
120
|
+
await this._connection.flushPendingDatabaseSave()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Rolls back and persists bytes after the outermost SQL.js transaction closes.
|
|
126
|
+
* @param {Pick<import("../base.js").QueryOptions, "operationOwner">} [options] - Transaction ownership.
|
|
127
|
+
* @returns {Promise<void>} - Resolves when rolled-back bytes are persisted.
|
|
128
|
+
*/
|
|
129
|
+
async rollbackTransaction(options = {}) {
|
|
130
|
+
const outermostTransaction = this._transactionsCount === 1
|
|
131
|
+
|
|
132
|
+
await super.rollbackTransaction(options)
|
|
133
|
+
|
|
134
|
+
if (outermostTransaction && !this.args?.getConnection) {
|
|
135
|
+
if (!this._connection) throw new Error("SQLite web connection has not been initialized")
|
|
136
|
+
|
|
137
|
+
await this._connection.flushPendingDatabaseSave()
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
67
141
|
/**
|
|
68
142
|
* Runs get connection.
|
|
69
143
|
* @returns {ConnectionSqlJs | SqliteWebConnection} - The connection.
|
|
@@ -134,6 +134,16 @@ export default class VelociousDatabaseConnectionDriversSqliteSqlAlterTable exten
|
|
|
134
134
|
|
|
135
135
|
for (const currentForeignKey of currentTableData.getForeignKeys()) {
|
|
136
136
|
const alterForeignKey = alterTableData.getForeignKeys().find((foreignKey) => foreignKey.getName() == currentForeignKey.getName())
|
|
137
|
+
|
|
138
|
+
if (alterForeignKey?.getDropForeignKey()) {
|
|
139
|
+
const targetColumnName = columnRenames.get(currentForeignKey.getColumnName()) || currentForeignKey.getColumnName()
|
|
140
|
+
const targetColumn = targetTableData.getColumns().find((column) => column.getActualName() == targetColumnName)
|
|
141
|
+
|
|
142
|
+
if (targetColumn) targetColumn.setForeignKey(undefined)
|
|
143
|
+
|
|
144
|
+
continue
|
|
145
|
+
}
|
|
146
|
+
|
|
137
147
|
const finalForeignKey = this._renameForeignKeyColumn(alterForeignKey || currentForeignKey, columnRenames)
|
|
138
148
|
|
|
139
149
|
seenForeignKeyNames.add(finalForeignKey.getName())
|
|
@@ -141,11 +151,14 @@ export default class VelociousDatabaseConnectionDriversSqliteSqlAlterTable exten
|
|
|
141
151
|
}
|
|
142
152
|
|
|
143
153
|
for (const alterForeignKey of alterTableData.getForeignKeys()) {
|
|
154
|
+
if (alterForeignKey.getDropForeignKey()) continue
|
|
144
155
|
if (seenForeignKeyNames.has(alterForeignKey.getName())) continue
|
|
145
156
|
|
|
146
157
|
targetTableData.addForeignKey(this._renameForeignKeyColumn(alterForeignKey, columnRenames))
|
|
147
158
|
}
|
|
148
159
|
|
|
160
|
+
const targetColumnNames = new Set(targetTableData.getColumns().map((column) => column.getActualName()))
|
|
161
|
+
|
|
149
162
|
for (const currentIndex of currentTableData.getIndexes()) {
|
|
150
163
|
const renamedColumns = currentIndex.getColumns().map((columnName) => {
|
|
151
164
|
if (typeof columnName != "string") return columnName
|
|
@@ -153,6 +166,10 @@ export default class VelociousDatabaseConnectionDriversSqliteSqlAlterTable exten
|
|
|
153
166
|
return columnRenames.get(columnName) || columnName
|
|
154
167
|
})
|
|
155
168
|
|
|
169
|
+
const indexColumnNames = renamedColumns.map((column) => typeof column == "string" ? column : column.getName())
|
|
170
|
+
|
|
171
|
+
if (indexColumnNames.some((columnName) => !targetColumnNames.has(columnName))) continue
|
|
172
|
+
|
|
156
173
|
targetTableData.addIndex(new TableIndex(renamedColumns, {
|
|
157
174
|
name: currentIndex.getName(),
|
|
158
175
|
unique: currentIndex.getUnique()
|
|
@@ -177,6 +194,7 @@ export default class VelociousDatabaseConnectionDriversSqliteSqlAlterTable exten
|
|
|
177
194
|
|
|
178
195
|
return new TableForeignKey({
|
|
179
196
|
columnName: renamed,
|
|
197
|
+
dropForeignKey: foreignKey.getDropForeignKey(),
|
|
180
198
|
isNewForeignKey: foreignKey.getIsNewForeignKey(),
|
|
181
199
|
name: foreignKey.getName(),
|
|
182
200
|
referencedColumnName: foreignKey.getReferencedColumnName(),
|
|
@@ -270,6 +270,57 @@ export default class VelociousDatabaseMigration {
|
|
|
270
270
|
)
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
+
/**
|
|
274
|
+
* RemoveForeignKeyArgsType type.
|
|
275
|
+
* @typedef {object} RemoveForeignKeyArgsType
|
|
276
|
+
* @property {string} [columnName] - Override the derived foreign-key column name.
|
|
277
|
+
*/
|
|
278
|
+
/**
|
|
279
|
+
* Runs remove foreign key.
|
|
280
|
+
* @param {string} tableName - Table the foreign key lives on.
|
|
281
|
+
* @param {string} referenceName - Singular reference name used to derive the FK column.
|
|
282
|
+
* @param {RemoveForeignKeyArgsType} [args] - Optional overrides.
|
|
283
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
284
|
+
*/
|
|
285
|
+
async removeForeignKey(tableName, referenceName, args = {}) {
|
|
286
|
+
const {columnName, ...restArgs} = args
|
|
287
|
+
|
|
288
|
+
restArgsError(restArgs)
|
|
289
|
+
|
|
290
|
+
const resolvedColumnName = columnName || `${inflection.underscore(referenceName)}_id`
|
|
291
|
+
const driver = this.getDriver()
|
|
292
|
+
let maximumRemovals = 0
|
|
293
|
+
let previousMatchingCount = 0
|
|
294
|
+
|
|
295
|
+
for (let removalAttempt = 0; ; removalAttempt++) {
|
|
296
|
+
const table = await driver.getTableByName(tableName)
|
|
297
|
+
|
|
298
|
+
if (!table) throw new Error(`Table ${tableName} does not exist`)
|
|
299
|
+
|
|
300
|
+
const foreignKeys = await table.getForeignKeys()
|
|
301
|
+
const matchingForeignKeys = foreignKeys.filter((foreignKey) => foreignKey.getColumnName() == resolvedColumnName)
|
|
302
|
+
|
|
303
|
+
if (matchingForeignKeys.length === 0) {
|
|
304
|
+
if (removalAttempt === 0) throw new Error(`No foreign key on ${tableName}.${resolvedColumnName}`)
|
|
305
|
+
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (removalAttempt === 0) {
|
|
310
|
+
maximumRemovals = matchingForeignKeys.length
|
|
311
|
+
} else if (matchingForeignKeys.length >= previousMatchingCount) {
|
|
312
|
+
throw new Error(`Foreign key removal did not reduce matches on ${tableName}.${resolvedColumnName}`)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (removalAttempt >= maximumRemovals) {
|
|
316
|
+
throw new Error(`Foreign key removal exceeded expected matches on ${tableName}.${resolvedColumnName}`)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
previousMatchingCount = matchingForeignKeys.length
|
|
320
|
+
await driver.removeForeignKey(tableName, matchingForeignKeys[0])
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
273
324
|
/**
|
|
274
325
|
* Runs add reference.
|
|
275
326
|
* @param {string} tableName - Table name.
|
|
@@ -298,16 +349,54 @@ export default class VelociousDatabaseMigration {
|
|
|
298
349
|
}
|
|
299
350
|
}
|
|
300
351
|
|
|
352
|
+
/**
|
|
353
|
+
* RemoveReferenceArgsType type.
|
|
354
|
+
* @typedef {object} RemoveReferenceArgsType
|
|
355
|
+
* @property {string} [columnName] - Override the derived reference column name.
|
|
356
|
+
* @property {string} [indexName] - Explicit generated index name to remove.
|
|
357
|
+
*/
|
|
301
358
|
/**
|
|
302
359
|
* Runs remove reference.
|
|
303
360
|
* @param {string} tableName - Table name.
|
|
304
361
|
* @param {string} referenceName - Reference name.
|
|
362
|
+
* @param {RemoveReferenceArgsType} [args] - Optional overrides.
|
|
305
363
|
* @returns {Promise<void>} - Resolves when complete.
|
|
306
364
|
*/
|
|
307
|
-
async removeReference(tableName, referenceName) {
|
|
308
|
-
const columnName =
|
|
365
|
+
async removeReference(tableName, referenceName, args = {}) {
|
|
366
|
+
const {columnName, indexName, ...restArgs} = args
|
|
367
|
+
|
|
368
|
+
restArgsError(restArgs)
|
|
369
|
+
|
|
370
|
+
const resolvedColumnName = columnName || `${inflection.underscore(referenceName)}_id`
|
|
371
|
+
const driver = this.getDriver()
|
|
372
|
+
const table = await driver.getTableByName(tableName)
|
|
373
|
+
|
|
374
|
+
if (!table) throw new Error(`Table ${tableName} does not exist`)
|
|
375
|
+
|
|
376
|
+
const foreignKeys = await table.getForeignKeys()
|
|
377
|
+
|
|
378
|
+
for (const foreignKey of foreignKeys) {
|
|
379
|
+
if (foreignKey.getColumnName() != resolvedColumnName) continue
|
|
380
|
+
|
|
381
|
+
await driver.removeForeignKey(tableName, foreignKey)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const expectedIndexName = indexName || this._removeIndexName(tableName, [resolvedColumnName])
|
|
385
|
+
const indexes = await table.getIndexes()
|
|
386
|
+
const generatedIndex = indexes.find((index) => {
|
|
387
|
+
const indexColumnNames = index.getColumnNames()
|
|
388
|
+
|
|
389
|
+
return !index.isPrimaryKey() &&
|
|
390
|
+
index.getName() == expectedIndexName &&
|
|
391
|
+
indexColumnNames.length == 1 &&
|
|
392
|
+
indexColumnNames[0] == resolvedColumnName
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
if (generatedIndex) {
|
|
396
|
+
await this.removeIndex(tableName, generatedIndex.getName())
|
|
397
|
+
}
|
|
309
398
|
|
|
310
|
-
this.removeColumn(tableName,
|
|
399
|
+
await this.removeColumn(tableName, resolvedColumnName)
|
|
311
400
|
}
|
|
312
401
|
|
|
313
402
|
/**
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Explicit connection facade that tags operation-owned asynchronous work while
|
|
5
|
+
* forwarding the driver's synchronous SQL-builder and capability APIs.
|
|
6
|
+
*/
|
|
7
|
+
export default class VelociousDatabaseOperationConnection {
|
|
8
|
+
/**
|
|
9
|
+
* Runs constructor.
|
|
10
|
+
* @param {object} args - Connection ownership.
|
|
11
|
+
* @param {import("./drivers/base.js").default} args.connection - Pinned physical connection.
|
|
12
|
+
* @param {import("./operation.js").default} args.operation - Owning operation.
|
|
13
|
+
* @param {symbol} args.owner - Opaque lease owner token.
|
|
14
|
+
*/
|
|
15
|
+
constructor({connection, operation, owner}) {
|
|
16
|
+
this._physicalConnection = connection
|
|
17
|
+
this._operation = operation
|
|
18
|
+
this._owner = owner
|
|
19
|
+
|
|
20
|
+
return new Proxy(this, {
|
|
21
|
+
get: (target, property, receiver) => {
|
|
22
|
+
if (Reflect.has(target, property)) {
|
|
23
|
+
const value = Reflect.get(target, property, receiver)
|
|
24
|
+
|
|
25
|
+
return typeof value === "function" ? value.bind(target) : value
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const value = Reflect.get(connection, property, receiver)
|
|
29
|
+
|
|
30
|
+
return typeof value === "function" ? value.bind(receiver) : value
|
|
31
|
+
},
|
|
32
|
+
set: (target, property, value, receiver) => {
|
|
33
|
+
if (Reflect.has(target, property)) {
|
|
34
|
+
return Reflect.set(target, property, value, receiver)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return Reflect.set(connection, property, value, connection)
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Runs a tagged SQL query on the pinned connection.
|
|
44
|
+
* @param {string} sql - SQL string.
|
|
45
|
+
* @param {import("./drivers/base.js").QueryOptions} [options] - Query options.
|
|
46
|
+
* @returns {Promise<import("./drivers/base.js").QueryResultType>} - Query result.
|
|
47
|
+
*/
|
|
48
|
+
async query(sql, options = {}) {
|
|
49
|
+
this._operation.assertActive()
|
|
50
|
+
|
|
51
|
+
return await this._physicalConnection.query(sql, {...options, operationOwner: this._owner})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Streams an operation-owned SQL query.
|
|
56
|
+
* @param {string} sql - SQL string.
|
|
57
|
+
* @param {import("./drivers/base.js").QueryOptions} [options] - Query options.
|
|
58
|
+
* @yields {Record<string, unknown>} - Query rows.
|
|
59
|
+
*/
|
|
60
|
+
async *queryStream(sql, options = {}) {
|
|
61
|
+
this._operation.assertActive()
|
|
62
|
+
|
|
63
|
+
yield* this._physicalConnection.queryStream(sql, {...options, operationOwner: this._owner})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Executes an operation-owned mutation and returns its affected row count.
|
|
68
|
+
* @param {string} sql - Mutation SQL string.
|
|
69
|
+
* @param {import("./drivers/base.js").QueryOptions} [options] - Query options.
|
|
70
|
+
* @returns {Promise<number>} - Affected row count.
|
|
71
|
+
*/
|
|
72
|
+
async affectedRows(sql, options = {}) {
|
|
73
|
+
this._operation.assertActive()
|
|
74
|
+
|
|
75
|
+
return await this._physicalConnection.affectedRows(sql, {...options, operationOwner: this._owner})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Runs an operation-owned transaction or nested savepoint.
|
|
80
|
+
* @template T
|
|
81
|
+
* @param {() => Promise<T>} callback - Transaction callback.
|
|
82
|
+
* @returns {Promise<T>} - Callback result.
|
|
83
|
+
*/
|
|
84
|
+
async transaction(callback) {
|
|
85
|
+
this._operation.assertActive()
|
|
86
|
+
|
|
87
|
+
return /** @type {Promise<T>} */ (this._physicalConnection.transaction(callback, {operationOwner: this._owner}))
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Registers an operation-owned after-commit callback.
|
|
92
|
+
* @param {() => void | Promise<void>} callback - Callback.
|
|
93
|
+
* @returns {Promise<void>} - Resolves after registration or execution.
|
|
94
|
+
*/
|
|
95
|
+
async afterCommit(callback) {
|
|
96
|
+
this._operation.assertActive()
|
|
97
|
+
|
|
98
|
+
await this._physicalConnection.afterCommit(callback, {operationOwner: this._owner})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Returns the last inserted identifier through the operation lease.
|
|
103
|
+
* @returns {Promise<number>} - Last inserted identifier.
|
|
104
|
+
*/
|
|
105
|
+
async lastInsertID() {
|
|
106
|
+
this._operation.assertActive()
|
|
107
|
+
|
|
108
|
+
return await this._physicalConnection.lastInsertID({operationOwner: this._owner})
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Exclusive lease installed on a shared physical connection while one
|
|
5
|
+
* operation-scoped transaction owns it.
|
|
6
|
+
*/
|
|
7
|
+
export default class VelociousDatabaseOperationLease {
|
|
8
|
+
/**
|
|
9
|
+
* Runs constructor.
|
|
10
|
+
* @param {symbol} owner - Opaque operation owner token.
|
|
11
|
+
*/
|
|
12
|
+
constructor(owner) {
|
|
13
|
+
this.owner = owner
|
|
14
|
+
this.released = false
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the lease waiters.
|
|
17
|
+
* @type {() => void} */
|
|
18
|
+
let release = () => {}
|
|
19
|
+
|
|
20
|
+
this.releasedPromise = new Promise((resolve) => {
|
|
21
|
+
release = () => resolve(undefined)
|
|
22
|
+
})
|
|
23
|
+
this.releasePromise = release
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Waits until the lease is released unless `owner` owns it.
|
|
28
|
+
* @param {symbol | undefined} owner - Candidate operation owner.
|
|
29
|
+
* @returns {Promise<void>} - Resolves when access is allowed.
|
|
30
|
+
*/
|
|
31
|
+
async wait(owner) {
|
|
32
|
+
if (owner === this.owner) return
|
|
33
|
+
|
|
34
|
+
await this.releasedPromise
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Releases all waiters exactly once.
|
|
39
|
+
* @returns {void}
|
|
40
|
+
*/
|
|
41
|
+
release() {
|
|
42
|
+
if (this.released) return
|
|
43
|
+
|
|
44
|
+
this.released = true
|
|
45
|
+
this.releasePromise()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import OperationConnection from "./operation-connection.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Explicit owner for model work performed on one pinned transactional
|
|
7
|
+
* connection.
|
|
8
|
+
*/
|
|
9
|
+
export default class VelociousDatabaseOperation {
|
|
10
|
+
/**
|
|
11
|
+
* Runs constructor.
|
|
12
|
+
* @param {object} args - Operation ownership.
|
|
13
|
+
* @param {import("../configuration.js").default} args.configuration - Owning configuration.
|
|
14
|
+
* @param {string} args.configurationReuseKey - Physical database configuration key captured at checkout.
|
|
15
|
+
* @param {import("./drivers/base.js").default} args.connection - Pinned physical connection.
|
|
16
|
+
* @param {string} args.databaseIdentifier - Singular database identifier.
|
|
17
|
+
* @param {symbol} args.owner - Opaque pool lease owner.
|
|
18
|
+
*/
|
|
19
|
+
constructor({configuration, configurationReuseKey, connection, databaseIdentifier, owner}) {
|
|
20
|
+
this._active = true
|
|
21
|
+
this._configuration = configuration
|
|
22
|
+
this._configurationReuseKey = configurationReuseKey
|
|
23
|
+
this._databaseIdentifier = databaseIdentifier
|
|
24
|
+
this._connection = new OperationConnection({
|
|
25
|
+
connection,
|
|
26
|
+
operation: this,
|
|
27
|
+
owner
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns an operation-bound model query/create scope.
|
|
33
|
+
* @template {typeof import("./record/index.js").default} MC
|
|
34
|
+
* @param {MC} ModelClass - Model class to bind.
|
|
35
|
+
* @returns {import("./query/model-class-query.js").default<MC>} - Operation-bound scope.
|
|
36
|
+
*/
|
|
37
|
+
forModel(ModelClass) {
|
|
38
|
+
this.assertActive()
|
|
39
|
+
this.assertModel(ModelClass)
|
|
40
|
+
|
|
41
|
+
return ModelClass._newQuery({
|
|
42
|
+
driver: this.connection(),
|
|
43
|
+
operation: this
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Verifies that a model belongs to this operation's configuration and database.
|
|
49
|
+
* @param {typeof import("./record/index.js").default} ModelClass - Model class to verify.
|
|
50
|
+
* @returns {void}
|
|
51
|
+
*/
|
|
52
|
+
assertModel(ModelClass) {
|
|
53
|
+
if (ModelClass._getConfiguration() !== this._configuration) {
|
|
54
|
+
throw new Error(`${ModelClass.getModelName()} belongs to another Velocious configuration`)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const modelDatabaseIdentifier = ModelClass.getDatabaseIdentifier()
|
|
58
|
+
|
|
59
|
+
if (modelDatabaseIdentifier !== this._databaseIdentifier) {
|
|
60
|
+
throw new Error(`${ModelClass.getModelName()} uses database ${JSON.stringify(modelDatabaseIdentifier)}, not operation database ${JSON.stringify(this._databaseIdentifier)}`)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Binds a loaded or built record to this operation.
|
|
66
|
+
* @template {import("./record/index.js").default} Model
|
|
67
|
+
* @param {Model} record - Record to bind.
|
|
68
|
+
* @returns {Model} - Bound record.
|
|
69
|
+
*/
|
|
70
|
+
bindRecord(record) {
|
|
71
|
+
this.assertActive()
|
|
72
|
+
this.assertModel(record.getModelClass())
|
|
73
|
+
record.bindDatabaseOperation(this)
|
|
74
|
+
|
|
75
|
+
return record
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Registers a callback owned by the current operation transaction frame.
|
|
80
|
+
* @param {() => void | Promise<void>} callback - Callback.
|
|
81
|
+
* @returns {Promise<void>} - Resolves after registration or execution.
|
|
82
|
+
*/
|
|
83
|
+
async afterCommit(callback) {
|
|
84
|
+
this.assertActive()
|
|
85
|
+
await this.connection().afterCommit(callback)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Runs a nested operation transaction/savepoint.
|
|
90
|
+
* @template T
|
|
91
|
+
* @param {() => Promise<T>} callback - Callback.
|
|
92
|
+
* @returns {Promise<T>} - Callback result.
|
|
93
|
+
*/
|
|
94
|
+
async transaction(callback) {
|
|
95
|
+
this.assertActive()
|
|
96
|
+
|
|
97
|
+
return await this.connection().transaction(callback)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Returns the deliberately exposed operation connection facade for raw SQL.
|
|
102
|
+
* @returns {import("./drivers/base.js").default} - Operation-bound connection.
|
|
103
|
+
*/
|
|
104
|
+
connection() {
|
|
105
|
+
this.assertActive()
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Narrows the Proxy facade to the complete driver surface that it forwards.
|
|
109
|
+
* @type {import("./drivers/base.js").default}
|
|
110
|
+
*/
|
|
111
|
+
const connectionFacade = /** @type {?} */ (this._connection)
|
|
112
|
+
|
|
113
|
+
return connectionFacade
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Raises when an operation handle has left its callback.
|
|
118
|
+
* @returns {void}
|
|
119
|
+
*/
|
|
120
|
+
assertActive() {
|
|
121
|
+
if (!this._active) throw new Error("Database operation has completed")
|
|
122
|
+
|
|
123
|
+
const currentReuseKey = this
|
|
124
|
+
._configuration
|
|
125
|
+
.getDatabasePool(this._databaseIdentifier)
|
|
126
|
+
.getConfigurationReuseKey()
|
|
127
|
+
|
|
128
|
+
if (currentReuseKey !== this._configurationReuseKey) {
|
|
129
|
+
throw new Error(`Database operation for ${JSON.stringify(this._databaseIdentifier)} belongs to a different physical database than the current tenant context`)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Expires the operation and all scopes/records bound to it.
|
|
135
|
+
* @returns {void}
|
|
136
|
+
*/
|
|
137
|
+
complete() {
|
|
138
|
+
this._active = false
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -241,9 +241,21 @@ class VelociousDatabasePoolBase {
|
|
|
241
241
|
* @returns {boolean} - Whether connection matches current resolved configuration.
|
|
242
242
|
*/
|
|
243
243
|
connectionMatchesCurrentConfiguration(connection) {
|
|
244
|
+
return this.getConnectionConfigurationReuseKey(connection) === this.getConfigurationReuseKey()
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Returns the resolved database configuration key stamped on a connection at checkout.
|
|
249
|
+
* @param {import("../drivers/base.js").default} connection - Checked-out connection.
|
|
250
|
+
* @returns {string} - Connection configuration reuse key.
|
|
251
|
+
*/
|
|
252
|
+
getConnectionConfigurationReuseKey(connection) {
|
|
244
253
|
const connectionWithPoolKey = /** @type {import("../drivers/base.js").default & {[POOL_CONFIGURATION_KEY]?: string}} */ (connection)
|
|
254
|
+
const reuseKey = connectionWithPoolKey[POOL_CONFIGURATION_KEY]
|
|
255
|
+
|
|
256
|
+
if (!reuseKey) throw new Error("Database connection is missing its configuration reuse key")
|
|
245
257
|
|
|
246
|
-
return
|
|
258
|
+
return reuseKey
|
|
247
259
|
}
|
|
248
260
|
|
|
249
261
|
/**
|
|
@@ -357,6 +369,19 @@ class VelociousDatabasePoolBase {
|
|
|
357
369
|
throw new Error("'withConnection' not implemented")
|
|
358
370
|
}
|
|
359
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Runs an operation on a freshly checked-out connection.
|
|
374
|
+
* @template T
|
|
375
|
+
* @param {ConnectionCheckoutOptions} options - Checkout options.
|
|
376
|
+
* @param {(connection: import("../drivers/base.js").default, owner: symbol) => Promise<T>} callback - Operation callback.
|
|
377
|
+
* @returns {Promise<T>} - Resolves with the callback result.
|
|
378
|
+
*/
|
|
379
|
+
async withOperationConnection(options, callback) {
|
|
380
|
+
const owner = Symbol("database-operation-owner")
|
|
381
|
+
|
|
382
|
+
return await this.withConnection(options, async (connection) => await callback(connection, owner))
|
|
383
|
+
}
|
|
384
|
+
|
|
360
385
|
/**
|
|
361
386
|
* Ensures a reusable connection exists for contexts where AsyncLocalStorage isn't set.
|
|
362
387
|
* Default implementation just checks out a connection.
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import BasePool from "./base.js"
|
|
4
|
+
import OperationLease from "../operation-lease.js"
|
|
4
5
|
|
|
5
6
|
export default class VelociousDatabasePoolSingleMultiUser extends BasePool {
|
|
6
7
|
activeCheckoutCount = 0
|
|
7
8
|
suppressedConnectionContextCount = 0
|
|
9
|
+
operationLeaseQueue = Promise.resolve()
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Checkout names of the currently-active nested checkouts, innermost last. The
|
|
@@ -107,6 +109,53 @@ export default class VelociousDatabasePoolSingleMultiUser extends BasePool {
|
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Runs an operation under an exclusive FIFO lease on the reusable physical connection.
|
|
114
|
+
* @template T
|
|
115
|
+
* @param {import("./base.js").ConnectionCheckoutOptions} options - Checkout options.
|
|
116
|
+
* @param {(connection: import("../drivers/base.js").default, owner: symbol) => Promise<T>} callback - Operation callback.
|
|
117
|
+
* @returns {Promise<T>} - Resolves with the callback result.
|
|
118
|
+
*/
|
|
119
|
+
async withOperationConnection(options, callback) {
|
|
120
|
+
const previousLease = this.operationLeaseQueue
|
|
121
|
+
/**
|
|
122
|
+
* Resolves this FIFO queue turn.
|
|
123
|
+
* @type {() => void} */
|
|
124
|
+
let releaseQueue = () => {}
|
|
125
|
+
const queueTurn = new Promise((resolve) => {
|
|
126
|
+
releaseQueue = () => resolve(undefined)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
this.operationLeaseQueue = previousLease.then(async () => await queueTurn)
|
|
130
|
+
await previousLease
|
|
131
|
+
|
|
132
|
+
const owner = Symbol("single-pool-operation-owner")
|
|
133
|
+
const operationLease = new OperationLease(owner)
|
|
134
|
+
/** @type {import("../drivers/base.js").default | undefined} */
|
|
135
|
+
let connection
|
|
136
|
+
let operationLeaseInstalled = false
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
connection = await this.checkout(options)
|
|
140
|
+
await connection.setOperationLease(operationLease)
|
|
141
|
+
operationLeaseInstalled = true
|
|
142
|
+
|
|
143
|
+
return await callback(connection, owner)
|
|
144
|
+
} finally {
|
|
145
|
+
operationLease.release()
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
if (connection && operationLeaseInstalled) connection.clearOperationLease(operationLease)
|
|
149
|
+
} finally {
|
|
150
|
+
try {
|
|
151
|
+
if (connection) await this.checkin(connection)
|
|
152
|
+
} finally {
|
|
153
|
+
releaseQueue()
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
110
159
|
/**
|
|
111
160
|
* Runs without current connection context.
|
|
112
161
|
* @template T
|
|
@@ -64,10 +64,16 @@ export default class VelociousDatabaseQueryAlterTableBase extends QueryBase {
|
|
|
64
64
|
// SQLite's ALTER TABLE does not support adding constraints; the SQLite driver overrides
|
|
65
65
|
// alterTableSQLs entirely (via TableRebuilder) so this base path is never invoked there.
|
|
66
66
|
for (const foreignKey of tableData.getForeignKeys()) {
|
|
67
|
-
if (!foreignKey.getIsNewForeignKey()) continue
|
|
67
|
+
if (!foreignKey.getIsNewForeignKey() && !foreignKey.getDropForeignKey()) continue
|
|
68
68
|
|
|
69
69
|
if (actionCount > 0) sql += ", "
|
|
70
70
|
|
|
71
|
+
if (foreignKey.getDropForeignKey()) {
|
|
72
|
+
sql += this.getDropForeignKeySQL(foreignKey)
|
|
73
|
+
actionCount++
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
|
|
71
77
|
sql += "ADD"
|
|
72
78
|
|
|
73
79
|
if (foreignKey.getName()) {
|
|
@@ -101,4 +107,17 @@ export default class VelociousDatabaseQueryAlterTableBase extends QueryBase {
|
|
|
101
107
|
|
|
102
108
|
return sqls
|
|
103
109
|
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Runs get drop foreign key sql.
|
|
113
|
+
* @param {import("../table-data/table-foreign-key.js").default} foreignKey - Foreign key to drop.
|
|
114
|
+
* @returns {string} - SQL fragment that removes the foreign key.
|
|
115
|
+
*/
|
|
116
|
+
getDropForeignKeySQL(foreignKey) {
|
|
117
|
+
const name = foreignKey.getName()
|
|
118
|
+
|
|
119
|
+
if (!name) throw new Error(`Cannot remove unnamed foreign key on ${foreignKey.getTableName()}.${foreignKey.getColumnName()}`)
|
|
120
|
+
|
|
121
|
+
return `DROP CONSTRAINT ${this.getOptions().quoteIndexName(name)}`
|
|
122
|
+
}
|
|
104
123
|
}
|