Skip to content

Commit

Permalink
Add custom mapper to @params, parse param value more properly
Browse files Browse the repository at this point in the history
  • Loading branch information
kientux committed Jul 5, 2022
1 parent 9f56bb7 commit 90a72e8
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 6 deletions.
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Serialize object to API parameters using convenience property wrapper.

_Useful to generate query items for URLComponents when build URLRequest_

```swift
let params = ParamSerializer().serialize(object: object)

Expand All @@ -16,7 +17,7 @@ components.queryItems = params.map { URLQueryItem(name: $0.key, value: "\($0.val
- Nil and empty array will be remove automatically
- Auto handle array of elements that conform to `CustomStringConvertible`
- Auto expand nested params
- Support custom type by conforms to `ParamConvertible`
- Support any custom type by conforms to `ParamConvertible`, or simply use an in-place custom mapper

```swift
struct ApiParam: ParamsContainer {
Expand Down Expand Up @@ -61,6 +62,30 @@ print(serialized)
// [..., "date": "1970-01-01T00:00:01Z"]
```

### _...or just use a custom mapper in-place_

```swift
struct ApiParam: ParamsContainer {

@Params(mapper: {
if let i = $0 {
return i + 1
} else {
return nil
}
})
var autoIncrement: Int? = nil
}

let params = ApiParam(autoIncrement: 100)
let serialized = ParamSerializer().serialize(object: params)
print(serialized)

// ["autoIncrement": 101]
```

> Note: Conversion will go through custom mapper first, if the returned value also conforms to `ParamConvertible` then it will be converted again using the `ParamConvertible` implementation.
### Nested params will be expanded if also conforms to `ParamsContainer`

```swift
Expand Down Expand Up @@ -116,4 +141,4 @@ let serialized = ParamSerializer(config: config).serialize(object: params)
print(serialized)

// ["THISSHOULDBESNAKECASE": 0]
```
```
6 changes: 6 additions & 0 deletions Sources/Parameterize/ParamSerializer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ public class ParamSerializer {
break
}

// if value is double-wrapped in an Optional
// then the above check is not enough, even when value is actually nil.
if let v = value as? OptionalProtocol, v.isNil {
break
}

if config.ignoreEmptyString, let s = value as? String, s.isEmpty {
break
}
Expand Down
24 changes: 20 additions & 4 deletions Sources/Parameterize/Params.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,22 @@ import Foundation
@propertyWrapper
public struct Params<T> {

public typealias Mapper = (T) -> Any?

let name: String
let mapper: Mapper?

public var wrappedValue: T

public var projectedValue: T {
wrappedValue
}

public init(wrappedValue: T, _ name: String = "") {
public init(wrappedValue: T,
_ name: String = "",
mapper: Mapper? = nil) {
self.name = name
self.mapper = mapper
self.wrappedValue = wrappedValue
}
}
Expand All @@ -30,14 +36,24 @@ extension Params: ParameterPair {
}

var value: Any? {
var v: Any? = wrappedValue
if let mapper = mapper {
return process(value: mapper(wrappedValue))
} else {
return process(value: wrappedValue)
}
}

private func process(value: Any?) -> Any? {
var v: Any? = nil

if let value = wrappedValue as? OptionalProtocol {
if let value = value as? OptionalProtocol {
v = value.wrapped
} else {
v = value
}

if let value = v as? ParamConvertible {
return value.parameterValue
v = value.parameterValue
}

return v
Expand Down
26 changes: 26 additions & 0 deletions Tests/ParameterizeTests/ParameterizeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ final class ParameterizeTests: XCTestCase {

XCTAssertEqual(serialized["created_on_min"] as? String, "1970-01-01T00:00:01Z")
XCTAssertEqual(serialized["custom_type"] as? String, "https%3A%2F%2Fgoogle%2Ecom")
XCTAssert(!serialized.keys.contains("created_on_max"))
}

func testNestedContainer() throws {
Expand Down Expand Up @@ -69,6 +70,19 @@ final class ParameterizeTests: XCTestCase {
.serialize(object: params)
XCTAssert(serialized.keys.contains("NAMINGCONVERT"))
}

func testCustomMapper() throws {
var params = ProductParams(customMapper: 123, optionalCustomMapper: nil)
var serialized = ParamSerializer().serialize(object: params)

XCTAssertEqual(serialized["customMapper"] as? Int, 124)
XCTAssert(!serialized.keys.contains("optionalCustomMapper"))

params.optionalCustomMapper = 100

serialized = ParamSerializer().serialize(object: params)
XCTAssertEqual(serialized["optionalCustomMapper"] as? Int, 101)
}
}

struct ProductParams: ParamsContainer {
Expand Down Expand Up @@ -109,6 +123,18 @@ struct ProductParams: ParamsContainer {
@Params
var NamingConvert2: Int = 0

@Params(mapper: { $0 + 1 })
var customMapper: Int = 0

@Params(mapper: {
if let i = $0 {
return i + 1
} else {
return nil
}
})
var optionalCustomMapper: Int? = nil

var filter: Filter = .init()

struct Filter: ParamsContainer {
Expand Down

0 comments on commit 90a72e8

Please sign in to comment.