はじめに
前回の記事【Swift4】Realm+Codableを使ったお手軽なDB Part.2(リレーション編)の続き、Part3です。
今回はRealmへのクエリをまとめました!😀
Codableから少し遠ざかってしまいますが、あしからず。
Realmへのクエリ
RealmへのクエリはCore Dataと同様にNSPredicateを使用します。formatを文字列として指定する必要があったりと、あまり使い勝手がよくありません。
そのため、SwiftでRealmを使う時のTips(3) NSPredicate編をそのまま使わせて頂いています😎
テーブル全件取得
realm.objects(<Type>.self)
1件取得
プライマリーキーが設定されているテーブルは、以下のように取得できます。
realm.object(ofType: <Type>.self, forPrimaryKey: <Key>)
クエリを用いての取得(よく使うもの)
// =
realm.objects(<Type>.self).filter(NSPredicate("<key>", equal: "<query>" as AnyObject))
// !=
realm.objects(<Type>.self).filter(NSPredicate("<key>", notEqual: "<query>" as AnyObject))
// 部分一致
realm.objects(<Type>.self).filter(NSPredicate("<key>", contains: "<query>" as AnyObject))
// IN句
realm.objects(<Type>.self).filter(NSPredicate("<key>", valuesIn: [<query>] as [AnyObject]))
// 条件の結合
let predicates = NSPredicate.empty()
.and(NSPredicate("<key>", equal: "<query>" as AnyObject))
.or(NSPredicate("<key>", equal: "<query>" as AnyObject))
...
realm.objects(<Type>.self).filter(predicates)
// 結果のソート
realm.objects(<Type>.self).sorted(byKeyPath: "<key>", ascending: false)
このように、クラス拡張とメソッドチェインを使うことで、Realmへのアクセスが断然使いやすくなりました!
enum定義
NSPredicateの拡張によって使いやすくなったクエリですが、keyを直打ちするのがスマートではありません🙃
Typoやカラムの変更があった際に、コンパイルしても気づくことが出来ず、実行時にクラッシュする原因になります。
そこで各テーブル(クラス)に各変数の名前をenumで定義してあげます。前回の記事で使用したSalesクラスを元にすると、
enum StringKey: String {
case id
case date
case birthday
case productID
case employeeID
case employee
case products
case customer
}
これとクエリを組み合わせると、
realm.objects(Sales.self).filter(NSPredicate(Sales.StringKey.id.rawValue, equal: 553 as AnyObject))
このような感じになります。少し1行が長くなってしまっていますが、コンパイラの支援を受けることが出来ます!
クエリのラップクラス
Clean Architectureなどのアーキテクチャを使用してアプリ開発を行う場合、実際のRealmへのアクセスとデータベースへのI/Fは分離し、データベースに依存しないような構成を取ることがあると思います。
class DataStore {
let realm = try! Realm()
func readAll<T: Object>() -> [T] {
let result = realm.objects(T.self)
return Array(result)
}
func readEqual<T: Object>(ofTypes: String, forQuery: AnyObject) -> [T] {
let result = realm.objects(T.self).filter(NSPredicate(ofTypes, equal: forQuery))
return Array(result)
}
func create<T: Object>(data: [T]) {
try! realm.write {
realm.add(data)
}
}
func delete<T: Object>(_ type: T.Type, predicates: NSPredicate) {
try! realm.write {
let obj = realm.objects(T.self).filter(predicates)
realm.delete(obj)
}
}
}
そのため、このようなCRUDに相当するクラスを作成しました。(今回は説明のため、force-unwrappingはそのままです)
Genericsメソッドにしてあるので、このクラスを使うことですべてのテーブルにアクセス出来るようになります😎
さいごに
今回の記事では、クエリ編としてRealmをより便利に使うためのポイントを紹介しました。
続編書きました!
【Swift4】Realm+Codableを使ったお手軽なDB Part.4(番外編)
株式会社Nexceed にて、一緒に働いてくれる仲間を募集中です