Created
June 25, 2020 15:57
-
-
Save cemolcay/35083e79ad4e4f1a0da0f87fc940c31c to your computer and use it in GitHub Desktop.
Validates swift dictionary with rules
This file contains hidden or 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
import UIKit | |
var data: [String: Any] = [ | |
"connection": [ | |
"wifi": [ | |
"sx": 1.1, | |
"tx": 11 | |
], | |
"cell": [ | |
"rx": 10, | |
"tx": 0.1 | |
] | |
], | |
"system": [ | |
"device": [ | |
"name": "Somee", | |
"version": "0.0.1" | |
] | |
] | |
] | |
var rules: [String: Any] = [ | |
"connection": [ | |
"wifi": [ | |
"sx": "Double(0.0,1.0)", | |
"tx": "Int(1,10)" | |
], | |
"cell": [ | |
"rx": "Int(<10)", | |
"tx": "Double(>0.0)" | |
] | |
], | |
"system": [ | |
"device": [ | |
"name": "String[Some,Some 2,Some 3]" | |
] | |
] | |
] | |
protocol ValidatorDataType: Comparable {} | |
extension String: ValidatorDataType {} | |
extension Double: ValidatorDataType {} | |
extension Float: ValidatorDataType {} | |
extension Int: ValidatorDataType {} | |
enum Validator<T: ValidatorDataType>: CustomStringConvertible { | |
case range(ClosedRange<T>) | |
case one(Array<T>) | |
case greaterThan(T) | |
case lessThan(T) | |
func isValid(value: T) -> Bool { | |
switch self { | |
case .range(let r): | |
return r.contains(value) | |
case .one(let o): | |
return o.contains(value) | |
case .greaterThan(let v): | |
return value > v | |
case .lessThan(let v): | |
return value < v | |
} | |
} | |
var description: String { | |
var type = "" | |
switch T.self { | |
case is String.Type: | |
type = "String" | |
case is Double.Type: | |
type = "Double" | |
case is Float.Type: | |
type = "Float" | |
case is Int.Type: | |
type = "Int" | |
default: | |
type = "" | |
} | |
switch self { | |
case .range(let range): | |
return "\(type)(\(range.lowerBound),\(range.upperBound)" | |
case .one(let array): | |
return "\(type)[\(array.map({ "\($0)" }).joined(separator: ","))]" | |
case .greaterThan(let value): | |
return "\(type)(>\(value))" | |
case .lessThan(let value): | |
return "\(type)(<\(value))" | |
} | |
} | |
} | |
public func validate(data: [String: Any], rules: [String: Any]) -> [String: Any] { | |
var validatedData = data | |
for (key, value) in validatedData { | |
if let valueData = value as? [String: Any], | |
let valueRules = rules[key] as? [String: Any] { | |
validatedData[key] = validate(data: valueData, rules: valueRules) | |
} | |
guard let validValue = rules[key] as? String else { continue } | |
print(key, value, validValue) | |
do { | |
let oneTypePattern = "^(.*?)\\[" | |
let onePattern = "\\[([^()]*)\\]" | |
let rangeTypePattern = "^(.*?)\\(" | |
let rangePattern = "\\(([^()]*)\\)" | |
let patternRange = NSRange(0 ..< validValue.count) | |
if let oneTypeMatch = try NSRegularExpression(pattern: oneTypePattern, options: []) | |
.firstMatch(in: validValue, options: [], range: patternRange), | |
let oneTypeRange = Range(oneTypeMatch.range(at: 1), in: validValue) { | |
let oneType = validValue[oneTypeRange] | |
if let oneArrayMatch = try NSRegularExpression(pattern: onePattern, options: []) | |
.firstMatch(in: validValue, options: [], range: patternRange), | |
let oneArrayRange = Range(oneArrayMatch.range(at: 1), in: validValue) { | |
let oneArray = validValue[oneArrayRange].split(separator: ",") | |
switch String(oneType) { | |
case "String": | |
guard let value = value as? String else { break } | |
let validator = Validator<String>.one(oneArray.map({ String($0) })) | |
let isValid = validator.isValid(value: value) | |
validatedData[key] = isValid ? value : "!(\(value),\(validator))" | |
print(isValid) | |
case "Int": | |
guard let value = value as? Double else { break } | |
let validator = Validator<Int>.one(oneArray.compactMap({ Int($0) })) | |
let isValid = validator.isValid(value: Int(value)) | |
validatedData[key] = isValid ? value : "!(\(value),\(validator))" | |
print(isValid) | |
case "Float": | |
guard let value = value as? Double else { break } | |
let validator = Validator<Float>.one(oneArray.compactMap({ Float($0) })) | |
let isValid = validator.isValid(value: Float(value)) | |
validatedData[key] = isValid ? value : "!(\(value),\(validator))" | |
print(isValid) | |
case "Double": | |
guard let value = value as? Double else { break } | |
let validator = Validator<Double>.one(oneArray.compactMap({ Double($0) })) | |
let isValid = validator.isValid(value: value) | |
validatedData[key] = isValid ? value : "!(\(value),\(validator))" | |
print(isValid) | |
default: | |
break | |
} | |
} | |
} | |
if let rangeTypeMatch = try NSRegularExpression(pattern: rangeTypePattern, options: []) | |
.firstMatch(in: validValue, options: [], range: patternRange), | |
let rangeTypeRange = Range(rangeTypeMatch.range(at: 1), in: validValue) { | |
let rangeType = validValue[rangeTypeRange] | |
if let rangeArrayMatch = try NSRegularExpression(pattern: rangePattern, options: []) | |
.firstMatch(in: validValue, options: [], range: patternRange), | |
let rangeArrayRange = Range(rangeArrayMatch.range(at: 1), in: validValue) { | |
var rangeValue = "" | |
var validatorType = "" | |
if validValue[rangeArrayRange].first == ">" { | |
validatorType = "greaterThan" | |
rangeValue = String(validValue[rangeArrayRange].dropFirst()) | |
} else if validValue[rangeArrayRange].first == "<" { | |
validatorType = "lessThan" | |
rangeValue = String(validValue[rangeArrayRange].dropFirst()) | |
} else { | |
validatorType = "range" | |
rangeValue = String(validValue[rangeArrayRange]) | |
} | |
switch String(rangeType) { | |
case "String": | |
guard let value = value as? String else { break } | |
let val = rangeValue | |
var isValid: Bool! | |
var validator: Validator<String>! | |
if validatorType == "range" { | |
let arr = rangeValue.split(separator: ",").compactMap({ String($0) }) | |
guard arr.count == 2 else { break } | |
validator = .range(arr[0]...arr[1]) | |
} else if validatorType == "greaterThan" { | |
validator = .greaterThan(val) | |
} else if validatorType == "lessThan" { | |
validator = .lessThan(val) | |
} | |
isValid = validator.isValid(value: value) | |
validatedData[key] = isValid ? val : "!(\(value),\(validator!))" | |
print(isValid!) | |
case "Int": | |
guard let value = value as? Double else { break } | |
var isValid: Bool! | |
var validator: Validator<Int>! | |
if validatorType == "range" { | |
let arr = rangeValue.split(separator: ",").compactMap({ Int($0) }) | |
guard arr.count == 2 else { break } | |
validator = .range(arr[0]...arr[1]) | |
} else if validatorType == "greaterThan" { | |
guard let val = Int(rangeValue) else { break } | |
validator = .greaterThan(val) | |
} else if validatorType == "lessThan" { | |
guard let val = Int(rangeValue) else { break } | |
validator = .lessThan(val) | |
} | |
isValid = validator.isValid(value: Int(value)) | |
validatedData[key] = isValid ? value : "!(\(value),\(validator!))" | |
print(isValid!) | |
case "Float": | |
guard let value = value as? Double else { break } | |
var isValid: Bool! | |
var validator: Validator<Float>! | |
if validatorType == "range" { | |
let arr = rangeValue.split(separator: ",").compactMap({ Float($0) }) | |
guard arr.count == 2 else { break } | |
validator = .range(arr[0]...arr[1]) | |
} else if validatorType == "greaterThan" { | |
guard let val = Float(rangeValue) else { break } | |
validator = .greaterThan(val) | |
} else if validatorType == "lessThan" { | |
guard let val = Float(rangeValue) else { break } | |
validator = .lessThan(val) | |
} | |
isValid = validator.isValid(value: Float(value)) | |
validatedData[key] = isValid ? value : "!(\(value),\(validator!))" | |
print(isValid!) | |
case "Double": | |
guard let value = value as? Double else { break } | |
var isValid: Bool! | |
var validator: Validator<Double>! | |
if validatorType == "range" { | |
let arr = rangeValue.split(separator: ",").compactMap({ Double($0) }) | |
guard arr.count == 2 else { break } | |
validator = .range(arr[0]...arr[1]) | |
} else if validatorType == "greaterThan" { | |
guard let val = Double(rangeValue) else { break } | |
validator = .greaterThan(val) | |
} else if validatorType == "lessThan" { | |
guard let val = Double(rangeValue) else { break } | |
validator = .lessThan(val) | |
} | |
isValid = validator.isValid(value: value) | |
validatedData[key] = isValid ? value : "!(\(value),\(validator!))" | |
print(isValid!) | |
default: | |
break | |
} | |
} | |
} | |
print("-") | |
} catch { | |
continue | |
} | |
} | |
return validatedData | |
} | |
let valid = validate(data: data, rules: rules) | |
print(valid) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment