TypeConstraint

public struct TypeConstraint<T, E> : Constraint where E : Error

A Constraint that allows to evaluate complex data types.

struct RegistrationData {

    enum Error: Swift.Error {
        case username
        case password(Password)
        case email
        case underAge
    }

    enum Password {
        case missingUppercase
        case missingLowercase
        case missingDigits
        case missingSpecialChars
        case tooShort
    }

    var username: String
    var password: String
    var email: String
    var age: Int
}
var constraint = TypeConstraint<RegistrationData, RegistrationData.Error> {
    KeyPathConstraint(\.username) {
        BlockConstraint {
            $0.count >= 5
        } errorBuilder: {
            .username
        }
    }
    KeyPathConstraint(\.password) {
        GroupConstraint(.all) {
            PredicateConstraint {
                CharacterSetPredicate(.lowercaseLetters, mode: .inclusive)
            } errorBuilder: {
                .password(.missingLowercase)
            }
            PredicateConstraint{
                CharacterSetPredicate(.uppercaseLetters, mode: .inclusive)
            } errorBuilder: {
                .password(.missingUppercase)
            }
            PredicateConstraint {
                CharacterSetPredicate(.decimalDigits, mode: .inclusive)
            } errorBuilder: {
                .password(.missingDigits)
            }
            PredicateConstraint {
                CharacterSetPredicate(CharacterSet(charactersIn: "!?@#$%^&*()|\\/<>,.~`_+-="), mode: .inclusive)
            } errorBuilder: {
                .password(.missingSpecialChars)
            }
            PredicateConstraint {
                LengthPredicate(min: 8)
            }  errorBuilder: {
                .password(.tooShort)
            }
        }
    }
    KeyPathConstraint(\.email) {
        PredicateConstraint(EmailPredicate(), error: .email)
    }
    KeyPathConstraint(\.age) {
        PredicateConstraint(RangePredicate(min: 14), error: .underAge)
    }
}

let user = RegistrationData(username: "nsagora", password: "p@ssW0rd", email: "hello@nsagora.com", age: 21)
constraint.evaluate(with: user)
  • Declaration

    Swift

    public typealias InputType = T
  • Declaration

    Swift

    public typealias ErrorType = E
  • Create a new TypeConstraint instance.

     struct RegistrationData {
    
         enum Error: Swift.Error {
             case username
             case password(Password)
             case email
             case underAge
         }
    
         enum Password {
             case missingUppercase
             case missingLowercase
             case missingDigits
             case missingSpecialChars
             case tooShort
         }
    
         var username: String
         var password: String
         var email: String
         var age: Int
     }
    
    
     var constraint = TypeConstraint<RegistrationData, RegistrationData.Error>()
    
     constraint.set(for: \.username) {
         BlockConstraint {
             $0.count >= 5
         } errorBuilder: {
             .username
         }
     }
    
     constraint.set(for: \.password) {
         GroupConstraint(.all, constraints:
             PredicateConstraint {
                 CharacterSetPredicate(.lowercaseLetters, mode: .inclusive)
             } errorBuilder: {
                 .password(.missingLowercase)
             },
             PredicateConstraint{
                 CharacterSetPredicate(.uppercaseLetters, mode: .inclusive)
             } errorBuilder: {
                 .password(.missingUppercase)
             },
             PredicateConstraint {
                 CharacterSetPredicate(.decimalDigits, mode: .inclusive)
             } errorBuilder: {
                 .password(.missingDigits)
             },
             PredicateConstraint {
                 CharacterSetPredicate(CharacterSet(charactersIn: "!?@#$%^&*()|\\/<>,.~`_+-="), mode: .inclusive)
             } errorBuilder: {
                 .password(.missingSpecialChars)
             },
             PredicateConstraint {
                 LengthPredicate(min: 8)
             }  errorBuilder: {
                 .password(.tooShort)
             }
         )
     }
    
     constraint.set(for: \.email) {
         PredicateConstraint(EmailPredicate(), error: .email)
     }
    
     constraint.set(for: \.age) {
         PredicateConstraint(RangePredicate(min: 14), error: .underAge)
     }
    
     let user = RegistrationData(username: "nsagora", password: "p@ssW0rd", email: "hello@nsagora.com", age: 21)
     constraint.evaluate(with: user)
    

    Declaration

    Swift

    public init()
  • Set a Constraint on a property from the root object.

    Declaration

    Swift

    public mutating func set<C, V>(for keyPath: KeyPath<T, V>, constraint: C) where E == C.ErrorType, C : Constraint, V == C.InputType

    Parameters

    constraint

    A Constraint on the property at the provided KeyPath.

    keyPath

    The KeyPath for the property we set the Constraint on.

  • Set a Constraint on a property from the root object.

    Declaration

    Swift

    public mutating func set<C, V>(for keyPath: KeyPath<T, V>, constraintBuilder: () -> C) where E == C.ErrorType, C : Constraint, V == C.InputType

    Parameters

    constraint

    A Constraint on the property at the provided KeyPath.

    keyPath

    The KeyPath for the property we set the Constraint on.

  • Evaluates the input against the underlying constraints.

    Declaration

    Swift

    public func evaluate(with input: T) -> Result<Void, Summary<E>>

    Parameters

    input

    The input to be validated.

    Return Value

    .success if the input is valid,.failure containing the Summary of the failing Constraints otherwise.

ConstraintBuilder Extension

  • Create a new TypeConstraint instance.

    struct RegistrationData {
    
        enum Error: Swift.Error {
            case username
            case password(Password)
            case email
            case underAge
        }
    
        enum Password {
            case missingUppercase
            case missingLowercase
            case missingDigits
            case missingSpecialChars
            case tooShort
        }
    
        var username: String
        var password: String
        var email: String
        var age: Int
    }
    
    var constraint = TypeConstraint<RegistrationData, RegistrationData.Error> {
        KeyPathConstraint(\.username) {
            BlockConstraint {
                $0.count >= 5
            } errorBuilder: {
                .username
            }
        }
        KeyPathConstraint(\.password) {
            GroupConstraint(.all) {
                PredicateConstraint {
                    CharacterSetPredicate(.lowercaseLetters, mode: .inclusive)
                } errorBuilder: {
                    .password(.missingLowercase)
                }
                PredicateConstraint{
                    CharacterSetPredicate(.uppercaseLetters, mode: .inclusive)
                } errorBuilder: {
                    .password(.missingUppercase)
                }
                PredicateConstraint {
                    CharacterSetPredicate(.decimalDigits, mode: .inclusive)
                } errorBuilder: {
                    .password(.missingDigits)
                }
                PredicateConstraint {
                    CharacterSetPredicate(CharacterSet(charactersIn: "!?@#$%^&*()|\\/<>,.~`_+-="), mode: .inclusive)
                } errorBuilder: {
                    .password(.missingSpecialChars)
                }
                PredicateConstraint {
                    LengthPredicate(min: 8)
                }  errorBuilder: {
                    .password(.tooShort)
                }
            }
        }
        KeyPathConstraint(\.email) {
            PredicateConstraint(EmailPredicate(), error: .email)
        }
        KeyPathConstraint(\.age) {
            PredicateConstraint(RangePredicate(min: 14), error: .underAge)
        }
    }
    
    let user = RegistrationData(username: "nsagora", password: "p@ssW0rd", email: "hello@nsagora.com", age: 21)
    constraint.evaluate(with: user)
    

    Declaration

    Swift

    public init(@ConstraintBuilder<T, E> constraintBuilder: () -> [AnyConstraint<T, E>])