Skip to content

Instantly share code, notes, and snippets.

@groue
Last active August 23, 2022 14:43
Show Gist options
  • Save groue/33b80a21285ace48974670096342791b to your computer and use it in GitHub Desktop.
Save groue/33b80a21285ace48974670096342791b to your computer and use it in GitHub Desktop.
Deferred unique indexes with GRDB
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