Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7fe5306
Moved Database.Encoder/Decoder to a new target and rebranded as Struc…
mortenbekditlevsen Oct 23, 2021
d806bf1
Import FirebaseSharedSwift and add test helpers
mortenbekditlevsen Oct 23, 2021
6df778d
Call a callable with encoded entity and decode the response. Also add…
mortenbekditlevsen Oct 23, 2021
47ca483
Fix header for EncoderDecoder.swift
mortenbekditlevsen Oct 27, 2021
9b87b59
Add scheme for running FirebaseSharedSwiftTests. Adding blindfolded a…
mortenbekditlevsen Oct 28, 2021
b900e9c
Merge remote-tracking branch 'morten/firebaseswiftshared' into codabl…
paulb777 Oct 29, 2021
9f27bce
Merge branch 'codable-refactor' into firebasefunctionsswift
mortenbekditlevsen Oct 30, 2021
ec86d61
Style
mortenbekditlevsen Oct 30, 2021
bfb1353
Style
mortenbekditlevsen Oct 30, 2021
c44c314
Implemented suggestion from Sebastian Schmidt
mortenbekditlevsen Nov 10, 2021
36d8d89
Moved Database.Encoder/Decoder to a new target and rebranded as Struc…
mortenbekditlevsen Oct 23, 2021
c6c8136
Import FirebaseSharedSwift and add test helpers
mortenbekditlevsen Oct 23, 2021
4a57a11
Fix header for EncoderDecoder.swift
mortenbekditlevsen Oct 27, 2021
fdf2355
Add scheme for running FirebaseSharedSwiftTests. Adding blindfolded a…
mortenbekditlevsen Oct 28, 2021
5d8275a
Merge branch 'codable-refactor2' into firebasefunctionsswift
mortenbekditlevsen Nov 17, 2021
2f1c7ae
Added tests for Firebase Functions Swift overlay. Added doc comments.…
mortenbekditlevsen Nov 18, 2021
8cb165b
Added tests for Firebase Functions Swift overlay. Added doc comments.…
mortenbekditlevsen Nov 18, 2021
3205e85
Move encoder and decoder to httpsCallable function
mortenbekditlevsen Nov 20, 2021
603c3e2
style.sh
mortenbekditlevsen Nov 23, 2021
381cf5d
Merge branch 'master' into firebasefunctionsswift
mortenbekditlevsen Nov 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions FirebaseDatabaseSwift/Sources/Codable/EncoderDecoder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import FirebaseDatabase
import FirebaseSharedSwift

extension Database {
public typealias Encoder = StructureEncoder
public typealias Decoder = StructureDecoder
}
111 changes: 111 additions & 0 deletions FirebaseDatabaseSwift/Tests/Codable/ServerValueCodingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,114 @@ extension CurrencyAmount: ExpressibleByFloatLiteral {
self.value = Decimal(value)
}
}

private func assertThat(_ dictionary: [String: Any],
file: StaticString = #file,
line: UInt = #line) -> DictionarySubject {
return DictionarySubject(dictionary, file: file, line: line)
}

func assertThat<X: Equatable & Codable>(_ model: X, file: StaticString = #file,
line: UInt = #line) -> CodableSubject<X> {
return CodableSubject(model, file: file, line: line)
}

func assertThat<X: Equatable & Encodable>(_ model: X, file: StaticString = #file,
line: UInt = #line) -> EncodableSubject<X> {
return EncodableSubject(model, file: file, line: line)
}

class EncodableSubject<X: Equatable & Encodable> {
var subject: X
var file: StaticString
var line: UInt

init(_ subject: X, file: StaticString, line: UInt) {
self.subject = subject
self.file = file
self.line = line
}

@discardableResult
func encodes(to expected: [String: Any],
using encoder: Database.Encoder = .init()) -> DictionarySubject {
let encoded = assertEncodes(to: expected, using: encoder)
return DictionarySubject(encoded, file: file, line: line)
}

func failsToEncode() {
do {
let encoder = Database.Encoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
_ = try encoder.encode(subject)
} catch {
return
}
XCTFail("Failed to throw")
}

func failsEncodingAtTopLevel() {
do {
let encoder = Database.Encoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
_ = try encoder.encode(subject)
XCTFail("Failed to throw", file: file, line: line)
} catch EncodingError.invalidValue(_, _) {
return
} catch {
XCTFail("Unrecognized error: \(error)", file: file, line: line)
}
}

private func assertEncodes(to expected: [String: Any],
using encoder: Database.Encoder = .init()) -> [String: Any] {
do {
let enc = try encoder.encode(subject)
XCTAssertEqual(enc as? NSDictionary, expected as NSDictionary, file: file, line: line)
return (enc as! NSDictionary) as! [String: Any]
} catch {
XCTFail("Failed to encode \(X.self): error: \(error)")
return ["": -1]
}
}
}

class CodableSubject<X: Equatable & Codable>: EncodableSubject<X> {
func roundTrips(to expected: [String: Any],
using encoder: Database.Encoder = .init(),
decoder: Database.Decoder = .init()) {
let reverseSubject = encodes(to: expected, using: encoder)
reverseSubject.decodes(to: subject, using: decoder)
}
}

class DictionarySubject {
var subject: [String: Any]
var file: StaticString
var line: UInt

init(_ subject: [String: Any], file: StaticString, line: UInt) {
self.subject = subject
self.file = file
self.line = line
}

func decodes<X: Equatable & Codable>(to expected: X,
using decoder: Database.Decoder = .init()) -> Void {
do {
let decoded = try decoder.decode(X.self, from: subject)
XCTAssertEqual(decoded, expected)
} catch {
XCTFail("Failed to decode \(X.self): \(error)", file: file, line: line)
}
}

func failsDecoding<X: Equatable & Codable>(to _: X.Type,
using decoder: Database.Decoder = .init()) -> Void {
XCTAssertThrowsError(
try decoder.decode(X.self, from: subject),
file: file,
line: line
)
}
}
74 changes: 74 additions & 0 deletions FirebaseFunctionsSwift/Sources/Codable/Callable+Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import Foundation
import FirebaseFunctions
import FirebaseSharedSwift

public extension Functions {
func httpsCallable<Request: Encodable,
Response: Decodable>(_ name: String,
requestType: Request.Type,
responseType: Response.Type)
-> Callable<Request, Response> {
return Callable(callable: httpsCallable(name))
}
}

public struct Callable<Request: Encodable, Response: Decodable> {
enum CallableError: Error {
case internalError
}

private let callable: HTTPSCallable
init(callable: HTTPSCallable) {
self.callable = callable
}

public func call(_ data: Request,
encoder: StructureEncoder = StructureEncoder(),
decoder: StructureDecoder = StructureDecoder(),
completion: @escaping (Result<Response, Error>)
-> Void) throws {
let encoded = try encoder.encode(data)
callable.call(encoded) { result, error in
do {
if let result = result {
let decoded = try decoder.decode(Response.self, from: result.data)
completion(.success(decoded))
} else if let error = error {
completion(.failure(error))
} else {
completion(.failure(CallableError.internalError))
}
} catch {
completion(.failure(error))
}
}
}

#if compiler(>=5.5) && canImport(_Concurrency)
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
public func call(_ data: Request,
encoder: StructureEncoder = StructureEncoder(),
decoder: StructureDecoder =
StructureDecoder()) async throws -> Response {
let encoded = try encoder.encode(data)
let result = try await callable.call(encoded)
return try decoder.decode(Response.self, from: result.data)
}
#endif
}
1 change: 1 addition & 0 deletions FirebaseSharedSwift/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Loading