Skip to content

Commit f893bc0

Browse files
Merge
1 parent 049d4b1 commit f893bc0

File tree

3 files changed

+124
-26
lines changed

3 files changed

+124
-26
lines changed

Sources/ImmutableMappable.swift

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,23 +152,62 @@ public extension Map {
152152
}
153153
return value
154154
}
155-
155+
156+
// MARK: [[BaseMappable]]
157+
/// Returns a `[[BaseMappable]]` or throws an error.
158+
public func value<T: BaseMappable>(_ key: String, nested: Bool? = nil, delimiter: String = ".",
159+
file: StaticString = #file, function: StaticString = #function,
160+
line: UInt = #line) throws -> [[T]] {
161+
let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter)
162+
guard let json2DArray = currentValue as? [[Any]] else {
163+
throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[[Any]]'", file: file,
164+
function: function, line: line)
165+
}
166+
return try json2DArray.map { jsonArray in
167+
try jsonArray.map { jsonObject -> T in
168+
return try Mapper<T>(context: context).mapOrFail(JSONObject: jsonObject)
169+
}
170+
}
171+
}
172+
173+
/// Returns a `[[BaseMappable]]` using transform or throws an error.
174+
public func value<Transform: TransformType>(_ key: String, nested: Bool? = nil, delimiter: String = ".",
175+
using transform: Transform, file: StaticString = #file,
176+
function: StaticString = #function,
177+
line: UInt = #line) throws -> [[Transform.Object]] {
178+
let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter)
179+
guard let json2DArray = currentValue as? [[Any]] else {
180+
throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[[Any]]'",
181+
file: file, function: function, line: line)
182+
}
183+
return try json2DArray.enumerated().map { i, jsonArray in
184+
try jsonArray.enumerated().map { j, json -> Transform.Object in
185+
guard let object = transform.transformFromJSON(json) else {
186+
throw MapError(key: "\(key)[\(i)][\(j)]", currentValue: json,
187+
reason: "Cannot transform to '\(Transform.Object.self)' using \(transform)", file: file,
188+
function: function, line: line)
189+
}
190+
return object
191+
}
192+
}
193+
}
194+
156195
}
157196

