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)
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.