Skip to content

Commit

Permalink
Merge pull request #73 from novi/fix-parameter-type
Browse files Browse the repository at this point in the history
Add support for table name, column type QueryParameter
  • Loading branch information
novi authored Feb 27, 2018
2 parents 38e7e80 + cdddf25 commit 667f561
Show file tree
Hide file tree
Showing 13 changed files with 78 additions and 38 deletions.
3 changes: 3 additions & 0 deletions Sources/MySQL/Blob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ extension Data: QueryParameterType {
buffer += "'"
return buffer
}
public func escapedForID() -> String? {
return nil
}
}

extension Data: QueryParameter {
Expand Down
2 changes: 1 addition & 1 deletion Sources/MySQL/Connection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public final class Connection {
return mysql_
}

internal var ping: Bool {
internal func ping() -> Bool {
_ = try? connectIfNeeded()
guard let mysql = mysql else {
return false
Expand Down
2 changes: 1 addition & 1 deletion Sources/MySQL/ConnectionPool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ final public class ConnectionPool: CustomStringConvertible {

private func getUsableConnection() -> Connection? {
for c in pool {
if c.isInUse == false && c.ping {
if c.isInUse == false && c.ping() {
c.isInUse = true
return c
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/MySQL/Date.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ extension Date: QueryParameter {
} // TODO: in Linux

// YYYY-MM-DD HH:MM:SS
return QueryParameterWrap( "'\(pad(num: comp.year ?? 0, digits: 4))-\(pad(num: comp.month ?? 0))-\(pad(num: comp.day ?? 0)) \(pad(num: comp.hour ?? 0)):\(pad(num: comp.minute ?? 0)):\(pad(num: comp.second ?? 0))'" )
return EscapedQueryParameter( "'\(pad(num: comp.year ?? 0, digits: 4))-\(pad(num: comp.month ?? 0))-\(pad(num: comp.day ?? 0)) \(pad(num: comp.hour ?? 0)):\(pad(num: comp.minute ?? 0)):\(pad(num: comp.second ?? 0))'" )
}
}

Expand Down
10 changes: 10 additions & 0 deletions Sources/MySQL/SQLType.swift → Sources/MySQL/EnumParameter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,19 @@ extension SQLEnumType where RawValue == String {
}
}


extension SQLEnumType where RawValue == String {
public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
return rawValue.queryParameter(option: option)
}
}

public protocol QueryEnumParameter: RawRepresentable, QueryParameter {

}

extension QueryEnumParameter where Self.RawValue: QueryParameter {
public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
return try rawValue.queryParameter(option: option)
}
}
9 changes: 8 additions & 1 deletion Sources/MySQL/ParameterBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@
// Copyright © 2015 Yusuke Ito. All rights reserved.
//

@available(*, deprecated)
public func build<A: QueryParameter>(_ p: (A) ) -> [QueryParameter] {
return [
p
]
}

@available(*, deprecated)
public func build<A: QueryParameter, B: QueryParameter>(_ p: (A, B) ) -> [QueryParameter] {
return [
p.0,
p.1
]
}

@available(*, deprecated)
public func build<A: QueryParameter, B: QueryParameter, C: QueryParameter>(_ p: (A, B, C) ) -> [QueryParameter] {
return [
p.0,
Expand All @@ -27,6 +30,7 @@ public func build<A: QueryParameter, B: QueryParameter, C: QueryParameter>(_ p:
]
}

@available(*, deprecated)
public func build<A: QueryParameter, B: QueryParameter, C: QueryParameter, D: QueryParameter>(_ p: (A, B, C, D) ) -> [QueryParameter] {
return [
p.0,
Expand All @@ -36,6 +40,7 @@ public func build<A: QueryParameter, B: QueryParameter, C: QueryParameter, D: Qu
]
}

@available(*, deprecated)
public func build<A: QueryParameter, B: QueryParameter, C: QueryParameter, D: QueryParameter, E: QueryParameter>(_ p: (A, B, C, D, E) ) -> [QueryParameter] {
return [
p.0,
Expand All @@ -46,6 +51,7 @@ public func build<A: QueryParameter, B: QueryParameter, C: QueryParameter, D: Qu
]
}

@available(*, deprecated)
public func build<A: QueryParameter, B: QueryParameter, C: QueryParameter, D: QueryParameter, E: QueryParameter, F: QueryParameter>(_ p: (A, B, C, D, E, F) ) -> [QueryParameter] {
return [
p.0,
Expand All @@ -57,6 +63,7 @@ public func build<A: QueryParameter, B: QueryParameter, C: QueryParameter, D: Qu
]
}

@available(*, deprecated)
public func build<A: QueryParameter, B: QueryParameter, C: QueryParameter, D: QueryParameter, E: QueryParameter, F: QueryParameter, G: QueryParameter>(_ p: (A, B, C, D, E, F, G) ) -> [QueryParameter] {
return [
p.0,
Expand All @@ -67,4 +74,4 @@ public func build<A: QueryParameter, B: QueryParameter, C: QueryParameter, D: Qu
p.5,
p.6
]
}
}
56 changes: 32 additions & 24 deletions Sources/MySQL/QueryParameterType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public struct QueryParameterNull: QueryParameter, ExpressibleByNilLiteral {

}
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( "NULL" )
return EscapedQueryParameter( "NULL" )
}
}

Expand All @@ -57,10 +57,10 @@ public struct QueryDictionary: QueryParameter {
var keyVals: [String] = []
for (k, v) in dict {
if v == nil || v?.omitOnQueryParameter == false {
keyVals.append("\(SQLString.escapeId(string: k)) = \(try QueryParameterOptional(v).queryParameter(option: option).escaped())")
keyVals.append("\(SQLString.escapeForID(string: k)) = \(try QueryParameterOptional(v).queryParameter(option: option).escaped())")
}
}
return QueryParameterWrap( keyVals.joined(separator: ", ") )
return EscapedQueryParameter( keyVals.joined(separator: ", ") )
}
}

Expand All @@ -82,7 +82,7 @@ public struct QueryArray: QueryParameter, QueryArrayType {
self.arr = arr.map { Optional($0) }
}
public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
return QueryParameterWrap( try arr.filter({ val in
return EscapedQueryParameter( try arr.filter({ val in
if let valid = val {
return valid.omitOnQueryParameter == false
}
Expand Down Expand Up @@ -137,109 +137,117 @@ struct QueryParameterOptional: QueryParameter {
}
}

struct QueryParameterWrap: QueryParameterType {
let val: String
init(_ val: String) {
self.val = val
struct EscapedQueryParameter: QueryParameterType {
private let value: String
private let idParameter: String?
init(_ val: String, idParameter: String? = nil) {
self.value = val
self.idParameter = idParameter
}
func escaped() -> String {
return val
return value
}
func escapedForID() -> String? {
return idParameter
}
}

extension String: QueryParameterType {
public func escaped() -> String {
return SQLString.escape(string: self)
}
public func escapedForID() -> String? {
return SQLString.escapeForID(string: self)
}
}

extension String: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( SQLString.escape(string: self) )
return self
}
}

extension Int: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension UInt: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension Int64: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension Int32: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension Int16: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension Int8: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension UInt64: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension UInt32: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension UInt16: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension UInt8: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension Double: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension Float: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(self) )
return EscapedQueryParameter( String(self) )
}
}

extension Bool: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( self ? "true" : "false" )
return EscapedQueryParameter( self ? "true" : "false" )
}
}

extension Decimal: QueryParameter {
public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
return QueryParameterWrap( String(describing: self) )
return EscapedQueryParameter( String(describing: self) )
}
}

