Skip to content

Commit

Permalink
- added shouldIncludeNilValues as member variable of Mapper and Map
Browse files Browse the repository at this point in the history
- only printing null when property is set to true
- added test
  • Loading branch information
tristanhimmelman committed Dec 11, 2016
1 parent c93e462 commit 4b5a2bd
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Sources/ImmutableMappable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ public extension Mapper where N: ImmutableMappable {
internal extension Mapper where N: BaseMappable {

internal func mapOrFail(JSON: [String: Any]) throws -> N {
let map = Map(mappingType: .fromJSON, JSON: JSON, context: context)
let map = Map(mappingType: .fromJSON, JSON: JSON, context: context, shouldIncludeNilValues: shouldIncludeNilValues)

// Check if object is ImmutableMappable, if so use ImmutableMappable protocol for mapping
if let klass = N.self as? ImmutableMappable.Type,
Expand Down
35 changes: 19 additions & 16 deletions Sources/Map.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,17 @@ public final class Map {
var keyIsNested = false
public internal(set) var nestedKeyDelimiter: String = "."
public var context: MapContext?
public var shouldIncludeNilValues = false

let toObject: Bool // indicates whether the mapping is being applied to an existing object

public init(mappingType: MappingType, JSON: [String: Any], toObject: Bool = false, context: MapContext? = nil) {
public init(mappingType: MappingType, JSON: [String: Any], toObject: Bool = false, context: MapContext? = nil, shouldIncludeNilValues: Bool = false) {

self.mappingType = mappingType
self.JSON = JSON
self.toObject = toObject
self.context = context
self.shouldIncludeNilValues = shouldIncludeNilValues
}

/// Sets the current mapper value and key.
Expand Down Expand Up @@ -133,10 +136,10 @@ private func valueFor(_ keyPathComponents: ArraySlice<String>, dictionary: [Stri
let object = dictionary[keyPath]
if object is NSNull {
return (true, nil)
} else if let dict = object as? [String: Any] , keyPathComponents.count > 1 {
} else if keyPathComponents.count > 1, let dict = object as? [String: Any] {
let tail = keyPathComponents.dropFirst()
return valueFor(tail, dictionary: dict)
} else if let array = object as? [Any] , keyPathComponents.count > 1 {
} else if keyPathComponents.count > 1, let array = object as? [Any] {
let tail = keyPathComponents.dropFirst()
return valueFor(tail, array: array)
} else {
Expand All @@ -159,19 +162,19 @@ private func valueFor(_ keyPathComponents: ArraySlice<String>, array: [Any]) ->
if let keyPath = keyPathComponents.first,
let index = Int(keyPath) , index >= 0 && index < array.count {

let object = array[index]
if object is NSNull {
return (true, nil)
} else if let array = object as? [Any] , keyPathComponents.count > 1 {
let tail = keyPathComponents.dropFirst()
return valueFor(tail, array: array)
} else if let dict = object as? [String: Any] , keyPathComponents.count > 1 {
let tail = keyPathComponents.dropFirst()
return valueFor(tail, dictionary: dict)
} else {
return (true, object)
}
let object = array[index]

if object is NSNull {
return (true, nil)
} else if keyPathComponents.count > 1, let array = object as? [Any] {
let tail = keyPathComponents.dropFirst()
return valueFor(tail, array: array)
} else if keyPathComponents.count > 1, let dict = object as? [String: Any] {
let tail = keyPathComponents.dropFirst()
return valueFor(tail, dictionary: dict)
} else {
return (true, object)
}
}

return (false, nil)
Expand Down
10 changes: 6 additions & 4 deletions Sources/Mapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ public enum MappingType {
public final class Mapper<N: BaseMappable> {

public var context: MapContext?
public var shouldIncludeNilValues = false

public init(context: MapContext? = nil){
public init(context: MapContext? = nil, shouldIncludeNilValues: Bool = false){
self.context = context
self.shouldIncludeNilValues = shouldIncludeNilValues
}

// MARK: Mapping functions that map to an existing object toObject
Expand All @@ -65,7 +67,7 @@ public final class Mapper<N: BaseMappable> {
/// Usefull for those pesky objects that have crappy designated initializers like NSManagedObject
public func map(JSON: [String: Any], toObject object: N) -> N {
var mutableObject = object
let map = Map(mappingType: .fromJSON, JSON: JSON, toObject: true, context: context)
let map = Map(mappingType: .fromJSON, JSON: JSON, toObject: true, context: context, shouldIncludeNilValues: shouldIncludeNilValues)
mutableObject.mapping(map: map)
return mutableObject
}
Expand All @@ -92,7 +94,7 @@ public final class Mapper<N: BaseMappable> {

/// Maps a JSON dictionary to an object that conforms to Mappable
public func map(JSON: [String: Any]) -> N? {
let map = Map(mappingType: .fromJSON, JSON: JSON, context: context)
let map = Map(mappingType: .fromJSON, JSON: JSON, context: context, shouldIncludeNilValues: shouldIncludeNilValues)

if let klass = N.self as? StaticMappable.Type { // Check if object is StaticMappable
if var object = klass.objectForMapping(map: map) as? N {
Expand Down Expand Up @@ -272,7 +274,7 @@ extension Mapper {
///Maps an object that conforms to Mappable to a JSON dictionary <String, Any>
public func toJSON(_ object: N) -> [String: Any] {
var mutableObject = object
let map = Map(mappingType: .toJSON, JSON: [:], context: context)
let map = Map(mappingType: .toJSON, JSON: [:], context: context, shouldIncludeNilValues: shouldIncludeNilValues)
mutableObject.mapping(map: map)
return map.JSON
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/ToJSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ internal final class ToJSON {
class func optionalBasicType<N>(_ field: N?, map: Map) {
if let field = field {
basicType(field, map: map)
} else {
} else if map.shouldIncludeNilValues {
basicType(NSNull(), map: map) //If BasicType is nil, emil NSNull into the JSON output
}
}
Expand Down
12 changes: 12 additions & 0 deletions Tests/ObjectMapperTests/BasicTypesTestsToJSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ class BasicTypesTestsToJSON: XCTestCase {

// MARK: Test mapping to JSON and back (basic types: Bool, Int, Double, Float, String)

func testShouldIncludeNilValues(){
let object = BasicTypes()

let JSONWithNil = Mapper<BasicTypes>(shouldIncludeNilValues: true).toJSONString(object, prettyPrint: true)
let JSONWithoutNil = Mapper<BasicTypes>(shouldIncludeNilValues: false).toJSONString(object, prettyPrint: true)

//TODO This test could be improved
XCTAssertNotNil(JSONWithNil)
XCTAssertTrue((JSONWithNil!.characters.count) > 5)
XCTAssertTrue((JSONWithNil!.characters.count) != (JSONWithoutNil!.characters.count))
}

func testMappingBoolToJSON(){
let value: Bool = true
let object = BasicTypes()
Expand Down

0 comments on commit 4b5a2bd

Please sign in to comment.