0

Firebase Android library has Exclude annotation which allows to ignore a property when saving/retrieving object to and from database.

Is there a similar property wrapper for Swift FirebaseFirestoreSwift library?

As far as I can see DocumentId annotation has equivalent property wrapper in Swift library.

What is the best way to exclude property from database in Codable object in Swift anyway?

Dharmaraj
  • 47,845
  • 8
  • 52
  • 84
Paul B
  • 3,989
  • 33
  • 46
  • 2
    Isn't that part of `Codable`? I.e. https://stackoverflow.com/questions/44655562/how-to-exclude-properties-from-swift-codable – Frank van Puffelen Mar 09 '23 at 14:27
  • Yes, @FrankvanPuffelen ` CodingKey` solution was the first thing that came to my mind. But it was quite verbose, so I decided to look if better way exists. There are already some property wrappers that are specific to Firebase Encoder/Decoder (@ServerTimestamp, @ExplicitNull, @DocumentID. So theoretically there could exist the convenience wrapper in question. As it exists for Android. – Paul B Mar 09 '23 at 14:48

2 Answers2

3

Using CodingKeys is the default mechanism to fine-tune Codable's mapping. If you're interested in how Codable works in general, check out this excellent book: Flight School Guide to Swift Codable and this Hacking with Swift article: Codable cheat sheet – Hacking with Swift.

The Firebase documentation has a comprehensive guide for using Codable with Firestore: Map Cloud Firestore data with Swift Codable, which talks about customising the mapping in this section:

Any property that is not listed as a case on the respective CodingKeys enum will be ignored during the mapping process. This can actually be convenient if we specifically want to exclude some of the properties from being mapped.

If you find anything missing in this guide, please let us know so we can add it.

Peter Friese
  • 6,709
  • 31
  • 43
  • Really comprehensive answer and probably the best one. I've shared my solution too, maybe someone will find it helpful or point out its weak sides. – Paul B Mar 23 '23 at 13:58
0

I've created such wrapper. It makes code more concise. It indeed deals with Codable, and should work fine with Firebase Coder as good as with any other one (such as JSONEncoder/Decoder). Let me modestly present

@CodableExcluded

import Foundation

@propertyWrapper
public struct CodableExcluded<Wrapped> {
    public var wrappedValue: Wrapped?
    
    public init(wrappedValue: Wrapped?) {
        self.wrappedValue = wrappedValue
    }
}

extension CodableExcluded: Encodable {
    public func encode(to encoder: Encoder) throws {
        // Do nothing. Actually this is never called due to empty `encode<Wrapped>` func in `KeyedEncodingContainer`
    }
}

extension CodableExcluded: Decodable {
    public init(from decoder: Decoder) throws {
        self.wrappedValue = nil
    }
}

extension KeyedDecodingContainer {
    public func decode<Wrapped>(_ type: CodableExcluded<Wrapped>.Type, forKey key: Self.Key) throws -> CodableExcluded<Wrapped> {
        CodableExcluded(wrappedValue: nil)
    }
}

extension KeyedEncodingContainer {
    public mutating func encode<Wrapped>(_ value: CodableExcluded<Wrapped>, forKey key: KeyedEncodingContainer<K>.Key) throws {
        // Do nothing.
    }
}

Usage

struct Test: Codable {
    var codedString = "This will be included during encoding and decoded back."
    @CodableExcluded var nonCodedString: String? = "This will NOT be included when encodig and assigned `nil` when decoded from decoded."
}

let data = try JSONEncoder().encode(Test())
print(String(data: data, encoding: .utf8) ?? "")

let obj = try JSONDecoder().decode(Test.self, from: data)
print(obj)
Paul B
  • 3,989
  • 33
  • 46