モノトーンの伝説日記

Apex Legends, Splatoon, Programming, and so on...

<mini> Realm Swift 環境で filter をコンパイル時に検証させる

 こんにちは。

1. Realm Swift の filter は NSPredicate のシステムに即しているが……

 それが故,filter は「テキスト」で記述されるためコンパイル時検証が弱い。

 そこで,引数として keyPath を渡し,強固に型チェックまでさせる。

2. keyPath は key をもつ型と key 自体の型を判別できる

 keyPath の型云々は以下を参照

qiita.com

 型を使って,「keyをもつ型」と「key に対する value の型」を強固に制約させる

import Foundation
import RealmSwift

extension Results {
    final func filter(_ keyPath: ReferenceWritableKeyPath<Element, String>, value: String) -> Results<Element> {
        let name = NSExpression(forKeyPath: keyPath).keyPath
        return self.filter("%K=%@", name, value)
    }

    final func filter(_ keyPath: ReferenceWritableKeyPath<Element, Int32>, value: Int32) -> Results<Element> {
        let name = NSExpression(forKeyPath: keyPath).keyPath
        return self.filter("%K=%d", name, value)
    }
    
    final func filter(_ keyPath: ReferenceWritableKeyPath<Element, Int64>, value: Int64) -> Results<Element> {
        let name = NSExpression(forKeyPath: keyPath).keyPath
        return self.filter("%K=%lld", name, value)
    }
    
    final func filter(_ keyPath: ReferenceWritableKeyPath<Element, Int>, value: Int) -> Results<Element> {
        let name = NSExpression(forKeyPath: keyPath).keyPath
#if arch(arm64) || arch(x86_64)
        return self.filter("%K=%lld", name, value)
#else
        return self.filter("%K=%d", name, value)
#endif
    }
}

 ※ Swift の Int は 32-bit 環境では 32-bit,64-bit 環境では 64-bit である。iOS 10 対応して,iPhone 5 や iPhone 5c への対応を行うときに気をつけなければならない。

 使用例

let account = realm
    .objects(AccountEntity.self)
    .filter(\.uuid, string: uuid)
    .first

 対象の型の中にある key を強制的に選択させることで,プログラミングのミスを回避する。

 オーバーヘッドがあるかどうかは知らない。まあ誤差程度でしょう

 「.」で入力を始めると,サジェストされないのがつらいですが…… 改善してください……

おまけ

 型が間違っているとコンパイルエラーとしてこんな感じに出る。

f:id:mntone:20190110104423p:plain