|
// |
|
// SwiftFirebase.swift |
|
// SwiftFirebase |
|
// |
|
// Created by mironal on 2017/05/27. |
|
// Copyright © 2017年 covelline. All rights reserved. |
|
// |
|
|
|
import Foundation |
|
|
|
import FirebaseDatabase |
|
import Unbox |
|
|
|
/// firebase に保存可能であることを示す |
|
public protocol FirebaseStorable { |
|
func firebaseValue() -> [AnyHashable: Any] |
|
} |
|
|
|
/// Firebase Database のモデル |
|
public protocol FirebaseModel {} |
|
|
|
/// Firebase Database のモデルへの参照 |
|
public protocol FirebaseRef { |
|
|
|
/// この参照が示すモデルの型 |
|
associatedtype Model: FirebaseModel |
|
|
|
/// Database.database().reference() の alias |
|
var rootRef: DatabaseReference { get } |
|
|
|
/// この参照への query |
|
var query: DatabaseQuery { get } |
|
} |
|
|
|
public extension FirebaseRef { |
|
var rootRef: DatabaseReference { |
|
return Database.database().reference() |
|
} |
|
} |
|
|
|
/// このモデルへの参照が値を作成可能であることを示す |
|
/// 対象となるオブジェクトが既に FirebaseModelRef に適合している場合はデフォルトの実装が存在する |
|
public protocol FirebaseCreatableValueRef: FirebaseRef { |
|
|
|
associatedtype Model: FirebaseStorable |
|
|
|
/// firebase の setValue(_ value: Any?, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) |
|
func setValue(_ value: Model, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) |
|
|
|
/// firebase の setValue(_ value: Any?, andPriority priority: Any?, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) |
|
func setValue(_ value: Model, andPriority priority: Any?, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) |
|
|
|
/// firebase の updateChildValues(_ values: [AnyHashable : Any], withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) |
|
func updateChildValues(_ values: Model, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) |
|
} |
|
|
|
/// このモデルへの参照が childByAutoId を使用した値を作成可能であることを示す |
|
/// 対象となるオブジェクトが既に FirebaseArrayModelRef に適合している場合はデフォルトの実装が存在する |
|
public protocol FirebaseChildCreatableValueRef: FirebaseRef { |
|
|
|
associatedtype Model: FirebaseStorable |
|
|
|
/// childByAutoId で value を作る |
|
func setChildValue(_ value: Model, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) |
|
|
|
/// firebase の func setValue(_ value: Any?, andPriority priority: Any?, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) |
|
func setChildValue(_ value: Model, andPriority priority: Any?, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) |
|
} |
|
|
|
/// このモデルへの参照が値を削除可能であることを示す |
|
/// 対象となるオブジェクトが既に FirebaseModelRef に適合している場合はデフォルトの実装が存在する |
|
public protocol FirebaseRemovableValueRef: FirebaseRef { |
|
|
|
/// firebase の removeValue(completionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) |
|
func removeValue(completionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) |
|
} |
|
|
|
/// モデル単体への参照 |
|
public protocol FirebaseModelRef: FirebaseRef { |
|
|
|
/// firebase の observeSingleEvent(of eventType: DataEventType, with block: @escaping (DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)? = nil) |
|
func observeSingleEvent(of eventType: DataEventType, with block: @escaping (Model, DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)?) |
|
|
|
/// firebase の observe(_ eventType: DataEventType, with block: @escaping (DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)? = nil) -> UInt |
|
func observe(_ eventType: DataEventType, with block: @escaping (Model, DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)?) -> UInt |
|
} |
|
|
|
/// モデル単体集合への参照 |
|
public protocol FirebaseArrayModelRef: FirebaseRef { |
|
|
|
/// firebase の observeSingleEvent(of eventType: DataEventType, with block: @escaping (DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)? = nil) |
|
func observeSingleEvent(of eventType: DataEventType, with block: @escaping ([String: Model], DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)?) |
|
|
|
/// firebase の observe(_ eventType: DataEventType, with block: @escaping (DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)? = nil) -> UInt |
|
func observe(_ eventType: DataEventType, with block: @escaping ([String: Model], DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)?) -> UInt |
|
} |
|
|
|
enum SwiftFirebaseError: Error { |
|
case paseError |
|
} |
|
|
|
// MARK - 便利なデフォルト実装達 |
|
|
|
public extension FirebaseModelRef where Model: Unboxable { |
|
|
|
func observeSingleEvent(of eventType: DataEventType, with block: @escaping (Model, DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)?) { |
|
|
|
query.observeSingleEvent(of: eventType, with: { snapshot in |
|
parse(snapshot: snapshot, block, withCancel: cancelBlock) |
|
}, withCancel: cancelBlock) |
|
} |
|
|
|
func observe(_ eventType: DataEventType, with block: @escaping (Model, DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)?) -> UInt { |
|
|
|
return query.observe(eventType, with: { snapshot in |
|
parse(snapshot: snapshot, block, withCancel: cancelBlock) |
|
}, withCancel: cancelBlock) |
|
} |
|
} |
|
|
|
public extension FirebaseArrayModelRef where Model: Unboxable { |
|
|
|
func observeSingleEvent(of eventType: DataEventType, with block: @escaping ([String: Model], DataSnapshot) -> Swift.Void, withCancel |
|
cancelBlock: ((Error) -> Swift.Void)? = nil) { |
|
|
|
query.observeSingleEvent(of: eventType, with: { snapshot in |
|
parse(snapshot: snapshot, block, withCancel: cancelBlock) |
|
}, withCancel: cancelBlock) |
|
} |
|
|
|
func observe(_ eventType: DataEventType, with block: @escaping ([String: Model], DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)?) -> UInt { |
|
|
|
return query.observe(eventType, with: { snapshot in |
|
parse(snapshot: snapshot, block, withCancel: cancelBlock) |
|
}, withCancel: cancelBlock) |
|
} |
|
} |
|
|
|
private func parse<Model: Unboxable>(snapshot: DataSnapshot, _ block: @escaping (Model, DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)?) { |
|
if let dictionary = snapshot.value as? [String: AnyObject], let model: Model = try? unbox(dictionary: dictionary) { |
|
block(model, snapshot) |
|
} else { |
|
print("Parse error \(Model.self)") |
|
cancelBlock?(SwiftFirebaseError.paseError) |
|
} |
|
} |
|
|
|
private func parse<Model: Unboxable>(snapshot: DataSnapshot, _ block: @escaping ([String: Model], DataSnapshot) -> Swift.Void, withCancel cancelBlock: ((Error) -> Swift.Void)?) { |
|
|
|
var error: SwiftFirebaseError? |
|
let models: [String: Model] = snapshot.children.reduce([:], { (result, child) -> [String: Model] in |
|
|
|
var result = result |
|
if let child = child as? DataSnapshot, |
|
let dict = child.value as? [String: Any], |
|
let model: Model = try? unbox(dictionary: dict) { |
|
|
|
result[child.key] = model |
|
} else { |
|
error = SwiftFirebaseError.paseError |
|
print("Parse error \(Model.self)") |
|
} |
|
return result |
|
}) |
|
|
|
if let error = error { |
|
cancelBlock?(error) |
|
} else { |
|
block(models, snapshot) |
|
} |
|
} |
|
|
|
public extension FirebaseChildCreatableValueRef where Self: FirebaseArrayModelRef { |
|
|
|
var childRef: DatabaseReference { |
|
return query.ref.childByAutoId() |
|
} |
|
|
|
func setChildValue(_ value: Model, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) { |
|
childRef.setValue(value.firebaseValue(), withCompletionBlock: block) |
|
} |
|
|
|
func setChildValue(_ value: Model, andPriority priority: Any?, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) { |
|
childRef.setValue(value.firebaseValue(), andPriority: priority, withCompletionBlock: block) |
|
} |
|
} |
|
|
|
public extension FirebaseCreatableValueRef where Self: FirebaseModelRef { |
|
|
|
func setValue(_ value: Model, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) { |
|
query.ref.setValue(value.firebaseValue(), withCompletionBlock: block) |
|
} |
|
|
|
func setValue(_ value: Model, andPriority priority: Any?, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) { |
|
query.ref.setValue(value.firebaseValue(), andPriority: priority, withCompletionBlock: block) |
|
} |
|
|
|
func updateChildValues(_ values: Model, withCompletionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) { |
|
query.ref.updateChildValues(values.firebaseValue(), withCompletionBlock: block) |
|
} |
|
} |
|
|
|
public extension FirebaseRemovableValueRef where Self: FirebaseModelRef { |
|
func removeValue(completionBlock block: @escaping (Error?, DatabaseReference) -> Swift.Void) { |
|
query.ref.removeValue(completionBlock: block) |
|
} |
|
} |