Last active
February 17, 2017 11:24
-
-
Save ukitaka/e7276162abb0310c297172910957e1e5 to your computer and use it in GitHub Desktop.
Readerモナド + PhantomTypeでRealmの処理を再利用可能かつ合成可能にする
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import RealmSwift | |
import Result | |
// MARK: - | |
public protocol _Read {} | |
public struct Read: _Read { } | |
public protocol _Write {} | |
public struct Write: _Write { } | |
public enum RealmError: Error { /* TODO */ } | |
public typealias RealmResult<T> = Result<T, RealmError> | |
public struct RealmTxn<RW, T> { | |
fileprivate let _run: (Realm) -> RealmResult<T> | |
public init(_ _run: @escaping (Realm) -> RealmResult<T>) { | |
self._run = _run | |
} | |
public func map<S>(_ f: @escaping (T) -> S) -> RealmTxn<RW, S> { | |
return RealmTxn<RW, S> { realm in | |
self._run(realm).map(f) | |
} | |
} | |
public func ask() -> RealmTxn<RW, Realm> { | |
return RealmTxn<RW, Realm> { realm in | |
return .success(realm) | |
} | |
} | |
} | |
// MARK: - flatMap | |
public extension RealmTxn where RW: _Read { | |
// Read & Write -> Write | |
public func flatMap<W: _Write, S>(_ f: @escaping (T) -> RealmTxn<W, S>) -> RealmTxn<W, S> { | |
return RealmTxn<W, S> { realm in | |
self._run(realm).flatMap { t in f(t)._run(realm) } | |
} | |
} | |
// Read & Read -> Read | |
public func flatMap<S>(_ f: @escaping (T) -> RealmTxn<RW, S>) -> RealmTxn<RW, S> { | |
return RealmTxn<RW, S> { realm in | |
self._run(realm).flatMap { t in f(t)._run(realm) } | |
} | |
} | |
} | |
public extension RealmTxn where RW: _Write { | |
// Write & Any -> Write | |
public func flatMap<RW2, S>(_ f: @escaping (T) -> RealmTxn<RW2, S>) -> RealmTxn<RW, S> { | |
return RealmTxn<RW, S> { realm in | |
self._run(realm).flatMap { t in f(t)._run(realm) } | |
} | |
} | |
} | |
// MARK: - run | |
// Readのみの場合はトランザクションを作成する必要なし | |
public func runTxn<R, T>(realm: Realm, txn: RealmTxn<R, T>) -> RealmResult<T> where R: _Read { | |
return txn._run(realm) | |
} | |
// Writeのみの場合はトランザクションを作成 | |
public func runTxn<W, T>(realm: Realm, txn: RealmTxn<W, T>) -> RealmResult<T> where W: _Write { | |
var result: RealmResult<T>! = nil // FIXME: これだからthrowは.... | |
do { | |
try realm.write { | |
result = txn._run(realm) | |
} | |
} catch { | |
result = .failure(error as! RealmError) | |
} | |
return result | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct User { | |
let id: Int | |
let name: String | |
} | |
func findByID(id: Int) -> RealmTxn<Read, User> { | |
return RealmTxn { _ in | |
return .success(User(id: id, name: "AAA")) // dummy | |
} | |
} | |
func findByName(name: String) -> RealmTxn<Read, User> { | |
return RealmTxn { _ in | |
return .success(User(id: 100, name: name)) // dummy | |
} | |
} | |
func updateUser(user: User) -> RealmTxn<Write, Void> { | |
return RealmTxn { _ in | |
return .success(print(user)) // dummy | |
} | |
} | |
func changeUserName(_ newName: String) -> (User) -> User { | |
return { user in | |
return User(id: user.id, name: newName) | |
} | |
} | |
// Read & Write = Write | |
let t1: RealmTxn<Write, Void> = findByID(id: 123) | |
.map(changeUserName("BBB")) | |
.flatMap(updateUser) | |
// Read & Read = Read | |
let t2: RealmTxn<Read, User> = findByID(id: 123) | |
.map { $0.name } | |
.flatMap(findByName) | |
let id = 2 | |
// Write & Read = Write | |
let t3: RealmTxn<Write, User> = updateUser(user: User(id: id, name: "BBB")) | |
.map(const(id)) | |
.flatMap(findByID) | |
runTxn(realm: Realm(), txn: t3) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
スレッドもPhantomTypeにすればより安全かもしれない