Dealing with optional variables (basic types and enum)
jimmyti opened this issue ยท 3 comments
jimmyti commented
I am learning how to use Genome, and so far I am impressed with the flexibility offered by Genome. ๐
- Is it possible to declare optional variables (both basic type and enum) that will not be mapped to JSON at all if they are nil?
- An extension to this question is how do I specify the transformToNode and transformFromNode functions for these optional variables?
- I am trying to extend Date class, making it NodeRepresentable and NodeConvertible. (See code below). Would this implementation be able to handle when date is nil during serialization (my intention is to skip saving date data if date is nil) and when the JSON data is absent during deserialization (my intention is to leave the date variable uninitialized)?
extension Date: NodeRepresentable {
public func makeNode(context: Context = EmptyNode) throws -> Node {
return .string(self.ISO8601String())
}
}
extension Date: NodeConvertible {
public init(node: Node, in context: Context) throws {
guard let string = node.string else {
throw NodeError.unableToConvert(node: node, expected: "\(String.self)")
}
guard let date = Date.dateFromISO8601String(string: string) else {
throw NodeError.unableToConvert(node: node, expected: "Date is stored in ISO8601 format")
}
self = date
}
}
Example class definition:
enum FooType: Int8 {
case typeA
case typeB
}
class Bar: BasicMappable {
var foo: FooType?
var date: Date?
var name: String?
required init() {
}
func sequence(map: Map) throws {
try foo <~> map["foo"]
try date <~> map["date"]
try name <~> map["name"]
}
}
loganwright commented
@jimmyti there's a lot here, so let me know if I miss something.
- What you have should automatically return
nil
fordate
property if the json atdate
isnil
. If that's not what you're seeing, there may be a bug. The expected behavior would be that if something is optional andnil
is received in JSON, it should becomenil
- You can define individually by simply adding
.transform
chained to the end
try date <~> map["date"]
.transformFromNode(stringToOptionalDate)
.transformToNode(optionalDateToString)
- It should be able to handle it. Internally Genome checks if JSON key is
nil
before passing to initializers. If it is nil and user is expecting optional we returnnil
, otherwise return error.
Let me know if you see other things!
jimmyti commented
@loganwright thank you for answering!
- In the case of transforming from variable to JSON, can I assume that the input to the transformToNode func will always be non-nil? transformToNode doesn't seem to like me returning an optional there. In other words, is it safe to code transformToNode for foo as such (using forced unwrapped):
- I have included a variable foos with type of [FooType]. Would you be able to show me the code to transform [FooType], i.e. transformToNode, transformFromNode.
enum FooType: Int8 {
case typeA
case typeB
}
class Bar: BasicMappable {
var foo: FooType?
var date: Date?
var name: String?
var foos: [FooType]?
required init() {
}
func sequence(map: Map) throws {
try foo <~> map["foo"]
.transformFromNode {
FooType(rawValue: $0)
}
.transformToNode {
$0!.rawValue
}
try date <~> map["date"]
try foos <~> map["foos"]
.transformFromNode {
// how to handle transforming node to enum collection
}
.transformToNode {
// how to handle transforming enum collection to JSON
}
}
}
loganwright commented
@jimmyti let me look into the optional thing, you should be able to, but the transform functions are super generic, and sometimes require more type information in unexpected ways. For this stuff though, I think you'd reduce a lot of your code by conforming FooType
to NodeConvertible
. Once you do that, you shouldn't need transformers for foo
or foos
, it'd just be:
func sequence(map: Map) throws {
try foo <~> map["foo"]
try date <~> map["date"]
try foos <~> map["foos"]
}