Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validation #175

Merged
merged 96 commits into from
May 7, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
3d769fe
linking validation lib dependency
loganwright Apr 9, 2016
95d38a8
adding some initial validation files
loganwright Apr 9, 2016
4cdfd45
updating xcode proj
loganwright Apr 9, 2016
39e927f
some alternative approaches built off of original validation
loganwright Apr 11, 2016
ee06934
adding initial base tested w/ closure returning self
loganwright Apr 11, 2016
a0f9a0d
validator protocol
loganwright Apr 11, 2016
43e6a41
adding validation suite protocol
loganwright Apr 11, 2016
3011a7a
some examples / testing
loganwright Apr 11, 2016
d29e0fc
laying out sketch for validation composition
loganwright Apr 11, 2016
14be548
passes => by for better readability and silencing conflicted file tem…
loganwright Apr 11, 2016
9c640ae
some restructuring
loganwright Apr 11, 2016
4d6612d
organization and extension
loganwright Apr 11, 2016
a613134
building w/ composition types
loganwright Apr 12, 2016
6f3872b
clean up composition
loganwright Apr 12, 2016
e68a3a9
some file organization
loganwright Apr 12, 2016
1a35132
publicizing
loganwright Apr 12, 2016
50dedcf
adding composition operators
loganwright Apr 12, 2016
e2b13c3
moving validatable to file
loganwright Apr 12, 2016
486d420
moving additional validatable code to separate file
loganwright Apr 12, 2016
ee31574
move operators to own file
loganwright Apr 12, 2016
b630847
moving validated struct to file
loganwright Apr 12, 2016
f822461
add validation error
loganwright Apr 12, 2016
bbf9a1e
breaking out logical composition classes
loganwright Apr 12, 2016
6bb59c1
sketching out some validators
loganwright Apr 12, 2016
6b33387
testing tweaks and package updates
loganwright Apr 12, 2016
41c5803
better to not use passes
loganwright Apr 12, 2016
e787819
moving to throwing validators over booleans
loganwright Apr 13, 2016
45d318b
fix Not<T>
loganwright Apr 13, 2016
20eea09
tweaking error scheme slightly
loganwright Apr 13, 2016
e07ca36
merge master
loganwright Apr 13, 2016
cf8cc3e
first swing at validation documentation
loganwright Apr 14, 2016
c10c137
rework count to be generic
loganwright Apr 14, 2016
acf886c
adding some count validation tests
loganwright Apr 14, 2016
b9e3787
adding initial node validation
loganwright Apr 14, 2016
724528d
adding example
tanner0101 Apr 14, 2016
2db3cb7
Merge branch 'validation' of github.com:qutheory/vapor into validation
tanner0101 Apr 14, 2016
2b0e0a3
validated => valid
loganwright Apr 14, 2016
544357c
file validated to Valid
loganwright Apr 14, 2016
82fb0e2
Merge branch 'validation' of github.com:qutheory/vapor into validation
loganwright Apr 14, 2016
6f41f36
validated to valid in merge
loganwright Apr 14, 2016
0a39cc3
getting data subscript validation to work
loganwright Apr 14, 2016
a323f19
tweaking extractable to not require an additional error type
loganwright Apr 14, 2016
58ededb
removing extranneous error type
loganwright Apr 14, 2016
b8d5a8e
rm comments
loganwright Apr 14, 2016
6866242
validation middleware
tanner0101 Apr 14, 2016
c2ba1a3
Merge branch 'validation' of github.com:qutheory/vapor into validation
tanner0101 Apr 14, 2016
cb87b12
no longer generic errors
loganwright Apr 14, 2016
6b6a0c8
adding name capabilities to failure
loganwright Apr 14, 2016
9ef2942
Merge branch 'validation' of github.com:qutheory/vapor into validation
loganwright Apr 14, 2016
ef7db3b
merging master
loganwright May 5, 2016
1c9a7bc
updating to 4 25
loganwright May 5, 2016
4362d62
add unique validation
loganwright May 5, 2016
0f0803f
add schemes
tanner0101 May 5, 2016
7148f13
comment formatting
tanner0101 May 5, 2016
630b8ac
more comment formatting fixes
tanner0101 May 5, 2016
7573e59
comment format
tanner0101 May 5, 2016
609e003
adding unique
loganwright May 5, 2016
1a1bfce
Merge branch 'validation' of github.com:qutheory/vapor into validation
loganwright May 5, 2016
e09ec64
more comment formatting
tanner0101 May 5, 2016
a77c6a7
Merge branch 'validation' of github.com:qutheory/vapor into validation
tanner0101 May 5, 2016
7231e81
add `allTests`
tanner0101 May 5, 2016
0150c25
convenience comment fixes
tanner0101 May 5, 2016
fdcd1a8
fix typo
tanner0101 May 5, 2016
0f0a153
typo (i think)
tanner0101 May 5, 2016
519f7fe
array spacing
tanner0101 May 5, 2016
fe04fb3
adding 'In' validator
loganwright May 5, 2016
45c520d
Merge branch 'validation' of github.com:qutheory/vapor into validation
loganwright May 5, 2016
3e639bc
Merge branch 'master' into validation
loganwright May 5, 2016
9de3bb5
new validation error type
loganwright May 5, 2016
ce0fdff
cleaning up validation error
loganwright May 5, 2016
6a20073
better validation error protocol
loganwright May 5, 2016
92798e8
add detailed failure test
loganwright May 5, 2016
4a3d0f8
documenting validation error
loganwright May 5, 2016
af784f0
documenting node validation
loganwright May 6, 2016
a264a88
Merge branch 'master' into validation
tanner0101 May 6, 2016
aadffdd
adding compare validator
loganwright May 6, 2016
05a84d4
Merge branch 'validation' of github.com:qutheory/vapor into validation
loganwright May 6, 2016
77c76d0
added contains
loganwright May 6, 2016
52d0f80
documenting collection validators
loganwright May 6, 2016
6741720
matches
loganwright May 6, 2016
231af31
breaking out convenience validators
loganwright May 6, 2016
615a639
disable docs rule
tanner0101 May 6, 2016
9ae78b9
share all schemes
tanner0101 May 6, 2016
67ab30a
update error message
tanner0101 May 6, 2016
dcd0125
Merge branch 'master' into validation
loganwright May 6, 2016
4a6a7c4
xcode
loganwright May 6, 2016
5758552
Merge branch 'validation' of github.com:qutheory/vapor into validation
loganwright May 6, 2016
b9c1cec
removing + operator for better pairing w/ '||' and '&&'
loganwright May 6, 2016
2d3f8b3
convenience tests
loganwright May 6, 2016
f8d75a3
Merge branch 'master' into validation
loganwright May 7, 2016
3b8127e
weird state
loganwright May 7, 2016
7d1e684
fixing issue w/ && in test condition
loganwright May 7, 2016
7554111
allow variable access on optionals wrapping nodes
loganwright May 7, 2016
e339f4c
Merge pull request #221 from qutheory/node-question-mark
loganwright May 7, 2016
9081fd0
Merge branch 'master' into validation
loganwright May 7, 2016
8dbe8d0
Merge branch 'validation' of github.com:qutheory/vapor into validation
loganwright May 7, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
disabled_rules:
- line_length
- valid_docs
opt_in_rules:
included:
excluded:
Expand Down
39 changes: 35 additions & 4 deletions Sources/Development/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ app.resource("users", controller: UserController.self)
//MARK: Request data

app.post("jsondata") { request in
print(request.data.json?["hi"]?.string)
print(request.data.json?["hi"].string)
return "yup"
}

Expand All @@ -46,14 +46,14 @@ app.get("json") { request in

app.post("json") { request in
//parse a key inside the received json
guard let count = request.data["unicorns"]?.int else {
guard let count = request.data["unicorns"].int else {
return Response(error: "No unicorn count provided")
}
return "Received \(count) unicorns"
}

app.post("form") { request in
guard let name = request.data["name"]?.string else {
guard let name = request.data["name"].string else {
return Response(error: "No name provided")
}

Expand All @@ -66,7 +66,7 @@ app.get("redirect") { request in

app.post("json2") { request in
//parse a key inside the received json
guard let count = request.data["unicorns"]?.int else {
guard let count = request.data["unicorns"].int else {
return Response(error: "No unicorn count provided")
}
return Response(status: .created, json: Json(["message":"Received \(count) unicorns"]))
Expand Down Expand Up @@ -157,6 +157,37 @@ app.get("cookies") { request in
return response
}

class Name: ValidationSuite {
static func validate(input value: String) throws {
let evaluation = OnlyAlphanumeric.self
&& Count.min(5)
&& Count.max(20)

try evaluation.validate(input: value)
}
}

class Employee {
var name: Valid<Name>

init(request: Request) throws {
name = try request.data["name"].validated()
}
}

extension Employee: JsonRepresentable {
func makeJson() -> Json {
return Json([
"name": name.value
])
}
}

app.get("validation") { request in
let employee = try Employee(request: request)
return employee
}

//MARK: Middleware

app.middleware(AuthMiddleware()) {
Expand Down
1 change: 1 addition & 0 deletions Sources/Vapor/Core/Application.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ public class Application {
public init(sessionDriver: SessionDriver? = nil) {
self.middleware = [
AbortMiddleware(),
ValidationMiddleware()
]

self.providers = []
Expand Down
2 changes: 1 addition & 1 deletion Sources/Vapor/Middleware/AbortMiddleware.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class AbortMiddleware: Middleware {

func errorResponse(_ status: Response.Status, message: String) throws -> Response {
let json = Json([
"error": "true",
"error": true,
"message": "\(message)"
])
return Response(status: status, json: json)
Expand Down
33 changes: 33 additions & 0 deletions Sources/Vapor/Node/Node.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,36 @@ public enum NodeError: ErrorProtocol {
*/
case UnableToConvert(node: Node, toType: String)
}

extension Extractable where Wrapped == Node {
public var isNull: Bool {
return extract()?.isNull ?? false
}
public var bool: Bool? {
return extract()?.bool
}
public var float: Float? {
return extract()?.float
}
public var double: Double? {
return extract()?.double
}
public var int: Int? {
return extract()?.int
}
public var uint: UInt? {
return extract()?.uint
}
public var string: String? {
return extract()?.string
}
public var array: [Node]? {
return extract()?.array
}
public var object: [String : Node]? {
return extract()?.object
}
public var json: Json? {
return extract()?.json
}
}
98 changes: 98 additions & 0 deletions Sources/Vapor/Validation/And.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
The MIT License (MIT) Copyright (c) 2016 Benjamin Encz

Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/**
This struct is used to encompass multiple Validators into one entity.

It is possible to access this struct directly using

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing Whitespace Violation: Lines should not have trailing whitespace. (trailing_whitespace)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing Whitespace Violation: Lines should not have trailing whitespace. (trailing_whitespace)

And(validatorOne, validatorTwo)

But it is more common to create And objects using the `+` operator:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing Whitespace Violation: Lines should not have trailing whitespace. (trailing_whitespace)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing Whitespace Violation: Lines should not have trailing whitespace. (trailing_whitespace)

validatorOne + validatorTwo
*/
public struct And<
V: Validator,
U: Validator where V.InputType == U.InputType> {
private typealias Validator = (input: V.InputType) throws -> Void
private let validator: Validator

/**
Convenience only.

Must stay private.
*/
private init(_ lhs: Validator, _ rhs: Validator) {
validator = { value in
try lhs(input: value)
try rhs(input: value)
}
}
}

extension And: Validator {
/**
Validator conformance that allows the 'And' struct
to concatenate multiple Validator types.

- parameter value: the value to validate

- throws: an error on failed validation
*/
public func validate(input value: V.InputType) throws {
try validator(input: value)
}
}

extension And {
/**
Used to combine two Validator types
*/
public init(_ lhs: V, _ rhs: U) {
self.init(lhs.validate, rhs.validate)
}
}

extension And where V: ValidationSuite {
/**
Used to combine two Validator types where one is a ValidationSuite
*/
public init(_ lhs: V.Type = V.self, _ rhs: U) {
self.init(lhs.validate, rhs.validate)
}
}

extension And where U: ValidationSuite {
/**
Used to combine two Validators where one is a ValidationSuite
*/
public init(_ lhs: V, _ rhs: U.Type = U.self) {
self.init(lhs.validate, rhs.validate)
}
}

extension And where V: ValidationSuite, U: ValidationSuite {
/**
Used to combine two ValidationSuite types
*/
public init(_ lhs: V.Type = V.self, _ rhs: U.Type = U.self) {
self.init(lhs.validate, rhs.validate)
}
}
29 changes: 29 additions & 0 deletions Sources/Vapor/Validation/Convenience/Alphanumeric.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leading Whitespace Violation: File shouldn't start with whitespace: currently starts with 1 whitespace characters (leading_whitespace)

/**
A validator that can be used to check that a
given string contains only alphanumeric characters
*/
public struct OnlyAlphanumeric: ValidationSuite {
private static let alphanumeric = "abcdefghijklmnopqrstuvwxyz0123456789"
private static let validCharacters = alphanumeric.characters

/**
Validate whether or not an input string contains only
alphanumeric characters. a...z0...9

- parameter value: input value to validate

- throws: an error if validation fails
*/
public static func validate(input value: String) throws {
let passed = value
.lowercased()
.characters
.filter(validCharacters.contains)
.count

if passed != value.characters.count {
throw error(with: value)
}
}
}
46 changes: 46 additions & 0 deletions Sources/Vapor/Validation/Convenience/Compare.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
Validate a comparable


- greaterThan: validate input is > associated value
- greaterThanOrEqual: validate input is >= associated value
- lessThan: validate input is < associated value
- lessThanOrEqual: validate input is <= associated value
- equals: validate input == associated value
- containedIn: validate low <= input && input <= high
*/
public enum Compare<ComparableType where ComparableType: Comparable, ComparableType: Validatable>: Validator {
public typealias InputType = ComparableType
case greaterThan(ComparableType)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type Name Violation: Type name should start with an uppercase character: 'greaterThan' (type_name)

case greaterThanOrEqual(ComparableType)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type Name Violation: Type name should start with an uppercase character: 'greaterThanOrEqual' (type_name)

case lessThan(ComparableType)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type Name Violation: Type name should start with an uppercase character: 'lessThan' (type_name)

case lessThanOrEqual(ComparableType)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type Name Violation: Type name should start with an uppercase character: 'lessThanOrEqual' (type_name)

case equals(ComparableType)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type Name Violation: Type name should start with an uppercase character: 'equals' (type_name)

case containedIn(low: ComparableType, high: ComparableType)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type Name Violation: Type name should start with an uppercase character: 'containedIn' (type_name)


/**
Validate that a string passes associated compare evaluation

- parameter value: input string to validate

- throws: an error if validation fails
*/
public func validate(input value: InputType) throws {
switch self {
case .greaterThan(let c) where value > c:
break
case .greaterThanOrEqual(let c) where value >= c:
break
case .lessThan(let c) where value < c:
break
case .lessThanOrEqual(let c) where value <= c:
break
case .equals(let e) where value == e:
break
case .containedIn(low: let l, high: let h) where l <= value && value <= h:
break
default:
throw error(with: value)
}
}
}
34 changes: 34 additions & 0 deletions Sources/Vapor/Validation/Convenience/Contains.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
Validate that a sequence contains a given value
*/
public struct Contains<
T where
T: Sequence,
T: Validatable,
T.Iterator.Element: Equatable>: Validator {

/**
The value expected to be in sequence
*/
public let expecting: T.Iterator.Element

/**
Create a validator to check that a sequence contains the given value

- parameter expecting: the value expected to be in sequence
*/
public init(_ expecting: T.Iterator.Element) {
self.expecting = expecting
}

/**
validate
*/
public func validate(input sequence: T) throws {
for element in sequence where element == expecting {
return
}

throw error(with: sequence)
}
}