はじめに
Swift4で開発しているアプリから、SQLiteのデータベースを扱う必要があった為、
GRDB.swiftというライブラリを使ってみた。
最新の環境で動くサンプルコードが、ググっても情報が少なかったので、
本記事で基本的な使用方法を記載します。
導入
CocoaPodsからインストール
Podfile
pod 'GRDB.swift'
エンティティ
サンプルコード用にユーザテーブルを定義します。
構造体にはCodable、RowConvertible、MutablePersistableのプロトコルを追加します。
UserTable.swift
struct UserTable : Codable, RowConvertible, MutablePersistable {
// 今回は全カラムNotNullで
var id: Int
var name: String
var age: Int
var lastUpdate: Int64
static var databaseTableName: String {
return "tbl_user" // テーブル名
}
static func create(_ db: Database) throws {
try db.create(table: databaseTableName, body: { (t: TableDefinition) in
t.column("id", .integer).primaryKey(onConflict: .replace, autoincrement: false)
t.column("name", .text).notNull()
t.column("age", .integer).notNull()
t.column("lastUpdate", .integer).notNull()
})
}
}
複合主キーを設定する場合は下記のようにします。
t.column("id", .integer).notNull()
t.column("name", .text).notNull()
t.primaryKey(["id", "name"], onConflict: .replace)
ヘルパークラス
各テーブルの生成処理を一元管理する為にヘルパークラスを作成します。
DatabaseHelper.swift
class DatabaseHelper {
private struct Const {
/// データベースファイル名
static let DB_FILE_NAME = "application.db"
/// データベースファイルの格納先
static let DB_FILE_PATH = "\(File.DocumentsPath)/\(DB_FILE_NAME)"
}
/// イニシャライザ
init() {
self.createDatabase()
}
/// データベースの操作
func inDatabase(_ block: (Database) throws -> Void) -> Bool {
do {
// 初回実行時にデータベースファイルを生成する
let dbQueue = try DatabaseQueue(path: Const.DB_FILE_PATH)
try dbQueue.inDatabase(block)
} catch let error {
Log.e("Database Error: \(error.localizedDescription)")
return false
}
return true
}
/// データベースの生成処理
private func createDatabase() {
if File.isExists(Const.DB_FILE_PATH) {
// 既にファイルが作成済みなら何もしない
return
}
let result = inDatabase { (db) in
// テーブルの作成処理
try UserTable.create(db)
// ※複数テーブルがある場合はここに追加する
}
if !result {
Log.e("create failed for Database.")
File.remove(Const.DB_FILE_PATH)
}
}
}
データの取得
全件取得
var result :[UserTable] = []
let helper = DatabaseHelper()
helper.inDatabase { (db) in
result = try UserTable.fetchAll(db)
}
// 出力
result.forEach { (it) in
Log.d("\(it.id) - \(it.name) - \(it.age) - \(it.lastUpdate)")
}
条件指定
filterメソッドのSQL指定を使うと、引数にWHEAE句を設定できる。
let helper = DatabaseHelper()
var entity: UserTable?
helper.inDatabase { (db) in
entity = try UserTable.filter(sql: "id = 3").fetchOne(db)
}
// 出力
if entity != nil {
Log.d("\(entity!.id) - \(entity!.name) - \(entity!.age) - \(entity!.lastUpdate)")
}
ソースにSQLを書きたくない場合は、カラム名指定で条件を設定できる。
let helper = DatabaseHelper()
helper.inDatabase { (db) in
try UserTable
.filter(Column("id") == 2)
.filter(Column("age") == 22)
.fetchOne(db)
}
データの挿入/更新
let helper = DatabaseHelper()
helper.inDatabase { (db) in
// エンティティを設定
var entity = UserTable(id: 1,
name: "hoge",
age: 11,
lastUpdate: Date.currentTimeMillis())
// 既に存在しているレコードなら上書きを行う
try entity.insert(db)
}
データの削除
全件削除
let helper = DatabaseHelper()
helper.inDatabase { (db) in
try UserTable.deleteAll(db)
}
条件指定
let helper = DatabaseHelper()
helper.inDatabase { (db) in
try UserTable.filter(sql: "id = 1").fetchOne(db)
try UserTable
.filter(Column("id") == 2)
.filter(Column("age") == 22)
.fetchOne(db)
}
トランザクション
let helper = DatabaseHelper()
helper.inDatabase { (db) in
// トランザクション開始
try db.beginTransaction()
do {
// 更新処理
.
.
.
} catch let error {
// ロールバック
try db.rollback()
throw error
}
// コミット
try db.commit()
}
生SQLの実行
取得
let helper = DatabaseHelper()
helper.inDatabase { (db) in
let rawSQL = """
SELECT
*
FROM
\(UserTable.databaseTableName)
"""
let rows = try Row.fetchAll(db, rawSQL)
// 出力
rows.forEach { (row) in
let id = row["id"]!
let name = row["name"]!
Log.d("\(id) - \(name)")
}
}
更新
let helper = DatabaseHelper()
helper.inDatabase { (db) in
let rawSQL = """
UPDATE
\(UserTable.databaseTableName)
SET
name = 'foo'
WHERE
id = 3
"""
try db.execute(rawSQL)
}
プレースホルダ
SQL文の一部をパラメータに置き換える方法です。
GRDB.StatementArgumentsには配列を指定し、先頭から順にSQL内の「?」割り当てられます。
let rawSQL = """
SELECT
*
FROM
\(UserTable.databaseTableName)
WHERE
name = ?
"""
let args = GRDB.StatementArguments(["hoge"])
let rows = try Row.fetchAll(db, rawSQL, arguments: args, adapter: nil)
終わりに
基本的なデータ操作は上記のサンプルで確認できるかと思います。
まだまだ機能が多くて使いこなせておりませんが、手軽にSQLiteが扱えました。