CodableWrappers icon indicating copy to clipboard operation
CodableWrappers copied to clipboard

`@EncodeNulls` and `@OptionalEncoding<X>` can’t be used together

Open Brett-Best opened this issue 3 years ago • 0 comments

I want to write something like this:

@Immutable @EncodeNulls @OptionalEncoding<DateFormatterEncoding<RFC3339DateCoder>> var completedOn: Date?

However, currently that doesn’t work. I did try a few variations but from what I could tell we don’t have the functionality to do this yet.

@jayrhynas kindly helped me out and we were able to come up with:

struct Model: Codable {
  @Immutable @EncodeOptionalNulls @OptionalEncoding<DateFormatterEncoding<RFC3339DateCoder>> var completedOn: Date?
}

/// Encodes an optional nil value in a singleValueContainer using `encodeNil` rather than it being omitted.
typealias EncodeOptionalNulls<T: Encodable & OptionalEncodingWrapper> = EncodingUses<OptionalNullStaticEncoder<T>>

struct OptionalNullStaticEncoder<T: Encodable>: StaticEncoder, AnyNullEncoder where T: OptionalEncodingWrapper {
  static func encode(value: T, to encoder: Encoder) throws {
    if case Optional<Any>.none = value.wrappedValue as Any {
      var container = encoder.singleValueContainer()
      try container.encodeNil()
      return
    }
    try value.encode(to: encoder)
  }
}

struct RFC3339DateCoder: DateFormatterStaticCoder {
  static let dateFormatter = with(DateFormatter()) {
    $0.timeZone = TimeZone(secondsFromGMT: 0)
    $0.locale = Locale(identifier: "en_US_POSIX")
    $0.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
  }
}

I’m not sure if the above could be simplified or made so that an additional StaticEncoder struct is not needed?

Brett-Best avatar Feb 10 '22 18:02 Brett-Best