Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Simple SQLite migration for Swift with the SQLite.swift framework
//
// MigrationCreateItems.swift
// Stash
//
// Created by Andrew C on 8/30/17.
// Copyright © 2017 Andrew Crookston. All rights reserved.
// License: MIT
//
import Foundation
import SQLite
final class MigrationCreateItems: SQLiteMigration {
static let name: String = "create_items"
static func migrate(connection: Connection) -> Bool {
do {
try connection.run(Table(Item.tableName).create { t in
t.column(Expression<Int64>("id"), primaryKey: .autoincrement)
t.column(Expression<String>("uid"), unique: true)
t.column(Expression<Int64>("type"))
t.column(Expression<String>("content"))
t.column(Expression<String?>("notes"))
t.column(Expression<String?>("metadata"))
})
return true
} catch {
print("#DB MIGRATION ERROR: \(error)")
return false
}
}
}
//
// SQLiteMigration.swift
// Stash
//
// Created by Andrew C on 8/30/17.
// Copyright © 2017 Andrew Crookston. All rights reserved.
// License: MIT
//
import Foundation
import SQLite
protocol SQLiteMigration {
static var name: String { get }
static func migrate(connection: Connection) -> Bool
}
final class SQLiteMigrator {
static func register(_ migration: SQLiteMigration.Type) {
sharedInstance.migrations.append(migration)
}
static func register(_ migrations: [SQLiteMigration.Type]) {
sharedInstance.migrations.append(contentsOf: migrations)
}
@discardableResult static func migrate(_ connection: Connection) -> Bool {
return sharedInstance.migrate(connection)
}
// MARK: - private
private static let schemaTable = Table("db_schema_migration")
private static let sharedInstance = SQLiteMigrator()
private var migrations = [SQLiteMigration.Type]()
private lazy var completed = [String]()
private init() {}
private func migrate(connection: Connection, migration: SQLiteMigration.Type) -> Bool {
print("#DB CHECKING MIGRATION: \(migration.name)")
if !hasMigrated(migration: migration) {
print("#DB MIGRATING: \(migration.name)")
if migration.migrate(connection: connection) {
completed(migration: migration, connection: connection)
return true
}
return true
}
return false
}
private func completed(migration: SQLiteMigration.Type, connection: Connection) {
completed.append(migration.name)
let name = Expression<String>("name")
do {
let insert = SQLiteMigrator.schemaTable.insert(name <- migration.self.name)
try connection.run(insert)
} catch {
print("#DB SAVE MIGRATED ERROR: \(error)")
}
}
private func hasMigrated(migration: SQLiteMigration.Type) -> Bool {
return completed.contains(migration.name)
}
private func setup(connection: Connection) {
createSchema(connection: connection)
completed = loadMigrations(connection: connection)
}
private func loadMigrations(connection: Connection) -> [String] {
var migrations = [String]()
let name = Expression<String>("name")
do {
for migration in try connection.prepare(SQLiteMigrator.schemaTable) {
migrations.append(migration[name])
}
} catch {
print("#DB LOAD MIGRATIONS ERROR: \(error)")
}
return migrations
}
@discardableResult private func createSchema(connection: Connection) -> Bool {
do {
try connection.run(SQLiteMigrator.schemaTable.create(ifNotExists: true) { t in
t.column(Expression<String>("name"), unique: true)
})
return true
} catch {
print("#DB MIGRATION ERROR: \(error)")
return false
}
}
private func migrate(_ connection: Connection) -> Bool {
setup(connection: connection)
for migration in migrations {
if !migrate(connection: connection, migration: migration) {
return false
}
}
return true
}
}
// After creating a db connection:
SQLiteMigrator.register(MigrationCreateItems.self)
SQLiteMigrator.migrate(connection)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.