Skip to content

Commit 5fdfc9d

Browse files
Hui-Wuwilhuff
authored andcommitted
Firestore swift Codable support (#3198)
FirestoreEncoder/Decoder and Timestamp/GeoPoint codable support.
1 parent f7d2616 commit 5fdfc9d

File tree

4 files changed

+1240
-4826
lines changed

4 files changed

+1240
-4826
lines changed

Firestore/Swift/Source/Codable/third_party/FirestoreDecoder.swift

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import Foundation
1818

1919
extension Firestore {
2020
public struct Decoder {
21-
fileprivate static let documentRefUserInfoKey = CodingUserInfoKey(rawValue: "DocumentRefUserInfoKey")
22-
2321
public init() {}
2422
/// Returns an instance of specified type from a Firestore document.
2523
///
@@ -28,22 +26,13 @@ extension Firestore {
2826
/// in `container` are directly supported:
2927
/// - GeoPoint
3028
/// - Timestamp
31-
/// - DocumentReference
3229
///
3330
/// - Parameters:
3431
/// - A type to decode a document to.
3532
/// - container: A Map keyed of String representing a Firestore document.
36-
/// - document: A reference to the Firestore Document that is being
37-
/// decoded.
3833
/// - Returns: An instance of specified type by the first parameter.
39-
public func decode<T: Decodable>(_: T.Type,
40-
from container: [String: Any],
41-
in document: DocumentReference? = nil) throws -> T {
34+
public func decode<T: Decodable>(_: T.Type, from container: [String: Any]) throws -> T {
4235
let decoder = _FirestoreDecoder(referencing: container)
43-
if let doc = document {
44-
decoder.userInfo[Firestore.Decoder.documentRefUserInfoKey!] = doc
45-
}
46-
4736
guard let value = try decoder.unbox(container, as: T.self) else {
4837
throw DecodingError.valueNotFound(
4938
T.self,
@@ -333,24 +322,6 @@ private struct _FirestoreKeyedDecodingContainer<K: CodingKey>: KeyedDecodingCont
333322
}
334323

335324
public func decode<T: Decodable>(_: T.Type, forKey key: Key) throws -> T {
336-
if T.self == SelfDocumentID.self {
337-
let docRef = decoder.userInfo[
338-
Firestore.Decoder.documentRefUserInfoKey!
339-
] as! DocumentReference?
340-
341-
if contains(key) {
342-
let docPath = (docRef != nil) ? docRef!.path : "nil"
343-
var codingPathCopy = codingPath.map { key in key.stringValue }
344-
codingPathCopy.append(key.stringValue)
345-
346-
throw FirestoreDecodingError.fieldNameConfict("Field name " +
347-
"\(codingPathCopy) was found from document \"\(docPath)\", " +
348-
"cannot assign the document reference to this field.")
349-
}
350-
351-
return SelfDocumentID(from: docRef) as! T
352-
}
353-
354325
let entry = try require(key: key)
355326

356327
decoder.codingPath.append(key)
@@ -1006,10 +977,6 @@ extension _FirestoreDecoder {
1006977

1007978
func unbox(_ value: Any, as type: Date.Type) throws -> Date? {
1008979
guard !(value is NSNull) else { return nil }
1009-
// Firestore returns all dates as Timestamp, converting it to Date so it can be used in custom objects.
1010-
if let timestamp = value as? Timestamp {
1011-
return timestamp.dateValue()
1012-
}
1013980
guard let date = value as? Date else {
1014981
throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value)
1015982
}
@@ -1066,7 +1033,7 @@ extension _FirestoreDecoder {
10661033
}
10671034
}
10681035

1069-
// Decoding an embedded container, this requires expanding the storage stack and
1036+
// Decoding an embeded container, this requires expanding the storage stack and
10701037
// then restore after decoding.
10711038
storage.push(container: value)
10721039
let decoded = try T(from: self)

Firestore/Swift/Source/Codable/third_party/FirestoreEncoder.swift

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,11 @@ extension Firestore {
3030
/// The Firestore pass-through types are:
3131
/// - GeoPoint
3232
/// - Timestamp
33-
/// - DocumentReference
3433
///
3534
/// - Parameter value: The Encodable object to convert to encoded data.
3635
/// - Returns: A Map keyed by String representing a document Firestore
3736
/// API can work with.
3837
public func encode<T: Encodable>(_ value: T) throws -> [String: Any] {
39-
// SelfDocumentID, DocumentReference and FieldValue cannot be
40-
// encoded directly.
41-
guard T.self != SelfDocumentID.self,
42-
T.self != DocumentReference.self,
43-
T.self != FieldValue.self else {
44-
throw FirestoreEncodingError.encodingIsNotSupported
45-
}
4638
guard let topLevel = try _FirestoreEncoder().box_(value) else {
4739
throw EncodingError.invalidValue(value,
4840
EncodingError.Context(codingPath: [],
@@ -215,11 +207,6 @@ private struct _FirestoreKeyedEncodingContainer<K: CodingKey>: KeyedEncodingCont
215207
public mutating func encode(_ value: Double, forKey key: Key) throws { container[key.stringValue] = encoder.box(value) }
216208

217209
public mutating func encode<T: Encodable>(_ value: T, forKey key: Key) throws {
218-
// `SelfDocumentID` is ignored during encoding.
219-
if T.self == SelfDocumentID.self {
220-
return
221-
}
222-
223210
encoder.codingPath.append(key)
224211
defer {
225212
encoder.codingPath.removeLast()
@@ -508,7 +495,7 @@ extension _FirestoreEncoder: SingleValueEncodingContainer {
508495
}
509496

510497
/// Special subclass of `_FirestoreEncoder` used by `superEncoder`.
511-
/// It inherits the codingPath from the referencing `_FirestoreEncoder` but uses its own
498+
/// It inherits the codingPath from the referencing `_FirestoreEncoder` but uses it's own
512499
/// storage. The encoded result will be written back to the referencing encoder's storage
513500
/// when it is `deinit`-ed.
514501
private class _FirestoreReferencingEncoder: _FirestoreEncoder {

0 commit comments

Comments
 (0)