firebase-ios-sdk: BUG DECODING KEYS FROM FIRESTORE.

Description

The firestore decoder keep in mind _JSONStringDictionaryDecodableMarker.Type. So for maps, if we have something like this:

{ "name": {"KEY": VALUE } }

and we decode it with a codable structure with a property of type [String: String] it works.

The Behavior using [EnumStringRawValue: String] does fail into:

typeMismatch : 2 elements
    - .0 : Swift.Array<Any>
    ▿ .1 : Context
      ▿ codingPath : 1 element
        - 0 : CodingKeys(stringValue: "KEY", intValue: nil)
      - debugDescription : "Expected to decode Array<Any> but found a dictionary instead."
      - underlyingError : nil

Because in this case key is always represented as a String

extension Dictionary : _JSONStringDictionaryDecodableMarker where Key == String, Value: Decodable {
  static var elementType: Decodable.Type { return Value.self }
} 

The expected behavior is to decode a map with an enum string raw representable if it can fit on the string raw representable cases.

Reproducing the issue

Add a document with a map in Firestore.

Try to decode it with document.data() passing as an argument your struct or class metatype. Inside of the struct or class metatype define a map with StringRawValueEnum as key.

Firebase SDK Version

10.23.0

Xcode Version

15.2

Installation Method

Swift Package Manager

Firebase Product(s)

Firestore

Targeted Platforms

iOS

Relevant Log Output

No response

If using Swift Package Manager, the project’s Package.resolved

Expand Package.resolved snippet

Replace this line with the contents of your Package.resolved.

If using CocoaPods, the project’s Podfile.lock

Expand Podfile.lock snippet

Replace this line with the contents of your Podfile.lock!

About this issue

  • Original URL
  • State: open
  • Created 3 months ago
  • Comments: 16 (8 by maintainers)

Most upvoted comments

The behavior is inherited from Apple’s JSONDecoder.

The reason is historical, but in the lines of: You can use anything as Dictionary keys as long as it can be hashed. But if it’s not a String then we can’t encode it to (and ditto decode from) a ‘keyed container’ (which requires keys to be Strings or Ints I believe).

Thus, the strategy was: if the key is not a String, we encode keys and values alternately into an unkeyedContainer (array/list).

This is why you see that it expects the (encoded) data to be in the shape of an array. When decoding.

At the time they missed the case: but what if your key still encodes as a String. Specifically: what if it’s RawRepresentable as a String.

And that’s what SE-0320 tries to deal with. But it’s too late to make a global fix. It must be done case by case, which is a real shame.