Expand Down
1 change: 1 addition & 0 deletions Sources/MySQL/Result.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ infix operator <| : DecodingPrecedence
infix operator <|? : DecodingPrecedence


@available(*, deprecated)
public protocol QueryRowResultType {
static func decodeRow(r: QueryRowResult) throws -> Self
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/SQLFormatter/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
public enum QueryFormatError: Error {
case castError(actual: String, expected: String, key: String)
case queryParameterCountMismatch(query: String)
case queryParameterIdTypeError(query: String)
case queryParameterIDTypeError(given: String, query: String)
}
9 changes: 5 additions & 4 deletions Sources/SQLFormatter/QueryFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import Foundation

public protocol QueryParameterType {
func escaped() -> String
func escapedForID() -> String? // returns nil, if not supported for query id parameter
}

public struct SQLString {

public static func escapeId(string str: String) -> String {
public static func escapeForID(string str: String) -> String {
var step1 = ""
for c in str {
switch c {
Expand Down Expand Up @@ -96,10 +97,10 @@ public struct QueryFormatter {
if placeHolderCount >= args.count {
throw QueryFormatError.queryParameterCountMismatch(query: query)
}
guard let val = args[placeHolderCount] as? String else {
throw QueryFormatError.queryParameterIdTypeError(query: query)
guard let escapedVal = args[placeHolderCount].escapedForID() else {
throw QueryFormatError.queryParameterIDTypeError(given: "\(args[placeHolderCount])", query: query)
}
formatted.replaceSubrange(r, with: SQLString.escapeId(string: val))
formatted.replaceSubrange(r, with: escapedVal)
scanRange = r.upperBound..<formatted.endIndex
case "?":
if placeHolderCount >= args.count {
Expand Down
4 changes: 2 additions & 2 deletions Tests/MySQLTests/ConnectionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ final class ConnectionTests: XCTestCase, MySQLTestType {

func testConnect() throws {
let conn = try pool.getConnection()
XCTAssertTrue(conn.ping)
XCTAssertTrue(conn.ping())
}

func testConnect2() throws {
let conn = try pool.getConnection()
_ = try conn.query("SELECT 1;" as String)
XCTAssertTrue(conn.ping)
XCTAssertTrue(conn.ping())
}

struct Option: ConnectionOption {
Expand Down
11 changes: 8 additions & 3 deletions Tests/MySQLTests/QueryFormatterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,24 @@ extension QueryFormatterTests {

final class QueryFormatterTests: XCTestCase {

fileprivate enum TableName: String, QueryEnumParameter {
case user = "user"
}

func testBasicFormatting() throws {

let params: (String, String, Int, String, Int?) = (
let params: (String, TableName, String, Int, String, Int?) = (
"i.d",
TableName.user,
"id",
1,
"user's",
nil
)
let args = build(params)

let formatted = try QueryFormatter.format(query: "SELECT name,??,id FROM users WHERE ?? = ? OR name = ? OR age is ?;", args: Connection.buildArgs(args, option: queryOption) )
XCTAssertEqual(formatted, "SELECT name,`i`.`d`,id FROM users WHERE `id` = 1 OR name = 'user\\'s' OR age is NULL;")
let formatted = try QueryFormatter.format(query: "SELECT name,??,id FROM ?? WHERE ?? = ? OR name = ? OR age is ?;", args: Connection.buildArgs(args, option: queryOption) )
XCTAssertEqual(formatted, "SELECT name,`i`.`d`,id FROM `user` WHERE `id` = 1 OR name = 'user\\'s' OR age is NULL;")
}

func testPlaceholder() throws {
Expand Down
5 changes: 5 additions & 0 deletions Tests/MySQLTests/SQLTypeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ final class SQLTypeTests: XCTestCase {
case second = "second' 2"
}

enum SomeEnumParameter: String, QueryEnumParameter {
case first = "first 1"
case second = "second' 2"
}

enum SomeEnumCodable: String, Codable, QueryParameter {
case first = "first 1"
case second = "second' 2"
Expand Down

0 comments on commit 667f561

Please sign in to comment.