Skip to content

Add NullCodable capabilities #8

@mdb1

Description

@mdb1

Some requests require the json objects to explicitly use "null", add the NullCodable struct to handle those scenarios

//
//  JSONEncoder+NullCodable.swift
//
//
//  Created by Manu on 17/05/2023.
//  Based on: https://github.com/g-mark/NullCodable

import Foundation

/// Property wrapper that encodes `nil` optional values as `null`
/// when encoded using `JSONEncoder`.
///
/// For example, adding `@NullCodable` like this:
/// ```swift
/// struct Test: Codable {
///     @NullCodable var name: String? = nil
/// }
/// ```
/// will encode as: "{\\"name\\": null}" - as opposed to the default,
/// which is to omit the property from the encoded json, like: "{}".
@propertyWrapper
public struct NullCodable<Wrapped> {
    /// The wrapper value.
    public var wrappedValue: Wrapped?

    /// Initializer.
    public init(wrappedValue: Wrapped?) {
        self.wrappedValue = wrappedValue
    }
}

extension NullCodable: Encodable where Wrapped: Encodable {
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch wrappedValue {
        case let .some(value):
            try container.encode(value)
        case .none:
            try container.encodeNil()
        }
    }
}

extension NullCodable: Decodable where Wrapped: Decodable {
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if !container.decodeNil() {
            wrappedValue = try container.decode(Wrapped.self)
        }
    }
}

extension NullCodable: Equatable where Wrapped: Equatable {}

public extension KeyedDecodingContainer {
    /// Decoding method.
    func decode<Wrapped>(
        _: NullCodable<Wrapped>.Type,
        forKey key: KeyedDecodingContainer<K>.Key
    ) throws -> NullCodable<Wrapped> where Wrapped: Decodable {
        try decodeIfPresent(NullCodable<Wrapped>.self, forKey: key) ?? NullCodable<Wrapped>(wrappedValue: nil)
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions