Last active
August 23, 2022 14:43
-
-
Save groue/33b80a21285ace48974670096342791b to your computer and use it in GitHub Desktop.
Deferred unique indexes with GRDB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import GRDB | |
extension Database { | |
/// Executes the provided closure with deferred unique indexes | |
func withDeferredUniqueIndexes(_ execute: () throws -> Void) throws { | |
try inSavepoint { | |
// Fetch all unique indexes, but primary keys. | |
let uniqueConstraints: [(table: String, index: IndexInfo)] = try String | |
.fetchAll(self, sql: "SELECT name FROM sqlite_master WHERE type = 'table'") | |
.filter { !Database.isGRDBInternalTable($0) } | |
.flatMap { table in | |
try indexes(on: table) | |
.filter(\.isUnique) | |
.filter { try $0.columns != primaryKey(table).columns } | |
.map { (table: table, index: $0) } | |
} | |
// Drop indexes | |
for constraint in uniqueConstraints { | |
try drop(index: constraint.index.name) | |
} | |
// Execute closure | |
var executeError: Error? | |
do { | |
try execute() | |
} catch { | |
executeError = error | |
} | |
// Restore indexes | |
var restoreError: Error? | |
do { | |
for constraint in uniqueConstraints { | |
try create( | |
index: constraint.index.name, | |
on: constraint.table, | |
columns: constraint.index.columns, | |
options: .unique) | |
} | |
} catch { | |
restoreError = error | |
} | |
// Throw first error | |
if let error = executeError ?? restoreError { | |
throw error | |
} | |
// Commit savepoint | |
return .commit | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment