null value under KeyPath
kamil-tomaszewski opened this issue · 6 comments
Hi,
Awesome library! I'm trying to figure out how to handle a case when a given field may contain null value. Right now I receive
UnexpectedInputType("Unexpectedly found nil input. KeyPath: .KeyPath(Date2) Expected: String")
which is quite understandable given it contains null
value.
How should I approach it?
@kamil-tomaszewski Thanks for checking it out!
That error occurs because it's expecting to find a value of type String
for your model, but unfortunately it's finding nil
.
Instead, you should use type String?
so that nil
is an acceptable value.
Let me know if that doesn't solve your problem.
Best,
Logan
Then we have a problem :) Here's the struct:
struct Event {
var id: Int?
var name: String?
var date1: NSDate?
var date2: NSDate?
var location: String = ""
var city: String = ""
var state: String = ""
func fullLocation() -> String {
return location + " " + city + ", " + state
}
}
And here's the mapping:
extension Event: StandardMappable {
init(map: Map) throws {
try id <~ map["EventID"]
try name <~ map["Name"]
try location <~ map["Location"]
try city <~ map["City"]
try state <~ map["State"]
try date1 <~ map["Date1"]
.transformFromJson(NSDate.dateWithJSString)
try date2 <~ map["Date2"]
.transformFromJson(NSDate.dateWithJSString)
}
mutating func sequence(map: Map) throws {
try id ~> map["EventID"]
try name ~> map["Name"]
try location ~> map["Location"]
try city ~> map["City"]
try state ~> map["State"]
}
}
As you can see date2 is clearly an optional, yet it still expects a String.
The interesting part of JSON:
"Date2":null
I see what's going on now, I didn't realize you were using a transformer. Transformers fall under the same type restrictions as variables, so if NSDate.dateWithJSString
expects a String
and we receive nil
in the Json, the system doesn't know how to handle it.
If you make dateWithJSString
accept a String?
it should be resolved. Or you could put it in a closure:
try date2 <~ map["Date2"]
.transformFromJson { (input: String?) -> NSDate? in
guard let input = input else { return nil }
return NSDate.dateWithJSString(input)
}
I've considered in the past investigating transform returns and if it's optional, skip the transformer and return the argument. Unfortunately, this creates some situations where the user expects a failure for an unsatisfied value, and it won't exactly work. For now, you'll have to be explicit about input types in transformers.
Thanks for your help! :) This works, and as you've mentioned this is truly better approach than skipping the transformer.
I've also found an issue with keyPath names, but I'll post it with a playground so you can test it.
Awesome library TBH, I very much like the failure driven approach.
@kamil-tomaszewski Happy to investigate the key paths issue as well, there are a few caveats to the current system, and I'm happy to help figure out what's going on.
Closing this for now, we can still chat about the keypath on this thread, and reopen if we need to.