Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 50 additions & 23 deletions Sources/Postie/Query/QueryItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ internal protocol QueryItemProtocol {

/// Path parameter value which should be serialized and appended to the URL
var untypedValue: QueryItemValue { get }

}

@propertyWrapper
Expand All @@ -18,67 +17,95 @@ public struct QueryItem<T> where T: QueryItemValue {
self.wrappedValue = wrappedValue
}

public init(defaultValue: T) {
self.wrappedValue = defaultValue
}

public init(name: String?, defaultValue: T) {
public init(name: String? = nil, defaultValue: T) {
self.name = name
self.wrappedValue = defaultValue
wrappedValue = defaultValue
}
}

// MARK: - Encodable

extension QueryItem: Encodable where T: Encodable {}

// MARK: - QueryItemProtocol

extension QueryItem: QueryItemProtocol {

var untypedValue: QueryItemValue {
self.wrappedValue
wrappedValue
}
}

extension QueryItem where T == String {
public extension QueryItem where T == Bool {

public init(name: String?) {
init(name: String?) {
self.name = name
self.wrappedValue = ""
wrappedValue = false
}
}

extension QueryItem where T == String? {
public extension QueryItem where T == Bool? {

public init(name: String?) {
init(name: String?) {
self.name = name
self.wrappedValue = nil
wrappedValue = nil
}
}

extension QueryItem where T == Int? {
public extension QueryItem where T == Double {

public init(name: String?) {
init(name: String?) {
self.name = name
self.wrappedValue = nil
wrappedValue = .zero
}
}

extension QueryItem where T == Bool? {
public extension QueryItem where T == Double? {

public init(name: String?) {
init(name: String?) {
self.name = name
self.wrappedValue = nil
wrappedValue = nil
}
}

extension QueryItem: Encodable where T: Encodable {}
public extension QueryItem where T == Int? {

init(name: String?) {
self.name = name
wrappedValue = nil
}
}

public extension QueryItem where T == String {

init(name: String?) {
self.name = name
wrappedValue = ""
}
}

public extension QueryItem where T == String? {

init(name: String?) {
self.name = name
wrappedValue = nil
}
}

// MARK: - OptionalType

public protocol OptionalType {
associatedtype Wrapped
static var none: Self { get }
}

// MARK: - Optional + OptionalType

extension Optional: OptionalType {}

extension QueryItem where T: OptionalType, T.Wrapped: RawRepresentable {
public extension QueryItem where T: OptionalType, T.Wrapped: RawRepresentable {

public init(name: String?) {
init(name: String?) {
self.init(defaultValue: .none)
self.name = name
}
Expand Down
85 changes: 59 additions & 26 deletions Sources/Postie/Query/QueryItemValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,29 @@ public protocol QueryItemValue {
func iterateCollection(_ iterator: (QueryItemValue) -> Void)
}

extension String: QueryItemValue {
// MARK: - Array + QueryItemValue

extension Array: QueryItemValue where Element: QueryItemValue {

public var serializedQueryItem: String? {
self
fatalError("This method should not be called. Multiple query items should be added to the query individually")
}

public var isCollection: Bool {
return true
}

public func iterateCollection(_ iterator: (QueryItemValue) -> Void) {
forEach(iterator)
}
}

// MARK: - Bool + QueryItemValue

extension Bool: QueryItemValue {

public var serializedQueryItem: String? {
self ? "true" : "false"
}

public var isCollection: Bool { false }
Expand All @@ -20,10 +39,12 @@ extension String: QueryItemValue {
}
}

extension Int: QueryItemValue {
// MARK: - Double + QueryItemValue

extension Double: QueryItemValue {

public var serializedQueryItem: String? {
self.description
description
}

public var isCollection: Bool { false }
Expand All @@ -33,10 +54,12 @@ extension Int: QueryItemValue {
}
}

extension Bool: QueryItemValue {
// MARK: - Int + QueryItemValue

extension Int: QueryItemValue {

public var serializedQueryItem: String? {
self ? "true" : "false"
description
}

public var isCollection: Bool { false }
Expand All @@ -46,39 +69,49 @@ extension Bool: QueryItemValue {
}
}

extension Optional: QueryItemValue where Wrapped: QueryItemValue {
// MARK: - String + QueryItemValue

extension String: QueryItemValue {

public var serializedQueryItem: String? {
guard let value = self else { return nil }
return value.serializedQueryItem
self
}

public var isCollection: Bool {
guard let value = self else { return false }
return value.isCollection
}
public var isCollection: Bool { false }

public func iterateCollection(_ iterator: (QueryItemValue) -> Void) {
guard let value = self else { return }
return value.iterateCollection(iterator)
fatalError("Not supported")
}
}

extension Array: QueryItemValue where Element: QueryItemValue {
// MARK: - Optional + QueryItemValue

extension Optional: QueryItemValue where Wrapped: QueryItemValue {

public var serializedQueryItem: String? {
fatalError("This method should not be called. Multiple query items should be added to the query individually")
guard let value = self else {
return nil
}
return value.serializedQueryItem
}

public var isCollection: Bool {
return true
guard let value = self else {
return false
}
return value.isCollection
}

public func iterateCollection(_ iterator: (QueryItemValue) -> Void) {
forEach(iterator)
guard let value = self else {
return
}
return value.iterateCollection(iterator)
}
}

// MARK: - Set + QueryItemValue

extension Set: QueryItemValue where Element: QueryItemValue {

public var serializedQueryItem: String? {
Expand All @@ -94,17 +127,17 @@ extension Set: QueryItemValue where Element: QueryItemValue {
}
}

extension QueryItemValue where Self: RawRepresentable, RawValue: QueryItemValue {
public extension QueryItemValue where Self: RawRepresentable, RawValue: QueryItemValue {

public var serializedQueryItem: String? {
self.rawValue.serializedQueryItem
var serializedQueryItem: String? {
rawValue.serializedQueryItem
}

public var isCollection: Bool {
self.rawValue.isCollection
var isCollection: Bool {
rawValue.isCollection
}

public func iterateCollection(_ iterator: (QueryItemValue) -> Void) {
self.rawValue.iterateCollection(iterator)
func iterateCollection(_ iterator: (QueryItemValue) -> Void) {
rawValue.iterateCollection(iterator)
}
}
34 changes: 17 additions & 17 deletions Sources/Postie/Strategies/Headers/DefaultHeaderStrategy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@ import Foundation

public struct DefaultHeaderStrategy: ResponseHeaderDecodingStrategy {

public typealias RawValue = String
public typealias RawValue = String

public static func decode(decoder: Decoder) throws -> RawValue {
guard let key = decoder.codingPath.last?.stringValue else {
throw ResponseHeaderDecodingError.missingCodingKey
}
// Check if the decoder is response decoder, otherwise fall back to default decoding logic
guard let responseDecoding = decoder as? ResponseDecoding else {
return try RawValue(from: decoder)
}
// Transform dash separator to camelCase
guard let value = responseDecoding.valueForHeaderCaseInsensitive(key) else {
throw DecodingError.valueNotFound(RawValue.self, DecodingError.Context(
codingPath: decoder.codingPath,
debugDescription: "Missing value for case-insensitive header key: \(key)"
))
}
return value
public static func decode(decoder: Decoder) throws -> RawValue {
guard let key = decoder.codingPath.last?.stringValue else {
throw ResponseHeaderDecodingError.missingCodingKey
}
// Check if the decoder is response decoder, otherwise fall back to default decoding logic
guard let responseDecoding = decoder as? ResponseDecoding else {
return try RawValue(from: decoder)
}
// Transform dash separator to camelCase
guard let value: RawValue = responseDecoding.valueForHeaderCaseInsensitive(key) else {
throw DecodingError.valueNotFound(RawValue.self, DecodingError.Context(
codingPath: decoder.codingPath,
debugDescription: "Missing value for case-insensitive header key: \(key)"
))
}
return value
}
}