5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Swift4】Realm+Codableを使ったお手軽なDB Part.3(クエリ編)

Last updated at Posted at 2018-11-02

はじめに

前回の記事【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は分離し、データベースに依存しないような構成を取ることがあると思います。

DataStore.swift
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 にて、一緒に働いてくれる仲間を募集中です:point_down::point_down::point_down:

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?