Created
October 27, 2019 00:38
-
-
Save ryanmeisters/657297a3418e540c7a2eac40c0b0b29b to your computer and use it in GitHub Desktop.
This file contains 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 Foundation | |
import ReactiveSwift | |
struct VoidResult: Codable {} | |
enum FunctionServiceError: Error { | |
case encodingError(_ error: Error) | |
case decodingError(_ error: Error) | |
case functonCallError(_ error: FunctionsError) | |
case error(_ error: Error) | |
case noData | |
} | |
struct FirebaseFunctionService { | |
private let functions = App.current.firebaseContainer.functions | |
func get<ResourceType: FunctionResource>(_ resource: ResourceType) -> SignalProducer<ResourceType.ResultType, FunctionServiceError> { | |
do { | |
let data = try JSONSerialization.jsonObject(with: try JSONEncoder().encode(resource)) as? [String: Any] | |
return functions.reactive.call(ResourceType.functionName, data: data) | |
.mapError { FunctionServiceError.functonCallError($0) } | |
.attemptMap { res -> Result<ResourceType.ResultType, FunctionServiceError> in | |
do { | |
let data = try JSONSerialization.data(withJSONObject: res) | |
let decoder = JSONDecoder.withFirestoreDateParsing | |
let decoded = try decoder.decode(ResourceType.ResultType.self, from: data) | |
return .success(decoded) | |
} catch let e as DecodingError { | |
// swiftformat:disable:next redundantReturn | |
return .failure(.decodingError(e)) | |
} catch { | |
return .failure(.error(error)) | |
} | |
} | |
} catch { | |
return .init(error: .encodingError(error)) | |
} | |
} | |
} | |
extension JSONDecoder { | |
static var withFirestoreDateParsing: JSONDecoder { | |
let decoder = JSONDecoder() | |
decoder.dateDecodingStrategy = .custom(dateStrategy) | |
return decoder | |
} | |
static func dateStrategy(_ decoder: Decoder) throws -> Date { | |
let container = try decoder.singleValueContainer() | |
let val = try container.decode([String: Int].self) | |
if let seconds = val["_seconds"] { | |
return Date(timeIntervalSince1970: Double(seconds)) | |
} | |
return Date() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment