-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Custom JSON Structure
- Loading branch information
Showing
8 changed files
with
437 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// | ||
// Utils.swift | ||
// VGSFramework | ||
// | ||
// Created by Dima on 10.03.2020. | ||
// Copyright © 2020 VGS. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
/// Merge two <key:value> objects and their nested values. Returns [String: Any]. Values in d2 will override values in d1 if keys are same!!!! | ||
func deepMerge(_ d1: [String: Any], _ d2: [String: Any]) -> [String: Any] { | ||
var result = d1 | ||
for (k2, v2) in d2 { | ||
if let v2 = v2 as? [String: Any], let v1 = result[k2] as? [String: Any] { | ||
result[k2] = deepMerge(v1, v2) | ||
} else { | ||
result[k2] = v2 | ||
} | ||
} | ||
return result | ||
} | ||
|
||
/// Convert string key with separator into dictionary. Ex.: user.name : "Joe" -> ["user": ["name": " Joe"]] | ||
func mapStringKVOToDictionary(key: String, value: Any, separator: String.Element) -> [String: Any] { | ||
let components = key.split(separator: separator).map { String($0) } | ||
|
||
var dict = [String: Any]() | ||
// swiftlint:disable identifier_name | ||
var i = components.count - 1 | ||
|
||
while i >= 0 { | ||
if i == components.count - 1 { | ||
dict[components[i]] = value | ||
} else { | ||
let newDict = [components[i]: dict] | ||
dict = newDict | ||
} | ||
i -= 1 | ||
} | ||
return dict | ||
} | ||
|
||
extension Dictionary { | ||
/// Resturn JSON string representation of dictionary with sorted keys | ||
@available(iOS 11.0, *) | ||
var jsonStringRepresentation: String? { | ||
guard let theJSONData = try? JSONSerialization.data(withJSONObject: self, | ||
options: [.prettyPrinted, .sortedKeys]) else { | ||
return nil | ||
} | ||
|
||
return String(data: theJSONData, encoding: .ascii) | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
framework/Sources/VGSFramework/Core/VGSCollect+internal.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// | ||
// VGSCollect+internal.swift | ||
// VGSFramework | ||
// | ||
// Created by Dima on 10.03.2020. | ||
// Copyright © 2020 VGS. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
internal extension VGSCollect { | ||
|
||
/// Validate tenant id | ||
class func tenantIDValid(_ tenantId: String) -> Bool { | ||
return tenantId.isAlphaNumeric | ||
} | ||
|
||
/// Validate stored textfields input data | ||
func validateStoredInputData() -> Error? { | ||
return validate(storage.elements) | ||
} | ||
|
||
/// Validate specific textfields input data | ||
func validate(_ input: [VGSTextField]) -> Error? { | ||
var isRequiredErrorFields = [String]() | ||
var isRequiredValidOnlyErrorFields = [String]() | ||
|
||
for textField in input { | ||
if textField.isRequired, textField.text.isNilOrEmpty { | ||
isRequiredErrorFields.append(textField.fieldName) | ||
} | ||
if textField.isRequiredValidOnly && !textField.state.isValid { | ||
isRequiredValidOnlyErrorFields.append(textField.fieldName) | ||
} | ||
} | ||
|
||
if isRequiredErrorFields.count > 0 { | ||
return VGSError(type: .inputDataRequired, userInfo: VGSErrorInfo(key: VGSSDKErrorInputDataRequired, description: "Input data can't be nil or empty", extraInfo: ["fields": isRequiredErrorFields])) | ||
} else if isRequiredValidOnlyErrorFields.count > 0 { | ||
return VGSError(type: .inputDataRequiredValidOnly, userInfo: VGSErrorInfo(key: VGSSDKErrorInputDataRequiredValid, description: "Input data should be valid only", extraInfo: ["fields": isRequiredValidOnlyErrorFields])) | ||
} | ||
return nil | ||
} | ||
|
||
/// Turns textfields data saved in Storage and extra data in format ready to submit | ||
func mapStoredInputDataForSubmit(with extraData: [String: Any]? = nil) -> [String: Any] { | ||
|
||
let textFieldsData: BodyData = storage.elements.reduce(into: BodyData()) { (dict, element) in | ||
dict[element.fieldName] = element.rawText | ||
} | ||
|
||
var body = mapInputFieldsDataToDictionary(textFieldsData) | ||
|
||
if let customData = extraData, customData.count != 0 { | ||
// NOTE: If there are similar keys on same level, body values will override customvalues values for that keys | ||
body = deepMerge(customData, body) | ||
} | ||
|
||
return body | ||
} | ||
|
||
/// Maps textfield string key with separator into nesting Dictionary | ||
func mapInputFieldsDataToDictionary(_ body: [String: Any]) -> [String: Any] { | ||
var resultDict = [String: Any]() | ||
for (key, value) in body { | ||
let mappedDict = mapStringKVOToDictionary(key: key, value: value, separator: ".") | ||
let newDict = deepMerge(resultDict, mappedDict) | ||
resultDict = newDict | ||
} | ||
return resultDict | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// | ||
// UtilsTest.swift | ||
// VGSFramework | ||
// | ||
// Created by Dima on 10.03.2020. | ||
// Copyright © 2020 VGS. All rights reserved. | ||
// | ||
|
||
import XCTest | ||
@testable import VGSFramework | ||
|
||
class UtilsTest: XCTestCase { | ||
|
||
func testMapStringKVOToDictionary() { | ||
let stringToMap = "user.data.card_number" | ||
let val = "any" | ||
let separator: String.Element = "." | ||
let expectedResult = [ | ||
"user": [ | ||
"data": [ | ||
"card_number": val | ||
] | ||
] | ||
] | ||
|
||
let result = mapStringKVOToDictionary(key: stringToMap, value: val, separator: separator) | ||
XCTAssertTrue(result.jsonStringRepresentation == expectedResult.jsonStringRepresentation) | ||
} | ||
|
||
func testMapStringKVOToDictionaryWithExtraSeparators() { | ||
let stringToMap = ".user.data...card_number." | ||
let val = "any" | ||
let separator: String.Element = "." | ||
let expectedResult = [ | ||
"user": [ | ||
"data": [ | ||
"card_number": val | ||
] | ||
] | ||
] | ||
|
||
let result = mapStringKVOToDictionary(key: stringToMap, value: val, separator: separator) | ||
XCTAssertTrue(result.jsonStringRepresentation == expectedResult.jsonStringRepresentation) | ||
} | ||
|
||
func testMapStringKVOToDictionaryWithNoSeparators() { | ||
let stringToMap = "card_number" | ||
let val = ["anyValue": "anyKey"] | ||
let separator: String.Element = "." | ||
let expectedResult = [ | ||
"card_number": val | ||
] | ||
|
||
let result = mapStringKVOToDictionary(key: stringToMap, value: val, separator: separator) | ||
XCTAssertTrue(result.jsonStringRepresentation == expectedResult.jsonStringRepresentation) | ||
} | ||
|
||
func testDeepMergeWithoutSimilarKeys() { | ||
let d1 = [ | ||
"user": [ | ||
"data": [ | ||
"card_number": "any" | ||
] | ||
] | ||
] | ||
|
||
let d2 = [ | ||
"data": [ | ||
"user": [ | ||
"id": "any" | ||
] | ||
] | ||
] | ||
|
||
let expectedResult = [ | ||
"user": [ | ||
"data": [ | ||
"card_number": "any" | ||
] | ||
], | ||
"data": [ | ||
"user": [ | ||
"id": "any" | ||
] | ||
] | ||
] | ||
let result = deepMerge(d1, d2) | ||
XCTAssertTrue(expectedResult.jsonStringRepresentation == result.jsonStringRepresentation) | ||
} | ||
|
||
func testDeepMergeWithSimilarKeys() { | ||
let d1 = [ | ||
"user": [ | ||
"data": [ | ||
"card_number": "any", | ||
"Id": "CapitalId" | ||
], | ||
"accountNumber": 1111 | ||
] | ||
] | ||
|
||
let d2 = [ | ||
"user": [ | ||
"data": [ | ||
"id": "anyId" | ||
], | ||
"accountNumber": 2222 | ||
] | ||
] | ||
|
||
let expectedResult = [ | ||
"user": [ | ||
"data": [ | ||
"card_number": "any", | ||
"id": "anyId", | ||
"Id": "CapitalId" | ||
], | ||
"accountNumber": 2222 | ||
] | ||
] | ||
let result = deepMerge(d1, d2) | ||
XCTAssertTrue(expectedResult.jsonStringRepresentation == result.jsonStringRepresentation) | ||
} | ||
} |
Oops, something went wrong.