158197
public extension Mapper where N: ImmutableMappable {
159-
198+
160199
public func map(JSON: [String: Any]) throws -> N {
161200
return try self.mapOrFail(JSON: JSON)
162201
}
163-
202+
164203
public func map(JSONString: String) throws -> N {
165204
return try mapOrFail(JSONString: JSONString)
166205
}
167-
206+
168207
public func map(JSONObject: Any) throws -> N {
169208
return try mapOrFail(JSONObject: JSONObject)
170209
}
171-
210+
172211
// MARK: Array mapping functions
173212

174213
public func mapArray(JSONArray: [[String: Any]]) throws -> [N] {

Sources/TransformOperators.swift

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -445,46 +445,53 @@ public func <- <Transform: TransformType>(left: inout Array<Transform.Object>!,
445445
}
446446
}
447447

448-
// MARK:- Array of Array of Mappable objects - Array<Array<T: BaseMappable>>> with transforms
448+
// MARK:- Array of Array of objects - Array<Array<T>>> with transforms
449449

450-
/// Array of Array Mappable objects with transform
451-
public func <- <Transform: TransformType>(left: inout Array<Array<Transform.Object>>, right: (Map, Transform)) where Transform.Object: BaseMappable {
450+
/// Array of Array of objects with transform
451+
public func <- <Transform: TransformType>(left: inout [[Transform.Object]], right: (Map, Transform)) {
452452
let (map, transform) = right
453-
if map.mappingType == .fromJSON && map.isKeyPresent, let original2DArray = map.currentValue as? [[Any]]{
453+
switch map.mappingType {
454+
case .toJSON:
455+
left >>> right
456+
case .fromJSON where map.isKeyPresent:
457+
guard let original2DArray = map.currentValue as? [[Any]] else { break }
454458
let transformed2DArray = original2DArray.flatMap { values in
455459
fromJSONArrayWithTransform(values as Any?, transform: transform)
456460
}
457461
FromJSON.basicType(&left, object: transformed2DArray)
458-
} else if map.mappingType == .toJSON {
459-
left >>> right
462+
default:
463+
break
460464
}
461465
}
462466

463-
public func >>> <Transform: TransformType>(left: Array<Array<Transform.Object>>, right: (Map, Transform)) where Transform.Object: BaseMappable {
467+
public func >>> <Transform: TransformType>(left: [[Transform.Object]], right: (Map, Transform)) {
464468
let (map, transform) = right
465-
if map.mappingType == .toJSON {
469+
if map.mappingType == .toJSON{
466470
let transformed2DArray = left.flatMap { values in
467471
toJSONArrayWithTransform(values, transform: transform)
468472
}
469473
ToJSON.basicType(transformed2DArray, map: map)
470474
}
471475
}
472476

473-
474-
/// Optional array of Mappable objects with transform
475-
public func <- <Transform: TransformType>(left:inout Array<Array<Transform.Object>>?, right: (Map, Transform)) where Transform.Object: BaseMappable {
477+
/// Optional array of objects with transform
478+
public func <- <Transform: TransformType>(left: inout [[Transform.Object]]?, right: (Map, Transform)) {
476479
let (map, transform) = right
477-
if map.mappingType == .fromJSON && map.isKeyPresent, let original2DArray = map.currentValue as? [[Any]]{
480+
switch map.mappingType {
481+
case .toJSON:
482+
left >>> right
483+
case .fromJSON where map.isKeyPresent:
484+
guard let original2DArray = map.currentValue as? [[Any]] else { break }
478485
let transformed2DArray = original2DArray.flatMap { values in
479486
fromJSONArrayWithTransform(values as Any?, transform: transform)
480487
}
481488
FromJSON.optionalBasicType(&left, object: transformed2DArray)
482-
} else if map.mappingType == .toJSON {
483-
left >>> right
489+
default:
490+
break
484491
}
485492
}
486493

487-
public func >>> <Transform: TransformType>(left: Array<Array<Transform.Object>>?, right: (Map, Transform)) where Transform.Object: BaseMappable {
494+
public func >>> <Transform: TransformType>(left: [[Transform.Object]]?, right: (Map, Transform)) {
488495
let (map, transform) = right
489496
if map.mappingType == .toJSON {
490497
let transformed2DArray = left?.flatMap { values in
@@ -495,16 +502,20 @@ public func >>> <Transform: TransformType>(left: Array<Array<Transform.Object>>?
495502
}
496503

497504

498-
/// Implicitly unwrapped Optional array of Mappable objects with transform
499-
public func <- <Transform: TransformType>(left: inout Array<Array<Transform.Object>>!, right: (Map, Transform)) where Transform.Object: BaseMappable {
505+
/// Implicitly unwrapped Optional array of objects with transform
506+
public func <- <Transform: TransformType>(left: inout [[Transform.Object]]!, right: (Map, Transform)) {
500507
let (map, transform) = right
501-
if map.mappingType == .fromJSON && map.isKeyPresent, let original2DArray = map.currentValue as? [[Any]] {
508+
switch map.mappingType {
509+
case .toJSON:
510+
left >>> right
511+
case .fromJSON where map.isKeyPresent:
512+
guard let original2DArray = map.currentValue as? [[Any]] else { break }
502513
let transformed2DArray = original2DArray.flatMap { values in
503514
fromJSONArrayWithTransform(values as Any?, transform: transform)
504515
}
505516
FromJSON.optionalBasicType(&left, object: transformed2DArray)
506-
} else if map.mappingType == .toJSON {
507-
left >>> right
517+
default:
518+
break
508519
}
509520
}
510521

Tests/ObjectMapperTests/ImmutableTests.swift

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ class ImmutableObjectTests: XCTestCase {
9090

9191
"prop31a": "String A",
9292
"prop31b": "String B",
93+
94+
// [[String]]
95+
"prop32": [["prop32"]],
96+
"prop33": [["prop33"]],
97+
"prop34": [["prop34"]],
98+
99+
// [[Base]]
100+
"prop35": [[["base": "prop35"]]],
101+
"prop36": [[["base": "prop36"]]],
102+
"prop37": [[["base": "prop37"]]],
93103

94104
"non.nested->key": "string",
95105
"nested": [
@@ -161,6 +171,14 @@ class ImmutableObjectTests: XCTestCase {
161171
XCTAssertEqual(immutable.prop31a.rawValue, StringEnum.A.rawValue)
162172
XCTAssertEqual(immutable.prop31b.rawValue, StringEnum.B.rawValue)
163173

174+
XCTAssertEqual(immutable.prop32[0][0], "prop32_TRANSFORMED")
175+
XCTAssertEqual(immutable.prop33![0][0], "prop33_TRANSFORMED")
176+
XCTAssertEqual(immutable.prop34[0][0], "prop34_TRANSFORMED")
177+
178+
XCTAssertEqual(immutable.prop35[0][0].base, "prop35")
179+
XCTAssertEqual(immutable.prop36![0][0].base, "prop36")
180+
XCTAssertEqual(immutable.prop37[0][0].base, "prop37")
181+
164182
XCTAssertEqual(immutable.nonnestedString, "string")
165183

166184
XCTAssertEqual(immutable.nestedInt, 123)
@@ -333,6 +351,14 @@ struct Struct {
333351
let prop31a: StringEnum
334352
let prop31b: StringEnum
335353

354+
let prop32: [[String]]
355+
let prop33: [[String]]?
356+
let prop34: [[String]]!
357+
358+
let prop35: [[Base]]
359+
let prop36: [[Base]]?
360+
let prop37: [[Base]]!
361+
336362
var nonnestedString: String
337363
var nestedInt: Int
338364
var nestedString: String
@@ -390,6 +416,14 @@ extension Struct: ImmutableMappable {
390416

391417
prop31a = try map.value("prop31a")
392418
prop31b = try map.value("prop31b")
419+
420+
prop32 = try map.value("prop32", using: stringTransform)
421+
prop33 = try? map.value("prop33", using: stringTransform)
422+
prop34 = try? map.value("prop34", using: stringTransform)
423+
424+
prop35 = try map.value("prop35")
425+
prop36 = try? map.value("prop36")
426+
prop37 = try? map.value("prop37")
393427

394428
nonnestedString = try map.value("non.nested->key", nested: false)
395429

@@ -454,6 +488,14 @@ extension Struct: ImmutableMappable {
454488
prop31a >>> map["prop31a"]
455489
prop31b >>> map["prop31b"]
456490

491+
prop32 >>> (map["prop32"], stringTransform)
492+
prop33 >>> (map["prop33"], stringTransform)
493+
prop34 >>> (map["prop34"], stringTransform)
494+
495+
prop35 >>> map["prop35"]
496+
prop36 >>> map["prop36"]
497+
prop37 >>> map["prop37"]
498+
457499
nonnestedString >>> map["non.nested->key", nested: false]
458500

459501
nestedInt >>> map["nested.int"]
@@ -476,7 +518,7 @@ let stringTransform = TransformOf<String, String>(
476518
return "\(str)_TRANSFORMED"
477519
},
478520
toJSON: { (str: String?) -> String? in
479-
return str?.replacingOccurrences(of: "_TRANSFORMED", with: "", options: [], range: nil)
521+
return str?.replacingOccurrences(of: "_TRANSFORMED", with: "")
480522
}
481523
)
482524

@@ -506,4 +548,10 @@ private func assertImmutableObjectsEqual(_ lhs: Struct, _ rhs: Struct) {
506548
XCTAssertEqual("\(lhs.prop20)", "\(rhs.prop20)")
507549
XCTAssertEqual("\(lhs.prop21)", "\(rhs.prop21)")
508550
XCTAssertEqual("\(lhs.prop22)", "\(rhs.prop22)")
551+
XCTAssertEqual("\(lhs.prop32)", "\(rhs.prop32)")
552+
XCTAssertEqual("\(lhs.prop33)", "\(rhs.prop33)")
553+
XCTAssertEqual("\(lhs.prop34)", "\(rhs.prop34)")
554+
XCTAssertEqual("\(lhs.prop35)", "\(rhs.prop35)")
555+
XCTAssertEqual("\(lhs.prop36)", "\(rhs.prop36)")
556+
XCTAssertEqual("\(lhs.prop37)", "\(rhs.prop37)")
509557
}

0 commit comments

Comments
 (0)