Skip to content

Instantly share code, notes, and snippets.

@acrookston
Last active April 28, 2018 22:09
Show Gist options
  • Select an option

  • Save acrookston/6dd5fad482a5ae74663d66213df18fe4 to your computer and use it in GitHub Desktop.

Select an option

Save acrookston/6dd5fad482a5ae74663d66213df18fe4 to your computer and use it in GitHub Desktop.

Revisions

  1. acrookston revised this gist Apr 28, 2018. 2 changed files with 2 additions and 2 deletions.
    2 changes: 1 addition & 1 deletion MigrationCreateItems.swift
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@
    //
    // Created by Andrew C on 8/30/17.
    // Copyright © 2017 Andrew Crookston. All rights reserved.
    // Licence: MIT
    // License: MIT
    //

    import Foundation
    2 changes: 1 addition & 1 deletion SQLiteMigration.swift
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@
    //
    // Created by Andrew C on 8/30/17.
    // Copyright © 2017 Andrew Crookston. All rights reserved.
    // Licence: MIT
    // License: MIT
    //

    import Foundation
  2. acrookston revised this gist Apr 28, 2018. 2 changed files with 2 additions and 0 deletions.
    1 change: 1 addition & 0 deletions MigrationCreateItems.swift
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,7 @@
    //
    // Created by Andrew C on 8/30/17.
    // Copyright © 2017 Andrew Crookston. All rights reserved.
    // Licence: MIT
    //

    import Foundation
    1 change: 1 addition & 0 deletions SQLiteMigration.swift
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,7 @@
    //
    // Created by Andrew C on 8/30/17.
    // Copyright © 2017 Andrew Crookston. All rights reserved.
    // Licence: MIT
    //

    import Foundation
  3. acrookston created this gist Apr 28, 2018.
    31 changes: 31 additions & 0 deletions MigrationCreateItems.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,31 @@
    //
    // MigrationCreateItems.swift
    // Stash
    //
    // Created by Andrew C on 8/30/17.
    // Copyright © 2017 Andrew Crookston. All rights reserved.
    //

    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
    }
    }
    }
    111 changes: 111 additions & 0 deletions SQLiteMigration.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,111 @@
    //
    // SQLiteMigration.swift
    // Stash
    //
    // Created by Andrew C on 8/30/17.
    // Copyright © 2017 Andrew Crookston. All rights reserved.
    //

    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
    }
    }
    3 changes: 3 additions & 0 deletions usage.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    // After creating a db connection:
    SQLiteMigrator.register(MigrationCreateItems.self)
    SQLiteMigrator.migrate(connection)