Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional values ignored when encoding #84

Open
Wiingaard opened this issue Dec 11, 2019 · 2 comments
Open

Optional values ignored when encoding #84

Wiingaard opened this issue Dec 11, 2019 · 2 comments

Comments

@Wiingaard
Copy link
Contributor

Wiingaard commented Dec 11, 2019

First of all, thank you very much how this super useful library, I've been using it a lot and I really like it 👍

I'm not sure this is an actual issue or it's the intended behavior, but I'm having issues encoding models with optional values into data that I can use to update child values in the Realtime Database.

See the following model:

struct TestModel: Codable {
    let id: String
    let optionalField: String?
}

This is how I would encode it:

let model = TestModel.init(id: "123", optionalField: nil)
let encoder = FirebaseEncoder()
let data = try! encoder.encode(model)

When I inspect data, I see the following:

po data
▿ 1 element
  ▿ 0 : 2 elements
    - key : id
    - value : 123

It's seen that the key-value pair for the optionalField isn't included in the result
Here I would expect it to be encoded into

let data: [String: Any] = [
    "id": "123",
    "optionalField": NSNull()
]
/*
po data
▿ 2 elements
  ▿ 0 : 2 elements
    - key : "optionalField"
    - value : <null>
  ▿ 1 : 2 elements
    - key : "id"
    - value : "123"
*/

Lets say I have the following data in the realtime Database

/testData
    /123
        /id: "123"
        /optionalField: "abc"

And I then want to update that model to at some point, with a an instance of the model that has optionalField as nil. I would do it like this:

let path = Database.database().reference(withPath: "testData/123")
    
let model = TestModel.init(id: "1234", optionalField: nil)
let encoder = FirebaseEncoder()
let data = try! encoder.encode(model)
    
let dataDict = data as! [String: Any]
path.updateChildValues(dataDict)

In this case the nothing is written to optionalField, because the FirebaseEncoder ignores that value when it's nil.

As mentioned, I'm not sure if this is the intent behaviour or a bug. On one hand, this is the same behavior the JSONEncoder has it also ignores nil-values. On the other hand it would be handy to have nil-value converted into NSNull, since this is what Firebase uses to delete values, and when inspecting the source code for _FirebaseEncoder, it seems to me that this is in fact the intended behaviour.

For now, I can work around this with using the setValue function on the DatabaseReference instead of the updateChildValues, but it sure would be handy for me if this optional value in fact would be encoded into NSNull.

@FrangSierra
Copy link

Any new about this? Any workaround possible @Wiingaard ? could u provide an example of how u are doing the workaround of this for multiple fields?

@jgale
Copy link

jgale commented Mar 17, 2020

You can use the ExplicitNull annotation to do what you want:

struct TestModel: Codable {
    let id: String
    @ExplicitNull let optionalField: String?
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants