Skip to content

Commit

Permalink
Merge pull request #39 from noppoMan/alias-functions
Browse files Browse the repository at this point in the history
add typesafe alias functions for ConditionalFilter
  • Loading branch information
noppoMan authored Feb 8, 2017
2 parents bf302af + df32784 commit 9dcec59
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 60 deletions.
34 changes: 18 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ let knex = con.knex()
```swift
let results = try knex.table("users").where("id" == 1).fetch()
print(results)

// or

let results = try knex.table("users").where(.withOperator("id", .equal, 1)).fetch()
print(results)
```

### where between and limit and offset
Expand All @@ -63,7 +58,7 @@ You can chain the conditional clauses like SQL and it's amazing expressive.
```swift
let results = try knex
.table("users")
.where(.between("id", 1, 1000))
.where(between("id", 1, 1000))
.limit(10)
.offset(10)
.fetch()
Expand Down Expand Up @@ -126,7 +121,7 @@ print(results)
```swift
let results = try knex
.table("users")
.where(.in("id",
.where(SwiftKnex.in("id",
QueryBuilder()
.select(col("id"))
.table("t1")
Expand Down Expand Up @@ -185,16 +180,23 @@ print(result?.insertId)
Note. Recently not supported entire clauses in Mysql.

* `where(_ filter: ConditionFilter)`
- `withOperator(field: String, op: Operator, value: Any)`
- `like(field: String, value: String)`
- `in(field: String, value: Any)`
- `notIn(field: String, value: Any)`
- `between(field: String, from: Any, to: Any)`
- `notBetween(field: String, from: Any, to: Any)`
- `isNull(field: String)`
- `isNotNull(field: String)`
- `raw(String)`
- `like`
- `in`
- `notIn`
- `between`
- `notBetween`
- `isNull`
- `isNotNull`
- `raw`
* `or(_ clause: ConditionFilter)`
- `like`
- `in`
- `notIn`
- `between`
- `notBetween`
- `isNull`
- `isNotNull`
- `raw`
* `join(_ table: String)`
* `leftJoin(_ table: String)`
* `rightJoin(_ table: String)`
Expand Down
69 changes: 37 additions & 32 deletions Sources/SwiftKnex/Clauses/ConditionalFilter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,32 @@ public protocol FilterQueryBuildable {
}

public indirect enum ConditionalFilter {
// basics
case withOperator(field: String, op: Operator, value: Any)
case withOperator(field: String, operator: Operator, value: Any)
case like(String, String)
case notLike(String, String)
case `in`(String, Any)
case notIn(String, Any)
case between(String, Any, Any)
case notBetween(String, Any, Any)
case isNull(String)
case isNotNull(String)

// comparison
case andComparison(ConditionalFilter, ConditionalFilter)
case orComparison(ConditionalFilter, ConditionalFilter)

// raw
case raw(String, [Any])
case and(ConditionalFilter, ConditionalFilter)
case or(ConditionalFilter, ConditionalFilter)
}

extension ConditionalFilter: FilterQueryBuildable {
public func toBindParams() throws -> [Any] {
switch self {
case .withOperator(_, op: _, let value):
case .withOperator(_, operator: _, let value):
return [pack(value: value)]

case .like(_, let value):
return [pack(value: value)]

case .notLike(_, let value):
return [pack(value: value)]

case .in(_, let value):
switch value {
case let values as [Any]:
Expand Down Expand Up @@ -88,14 +87,14 @@ extension ConditionalFilter: FilterQueryBuildable {
case .isNotNull(_):
return []

case .andComparison(let aFilter, let bFilter):
return try aFilter.toBindParams() + bFilter.toBindParams()

case .orComparison(let aFilter, let bFilter):
return try aFilter.toBindParams() + bFilter.toBindParams()

case .raw(_, let params):
return params

case .and(let a, let b):
return try a.toBindParams() + b.toBindParams()

case .or(let a, let b):
return try a.toBindParams() + b.toBindParams()
}
throw ConditionalFilterError.unrecognizedFilter
}
Expand All @@ -114,6 +113,12 @@ extension ConditionalFilter: FilterQueryBuildable {
}
return "\(pack(key: field)) LIKE ?"

case .notLike(let field, let value):
if !secure {
return "\(pack(key: field)) NOT LIKE \(value)"
}
return "\(pack(key: field)) NOT LIKE ?"

case .in(let field, let value):
switch value {
case let values as [Any]:
Expand Down Expand Up @@ -168,14 +173,14 @@ extension ConditionalFilter: FilterQueryBuildable {
case .isNotNull(let field):
return "\(pack(key: field)) IS NOT NULL"

case .andComparison(let aFilter, let bFilter):
return try "(\(aFilter.toQuery()) AND \(bFilter.toQuery()))"

case .orComparison(let aFilter, let bFilter):
return try "(\(aFilter.toQuery()) OR \(bFilter.toQuery()))"

case .raw(let query, _):
return query

case .and(let a, let b):
return try "(\(a.toQuery()) AND \(b.toQuery()))"

case .or(let a, let b):
return try "(\(a.toQuery()) OR \(b.toQuery()))"
}
throw ConditionalFilterError.unrecognizedFilter
}
Expand Down Expand Up @@ -235,46 +240,46 @@ func pack(value: Any) -> Any {
}

public func || (lhs: ConditionalFilter, rhs: ConditionalFilter) -> ConditionalFilter {
return .orComparison(lhs, rhs)
return .or(lhs, rhs)
}

public func && (lhs: ConditionalFilter, rhs: ConditionalFilter) -> ConditionalFilter {
return .andComparison(lhs, rhs)
return .and(lhs, rhs)
}

public func >(key: String, pred: Any) -> ConditionalFilter {
return .withOperator(field: key, op: .greaterThan, value: pred)
return .withOperator(field: key, operator: .greaterThan, value: pred)
}

public func >=(key: String, pred: Any) -> ConditionalFilter {
return .withOperator(field: key, op: .greaterThanEqual, value: pred)
return .withOperator(field: key, operator: .greaterThanEqual, value: pred)
}

public func <(key: String, pred: Any) -> ConditionalFilter {
return .withOperator(field: key, op: .smallerThan, value: pred)
return .withOperator(field: key, operator: .smallerThan, value: pred)
}

public func <=(key: String, pred: Any) -> ConditionalFilter {
return .withOperator(field: key, op: .smallerThanEqual, value: pred)
return .withOperator(field: key, operator: .smallerThanEqual, value: pred)
}

public func ==(key: String, pred: Any) -> ConditionalFilter {
return .withOperator(field: key, op: .equal, value: pred)
return .withOperator(field: key, operator: .equal, value: pred)
}

public func !=(key: String, pred: Any) -> ConditionalFilter {
return .withOperator(field: key, op: .notEqual, value: pred)
return .withOperator(field: key, operator: .notEqual, value: pred)
}

public enum ConditionConnector {
enum ConditionConnector {
case `where`(ConditionalFilter)
case and(ConditionalFilter)
case or(ConditionalFilter)
}

extension Collection where Self.Iterator.Element == ConditionConnector {

public func bindParams() throws -> [Any] {
func bindParams() throws -> [Any] {
var params = [Any]()

for c in self {
Expand All @@ -293,7 +298,7 @@ extension Collection where Self.Iterator.Element == ConditionConnector {
return params
}

public func build() throws -> String {
func build() throws -> String {
let clauses: [String] = try self.map({
switch $0 {
case .where(let clause):
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftKnex/Migration/Migrator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class MigrateRunner {
let deleteIDs = peformedAtLastBatches.map({ $0.id })
_ = try con.knex()
.table(con.config.migration.table)
.where(.in("id", deleteIDs))
.where(SwiftKnex.in("id", deleteIDs))
.delete(trx: trx)

print("Rollbacked last batch items: batch no \(lastBatch)")
Expand Down
92 changes: 92 additions & 0 deletions Sources/SwiftKnex/SwiftKnex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,95 @@ public final class Knex {
return Knex(config: config, connection: connection)
}
}

public func between(_ field: String, _ from: Int, _ to: Int) -> ConditionalFilter {
return .between(field, from, to)
}

public func between(_ field: String, _ from: Float, _ to: Float) -> ConditionalFilter {
return .between(field, from, to)
}

public func between(_ field: String, _ from: Double, _ to: Double) -> ConditionalFilter {
return .between(field, from, to)
}

public func between(_ field: String, _ from: String, _ to: String) -> ConditionalFilter {
return .between(field, from, to)
}

public func notBetween(_ field: String, _ from: Int, _ to: Int) -> ConditionalFilter {
return .notBetween(field, from, to)
}

public func notBetween(_ field: String, _ from: Float, _ to: Float) -> ConditionalFilter {
return .notBetween(field, from, to)
}

public func notBetween(_ field: String, _ from: Double, _ to: Double) -> ConditionalFilter {
return .notBetween(field, from, to)
}

public func notBetween(_ field: String, _ from: String, _ to: String) -> ConditionalFilter {
return .notBetween(field, from, to)
}

public func `in`(_ field: String, _ values: [Int]) -> ConditionalFilter {
return .in(field, values)
}

public func `in`(_ field: String, _ values: [Double]) -> ConditionalFilter {
return .in(field, values)
}

public func `in`(_ field: String, _ values: [Float]) -> ConditionalFilter {
return .in(field, values)
}

public func `in`(_ field: String, _ values: [String]) -> ConditionalFilter {
return .in(field, values)
}

public func `in`(_ field: String, _ queryBuilder: QueryBuilder) -> ConditionalFilter {
return .in(field, queryBuilder)
}

public func notIn(_ field: String, _ values: [Int]) -> ConditionalFilter {
return .notIn(field, values)
}

public func notIn(_ field: String, _ values: [Double]) -> ConditionalFilter {
return .notIn(field, values)
}

public func notIn(_ field: String, _ values: [Float]) -> ConditionalFilter {
return .notIn(field, values)
}

public func notIn(_ field: String, _ values: [String]) -> ConditionalFilter {
return .notIn(field, values)
}

public func notIn(_ field: String, _ queryBuilder: QueryBuilder) -> ConditionalFilter {
return .notIn(field, queryBuilder)
}

public func like(_ field: String, _ value: String) -> ConditionalFilter {
return .like(field, value)
}

public func notlike(_ field: String, _ value: String) -> ConditionalFilter {
return .notLike(field, value)
}

public func isNull(_ field: String) -> ConditionalFilter {
return .isNull(field)
}

public func isNotNull(_ field: String) -> ConditionalFilter {
return .isNotNull(field)
}

public func raw(_ query: String, _ params: [Any] = []) -> ConditionalFilter {
return .raw(query, params)
}
4 changes: 2 additions & 2 deletions Tests/SwiftKnexTests/JSONDataTypeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class JSONDataTypeTests: XCTestCase {

rows = try! con.knex()
.select(raw("JSON_UNQUOTE(JSON_EXTRACT(body, '$.name'))").as("name"))
.where(.raw("JSON_UNQUOTE(JSON_EXTRACT(body,'$.job')) = ?", ["Jedai"]))
.where(raw("JSON_UNQUOTE(JSON_EXTRACT(body,'$.job')) = ?", ["Jedai"]))
.table("json_table")
.fetch()

Expand All @@ -92,7 +92,7 @@ class JSONDataTypeTests: XCTestCase {
func testUpdate() {
let res = try! con.knex()
.table("json_table")
.where(.raw("JSON_UNQUOTE(JSON_EXTRACT(body,'$.name')) = ?", ["Luke"]))
.where(raw("JSON_UNQUOTE(JSON_EXTRACT(body,'$.name')) = ?", ["Luke"]))
.update(query: "body = JSON_REPLACE(body, '$.name', ?)", params: ["Obi Wan"])

XCTAssertEqual(res!.affectedRows, 1)
Expand Down
18 changes: 9 additions & 9 deletions Tests/SwiftKnexTests/SelectTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,25 +67,25 @@ class SelectTests: XCTestCase {
rows = try! con.knex().table("test_users").where("age" != 23).fetch()
XCTAssert(rows!.count == 6)

rows = try! con.knex().table("test_users").where(.like("email", "jac%")).fetch()
rows = try! con.knex().table("test_users").where(like("email", "jac%")).fetch()
XCTAssert(rows!.count == 2)

rows = try! con.knex().table("test_users").where(.in("name", ["Tonny", "Ray", "Julia"])).fetch()
rows = try! con.knex().table("test_users").where(SwiftKnex.in("name", ["Tonny", "Ray", "Julia"])).fetch()
XCTAssert(rows!.count == 3)

rows = try! con.knex().table("test_users").where(.notIn("name", ["Tonny", "Ray", "Julia"])).fetch()
rows = try! con.knex().table("test_users").where(notIn("name", ["Tonny", "Ray", "Julia"])).fetch()
XCTAssert(rows!.count == 4)

rows = try! con.knex().table("test_users").where(.between("age", 10, 30)).fetch()
rows = try! con.knex().table("test_users").where(between("age", 10, 30)).fetch()
XCTAssert(rows!.count == 4)

rows = try! con.knex().table("test_users").where(.notBetween("age", 10, 30)).fetch()
rows = try! con.knex().table("test_users").where(notBetween("age", 10, 30)).fetch()
XCTAssert(rows!.count == 3)

rows = try! con.knex().table("test_users").where(.isNull("country")).fetch()
rows = try! con.knex().table("test_users").where(isNull("country")).fetch()
XCTAssert(rows!.count == 2)

rows = try! con.knex().table("test_users").where(.isNotNull("country")).fetch()
rows = try! con.knex().table("test_users").where(isNotNull("country")).fetch()
XCTAssert(rows!.count == 5)

rows = try! con.knex().table("test_users").where("name" == "Jack").where("country" == "USA").fetch()
Expand All @@ -103,11 +103,11 @@ class SelectTests: XCTestCase {

XCTAssert(rows!.count == 3)

rows = try! con.knex().table("test_users").where(.in("id", QueryBuilder().select(col("id")).table("test_users").where("country" == "USA"))).fetch()
rows = try! con.knex().table("test_users").where(SwiftKnex.in("id", QueryBuilder().select(col("id")).table("test_users").where("country" == "USA"))).fetch()

XCTAssert(rows!.count == 3)

rows = try! con.knex().table("test_users").where(.notIn("id", QueryBuilder().select(col("id")).table("test_users").where("country" == "USA"))).fetch()
rows = try! con.knex().table("test_users").where(notIn("id", QueryBuilder().select(col("id")).table("test_users").where("country" == "USA"))).fetch()

XCTAssert(rows!.count == 4)
}
Expand Down

0 comments on commit 9dcec59

Please sign in to comment.