Full Code of novi/mysql-swift for AI

master 07574370c94c cached
42 files
133.4 KB
32.6k tokens
1 symbols
1 requests
Download .txt
Repository: novi/mysql-swift
Branch: master
Commit: 07574370c94c
Files: 42
Total size: 133.4 KB

Directory structure:
gitextract_zidf83u4/

├── .circleci/
│   └── config.yml
├── .gitignore
├── LICENSE.md
├── Package.swift
├── Package@swift-5.swift
├── README.md
├── Sources/
│   ├── MySQL/
│   │   ├── AutoincrementID.swift
│   │   ├── Blob.swift
│   │   ├── Connection.swift
│   │   ├── ConnectionPool.swift
│   │   ├── Date.swift
│   │   ├── Error.swift
│   │   ├── IDType.swift
│   │   ├── Query.swift
│   │   ├── QueryParameter-Data.swift
│   │   ├── QueryParameterType.swift
│   │   ├── RawRepresentableParameter.swift
│   │   ├── Result-SQLRawStringDecodable.swift
│   │   ├── Result.swift
│   │   ├── Sync.swift
│   │   └── Transaction.swift
│   ├── SQLFormatter/
│   │   ├── Error.swift
│   │   └── QueryFormatter.swift
│   └── cmysql/
│       ├── macos.pc
│       ├── module.modulemap
│       └── shim.h
└── Tests/
    ├── LinuxMain.swift
    ├── MySQLTests/
    │   ├── BlobTests.swift
    │   ├── ConnectionPoolTests.swift
    │   ├── ConnectionTests.swift
    │   ├── DateTests.swift
    │   ├── EscapeTests.swift
    │   ├── Model.swift
    │   ├── MySQLConnection.swift
    │   ├── QueryDecimalTypeTests.swift
    │   ├── QueryFormatterTests.swift
    │   ├── QueryParameterTests.swift
    │   ├── QueryTests.swift
    │   ├── QueryURLTypeTests.swift
    │   └── XCTestManifests.swift
    └── SQLFormatterTests/
        ├── SQLFormatterTests.swift
        └── XCTestManifests.swift

================================================
FILE CONTENTS
================================================

================================================
FILE: .circleci/config.yml
================================================
version: 2


jobs:
  mac-swift5.3:
    macos:
      xcode: "12.3.0"
    steps:
      - checkout
      - run: brew tap novi/tap && brew install novi/tap/cmysqlmariadb
      - run: mkdir -p /usr/local/etc/my.cnf.d /usr/local/var/mysql #workaround
      - run: sh -c "mysqld_safe --skip-grant-tables & sleep 5"
      - run: mysql -u root -e "create database IF NOT EXISTS test;"
      - run: swift build
      - run: swift test
  mac-swift5.3-mysql:
    macos:
      xcode: "12.3.0"
    steps:
      - checkout
      - run: brew tap novi/tap && brew install novi/tap/cmysql
      - run: mkdir -p /usr/local/var/mysql/data && echo "datadir=/usr/local/var/mysql/data" >> /usr/local/etc/my.cnf && mysqld --initialize-insecure
      - run: mysql.server start
      - run: mysql -u root -e "create database IF NOT EXISTS test;"
      - run: swift build
      - run: swift test

  linux-swift5.0:
    docker:
      - image: yusukeito/swift-basic:swift5.0
      - image: mariadb:10.3
        environment:
          MYSQL_USER: root
          MYSQL_DATABASE: "test"
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
          MYSQL_ROOT_HOST: "%"
          DATABASE_HOST: "%"
    steps:
      - checkout
      - run: sleep 10 #wait for mysql
      - run: swift build
      - run: swift test

  linux-swift5.1:
    docker:
      - image: yusukeito/swift-basic:swift5.1-cgrpc
      - image: mariadb:10.3
        environment:
          MYSQL_USER: root
          MYSQL_DATABASE: "test"
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
          MYSQL_ROOT_HOST: "%"
          DATABASE_HOST: "%"
    steps:
      - checkout
      - run: sleep 10 #wait for mysql
      - run: swift build
      - run: swift test

  linux-swift5.2:
    docker:
      - image: yusukeito/swift-basic:swift5.2-grpc-1
      - image: mariadb:10.3
        environment:
          MYSQL_USER: root
          MYSQL_DATABASE: "test"
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
          MYSQL_ROOT_HOST: "%"
          DATABASE_HOST: "%"
    steps:
      - checkout
      - run: sleep 10 #wait for mysql
      - run: swift build
      - run: swift test

  linux-swift5.3:
    docker:
      - image: yusukeito/swift-basic:swift5.3-grpc-1
      - image: mariadb:10.3
        environment:
          MYSQL_USER: root
          MYSQL_DATABASE: "test"
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
          MYSQL_ROOT_HOST: "%"
          DATABASE_HOST: "%"
    steps:
      - checkout
      - run: sleep 10 #wait for mysql
      - run: swift build
      - run: swift test

workflows:
  version: 2
  build_and_test:
    jobs:
      - mac-swift5.3
      - mac-swift5.3-mysql
      - linux-swift5.0
      - linux-swift5.1
      - linux-swift5.2
      - linux-swift5.3

================================================
FILE: .gitignore
================================================
# OS X Finder
.DS_Store

# Xcode per-user config
*.mode1
*.mode1v3
*.mode2v3
*.perspective
*.perspectivev3
*.pbxuser
#*.xcworkspace
xcuserdata

# Build products
build/
*.o
*.LinkFileList
*.hmap

# Automatic backup files
*~.nib/
*.swp
*~
*.dat
*.dep
docs/

Cartfile.resolved
Carthage/
.build/

Constants.swift
/*.xcodeproj
.swiftpm/


================================================
FILE: LICENSE.md
================================================
Copyright (c) 2015-18 Yusuke Ito

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.


================================================
FILE: Package.swift
================================================
// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "MySQL",
    products: [
        .library(name: "MySQL", targets: ["MySQL"])
    ],
    dependencies: [
        .package(url: "https://github.com/novi/cmysql.git", from: "2.0.0"),
    ],
    targets: [
        .target(
            name: "SQLFormatter"
        ),
        .target(
            name: "MySQL",
            dependencies: [
                "SQLFormatter",
            ]
        ),
        .testTarget(
            name: "MySQLTests",
            dependencies: [
                "MySQL"
            ]
        ),
        .testTarget(
            name: "SQLFormatterTests",
            dependencies: [
                "MySQL"
            ]
        )
    ],
    swiftLanguageVersions: [4]
)


================================================
FILE: Package@swift-5.swift
================================================
// swift-tools-version:5.0
import PackageDescription

let package = Package(
    name: "mysql-swift",
    products: [
        .library(name: "MySQL", targets: ["MySQL"])
    ],
    targets: [
        .systemLibrary(
            name: "CMySQL",
            path: "Sources/cmysql",
            pkgConfig: "cmysql",
            providers: [
                .brew(["cmysql"]),
                .apt(["libmysqlclient-dev"])
            ]
        ),
        .target(
            name: "SQLFormatter"
        ),
        .target(
            name: "MySQL",
            dependencies: [
                "CMySQL",
                "SQLFormatter",
            ]
        ),
        .testTarget(
            name: "MySQLTests",
            dependencies: [
                "MySQL"
            ]
        ),
        .testTarget(
            name: "SQLFormatterTests",
            dependencies: [
                "MySQL"
            ]
        )
    ]
)


================================================
FILE: README.md
================================================
mysql-swift
===========

**This library is obsolete and not maintained. Use [MySQLNIO](https://github.com/vapor/mysql-nio) instead.**

![Platform Linux, macOS](https://img.shields.io/badge/Platforms-Linux%2C%20macOS-lightgray.svg)
[![CircleCI](https://circleci.com/gh/novi/mysql-swift.svg?style=svg)](https://circleci.com/gh/novi/mysql-swift)



MySQL client library for Swift.
This is inspired by Node.js' [mysql](https://github.com/mysqljs/mysql).

* Based on libmysqlclient
* Raw SQL query
* Simple query formatting and escaping (same as Node's)
* Mapping queried results to `Codable` structs or classes

_Note:_ No asynchronous I/O support currently. It depends libmysqlclient.

```swift
// Declare a model

struct User: Codable, QueryParameter {
    let id: Int
    let userName: String
    let age: Int?
    let status: Status
    let createdAt: Date
    
    enum Status: String, Codable {
        case created = "created"
        case verified = "verified"
    }
    
    private enum CodingKeys: String, CodingKey {
        case id
        case userName = "user_name"
        case age
        case status = "status"
        case createdAt = "created_at"
    }
}
    
// Selecting
let nameParam = "some one"
let ids: [QueryParameter] = [1, 2, 3, 4, 5, 6]
let optionalInt: Int? = nil
let rows: [User] = try conn.query("SELECT id,user_name,status,status,created_at FROM `user` WHERE (age > ? OR age is ?) OR name = ? OR id IN (?)", [50, optionalInt, nameParam, QueryArray(ids)] ])

// Inserting
let age: Int? = 26
let user = User(id: 0, userName: "novi", age: age, status: .created, createdAt: Date())
let status = try conn.query("INSERT INTO `user` SET ?", [user]) as QueryStatus
let newId = status.insertedId

// Updating
let tableName = "user"
let defaultAge = 30
try conn.query("UPDATE ?? SET age = ? WHERE age is NULL;", [tableName, defaultAge])

``` 

# Requirements

* Swift 5.0 or later
* MariaDB or MySQL Connector/C (libmysqlclient) 2.2.3 or later

## macOS

Install pkg-config `.pc` file in [cmysql](https://github.com/vapor-community/cmysql) or [cmysql-mariadb](https://github.com/novi/cmysql-mariadb/tree/mariadb).

```sh
# cmysql
$ brew tap novi/tap
$ brew install novi/tap/cmysql

# cmysql-mariadb
$ brew tap novi/tap
$ brew install novi/tap/cmysqlmariadb
```

## Ubuntu

* Install `libmariadbclient`
* Follow [Setting up MariaDB Repositories](https://downloads.mariadb.org/mariadb/repositories/#mirror=yamagata-university) and set up your repository.

```sh
$ sudo apt-get install libmariadbclient-dev
```

# Installation

## Swift Package Manager

* Add `mysql-swift` to `Package.swift` of your project.

```swift
// swift-tools-version:5.2
import PackageDescription

let package = Package(
    ...,
    dependencies: [
        .package(url: "https://github.com/novi/mysql-swift.git", .upToNextMajor(from: "0.9.0"))
    ],
    targets: [
        .target(
            name: "YourAppOrLibrary",
            dependencies: [
                // add a dependency
                .product(name: "MySQL", package: "mysql-swift")
            ]
        )
    ]
)
```

# Usage

## Connection & Querying

1. Create a pool with options (hostname, port, password,...).
2. Use `ConnectionPool.execute()`. It automatically get and release a connection. 

```swift
let option = Option(host: "your.mysql.host"...) // Define and create your option type
let pool = ConnectionPool(option: option) // Create a pool with the option
let rows: [User] = try pool.execute { conn in
	// The connection `conn` is held in this block
	try conn.query("SELECT * FROM users;") // And it returns result to outside execute block
}
```

## Transaction

```swift	
let wholeStaus: QueryStatus = try pool.transaction { conn in
	let status = try conn.query("INSERT INTO users SET ?;", [user]) as QueryStatus // Create a user
	let userId = status.insertedId // the user's id
	try conn.query("UPDATE info SET some_value = ? WHERE some_key = 'latest_user_id' ", [userId]) // Store user's id that we have created the above
}
wholeStaus.affectedRows == 1 // true
```



# License

MIT


================================================
FILE: Sources/MySQL/AutoincrementID.swift
================================================
//
//  AutoincrementID.swift
//  MySQL
//
//  Created by Yusuke Ito on 6/27/16.
//  Copyright © 2016 Yusuke Ito. All rights reserved.
//

import SQLFormatter

public enum AutoincrementID<I: IDType> {
    case noID
    case ID(I)

    public var id: I {
        switch self {
        case .noID: fatalError("\(self) has no ID")
        case .ID(let id): return id
        }
    }
}

extension AutoincrementID: Equatable {
    static public func ==<I>(lhs: AutoincrementID<I>, rhs: AutoincrementID<I>) -> Bool {
        switch (lhs, rhs) {
        case (.noID, .noID): return true
        case (.ID(let lhs), .ID(let rhs) ): return lhs.id == rhs.id
        default: return false
        }
    }
}

extension AutoincrementID: CustomStringConvertible {
    // where I: CustomStringConvertible
    // is not supported yet
    public var description: String {
        switch self {
        case .noID: return "noID"
        case .ID(let id):
            if let idVal = id as? CustomStringConvertible {
                return idVal.description
            } else {
                return "\(id)"
            }
        }
    }
}

extension AutoincrementID {
    public init(_ id: I) {
        self = .ID(id)
    }
}

/*
extension AutoincrementID where I: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> AutoincrementID<I> {
        return AutoincrementID(try I.fromSQLValue(string: string))
    }
}*/

extension AutoincrementID: QueryParameter {
    public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        switch self {
        case .noID: return ""
        case .ID(let id): return try id.queryParameter(option: option)
        }
    }
    public var omitOnQueryParameter: Bool {
        switch self {
        case .noID: return true
        case .ID: return false
        }
    }
}



/// MARK: Codable support

extension AutoincrementID: Decodable where I: Decodable {
    public init(from decoder: Decoder) throws {
        self = .ID(try I(from: decoder))
    }
}

extension AutoincrementID: Encodable where I: Encodable {
    public func encode(to encoder: Encoder) throws {
        switch self {
        case .noID:
        break // nothing to encode
        case .ID(let id):
            try id.encode(to: encoder)
        }
    }
}



================================================
FILE: Sources/MySQL/Blob.swift
================================================
//
//  Blob.swift
//  MySQL
//
//  Created by Yusuke Ito on 4/22/16.
//  Copyright © 2016 Yusuke Ito. All rights reserved.
//

import Foundation
import SQLFormatter

extension Data: SQLRawStringDecodable {
    public static func fromSQLValue(string: String) throws -> Data {
        fatalError("logic error, construct via init(:)")
    }
}

fileprivate let HexTable: [Character] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]

extension Data: QueryParameterType {
    public func escaped() -> String {
        var buffer = [Character](["x", "'"])
        buffer.reserveCapacity( self.count * 2 + 3 ) // 3 stands for "x''", 2 stands for 2 characters per a byte data
        for byte in self {
            buffer.append(HexTable[Int((byte >> 4) & 0x0f)])
            buffer.append(HexTable[Int(byte & 0x0f)])
        }
        buffer.append("'")
        return String(buffer)
    }
    
    public func escapedForID() -> String? {
        return nil // Data can not be used for ID(?? placeholder).
    }
}

extension Data: QueryParameter {
    public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        return self
    }
}

internal struct Blob: QueryParameter {
    let data: Data
    let dataType: QueryCustomDataParameterDataType
    public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        return self
    }
}

extension Blob: QueryParameterType {
    public func escaped() -> String {
        switch dataType {
        case .blob: return data.escaped()
        case .json:
            return "CONVERT(" + data.escaped() + " using utf8mb4)"
        }
    }
    
    public func escapedForID() -> String? {
        return nil // Data can not be used for ID(?? placeholder).
    }
}



================================================
FILE: Sources/MySQL/Connection.swift
================================================
//
//  Database.swift
//  MySQL
//
//  Created by ito on 2015/10/24.
//  Copyright © 2015年 Yusuke Ito. All rights reserved.
//

import CMySQL
import CoreFoundation
import Foundation

internal struct MySQLUtil {
    internal static func getMySQLError(_ mysql: UnsafeMutablePointer<MYSQL>) -> String {
        guard let strPtr = mysql_error(mysql) else {
            return "unknown error. could not get error with `mysql_error()`."
        }
        guard let errorString = String(validatingUTF8: strPtr) else {
            return "unknown error. could not get error as string."
        }
        return errorString
    }
}


public protocol ConnectionOption {
    var host: String { get }
    var port: Int { get }
    var user: String { get }
    var password: String { get }
    var database: String { get }
    var timeZone: TimeZone { get }
    var encoding: Connection.Encoding { get }
    var timeout: Int { get }
    var reconnect: Bool { get }
    var omitDetailsOnError: Bool { get }
}

fileprivate let defaultTimeZone = TimeZone(identifier: "UTC")!

public extension ConnectionOption {
    // Provide default options
    var timeZone: TimeZone {
        return defaultTimeZone
    }
    var encoding: Connection.Encoding {
        return .UTF8MB4
    }
    var timeout: Int {
        return 10
    }
    var reconnect: Bool {
        return true
    }
    var omitDetailsOnError: Bool {
        return true
    }
}

extension Connection {
    public enum Encoding: String {
        case UTF8 = "utf8"
        case UTF8MB4 = "utf8mb4"
    }
    
}

public enum ConnectionError: Error {
    case connectionError(String)
    case connectionPoolGetConnectionTimeoutError
}

public final class Connection {
    
    internal var isInUse: Bool = false
    private var mysql_: UnsafeMutablePointer<MYSQL>?
    
    internal let pool: ConnectionPool
    public let option: ConnectionOption
    
    internal init(option: ConnectionOption, pool: ConnectionPool) {
        self.option = option
        self.pool = pool
        self.mysql_ = nil
    }
    
    internal func release() {
        pool.releaseConnection(self)
    }
    
    internal static func setReconnect(_ reconnect: Bool, mysql: UnsafeMutablePointer<MYSQL>) {
        let reconnectPtr = UnsafeMutablePointer<my_bool>.allocate(capacity: 1)
        reconnectPtr.pointee = reconnect == false ? 0 : 1
        mysql_options(mysql, MYSQL_OPT_RECONNECT, reconnectPtr)
        reconnectPtr.deallocate()
    }
    
    func setReconnect(_ reconnect: Bool) {
        if let mysql = mysql {
            Connection.setReconnect(reconnect, mysql: mysql)
        }
    }
    
    internal func connect() throws -> UnsafeMutablePointer<MYSQL> {
        dispose()
        
        guard let mysql = mysql_init(nil) else {
            fatalError("mysql_init() failed.")
        }
        
        do {
            let timeoutPtr = UnsafeMutablePointer<Int>.allocate(capacity: 1)
            timeoutPtr.pointee = option.timeout
            mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, timeoutPtr)
            timeoutPtr.deallocate()
        }
        
        Connection.setReconnect(option.reconnect, mysql: mysql)
        
        if mysql_real_connect(mysql,
            option.host,
            option.user,
            option.password,
            option.database,
            UInt32(option.port), nil, 0) == nil {
            // error
                throw ConnectionError.connectionError(MySQLUtil.getMySQLError(mysql))
        }
        mysql_set_character_set(mysql, option.encoding.rawValue)
        self.mysql_ = mysql
        return mysql
    }
    
    internal func connectIfNeeded() throws -> UnsafeMutablePointer<MYSQL> {
        guard let mysql = self.mysql_ else {
            return try connect()
        }
        return mysql
    }
    
    private var mysql: UnsafeMutablePointer<MYSQL>? {
        guard mysql_ != nil else {
            return nil
        }
        return mysql_
    }
    
    internal func ping() -> Bool {
        _ = try? connectIfNeeded()
        guard let mysql = mysql else {
            return false
        }
        return mysql_ping(mysql) == 0
    }
    
    private func dispose() {
        guard let mysql = mysql else {
            return
        }
        mysql_close(mysql)
        self.mysql_ = nil
    }
    
    deinit {
        dispose()
    }
}




================================================
FILE: Sources/MySQL/ConnectionPool.swift
================================================
//
//  ConnectionPool.swift
//  MySQL
//
//  Created by ito on 12/24/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

import Dispatch
#if os(Linux)
    import Glibc
#endif
import CMySQL

fileprivate var LibraryInitialized: Atomic<Bool> = Atomic(false)

fileprivate func InitializeMySQLLibrary() {
    LibraryInitialized.syncWriting {
        guard $0 == false else {
            return
        }
        if mysql_server_init(0, nil, nil) != 0 { // mysql_library_init
            fatalError("could not initialize MySQL library with `mysql_server_init`.")
        }
        $0 = true
    }
}

extension Array where Element == Connection {
    mutating func preparedNewConnection(option: ConnectionOption, pool: ConnectionPool) -> Connection {
        let newConn = Connection(option: option, pool: pool)
        _ = try? newConn.connect()
        append(newConn)
        return newConn
    }
    
    func getUsableConnection() -> Connection? {
        for c in self {
            if c.isInUse == false && c.ping() {
                c.isInUse = true
                return c
            }
        }
        return nil
    }
    
    internal var inUseConnections: Int {
        var count: Int = 0
        for c in self {
            if c.isInUse {
                count += 1
            }
        }
        return count
    }
}

final public class ConnectionPool: CustomStringConvertible {
    
    
    private var initialConnections_: Atomic<Int> = Atomic(1)
    
    public var initialConnections: Int {
        get {
            return initialConnections_.sync { $0 }
        }
        set {
            initialConnections_.syncWriting {
                $0 = newValue
            }
            pool.syncWriting {
                while $0.count < newValue {
                    _  = $0.preparedNewConnection(option: self.option, pool: self)
                }
            }
        }
    }
    
    public var maxConnections: Int {
        get {
            return maxConnections_.sync { $0 }
        }
        set {
            maxConnections_.syncWriting {
                $0 = newValue
            }
        }
    }
    
    private var maxConnections_: Atomic<Int> = Atomic(10)
    
    internal private(set) var pool: Atomic<[Connection]> = Atomic([])
    
    @available(*, deprecated, renamed: "option")
    public var options: ConnectionOption {
        return option
    }
    
    public let option: ConnectionOption
    
    @available(*, deprecated, renamed: "init(option:)")
    public convenience init(options: ConnectionOption) {
        self.init(option: options)
    }
    
    public init(option: ConnectionOption) {
        self.option = option
        
        InitializeMySQLLibrary()
        
        for _ in 0..<initialConnections {
            pool.syncWriting {
                _ = $0.preparedNewConnection(option: option, pool: self)
            }
        }
    }
    public var timeoutForGetConnection: Int {
        get {
            return timeoutForGetConnection_.sync { $0 }
        }
        set {
            timeoutForGetConnection_.syncWriting {
                $0 = newValue
            }
        }
    }
    
    private var timeoutForGetConnection_: Atomic<Int> = Atomic(60)
    
    internal func getConnection() throws -> Connection {
        var connection: Connection? =
        pool.syncWriting {
            if let conn = $0.getUsableConnection() {
                return conn
            }
            if $0.count < maxConnections {
                let conn = $0.preparedNewConnection(option: option, pool: self)
                conn.isInUse = true
                return conn
            }
            return nil
        }
        
        if let conn = connection {
            return conn
        }
        
        let tickInMs = 50 // ms
        var timeoutCount = (timeoutForGetConnection*1000)/tickInMs
        while timeoutCount > 0 {
            usleep(useconds_t(1000*tickInMs))
            connection = pool.sync {
                $0.getUsableConnection()
            }
            if connection != nil {
                break
            }
            timeoutCount -= 1
        }
        
        guard let conn = connection else {
            throw ConnectionError.connectionPoolGetConnectionTimeoutError
        }
        return conn
    }
    
    internal func releaseConnection(_ conn: Connection) {
        pool.sync { _ in
            conn.isInUse = false
        }
    }
    
    public var description: String {
        let inUseConnections = pool.sync {
            $0.inUseConnections
        }
        return "connections:\n\tinitial:\(initialConnections), max:\(maxConnections), in-use:\(inUseConnections)"
    }
}


extension ConnectionPool {
    
    public func execute<T>( _ block: (_ conn: Connection) throws -> T  ) throws -> T {
        let conn = try getConnection()
        defer {
            releaseConnection(conn)
        }
        return try block(conn)
    }
    
}


================================================
FILE: Sources/MySQL/Date.swift
================================================
//
//  Date.swift
//  MySQL
//
//  Created by ito on 12/16/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//


import Foundation
import SQLFormatter

internal final class SQLDateCalendar {
    
    private static var calendars: Atomic<[TimeZone:Calendar]> = Atomic([:])
    
    internal static func calendar<T>(forTimezone timeZone: TimeZone, _ block: (_ calendar: Calendar) -> T) -> T {
        return calendars.syncWriting {
            if let calendar = $0[timeZone] {
                return block(calendar)
            }
            var calendar = Calendar(identifier: .gregorian)
            calendar.timeZone = timeZone
            $0[timeZone] = calendar
            return block(calendar)
        }
    }
}

fileprivate func pad(num: Int, digits: Int = 2) -> String {
    var str = String(num)
    if num < 0 {
        return str
    }
    while str.count < digits {
        str = "0" + str
    }
    return str
}


extension Date {
    
    internal init(sqlDate: String, timeZone: TimeZone) throws {
        
        switch sqlDate.count {
        case 19:
            let chars: [Character] = Array(sqlDate)
            if let year = Int(String(chars[0...3])),
                let month = Int(String(chars[5...6])),
                let day = Int(String(chars[8...9])),
                let hour = Int(String(chars[11...12])),
                let minute = Int(String(chars[14...15])),
                let second = Int(String(chars[17...18])), year > 0 && day > 0 && month > 0 {
                var comps = DateComponents()
                comps.year = year
                comps.month = month
                comps.day = day
                comps.hour = hour
                comps.minute = minute
                comps.second = second
                let parsedDate: Date? = SQLDateCalendar.calendar(forTimezone: timeZone) { calendar in
                    calendar.date(from :comps)
                }
                if let date = parsedDate {
                    self = date
                    return
                }
            }
        default: break
        }
        
        throw QueryError.SQLDateStringError(sqlDate)
    }
}

extension Date: QueryParameter {
    public func queryParameter(option: QueryParameterOption) -> QueryParameterType {
        let comp: DateComponents = SQLDateCalendar.calendar(forTimezone: option.timeZone) { calendar in
            calendar.dateComponents([ .year, .month,  .day,  .hour, .minute, .second], from: self)
        }        
        // YYYY-MM-DD HH:MM:SS
        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))'" )
    }
}

fileprivate func nanosecondsToString(_ nanosec: Int) -> String {
    let nanosecSecond = Double(nanosec % 1_000_000_000)/1_000_000_000.0
    var nanosecStr = String(format: "%.6f", nanosecSecond)
    nanosecStr.removeFirst()
    return String(nanosecStr)
}

extension DateComponents: QueryParameter {
    public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        if let year = self.year, let month = self.month, let day = self.day, let hour = self.hour, let minute = self.minute, let second = self.second {
            var string = "'\(pad(num: year, digits: 4))-\(pad(num: month))-\(pad(num: day)) \(pad(num: hour)):\(pad(num: minute)):\(pad(num: second))"
            if let nanosec = self.nanosecond {
                string += nanosecondsToString(nanosec)
            }
            return EscapedQueryParameter(string + "'")
        }
        
        if let hour = self.hour, let minute = self.minute, let second = self.second {
            var string = "'\(pad(num: hour)):\(pad(num: minute)):\(pad(num: second))"
            if let nanosec = self.nanosecond {
                string += nanosecondsToString(nanosec)
            }
            return EscapedQueryParameter(string + "'")
        }
        if let year = self.year {
            return EscapedQueryParameter("'\(pad(num: year))'")
        }
        throw QueryParameterError.dateComponentsError(self.description)
    }
}

fileprivate let DateTimeRegex: NSRegularExpression = {
    return try! NSRegularExpression(pattern: "^(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})\\.?(\\d*)$", options: [])
}()

fileprivate let TimeRegex: NSRegularExpression = {
    return try! NSRegularExpression(pattern: "^(\\-?\\d{1,3}):(\\d{2}):(\\d{2})\\.?(\\d*)$", options: [])
}()

fileprivate let DateRegex: NSRegularExpression = {
    return try! NSRegularExpression(pattern: "^(\\d{4})-(\\d{2})-(\\d{2})$", options: [])
}()


fileprivate func stringToNanoseconds<S: StringProtocol>(_ string: S) -> Int? {
    guard string.count > 0 else {
        return nil
    }
    guard let doubleValue = Double("0.\(string)") else {
        return nil
    }
    return Int(doubleValue * 1_000_000_000.0)
}

extension DateComponents: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> DateComponents {
        if string.count == 4 {
            // YEAR type
            return DateComponents(year: Int(string))
        }
        
        let wholeRange = NSRange(string.startIndex..<string.endIndex, in: string)
        
        // count of the string will be at least 19...
        // "2000-01-23 01:23:45"
        if string.count >= 19, let match = DateTimeRegex.firstMatch(in: string, options: [], range: wholeRange) {
            let year = Int(string[Range(match.range(at: 1), in: string)!])
            let month = Int(string[Range(match.range(at: 2), in: string)!])
            let day = Int(string[Range(match.range(at: 3), in: string)!])
            
            let hour = Int(string[Range(match.range(at: 4), in: string)!])
            let minute = Int(string[Range(match.range(at: 5), in: string)!])
            let second = Int(string[Range(match.range(at: 6), in: string)!])
            
            let nanosecond = String(string[Range(match.range(at: 7), in: string)!])
            return DateComponents(
                year: year,
                month: month,
                day: day,
                hour: hour,
                minute: minute,
                second: second,
                nanosecond: stringToNanoseconds(nanosecond)
            )
        }
        
        // "1:23:45"
        if string.count >= 7, let match = TimeRegex.firstMatch(in: string, options: [], range: wholeRange) {
            let hour = Int(string[Range(match.range(at: 1), in: string)!])
            let minute = Int(string[Range(match.range(at: 2), in: string)!])
            let second = Int(string[Range(match.range(at: 3), in: string)!])
            
            let nanosecond = string[Range(match.range(at: 4), in: string)!]
            return DateComponents(
                hour: hour,
                minute: minute,
                second: second,
                nanosecond: stringToNanoseconds(nanosecond)
            )
        }
        
        // "2000-01-23"
        if string.count == 10, let match = DateRegex.firstMatch(in: string, options: [], range: wholeRange) {
            let year = Int(string[Range(match.range(at: 1), in: string)!])
            let month = Int(string[Range(match.range(at: 2), in: string)!])
            let day = Int(string[Range(match.range(at: 3), in: string)!])
            return DateComponents(
                year: year,
                month: month,
                day: day
            )
        }
        throw QueryError.SQLDateStringError(string)
    }
}


================================================
FILE: Sources/MySQL/Error.swift
================================================
//
//  Error.swift
//  MySQL
//
//  Created by Yusuke Ito on 12/14/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

public enum QueryError: Error {
    
    case queryExecutionError(message: String, query: String)
    case resultFetchError(message: String, query: String)
    case resultNoFieldError(query: String)
    case resultRowFetchError(query: String)
    case resultFieldFetchError(query: String)
    case resultParseError(message: String, result: String)
    
    case resultCastError(actualValue: String, expectedType: String, forField: String)
    case resultDecodeError(rawSQLValue: String, forType: Any)
    case resultDecodeErrorMessage(message: String)
    case SQLDateStringError(String)
    case SQLRawStringDecodeError(error: Error, actualValue: String, expectedType: String, forField: String)
    
    case missingField(String)
}

public enum QueryParameterError: Error {
    case dateComponentsError(String)
}


================================================
FILE: Sources/MySQL/IDType.swift
================================================
//
//  IDType.swift
//  MySQL
//
//  Created by Yusuke Ito on 6/27/16.
//  Copyright © 2016 Yusuke Ito. All rights reserved.
//

import SQLFormatter

public protocol IDType: QueryParameter, Hashable, Codable {
    associatedtype T: QueryParameter, Hashable, Codable
    var id: T { get }
    init(_ id: T)
}

public extension IDType {
    
    func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        return try id.queryParameter(option: option)
    }
    #if swift(>=4.2)
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
    #else
    var hashValue: Int {
        return id.hashValue
    }
    #endif
}

extension IDType where Self: SQLRawStringDecodable, Self.T: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Self {
        return Self(try T.fromSQLValue(string: string))
    }
}

extension IDType {
    public static func ==(lhs: Self, rhs: Self) -> Bool {
        return lhs.id == rhs.id
    }
}

// MARK: Codable type
extension IDType {
    
    public init(from decoder: Decoder) throws {
        if T.self == Int.self {
            self.init(try decoder.singleValueContainer().decode(Int.self) as! T)
        } else if T.self == Int64.self {
            self.init(try decoder.singleValueContainer().decode(Int64.self) as! T)
        } else if T.self == UInt.self {
            self.init(try decoder.singleValueContainer().decode(UInt.self) as! T)
        } else if T.self == UInt64.self {
            self.init(try decoder.singleValueContainer().decode(UInt64.self) as! T)
        } else if T.self == String.self {
            self.init(try decoder.singleValueContainer().decode(String.self) as! T)
        } else {
            fatalError("`init(from:)` of \(Self.self) is not implemented")
        }
    }
    
    public func encode(to encoder: Encoder) throws {
        if T.self == Int.self {
            var container = encoder.singleValueContainer()
            try container.encode(id as! Int)
        } else if T.self == Int64.self {
            var container = encoder.singleValueContainer()
            try container.encode(id as! Int64)
        } else if T.self == UInt.self {
            var container = encoder.singleValueContainer()
            try container.encode(id as! UInt)
        } else if T.self == UInt64.self {
            var container = encoder.singleValueContainer()
            try container.encode(id as! UInt64)
        } else if T.self == String.self {
            var container = encoder.singleValueContainer()
            try container.encode(id as! String)
        } else {
            fatalError("`encode(to:)` of \(Self.self) is not implemented")
        }
    }
}

// TODO: this implementation does not work in release build, Swift 4.1
/*
extension IDType {
    
    public init(from decoder: Decoder) throws {
        fatalError("`init(from:)` of \(Self.self) is not implemented")
    }
    
    public func encode(to encoder: Encoder) throws {
        fatalError("`encode(to:)` of \(Self.self) is not implemented")
    }
}


extension IDType where T == Int {
    public init(from decoder: Decoder) throws {
        self.init(try decoder.singleValueContainer().decode(Int.self))
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(id)
    }
}

extension IDType where T == Int64 {
    public init(from decoder: Decoder) throws {
        self.init(try decoder.singleValueContainer().decode(Int64.self))
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(id)
    }
}

extension IDType where T == UInt {
    public init(from decoder: Decoder) throws {
        self.init(try decoder.singleValueContainer().decode(UInt.self))
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(id)
    }
}

extension IDType where T == UInt64 {
    public init(from decoder: Decoder) throws {
        self.init(try decoder.singleValueContainer().decode(UInt64.self))
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(id)
    }
}

extension IDType where T == String {
    public init(from decoder: Decoder) throws {
        self.init(try decoder.singleValueContainer().decode(String.self))
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(id)
    }
}
 */


================================================
FILE: Sources/MySQL/Query.swift
================================================
//
//  Connection.swift
//  MySQL
//
//  Created by ito on 2015/10/24.
//  Copyright © 2015年 Yusuke Ito. All rights reserved.
//

import CMySQL
import SQLFormatter
import Foundation

public struct QueryStatus: CustomStringConvertible {
    public let affectedRows: UInt64?
    public let insertedID: UInt64
    
    init(mysql: UnsafeMutablePointer<MYSQL>) {
        self.insertedID = mysql_insert_id(mysql)
        let arows = mysql_affected_rows(mysql)
        if arows == (~0) {
            self.affectedRows = nil // error or select statement
        } else {
            self.affectedRows = arows
        }
    }
    
    public var description: String {
        return "insertedID:\(insertedID), affectedRows:" + (affectedRows != nil ? ("\(affectedRows!)") : "nil")
    }
}

internal extension String {
    func subString(max: Int) -> String {
        guard let r = index(startIndex, offsetBy: max, limitedBy: endIndex) else {
            return self
        }
        return String(self[startIndex..<r])
    }
}

extension Connection {
    
    internal struct NullValue {
        static let null = NullValue()
    }
    
    internal struct EmptyRowResult: Decodable {
        static func decodeRow(r: QueryRowResult) throws -> EmptyRowResult {
            return EmptyRowResult()
        }
    }
    
    internal struct Field {
        let name: String
        let type: enum_field_types
        init?(f: MYSQL_FIELD) {
            if f.name == nil {
                return nil
            }
            guard let fs = String(validatingUTF8: f.name) else {
                return nil
            }
            self.name = fs
            self.type = f.type
        }
        var isDate: Bool {
            return type == MYSQL_TYPE_DATE ||
                type == MYSQL_TYPE_DATETIME ||
                type == MYSQL_TYPE_TIME ||
                type == MYSQL_TYPE_TIMESTAMP
        }
        
    }
    
    internal enum FieldValue {
        case null
        case binary(Data)
        case date(dateString: String, timezone: TimeZone)
        
        static func makeBinary(ptr: UnsafeMutablePointer<Int8>, length: UInt) -> FieldValue {
            let data = Data(bytes: UnsafeRawPointer(ptr), count: Int(length))
            return FieldValue.binary(data)
        }
        
        func string() throws -> String {
            switch self {
            case .null:
                throw QueryError.resultParseError(message: "the field is not string.", result: "null")
            case .date(let string, _):
                return string
            case .binary(let data):
                guard let string = String(data: data, encoding: .utf8) else {
                    throw QueryError.resultParseError(message: "invalid utf8 string bytes.", result: "")
                }
                return string
            }
        }
    }
    
    fileprivate func query<T: Decodable>(query formattedQuery: String, option: QueryParameterOption) throws -> ([T], QueryStatus) {
        let (rows, status) = try self.query(query: formattedQuery, option: option)
        
        return try (rows.map({ try T(from: QueryRowResultDecoder(row: $0))}), status)
    }
    
    fileprivate func query(query formattedQuery: String, option: QueryParameterOption) throws -> ([QueryRowResult], QueryStatus) {
        let mysql = try connectIfNeeded()
        
        func queryPrefix() -> String {
            if self.option.omitDetailsOnError {
                return ""
            }
            return formattedQuery.subString(max: 1000)
        }
        
        guard mysql_real_query(mysql, formattedQuery, UInt(formattedQuery.utf8.count)) == 0 else {
            throw QueryError.queryExecutionError(message: MySQLUtil.getMySQLError(mysql), query: queryPrefix())
        }
        let status = QueryStatus(mysql: mysql)
        
        let res = mysql_use_result(mysql)
        guard res != nil else {
            if mysql_field_count(mysql) == 0 {
                // actual no result
                return ([], status)
            }
            throw QueryError.resultFetchError(message: MySQLUtil.getMySQLError(mysql), query: queryPrefix())
        }
        defer {
            mysql_free_result(res)
        }
        
        let fieldCount = Int(mysql_num_fields(res))
        guard fieldCount > 0 else {
            throw QueryError.resultNoFieldError(query: queryPrefix())
        }
        
        // fetch field info
        guard let fieldDef = mysql_fetch_fields(res) else {
            throw QueryError.resultFieldFetchError(query: queryPrefix())
        }
        var fields:[Field] = []
        for i in 0..<fieldCount {
            guard let f = Field(f: fieldDef[i]) else {
                throw QueryError.resultFieldFetchError(query: queryPrefix())
            }
            fields.append(f)
        }
        
        // fetch rows
        var rows:[QueryRowResult] = []
        
        var rowCount: Int = 0
        while true {
            guard let row = mysql_fetch_row(res) else {
                break // end of rows
            }
            
            guard let lengths = mysql_fetch_lengths(res) else {
                throw QueryError.resultRowFetchError(query: queryPrefix())
            }
            
            var fieldValues: [FieldValue] = []
            for i in 0..<fieldCount {
                let field = fields[i]
                if let valf = row[i], row[i] != nil {
                    let binary = FieldValue.makeBinary(ptr: valf, length: lengths[i])
                    if field.isDate {
                        fieldValues.append(FieldValue.date(dateString: try binary.string(), timezone: option.timeZone))
                    } else {
                        fieldValues.append(binary)
                    }                    
                } else {
                    fieldValues.append(FieldValue.null)
                }
                
            }
            rowCount += 1
            if fields.count != fieldValues.count {
                throw QueryError.resultParseError(message: "invalid fetched column count", result: "")
            }
            rows.append(QueryRowResult(fields: fields, fieldValues: fieldValues))
        }
        
        return (rows, status)
    }
}

fileprivate struct QueryParameterDefaultOption: QueryParameterOption {
    let timeZone: TimeZone
}


extension Connection {
    
    internal static func buildParameters(_ params: [QueryParameter], option: QueryParameterOption) throws -> [QueryParameterType] {
        return try params.map { try $0.queryParameter(option: option) }
    }
    
    public func query<R: Decodable>(_ query: String, _ params: [QueryParameter] = []) throws -> ([R], QueryStatus) {
        let option = QueryParameterDefaultOption(
            timeZone: self.option.timeZone
        )
        let queryString = try QueryFormatter.format(query: query, parameters: type(of: self).buildParameters(params, option: option))
        return try self.query(query: queryString, option: option)
    }
    
    public func query<R: Decodable>(_ query: String, _ params: [QueryParameter] = [], option: QueryParameterOption) throws -> ([R], QueryStatus) {
        let queryString = try QueryFormatter.format(query: query, parameters: type(of: self).buildParameters(params, option: option))
        return try self.query(query: queryString, option: option)
    }
    
    public func query<R: Decodable>(_ query: String, _ params: [QueryParameter] = []) throws -> [R] {
        let (rows, _) = try self.query(query, params) as ([R], QueryStatus)
        return rows
    }
    
    public func query<R: Decodable>(_ query: String, _ params: [QueryParameter] = [], option: QueryParameterOption) throws -> [R] {
        let (rows, _) = try self.query(query, params, option: option) as ([R], QueryStatus)
        return rows
    }
    
    public func query(_ query: String, _ params: [QueryParameter] = []) throws -> QueryStatus {
        let (_, status) = try self.query(query, params) as ([EmptyRowResult], QueryStatus)
        return status
    }
    
    public func query(_ query: String, _ params: [QueryParameter] = [], option: QueryParameterOption) throws -> QueryStatus {
        let (_, status) = try self.query(query, params, option: option) as ([EmptyRowResult], QueryStatus)
        return status
    }
}


================================================
FILE: Sources/MySQL/QueryParameter-Data.swift
================================================
//
//  QueryParameter-Data.swift
//  MySQL
//
//  Created by Yusuke Ito on 4/29/18.
//

import Foundation

public protocol QueryRowResultCustomData {
    static func decode(fromRowData data: Data) throws -> Self
}

public enum QueryCustomDataParameterDataType {
    case blob
    case json
}

public protocol QueryCustomDataParameter {
    func encodeForQueryParameter() throws -> Data
    var queryParameterDataType: QueryCustomDataParameterDataType { get }
}

public extension QueryCustomDataParameter {
    var queryParameterDataType: QueryCustomDataParameterDataType {
        return .blob
    }
}



================================================
FILE: Sources/MySQL/QueryParameterType.swift
================================================
//
//  QueryParameterType.swift
//  MySQL
//
//  Created by Yusuke Ito on 12/28/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

import SQLFormatter
import Foundation

public protocol QueryParameter {
    func queryParameter(option: QueryParameterOption) throws -> QueryParameterType
    var omitOnQueryParameter: Bool { get }
}

public extension QueryParameter {
    var omitOnQueryParameter: Bool {
        return false
    }
}

public protocol QueryParameterOption {
    var timeZone: TimeZone { get }
}

internal struct QueryParameterNull: QueryParameter {
    
    private init() {
    }
    
    static let null = QueryParameterNull()
    
    func queryParameter(option: QueryParameterOption) -> QueryParameterType {
        return EscapedQueryParameter( "NULL" )
    }
}

@available(*, renamed: "QueryParameterDictionary")
typealias QueryDictionary = QueryParameterDictionary

public struct QueryParameterDictionary: QueryParameter {
    private let dict: [String: QueryParameter?]
    public init(_ dict: [String: QueryParameter?]) {
        self.dict = dict
    }
    public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        var keyVals: [String] = []
        for (k, v) in dict {
            if v == nil || v?.omitOnQueryParameter == false {
                keyVals.append("\(SQLString.escapeForID(k)) = \(try (v ?? QueryParameterNull.null).queryParameter(option: option).escaped())")
            }
        }
        return EscapedQueryParameter( keyVals.joined(separator:  ", ") )
    }
}

fileprivate protocol QueryParameterArrayType: QueryParameter {
    
}

@available(*, renamed: "QueryParameterArray")
typealias QueryArray = QueryParameterArray

public struct QueryParameterArray: QueryParameter, QueryParameterArrayType {
    private let arr: [QueryParameter?]
    public init(_ arr: [QueryParameter?]) {
        self.arr = arr
    }
    public init(_ arr: [QueryParameter]) {
        self.arr = arr.map { Optional($0) }
    }
    public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        return EscapedQueryParameter( try arr.filter({ val in
            if let valid = val {
                return valid.omitOnQueryParameter == false
            }
            return true
        }).map({
            if let val = $0 as? QueryParameterArrayType {
                return "(" + (try val.queryParameter(option: option).escaped()) + ")"
            }
            return try ($0 ?? QueryParameterNull.null).queryParameter(option: option).escaped()
        }).joined(separator: ", ") )
    }
}

extension Optional: QueryParameter where Wrapped: QueryParameter {
    public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        switch self {
        case .none:
            return QueryParameterNull.null.queryParameter(option: option)
        case .some(let value):
            return try value.queryParameter(option: option)
        }
    }
    public var omitOnQueryParameter: Bool {
        switch self {
        case .none:
            return false
        case .some(let value):
            return value.omitOnQueryParameter
        }
    }
}

internal 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 value
    }
    func escapedForID() -> String? {
        return idParameter
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/// MARK: Codable support

fileprivate final class QueryParameterEncoder: Encoder {
    let codingPath = [CodingKey]()
    
    let userInfo = [CodingUserInfoKey : Any]()
    
    var dict: [String: QueryParameter?] = [:]
    var singleValue: QueryParameter? = nil
    enum StorageType {
        case single
        case dictionary
    }
    
    var storageType: StorageType = .dictionary
    
    func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> where Key : CodingKey {
        return KeyedEncodingContainer(QueryParameterKeyedEncodingContainer<Key>(encoder: self))
    }
    
    func unkeyedContainer() -> UnkeyedEncodingContainer {
        fatalError("not supported unkeyedContainer in QueryParameter")
    }
    
    func singleValueContainer() -> SingleValueEncodingContainer {
        self.storageType = .single
        return QueryParameterSingleValueEncodingContainer(encoder: self)
    }
    
}


fileprivate struct QueryParameterSingleValueEncodingContainer: SingleValueEncodingContainer {
    let codingPath = [CodingKey]()
    
    var encoder: QueryParameterEncoder
    
    mutating func encodeNil() throws {
        encoder.singleValue = nil
    }
    
    mutating func encode(_ value: Bool) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: Int) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: Int8) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: Int16) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: Int32) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: Int64) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: UInt) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: UInt8) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: UInt16) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: UInt32) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: UInt64) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: Float) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: Double) throws {
        encoder.singleValue = value
    }
    
    mutating func encode(_ value: String) throws {
        encoder.singleValue = value
    }
    
    mutating func encode<T>(_ value: T) throws where T : Encodable {
        encoder.singleValue = value as? QueryParameter
    }
    
    
}

fileprivate struct QueryParameterKeyedEncodingContainer<Key : CodingKey> : KeyedEncodingContainerProtocol {
    fileprivate let codingPath = [CodingKey]()
    
    fileprivate let encoder: QueryParameterEncoder
    
    mutating func encodeNil(forKey key: Key) throws {
        encoder.dict[key.stringValue] = nil
    }
    
    mutating func encode(_ value: Bool, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: Int, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: Int8, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: Int16, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: Int32, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: Int64, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: UInt, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: UInt8, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: UInt16, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: UInt32, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: UInt64, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: Float, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: Double, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode(_ value: String, forKey key: Key) throws {
        encoder.dict[key.stringValue] = value
    }
    
    mutating func encode<T>(_ value: T, forKey key: Key) throws where T : Encodable {
        if T.self == Date.self {
            encoder.dict[key.stringValue] = value as! Date
        } else if T.self == DateComponents.self {
            encoder.dict[key.stringValue] = value as! DateComponents
        } else if T.self == Data.self {
            encoder.dict[key.stringValue] = value as! Data
        } else if T.self == URL.self {
            // encode absoluteString same as JSONEncoder
            // https://github.com/apple/swift/blob/master/stdlib/public/SDK/Foundation/JSONEncoder.swift
            encoder.dict[key.stringValue] = (value as! URL).absoluteString
        } else if T.self == Decimal.self {
            encoder.dict[key.stringValue] = (value as! Decimal).description
        } else if let custom = value as? QueryCustomDataParameter {
            if let param = value as? QueryParameter {
                if !param.omitOnQueryParameter {
                    let data = try custom.encodeForQueryParameter()
                    encoder.dict[key.stringValue] = Blob(data: data, dataType: custom.queryParameterDataType)
                }
            } else {
                let data = try custom.encodeForQueryParameter()
                encoder.dict[key.stringValue] = Blob(data: data, dataType: custom.queryParameterDataType)
            }
        } else {
            let singleValueEncoder = QueryParameterEncoder()
            try value.encode(to: singleValueEncoder)
            if let param = value as? QueryParameter {
                if !param.omitOnQueryParameter {
                    encoder.dict[key.stringValue] = singleValueEncoder.singleValue
                }
            } else {
                encoder.dict[key.stringValue] = singleValueEncoder.singleValue
            }
        }
        
        //fatalError("not supported type \(T.self)")
    }
    
    mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> where NestedKey : CodingKey {
        fatalError("nestedContainer in query parameter is not supported.")
    }
    
    mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
        fatalError("nestedUnkeyedContainer in query parameter is not supported.")
    }
    
    mutating func superEncoder() -> Encoder {
        fatalError("superEncoder in query parameter is not supported.")
    }
    
    mutating func superEncoder(forKey key: Key) -> Encoder {
        fatalError("superEncoder(forKey:) in query parameter is not supported.")
    }
}



extension Encodable where Self: QueryParameter {
    public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        let encoder = QueryParameterEncoder()
        try self.encode(to: encoder)
        switch encoder.storageType {
        case .dictionary:
            return try QueryParameterDictionary(encoder.dict).queryParameter(option: option)
        case .single:
            return try (encoder.singleValue ?? QueryParameterNull.null).queryParameter(option: option)
        }
    }
}


================================================
FILE: Sources/MySQL/RawRepresentableParameter.swift
================================================
//
//  RawRepresentableParameter.swift
//  MySQL
//
//  Created by Yusuke Ito on 4/21/16.
//  Copyright © 2016 Yusuke Ito. All rights reserved.
//

import SQLFormatter
import Foundation


public protocol QueryRawRepresentableParameter: RawRepresentable, QueryParameter {
    
}


extension QueryRawRepresentableParameter where RawValue: QueryParameter {
    public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        return try rawValue.queryParameter(option: option)
    }
}

/*
extension RawRepresentable where RawValue: QueryParameter {
    public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        return try rawValue.queryParameter(option: option)
    }
}*/



================================================
FILE: Sources/MySQL/Result-SQLRawStringDecodable.swift
================================================
//
//  ResultTypes.swift
//  MySQL
//
//  Created by Yusuke Ito on 12/28/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

import Foundation

extension Int: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Int {
        guard let val = Int(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension UInt: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> UInt {
        guard let val = UInt(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension Int64: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Int64 {
        guard let val = Int64(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension Int32: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Int32 {
        guard let val = Int32(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension Int16: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Int16 {
        guard let val = Int16(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension Int8: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Int8 {
        guard let val = Int8(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension UInt64: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> UInt64 {
        guard let val = UInt64(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension UInt32: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> UInt32 {
        guard let val = UInt32(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension UInt16: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> UInt16 {
        guard let val = UInt16(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension UInt8: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> UInt8 {
        guard let val = UInt8(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension Float: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Float {
        guard let val = Float(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension Double: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Double {
        guard let val = Double(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension String: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> String {
        return string
    }
}

extension Bool: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Bool {
        guard let val = Int(string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return Bool(val == 0 ? false : true )
    }
}

extension Decimal: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Decimal {
        guard let val = Decimal(string: string) else {
            throw QueryError.resultDecodeError(rawSQLValue: string, forType: self)
        }
        return val
    }
}

extension Date: SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Date {
        fatalError("invalid constructor (use init instead)")
    }
}


================================================
FILE: Sources/MySQL/Result.swift
================================================
//
//  Result.swift
//  MySQL
//
//  Created by ito on 12/10/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

import Foundation

internal protocol SQLRawStringDecodable {
    static func fromSQLValue(string: String) throws -> Self
}

internal struct QueryRowResult {
    
    private let fields: [Connection.Field]
    private let fieldValues: [Connection.FieldValue]
    internal let columnMap: [String: Connection.FieldValue] // the key is field name
    init(fields: [Connection.Field], fieldValues: [Connection.FieldValue]) {
        self.fields = fields
        self.fieldValues = fieldValues
        var map:[String: Connection.FieldValue] = [:]
        for i in 0..<fieldValues.count {
            map[fields[i].name] = fieldValues[i]
        }
        self.columnMap = map
    }
    
    func isNull(forField field: String) -> Bool {
        guard let fieldValue = columnMap[field] else {
            return false
        }
        switch fieldValue {
        case .null:
            return true
        case .binary, .date:
            return false
        }
    }
    
    private func castOrFail<T: SQLRawStringDecodable>(_ obj: String, field: String) throws -> T {
        //print("casting val \(obj) to \(T.self)")
        do {
            return try T.fromSQLValue(string: obj)
        } catch {
            throw QueryError.SQLRawStringDecodeError(error: error, actualValue: obj, expectedType: "\(T.self)", forField: field)
        }
    }
    
    private func getValue<T: SQLRawStringDecodable>(fieldValue: Connection.FieldValue, field: String) throws -> T {
        switch fieldValue {
        case .null:
            throw QueryError.resultCastError(actualValue: "NULL", expectedType: "\(T.self)", forField: field)
        case .date(let string, let timezone):
            if T.self == Date.self {
                return try Date(sqlDate: string, timeZone: timezone) as! T
            } else if T.self == DateComponents.self {
                return try DateComponents.fromSQLValue(string: string) as! T
            }
            throw QueryError.resultCastError(actualValue: "\(string)", expectedType: "\(T.self)", forField: field)
        case .binary(let data):
            //print("T is \(T.self)")
            if let bin = data as? T {
                return bin
            }
            return try castOrFail(fieldValue.string(), field: field)
        }
    }
    
    func getValue<T: SQLRawStringDecodable>(forField field: String) throws -> T {
        guard let fieldValue = columnMap[field] else {
            throw QueryError.missingField(field)
        }
        return try getValue(fieldValue: fieldValue, field: field)
    }    
}

internal struct QueryRowResultDecoder : Decoder {
    let codingPath = [CodingKey]()
    let userInfo = [CodingUserInfoKey : Any]()
    let row: QueryRowResult
    
    public func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> {
        return KeyedDecodingContainer(RowKeyedDecodingContainer<Key>(decoder: self))
    }
    
    public func unkeyedContainer() throws -> UnkeyedDecodingContainer {
        throw QueryError.resultDecodeErrorMessage(message: "Decoder unkeyedContainer not implemented")
    }
    
    public func singleValueContainer() throws -> SingleValueDecodingContainer {
        throw QueryError.resultDecodeErrorMessage(message: "Decoder singleValueContainer not implemented")
    }
}

fileprivate struct SQLStringDecoder: Decoder {
    let codingPath =  [CodingKey]()
    let userInfo = [CodingUserInfoKey : Any]()
    let sqlString: String
    
    struct SingleValue: SingleValueDecodingContainer {
        let codingPath =  [CodingKey]()
        let sqlString: String
        func decodeNil() -> Bool {
            fatalError()
        }
        
        func decode(_ type: Bool.Type) throws -> Bool {
            fatalError()
        }
        
        func decode(_ type: Int.Type) throws -> Int {
            return try Int.fromSQLValue(string: sqlString)
        }
        
        func decode(_ type: Int8.Type) throws -> Int8 {
            return try Int8.fromSQLValue(string: sqlString)
        }
        
        func decode(_ type: Int16.Type) throws -> Int16 {
            return try Int16.fromSQLValue(string: sqlString)
        }
        
        func decode(_ type: Int32.Type) throws -> Int32 {
            return try Int32.fromSQLValue(string: sqlString)
        }
        
        func decode(_ type: Int64.Type) throws -> Int64 {
            return try Int64.fromSQLValue(string: sqlString)
        }
        
        func decode(_ type: UInt.Type) throws -> UInt {
            return try UInt.fromSQLValue(string: sqlString)
        }
        
        func decode(_ type: UInt8.Type) throws -> UInt8 {
            return try UInt8.fromSQLValue(string: sqlString)
        }
        
        func decode(_ type: UInt16.Type) throws -> UInt16 {
            return try UInt16.fromSQLValue(string: sqlString)
        }
        
        func decode(_ type: UInt32.Type) throws -> UInt32 {
            return try UInt32.fromSQLValue(string: sqlString)
        }
        
        func decode(_ type: UInt64.Type) throws -> UInt64 {
            return try UInt64.fromSQLValue(string: sqlString)
        }
        
        func decode(_ type: Float.Type) throws -> Float {
            fatalError()
        }
        
        func decode(_ type: Double.Type) throws -> Double {
            fatalError()
        }
        
        func decode(_ type: String.Type) throws -> String {
            return sqlString
        }
        
        func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
            fatalError()
        }
        
    }

    func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey {
        throw QueryError.resultDecodeErrorMessage(message: "RawTypeDecoder container(keyedBy:) not implemented, you could implement `QueryRowResultCustomData` ")
    }
    
    func unkeyedContainer() throws -> UnkeyedDecodingContainer {
        throw QueryError.resultDecodeErrorMessage(message: "RawTypeDecoder unkeyedContainer not implemented")
    }
    
    func singleValueContainer() throws -> SingleValueDecodingContainer {
        return SingleValue(sqlString: sqlString)
    }
 }

fileprivate struct RowKeyedDecodingContainer<K : CodingKey> : KeyedDecodingContainerProtocol {
    typealias Key = K
    
    let decoder : QueryRowResultDecoder
    
    let allKeys = [Key]()
    
    let codingPath = [CodingKey]()
    
    func decodeNil(forKey key: K) throws -> Bool {
        return false
    }
    
    func contains(_ key: K) -> Bool {
        return decoder.row.columnMap[key.stringValue] != nil && !decoder.row.isNull(forField: key.stringValue)
    }
    
    func decode(_ type: Bool.Type, forKey key: K) throws -> Bool {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: Int.Type, forKey key: K) throws -> Int {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: Int8.Type, forKey key: K) throws -> Int8 {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: Int16.Type, forKey key: K) throws -> Int16 {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: Int32.Type, forKey key: K) throws -> Int32 {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: Int64.Type, forKey key: K) throws -> Int64 {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: UInt.Type, forKey key: K) throws -> UInt {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: UInt8.Type, forKey key: K) throws -> UInt8 {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: UInt16.Type, forKey key: K) throws -> UInt16 {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: UInt32.Type, forKey key: K) throws -> UInt32 {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: UInt64.Type, forKey key: K) throws -> UInt64 {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: Float.Type, forKey key: K) throws -> Float {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: Double.Type, forKey key: K) throws -> Double {
        return try decoder.row.getValue(forField: key.stringValue)
    }
    
    func decode(_ type: String.Type, forKey key: K) throws -> String {
        return try decoder.row.getValue(forField: key.stringValue) as String
    }
    
    func decode<T>(_ t: T.Type, forKey key: K) throws -> T where T : Decodable {
        if t == Data.self {
            return try decoder.row.getValue(forField: key.stringValue) as Data as! T
        } else if t == Date.self {
            return try decoder.row.getValue(forField: key.stringValue) as Date as! T
        } else if t == DateComponents.self {
            return try decoder.row.getValue(forField: key.stringValue) as DateComponents as! T
        } else if t == URL.self {
            let urlString = try decoder.row.getValue(forField: key.stringValue) as String
            guard let url = URL(string: urlString) else {
                throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath,
                                                                        debugDescription: "Invalid URL string."))
            }
            return url as! T
        } else if t == Decimal.self {
            return try decoder.row.getValue(forField: key.stringValue) as Decimal as! T
        } else if let customType = t as? QueryRowResultCustomData.Type {
            let data = try decoder.row.getValue(forField: key.stringValue) as Data
            return try customType.decode(fromRowData: data) as! T
        }
        guard let columnValue = decoder.row.columnMap[key.stringValue] else {
            throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: [key], debugDescription: ""))
        }
        let d = SQLStringDecoder(sqlString: try columnValue.string())
        return try T(from: d)
    }
    
    func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: K) throws -> KeyedDecodingContainer<NestedKey> {
        throw QueryError.resultDecodeErrorMessage(message: "KeyedDecodingContainer nestedContainer not implemented")
    }
    
    func nestedUnkeyedContainer(forKey key: K) throws -> UnkeyedDecodingContainer {
        throw QueryError.resultDecodeErrorMessage(message: "KeyedDecodingContainer nestedContainer not implemented")
    }
    
    func superDecoder() throws -> Decoder {
        throw QueryError.resultDecodeErrorMessage(message: "KeyedDecodingContainer superDecoder not implemented")
    }
    
    func superDecoder(forKey key: K) throws -> Decoder {
        throw QueryError.resultDecodeErrorMessage(message: "KeyedDecodingContainer superDecoder(forKey) not implemented")
    }
}


================================================
FILE: Sources/MySQL/Sync.swift
================================================
//
//  Sync.swift
//  MySQL
//
//  Created by Yusuke Ito on 1/12/16.
//  Copyright © 2016 Yusuke Ito. All rights reserved.
//

#if os(Linux)
    import Glibc
#elseif os(OSX)
    import Darwin.C
#endif

fileprivate final class Mutex {
    private var mutex = pthread_mutex_t()
    init() {
        pthread_mutex_init(&mutex, nil)
    }
    
    func lock() {
        pthread_mutex_lock(&mutex)
    }
    
    func unlock() {
        pthread_mutex_unlock(&mutex)
    }
    
    deinit {
        pthread_mutex_destroy(&mutex)
    }
}

internal struct Atomic<T> {
    private var value: T
    private let mutex = Mutex()
    init(_ value: T) {
        self.value = value
    }
    mutating func syncWriting<R>( _ block: (inout T) throws -> R) rethrows -> R {
        mutex.lock()
        defer {
            mutex.unlock()
        }
        let result = try block(&value)
        return result
    }
    
    func sync<R>( _ block: (T) throws -> R) rethrows -> R {
        mutex.lock()
        defer {
            mutex.unlock()
        }
        let result = try block(value)
        return result
    }
}


================================================
FILE: Sources/MySQL/Transaction.swift
================================================
//
//  Connection-Transaction.swift
//  MySQL
//
//  Created by ito on 12/24/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//


extension Connection {
    
    func beginTransaction() throws {
        _ = try query("START TRANSACTION;")
    }

    func commit() throws {
        _ = try query("COMMIT;")
    }
    
    func rollback() throws {
        _ = try query("ROLLBACK;")
    }
}

extension ConnectionPool {
    
    public func transaction<T>( _ block: (_ conn: Connection) throws -> T  ) throws -> T {
        let conn = try getConnection()
        defer {
            if option.reconnect {
                conn.setReconnect(true)
            }
            releaseConnection(conn)
        }
        
        // disable reconnect option of MySQL while transaction
        conn.setReconnect(false)
        
        try conn.beginTransaction()
        do {
            let result = try block(conn)
            try conn.commit()
            return result
        } catch {
            do {
                try conn.rollback()
            } catch {
                print("error while `ROLLBACK`.", error)
            }
            throw error
        }
    }
}


================================================
FILE: Sources/SQLFormatter/Error.swift
================================================
//
//  Error.swift
//  SQLFormatter
//
//  Created by Yusuke Ito on 4/5/16.
//  Copyright © 2016 Yusuke Ito. All rights reserved.
//

public enum QueryFormatError: Error {
    case placeholderCountMismatch(query: String)
    case parameterIDTypeError(givenValue: String, query: String)
}


================================================
FILE: Sources/SQLFormatter/QueryFormatter.swift
================================================
//
//  Query.swift
//  MySQL
//
//  Created by Yusuke Ito on 12/14/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

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 escapeForID(_ str: String) -> String {
        var step1 = ""
        for c in str {
            switch c {
            case "`":
                step1 += "``"
            default:
                step1.append(c)
            }
        }
        var out = ""
        for c in step1 {
            switch c {
            case ".":
                out += "`.`"
            default:
                out.append(c)
            }
        }
        return "`\(out)`"
    }
    
    public static func escape(_ str: String) -> String {
        var out = "'"
        for c in str.unicodeScalars {
            switch c {
            case "\0":
                out += "\\0"
            case "\n":
                out += "\\n"
            case "\r":
                out += "\\r"
            case "\u{8}":
                out += "\\b"
            case "\t":
                out += "\\t"
            case "\\":
                out += "\\\\"
            case "'":
                out += "\\'"
            case "\"":
                out += "\\\""
            case "\u{1A}":
                out += "\\Z"
            default:
                out.append(Character(c))
            }
        }
        out.append("'")
        return out
    }
    
    public static func escapeForLike(_ str: String, escapingWith: Character = "\\") -> String {
        var out = ""
        for c in str.unicodeScalars {
            switch c {
            case "%", "_":
                out.append(escapingWith)
            default: break
            }
            out.append(Character(c))
        }
        return out
    }
}

public struct QueryFormatter {
    
    public static func format(query: String, parameters: [QueryParameterType]) throws -> String {
        
        var placeHolderCount = 0
        
        var formatted = query + ""
        
        var valArgs: [QueryParameterType] = []
        var scanRange = formatted.startIndex..<formatted.endIndex
        
        // format ??
        while true {
            // TODO: use function in Swift.String
            let r1 = formatted.range(of: "??", options: [], range: scanRange, locale: nil)
            let r2 = formatted.range(of: "?", options: [], range: scanRange, locale: nil)
            let r: Range<String.Index>
            if let r1 = r1, let r2 = r2 {
                r = r1.lowerBound <= r2.lowerBound ? r1 : r2
            } else if let rr = r1 ?? r2 {
                r = rr
            } else {
                break
            }
            
            switch formatted[r] {
            case "??":
                if placeHolderCount >= parameters.count {
                    throw QueryFormatError.placeholderCountMismatch(query: query)
                }
                guard let escapedVal = parameters[placeHolderCount].escapedForID() else {
                    throw QueryFormatError.parameterIDTypeError(givenValue: "\(parameters[placeHolderCount])", query: query)
                }
                formatted.replaceSubrange(r, with: escapedVal)
                scanRange = r.upperBound..<formatted.endIndex
            case "?":
                if placeHolderCount >= parameters.count {
                    throw QueryFormatError.placeholderCountMismatch(query: query)
                }
                valArgs.append(parameters[placeHolderCount])
                scanRange = r.upperBound..<formatted.endIndex
            default: break
            }
            
            placeHolderCount += 1
            
            if placeHolderCount >= parameters.count {
                break
            }
        }
        
        //print(formatted, valArgs)
        
        placeHolderCount = 0
        var formattedChars = Array(formatted)
        var index = 0
        while index < formattedChars.count {
            if formattedChars[index] == "?" {
                if placeHolderCount >= valArgs.count {
                    throw QueryFormatError.placeholderCountMismatch(query: query)
                }
                let val = valArgs[placeHolderCount]
                formattedChars.remove(at: index)
                let valStr = val.escaped()
                formattedChars.insert(contentsOf: valStr, at: index)
                index += valStr.count - 1
                placeHolderCount += 1
            } else {
                index += 1
            }
        }
        
        return String(formattedChars)
    }
}



================================================
FILE: Sources/cmysql/macos.pc
================================================
prefix=/usr/local/opt/mysql
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: MySQL
Description: MySQL client library
Version: 2.0
Cflags: -I${includedir}
Libs: -L${libdir} -lmysqlclient


================================================
FILE: Sources/cmysql/module.modulemap
================================================
module CMySQL [system] {
    header "shim.h"
    link "mysqlclient"
    export *
}


================================================
FILE: Sources/cmysql/shim.h
================================================
#ifndef __CMYSQL_SHIM_H__
#define __CMYSQL_SHIM_H__

#include <mysql/mysql.h>

#if LIBMYSQL_VERSION_ID >= 80000
typedef int my_bool;
#endif

#endif



================================================
FILE: Tests/LinuxMain.swift
================================================
import XCTest

import MySQLTests
import SQLFormatterTests

var tests = [XCTestCaseEntry]()
tests += MySQLTests.__allTests()
tests += SQLFormatterTests.__allTests()

XCTMain(tests)


================================================
FILE: Tests/MySQLTests/BlobTests.swift
================================================
//
//  SQLTypeTests.swift
//  MySQL
//
//  Created by Yusuke Ito on 4/21/16.
//  Copyright © 2016 Yusuke Ito. All rights reserved.
//

import XCTest
@testable import MySQL
import Foundation

extension Row {
    
    fileprivate struct BlobTextRow: Codable, QueryParameter {
        let id: AutoincrementID<BlobTextID>
        
        let text1: String
        let binary1: Data
    }
    
    fileprivate struct JSONDataUser: Codable, Equatable, QueryCustomDataParameter, QueryRowResultCustomData {
        func encodeForQueryParameter() throws -> Data {
            let encoder = JSONEncoder()
            return try encoder.encode(self)
        }
        
        var queryParameterDataType: QueryCustomDataParameterDataType {
            return .json
        }
        
        static func decode(fromRowData data: Data) throws -> Row.JSONDataUser {
            let decoder = JSONDecoder()
            return try decoder.decode(self, from: data)
        }
        
        // this type decoded from and encoded to Data, like JSON, Protobuf...
        let name: String
    }
    
    fileprivate struct JSONColumnUser: Codable, QueryParameter, Equatable {
        let userName: String
        let jsonValue_blob: JSONDataUser
        let jsonValue_json: JSONDataUser
    }
    
}

final class BlobQueryTests: XCTestCase, QueryTestType {
    
    var constants: TestConstantsType!
    var pool: ConnectionPool!
    
    override func setUp() {
        super.setUp()
        
        prepare()
        try! createBlobTable()
    }
    
    func createBinaryBlobTable() throws {
        try dropTestTable()
        
        let conn = try pool.getConnection()
        let query = "CREATE TABLE `\(constants.tableName)` (" +
            "`id` int(11) unsigned NOT NULL AUTO_INCREMENT," +
            "`text1` mediumtext NOT NULL," +
            "`binary1` mediumblob NOT NULL," +
            "PRIMARY KEY (`id`)" +
        ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;"
        
        _ = try conn.query(query)
    }
    
    func createBlobTable() throws {
        try dropTestTable()
        
        let conn = try pool.getConnection()
        let query = "CREATE TABLE `\(constants.tableName)` (" +
            "`id` int(11) unsigned NOT NULL AUTO_INCREMENT," +
            "`text1` mediumtext NOT NULL," +
            "`binary1` mediumblob NOT NULL," +
            "PRIMARY KEY (`id`)" +
        ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
        
        _ = try conn.query(query)
    }
    
    func testInsertForCombinedUnicodeCharacter() throws {
        let str = "'゙ and áäèëî , ¥"
        
        let obj = Row.BlobTextRow(id: .noID, text1: str, binary1: Data() )
        let status: QueryStatus = try pool.execute { conn in
            try conn.query("INSERT INTO ?? SET ? ", [constants.tableName, obj])
        }
        XCTAssertEqual(status.insertedID, 1)
        
    }
    
    func testBlobAndTextOnBinCollation() throws {
        
        try createBinaryBlobTable()
        
        let testBinary: [UInt8] = Array( (UInt8(0)...UInt8(255)) )
        
        let obj = Row.BlobTextRow(id: .noID, text1: "", binary1: Data(testBinary) )
        let status: QueryStatus = try pool.execute { conn in
            try conn.query("INSERT INTO ?? SET ? ", [constants.tableName, obj])
        }
        XCTAssertEqual(status.insertedID, 1)
        
        let rows: [Row.BlobTextRow] = try pool.execute{ conn in
            try conn.query("SELECT * FROM ??", [constants.tableName])
        }
        XCTAssertEqual(rows.count, 1)
        XCTAssertEqual(rows[0].binary1.count, 256)
        XCTAssertEqual(rows[0].binary1, Data(testBinary))
        
        print(rows[0].binary1, testBinary)
    }
    
    func testEscapeBlob() throws {
        
        do {
            let testBinary: [UInt8] = [0, 0x1, 0x9, 0x10, 0x1f, 0x99, 0xff, 0x00, 0x0a]
            let str = try Data(testBinary).queryParameter(option: queryOption).escaped()
            XCTAssertEqual(str, "x'000109101f99ff000a'")
        }
    }
    
    
    private func createJSONValueTable() throws {
        try dropTestTable()
        
        let conn = try pool.getConnection()
        let query = """
        CREATE TABLE `\(constants.tableName)` (
        `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
        `userName` mediumtext NOT NULL,
        `jsonValue_blob` mediumblob NOT NULL,
        `jsonValue_json` json NOT NULL,
        PRIMARY KEY (`id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
        """
        
        _ = try conn.query(query)
    }
    
    func testJSONColumnValue() throws {
        
        try createJSONValueTable()
        
        let jsonValue = Row.JSONDataUser(name: "name in json value")
        let user = Row.JSONColumnUser(userName: "john", jsonValue_blob: jsonValue, jsonValue_json: jsonValue)
        let status: QueryStatus = try pool.execute { conn in
            try conn.query("INSERT INTO ?? SET ? ", [constants.tableName, user])
        }
        XCTAssertEqual(status.insertedID, 1)
        
        let rows: [Row.JSONColumnUser] = try pool.execute{ conn in
            try conn.query("SELECT * FROM ??", [constants.tableName])
        }
        XCTAssertEqual(rows.count, 1)
        XCTAssertEqual(rows[0], user)
    }
    
}


================================================
FILE: Tests/MySQLTests/ConnectionPoolTests.swift
================================================
//
//  ConnectionPoolTests.swift
//  MySQL
//
//  Created by ito on 12/24/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

import Foundation
import Dispatch
import XCTest
@testable import MySQL

final class ConnectionPoolTests: XCTestCase, MySQLTestType {

    
    var constants: TestConstantsType!
    var pool: ConnectionPool!
    
    override func setUp() {
        super.setUp()
        
        prepare()
    }

    func testGetConnection() throws {
        
        let initialConnection = 1
        
        XCTAssertEqual(pool.pool.sync { $0.count }, initialConnection)
        XCTAssertEqual(pool.pool.sync { $0.inUseConnections }, 0)
        
        var connections: [Connection] = []
        for _ in 0..<initialConnection {
            let con = try pool.getConnection()
            connections.append(con)
        }
        XCTAssertEqual(connections.count, initialConnection)
        XCTAssertEqual(pool.pool.sync { $0.inUseConnections }, initialConnection)
        
        // increse initial connections
        pool.initialConnections = 7
        XCTAssertEqual(pool.pool.sync { $0.count }, 7)
        
        // get connection while max connections count
        while connections.count < pool.maxConnections {
            let con = try pool.getConnection()
            connections.append(con)
        }
        
        XCTAssertEqual(connections.count, pool.maxConnections)
        XCTAssertEqual(pool.pool.sync { $0.count }, pool.maxConnections)
        XCTAssertEqual(pool.pool.sync { $0.inUseConnections }, pool.maxConnections)
        
        // this connection getting failure
        pool.timeoutForGetConnection = 2
        XCTAssertThrowsError(try pool.getConnection())
        
        for c in connections {
            // release connections that we have got
            c.release()
        }
        connections.removeAll()
        XCTAssertEqual(pool.pool.sync { $0.inUseConnections }, 0)
        XCTAssertEqual(pool.pool.sync { $0.count }, pool.maxConnections)
    }
    
    
    func testExecutionBlock() throws {
        
        var thisConn: Connection!
        try pool.execute { conn in
            thisConn = conn
            XCTAssertEqual(conn.isInUse, true)
            _ = try conn.query("SELECT 1 + 2;")
        }
        XCTAssertEqual(thisConn.isInUse, false)
    }

    private var errors: [Error?] = []
    private var errorSemaphore = DispatchSemaphore(value: 0)
    
    func testThreadingConnectionPool() throws {
        
        pool.maxConnections = 3
        pool.initialConnections = 3
        
        if #available(OSX 10.12, *) {
            
            let THREAD_COUNT = 10
            errors = [Error?](repeating: nil, count: THREAD_COUNT)
            let semaphore = DispatchSemaphore(value: 0)
            
            
            for i in 0..<THREAD_COUNT {
                Thread.detachNewThread {
                    print(Thread.current)
                    do {
                        try self.pool.execute { conn in
                            _ = try conn.query("SELECT 1 + 2;")
                            sleep(1)
                        }
                        print("done", Thread.current)
                    } catch {
                        print("error while executing", error)
                        self.errors[i] = error
                    }
                    
                    semaphore.signal()
                }
            }
            
            print("waiting until thread is done.")
            
            for _ in 0..<THREAD_COUNT {
                semaphore.wait()
            }
            
            print("thread done", errors)
            
            for i in 0..<THREAD_COUNT {
                if let error = errors[i] {
                    XCTFail("\(error)")
                }
            }
            
        } else {
            fatalError()
        }
    }
    
}


================================================
FILE: Tests/MySQLTests/ConnectionTests.swift
================================================
//
//  ConnectionTest.swift
//  MySQL
//
//  Created by ito on 12/20/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

import XCTest
@testable import MySQL

final class ConnectionTests: XCTestCase, MySQLTestType {
    
    var constants: TestConstantsType!
    var pool: ConnectionPool!

    override func setUp() {
        super.setUp()
        
        prepare()
    }
    
    func testConnect() throws {
        let conn = try pool.getConnection()
        XCTAssertTrue(conn.ping())
    }
    
    func testConnect2() throws {
        let conn = try pool.getConnection()
        _ = try conn.query("SELECT 1;" as String)
        XCTAssertTrue(conn.ping())
    }
    
    struct Option: ConnectionOption {
        let host: String = "dummy"
        let port: Int = 3306
        let user: String = "dummy"
        let password: String = "dummy"
        let database: String = "dummy"
    }
    
    func testDefaultConnectionOption() {
        
        let option = Option()
        
        XCTAssertNotNil(option.timeZone)
    }
}


================================================
FILE: Tests/MySQLTests/DateTests.swift
================================================
//
//  DateTests.swift
//  MySQL
//
//  Created by ito on 12/20/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

import XCTest
import CoreFoundation
import Foundation
@testable import MySQL

struct QueryParameterTestOption: QueryParameterOption {
    let timeZone: TimeZone
}

extension XCTestCase {
    var queryOption: QueryParameterOption {
        return QueryParameterTestOption(timeZone: TimeZone(abbreviation: "UTC")!)
    }
}

final class DateTests : XCTestCase {
    
    func testSQLDate() throws {
        
        let gmt = QueryParameterTestOption(timeZone: TimeZone(abbreviation: "UTC")!)
        let losAngeles = QueryParameterTestOption(timeZone: TimeZone(identifier: "America/Los_Angeles")!)
        
        let expected = "2003-01-02 03:04:05" // no timezone
        
        let date = Date(timeIntervalSince1970: 1041476645) // "2003-01-02 03:04:05" at GMT
        XCTAssertEqual(date.queryParameter(option: gmt).escaped(), "'\(expected)'")
        
        let sqlDate = try Date(sqlDate: expected, timeZone: losAngeles.timeZone)
        let dateAtLos = Date(timeIntervalSince1970: 1041476645 + 3600*8)
    
        XCTAssertEqual(sqlDate, dateAtLos, "create date from sql string")
        XCTAssertEqual(sqlDate.queryParameter(option: losAngeles).escaped(), "'\(expected)'")
        
        XCTAssertEqual(sqlDate, dateAtLos)
        
        XCTAssertNotEqual(try Date(sqlDate: expected, timeZone: losAngeles.timeZone),
            try Date(sqlDate: expected, timeZone: gmt.timeZone))
        
        XCTAssertEqual(try Date(sqlDate: expected, timeZone: losAngeles.timeZone),
            try Date(sqlDate: expected, timeZone: losAngeles.timeZone))
    }
    
    func testSQLCalendar() {
        let timeZone = TimeZone(abbreviation: "PDT")!
        let cal1 = SQLDateCalendar.calendar(forTimezone: timeZone, { $0 })
        let cal2 = SQLDateCalendar.calendar(forTimezone: timeZone, { $0 })
        XCTAssertEqual(cal1, cal2)
        XCTAssertEqual(cal1.hashValue, cal2.hashValue)
    }
    
    func testDateComponents() throws {
        
        do {
            // YEAR
            let comps = try DateComponents.fromSQLValue(string: "9999")
            XCTAssertEqual(comps.year, 9999)
        }
        
        do {
            // DATETIME
            // with nanoseconds
            let comps = try DateComponents.fromSQLValue(string: "9999-12-31 23:59:58.123456")
            XCTAssertEqual(comps.year, 9999)
            XCTAssertEqual(comps.month, 12)
            XCTAssertEqual(comps.day, 31)
            
            XCTAssertEqual(comps.hour, 23)
            XCTAssertEqual(comps.minute, 59)
            XCTAssertEqual(comps.second, 58)
            
            XCTAssertEqual(comps.nanosecond, 123456_000)
        }
        
        do {
            // DATETIME
            let comps = try DateComponents.fromSQLValue(string: "9999-12-31 23:59:58")
            XCTAssertEqual(comps.year, 9999)
            XCTAssertEqual(comps.month, 12)
            XCTAssertEqual(comps.day, 31)
            
            XCTAssertEqual(comps.hour, 23)
            XCTAssertEqual(comps.minute, 59)
            XCTAssertEqual(comps.second, 58)
        }
        
        do {
            // TIME
            // negative hours
            let comps = try DateComponents.fromSQLValue(string: "-123:59:58")
            
            XCTAssertEqual(comps.hour, -123)
            XCTAssertEqual(comps.minute, 59)
            XCTAssertEqual(comps.second, 58)
        }
        
        do {
            // TIME
            // with nanoseconds
            let comps = try DateComponents.fromSQLValue(string: "893:59:58.123456")
            XCTAssertEqual(comps.hour, 893)
            XCTAssertEqual(comps.minute, 59)
            XCTAssertEqual(comps.second, 58)
            
            XCTAssertEqual(comps.nanosecond, 123456_000)
        }
        
        do {
            // DATE
            let comps = try DateComponents.fromSQLValue(string: "9999-12-31")
            XCTAssertEqual(comps.year, 9999)
            XCTAssertEqual(comps.month, 12)
            XCTAssertEqual(comps.day, 31)
        }
        
    }
}


================================================
FILE: Tests/MySQLTests/EscapeTests.swift
================================================
//
//  EscapeTests.swift
//  MySQL
//
//  Created by ito on 12/20/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

import XCTest
@testable import MySQL
import SQLFormatter

final class EscapeTests: XCTestCase {

    // https://github.com/mysqljs/mysql/blob/master/test/unit/protocol/test-SqlString.js
    func testStringEscape() {
        XCTAssertEqual(SQLString.escape("Sup'er"), "'Sup\\'er'")
        
        XCTAssertEqual(SQLString.escape("\u{00A5}"), "'¥'")
        XCTAssertEqual(SQLString.escape("\\"), "'\\\\'")
        
        // escape combined character
        XCTAssertEqual(SQLString.escape("'゙"), "'\\'゙'")
    }
    
    func testBasicTypes() throws {
        
        let strVal: String = "Sup'er"
        let strValOptional: String? = "Sup'er Super"
        let strValOptionalNone: String? = nil
        
        
        XCTAssertEqual(strVal.queryParameter(option: queryOption).escaped(), "'Sup\\'er'")
        XCTAssertEqual(try strValOptional.queryParameter(option: queryOption).escaped(), "'Sup\\'er Super'")
        XCTAssertEqual(try ((strValOptionalNone ?? QueryParameterNull.null) as QueryParameter).queryParameter(option: queryOption).escaped(), "NULL")
    }
    
    func testArrayType() throws {
        
        let strVal: String = "Sup'er"
        let strValOptional: String? = "Sup'er Super"
        let strValOptionalNone: String? = nil
        
        let strs: [QueryParameter] = [strVal, strVal]
        
        XCTAssertEqual(try QueryParameterArray(strs).queryParameter(option: queryOption).escaped(), "'Sup\\'er', 'Sup\\'er'")
        
        let strsOptional1: [QueryParameter?] = [strVal, strValOptional]
        XCTAssertEqual(try QueryParameterArray(strsOptional1).queryParameter(option: queryOption).escaped(), "'Sup\\'er', 'Sup\\'er Super'")
        
        let strsOptional2: [QueryParameter?] = [strVal, strValOptionalNone]
        XCTAssertEqual(try QueryParameterArray(strsOptional2).queryParameter(option: queryOption).escaped(), "'Sup\\'er', NULL")
        
        
        let arr = QueryParameterArray(strs)
        let arrayOfArr = QueryParameterArray( [arr] )
        XCTAssertEqual(try arrayOfArr.queryParameter(option: queryOption).escaped(), "('Sup\\'er', 'Sup\\'er')")
        
        let strInt:[QueryParameter] = [strVal, 271]
        XCTAssertEqual(try QueryParameterArray(strInt).queryParameter(option: queryOption).escaped(), "'Sup\\'er', 271")
        
        let strOptionalAndInt:[QueryParameter] = [strValOptional, 3.14]
        XCTAssertEqual(try QueryParameterArray(strOptionalAndInt).queryParameter(option: queryOption).escaped(), "'Sup\\'er Super', 3.14")
    }
    
    func testNestedArray() throws {
        
        let strVal: String = "Sup'er"
        let strValOptionalNone: String? = nil
        let child: [QueryParameter] = [strVal, strValOptionalNone]
        let strs: [QueryParameter] = [strVal, strValOptionalNone, QueryParameterArray(child)]
        
        XCTAssertEqual(try QueryParameterArray(strs).queryParameter(option: queryOption).escaped(), "\'Sup\\\'er\', NULL, (\'Sup\\\'er\', NULL)")
        
    }
    
    func testAutoincrement() throws {
        let strVal: String = "Sup'er"
        
        do {
            let userID: AutoincrementID<UserID> = .ID(UserID(333))
            XCTAssertEqual(try userID.queryParameter(option: queryOption).escaped(), "333")
            let arr: [QueryParameter] = [strVal, userID]
            XCTAssertEqual(try QueryParameterArray(arr).queryParameter(option: queryOption).escaped(), "\'Sup\\\'er\', 333")
        }
        
        do {
            let stringID: AutoincrementID<SomeStringID> = .ID(SomeStringID("id-555@"))
            XCTAssertEqual(try stringID.queryParameter(option: queryOption).escaped(), "\'id-555@\'")
            let arr: [QueryParameter] = [strVal, stringID]
            XCTAssertEqual(try QueryParameterArray(arr).queryParameter(option: queryOption).escaped(), "\'Sup\\\'er\', \'id-555@\'")
        }
        
        do {
            let noID: AutoincrementID<UserID> = .noID
            XCTAssertEqual(try noID.queryParameter(option: queryOption).escaped(), "\'\'")
            
            let arr: [QueryParameter] = [strVal, noID]
            XCTAssertEqual(try QueryParameterArray(arr).queryParameter(option: queryOption).escaped(), "\'Sup\\\'er\'")
        }
    }
    
    func testDictionary() {
        
        
        let strVal: String = "Sup'er"
        let strValOptional: String? = "Sup'er Super"
        let strValOptionalNone: String? = nil
        
        let dict = QueryParameterDictionary([
            "string": strVal,
            "stringOptional": strValOptional,
            "stringNone" : strValOptionalNone
            ])
        
        let expectedResult = Set(arrayLiteral: "`string` = 'Sup\\'er'", "`stringOptional` = 'Sup\\'er Super'", "`stringNone` = NULL")
        let escaped = try! dict.queryParameter(option: queryOption).escaped()
        XCTAssertEqual(Set(escaped.split(separator: ",").map(String.init).map({ $0.trimmingCharacters(in: .whitespaces) })), expectedResult)
        
    }
    
}


================================================
FILE: Tests/MySQLTests/Model.swift
================================================
//
//  Model.swift
//  MySQL
//
//  Created by ito on 12/20/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

import MySQL
import Foundation

struct UserID: IDType {
    let id: Int
    init(_ id: Int) {
        self.id = id
    }
}

struct BlobTextID: IDType {
    let id: Int
    init(_ id: Int) {
        self.id = id
    }
}

struct SomeStringID: IDType {
    let id: String
    init(_ id: String) {
        self.id = id
    }
}


final class Row {
    private init() { }
}


================================================
FILE: Tests/MySQLTests/MySQLConnection.swift
================================================
//
//  MySQLTests.swift
//  MySQLTests
//
//  Created by ito on 2015/10/24.
//  Copyright © 2015年 Yusuke Ito. All rights reserved.
//

import XCTest
import MySQL
import Foundation

/*
 
struct TestConstants: TestConstantsType {
    let host: String = ""
    let port: Int = 3306
    let user: String = ""
    let password: String = ""
    let database: String = "test"
    let tableName: String = "unit_test_db_3894" // Unit test creates a table
    let encoding: Connection.Encoding = .UTF8MB4
    let timeZone: Connection.TimeZone = Connection.TimeZone(GMTOffset: 60 * 60 * 9) // JST
}

*/

struct DummyConstants: TestConstantsType {
    let host: String = "127.0.0.1"
    let port: Int = 3306
    let user: String = "root"
    let password: String = ""
    let database: String = "test"
    let tableName: String = "unit_test_db_3894"
    let encoding: Connection.Encoding = .UTF8MB4
    let timeZone: TimeZone = TimeZone(abbreviation: "JST")! // JST
    let reconnect: Bool = true
}

protocol TestConstantsType: ConnectionOption {
    var tableName: String { get }
}

protocol MySQLTestType: class {
    var constants: TestConstantsType! { get set }
    var pool: ConnectionPool! { get set }
}

extension MySQLTestType {
    func prepare() {
        self.constants = DummyConstants() // !!! Replace with your MySQL connection !!!
        self.pool = ConnectionPool(option: constants)
        
        XCTAssertEqual(constants.timeZone, TimeZone(abbreviation: "JST"), "test MySQL's timezone should be JST")
    }
}




================================================
FILE: Tests/MySQLTests/QueryDecimalTypeTests.swift
================================================
//
//  QueryDecimalTypeTests.swift
//  MySQLTests
//
//  Created by Yusuke Ito on 5/1/18.
//

import XCTest
@testable import MySQL
import Foundation

extension Row {
    fileprivate struct DecimalRow: Codable, QueryParameter, Equatable {
        let valueDoubleColumn: Decimal
        let valueTextColumn: Decimal
        private enum CodingKeys: String, CodingKey {
            case valueDoubleColumn = "value_double_col"
            case valueTextColumn = "value_text_col"
        }
    }
}


final class QueryDecimalTypeTests: XCTestCase, QueryTestType {
    var constants: TestConstantsType!
    var pool: ConnectionPool!
    
    override func setUp() {
        super.setUp()
        
        prepare()
        try! createDecimalTestTable()
    }
    
    private func createDecimalTestTable() throws {
        try dropTestTable()
        
        let conn = try pool.getConnection()
        let query = """
        CREATE TABLE `\(constants.tableName)` (
        `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
        `value_double_col` DOUBLE NOT NULL DEFAULT 0,
        `value_text_col` MEDIUMTEXT,
        PRIMARY KEY (`id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
        """
        
        _ = try conn.query(query)
    }
    
    
    func testDecimalType() throws {
        let value = Decimal(string: "1.549")!
        let row = Row.DecimalRow(valueDoubleColumn: value, valueTextColumn: value)
        
        try pool.execute { conn in
            _ = try conn.query("INSERT INTO ?? SET ? ", [constants.tableName, row])
        }
        
        let rows: [Row.DecimalRow] = try pool.execute {
            try $0.query("SELECT * FROM ?? ORDER BY id ASC", [constants.tableName])
        }
        
        XCTAssertEqual(rows[0], row)
    }
    
    func testDecimalType_largerValue() throws {
        let value = Decimal(string: "1.23e100")!
        let row = Row.DecimalRow(valueDoubleColumn: value, valueTextColumn: value)
    
        try pool.execute { conn in
            _ = try conn.query("INSERT INTO ?? SET ? ", [constants.tableName, row])
        }
        
        let rows: [Row.DecimalRow] = try pool.execute {
            try $0.query("SELECT * FROM ?? ORDER BY id ASC", [constants.tableName])
        }
        
        XCTAssertEqual(rows[0], row)
    }
}


================================================
FILE: Tests/MySQLTests/QueryFormatterTests.swift
================================================
//
//  QueryFormatterTests.swift
//  MySQL
//
//  Created by ito on 12/20/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

import XCTest
@testable import MySQL
import SQLFormatter


final class QueryFormatterTests: XCTestCase {
    
    fileprivate enum TableName: String, QueryRawRepresentableParameter {
        case user = "user"
    }
    
    func testBasicFormatting() throws {
        
        let params: (String, TableName, String, Int, String, Int?) = (
            "i.d",
            TableName.user,
            "id",
            1,
            "user's",
            nil
        )
        let args: [QueryParameter] = [
            params.0,
            params.1,
            params.2,
            params.3,
            params.4,
            params.5,
        ]
        
        let formatted = try QueryFormatter.format(query: "SELECT name,??,id FROM ?? WHERE ?? = ? OR name = ? OR age is ?;", parameters: Connection.buildParameters(args, option: queryOption) )
        XCTAssertEqual(formatted, "SELECT name,`i`.`d`,id FROM `user` WHERE `id` = 1 OR name = 'user\\'s' OR age is NULL;")
    }
    
    func testLikeEscape() {
        
        XCTAssertEqual(SQLString.escapeForLike("ap%ple_"), "ap\\%ple\\_")
        XCTAssertEqual(SQLString.escapeForLike("ap\\%ple_"), "ap\\\\%ple\\_")
        
        XCTAssertEqual(SQLString.escapeForLike("ap%ple_", escapingWith: "$"), "ap$%ple$_")
        XCTAssertEqual(SQLString.escapeForLike("ap\\%ple_", escapingWith: "$"), "ap\\$%ple$_")
    }
    
    func testPlaceholder() throws {
        let params: [QueryParameter] = ["name", "message??", "col", "hello??", "hello?"]
        let formatted = try QueryFormatter.format(query: "SELECT ??, ?, ??, ?, ?", parameters: Connection.buildParameters(params, option: queryOption))
        XCTAssertEqual(formatted, "SELECT `name`, 'message??', `col`, 'hello??', 'hello?'")
    }
    
    func testStringUtil() {
        let someString = "abcdefghijklmn12345"
        XCTAssertEqual(someString.subString(max: 10), "abcdefghij")
        XCTAssertEqual(someString.subString(max: 1000), someString)
        
        XCTAssertEqual("".subString(max: 10), "")
    }
}


================================================
FILE: Tests/MySQLTests/QueryParameterTests.swift
================================================
//
//  QueryParameterTests.swift
//  MySQL
//
//  Created by Yusuke Ito on 4/21/16.
//  Copyright © 2016 Yusuke Ito. All rights reserved.
//

import XCTest
import MySQL
import SQLFormatter

// the URL as QueryParameter should be
extension URL: QueryParameter {
    public func queryParameter(option: QueryParameterOption) throws -> QueryParameterType {
        return self.absoluteString.queryParameter(option: option)
    }
}

extension QueryParameterTests {
    static var allTests : [(String, (QueryParameterTests) -> () throws -> Void)] {
        return [
                ("testIDType", testIDType),
                ("testIDTypeInContainer", testIDTypeInContainer),
                ("testEnumType", testEnumType),
                ("testAutoincrementType", testAutoincrementType),
                ("testDateComponentsType", testDateComponentsType),
                ("testDataAndURLType", testDataAndURLType),
                ("testDecimalType", testDecimalType),
                ("testCodableIDType", testCodableIDType),
                ("testCodableIDType_AutoincrementNoID", testCodableIDType_AutoincrementNoID)
        ]
    }
}

final class QueryParameterTests: XCTestCase {
    
    
    private struct IDInt: IDType {
        let id: Int
        init(_ id: Int) {
            self.id = id
        }
    }
    
    private struct IDString: IDType {
        let id: String
        init(_ id: String) {
            self.id = id
        }
    }
    
    private struct ModelWithIDType_StringAutoincrement: Encodable, QueryParameter {
        let idStringAutoincrement: AutoincrementID<IDString>
    }
    
    private struct ModelWithIDType_IntAutoincrement: Encodable, QueryParameter {
        let idIntAutoincrement: AutoincrementID<IDInt>
    }
    
    private enum SomeEnumParameter: String, QueryRawRepresentableParameter {
        case first = "first 1"
        case second = "second' 2"
    }
    
    private enum SomeEnumCodable: String, Codable, QueryParameter {
        case first = "first 1"
        case second = "second' 2"
    }
    
    // https://developer.apple.com/documentation/swift/optionset
    private struct ShippingOptions: OptionSet, QueryRawRepresentableParameter {
        let rawValue: Int
        
        static let nextDay    = ShippingOptions(rawValue: 1 << 0)
        static let secondDay  = ShippingOptions(rawValue: 1 << 1)
        static let priority   = ShippingOptions(rawValue: 1 << 2)
        static let standard   = ShippingOptions(rawValue: 1 << 3)
        
        static let express: ShippingOptions = [.nextDay, .secondDay]
        static let all: ShippingOptions = [.express, .priority, .standard]
    }
    
    private struct ModelWithData: Encodable, QueryParameter {
        let data: Data
    }
    
    private struct ModelWithDate: Encodable, QueryParameter {
        let date: Date
    }
    
    private struct ModelWithDateComponents: Encodable, QueryParameter {
        let dateComponents: DateComponents
    }
    
    private struct ModelWithURL: Encodable, QueryParameter {
        let url: URL
    }
    
    private struct ModelWithDecimal: Encodable, QueryParameter {
        let value: Decimal
    }

    func testIDType() throws {
        
        let idInt: QueryParameter = IDInt(1234)
        XCTAssertEqual(try idInt.queryParameter(option: queryOption).escaped(), "1234")
        
        //let id: SomeID = try SomeID.fromSQLValue(string: "5678")
        //XCTAssertEqual(id.id, 5678)
        
        let idString: QueryParameter = IDString("123abc")
        XCTAssertEqual(try idString.queryParameter(option: queryOption).escaped(), "'123abc'")
        
        
        let idIntAutoincrement: QueryParameter = AutoincrementID(IDInt(1234))
        XCTAssertEqual(try idIntAutoincrement.queryParameter(option: queryOption).escaped(), "1234")
        
        let idStringAutoincrement: QueryParameter = AutoincrementID(IDString("123abc"))
        XCTAssertEqual(try idStringAutoincrement.queryParameter(option: queryOption).escaped(), "'123abc'")
        
    }
    
    func testIDTypeInContainer() throws {
        
        do {
            let param: QueryParameter = ModelWithIDType_IntAutoincrement(idIntAutoincrement: .ID(IDInt(1234)))
            XCTAssertEqual(try param.queryParameter(option: queryOption).escaped(), "`idIntAutoincrement` = 1234")
        }
        do {
            let param: QueryParameter = ModelWithIDType_StringAutoincrement(idStringAutoincrement: .ID(IDString("123abc")))
            XCTAssertEqual(try param.queryParameter(option: queryOption).escaped(), "`idStringAutoincrement` = '123abc'")
        }
        
    }
    
    func testEnumType() throws {
        
        do {
            let someVal: QueryParameter = SomeEnumParameter.second
            let escaped = "second' 2".escaped()
            XCTAssertEqual(try someVal.queryParameter(option: queryOption).escaped() , escaped)
        }
        
        do {
            let someVal: QueryParameter = SomeEnumCodable.second
            let escaped = "second' 2".escaped()
            XCTAssertEqual(try someVal.queryParameter(option: queryOption).escaped() , escaped)
        }
        
        do {
            let someOption: QueryParameter = ShippingOptions.all
            XCTAssertEqual(try someOption.queryParameter(option: queryOption).escaped() , "\(ShippingOptions.all.rawValue)")
        }
    }
    
    func testAutoincrementType() throws {
        
        let userID: AutoincrementID<UserID> = .ID(UserID(333))
        XCTAssertEqual(userID, AutoincrementID.ID(UserID(333)))
        
        let someStringID: AutoincrementID<SomeStringID> = .ID(SomeStringID("id678@"))
        XCTAssertEqual(someStringID, AutoincrementID.ID(SomeStringID("id678@")))
        
        let noID: AutoincrementID<UserID> = .noID
        XCTAssertEqual(noID, AutoincrementID.noID)
    }
    
    func testDateComponentsType() throws {

        do {
            let compsEmpty = DateComponents()
            let model = ModelWithDateComponents(dateComponents: compsEmpty)
            let _ = try model.queryParameter(option: queryOption).escaped()
            XCTFail("this should be throws an error")
        } catch {
            // OK
        }
        do {
            // MySQL YEAR type
            var comps = DateComponents()
            comps.year = 2155
            let model = ModelWithDateComponents(dateComponents: comps)
            
            let queryString = try model.queryParameter(option: queryOption).escaped()
            XCTAssertEqual(queryString, "`dateComponents` = '2155'")
        }
        
        do {
            // MySQL TIME type
            var comps = DateComponents()
            comps.hour = -838
            comps.minute = 59
            comps.second = 59
            let model = ModelWithDateComponents(dateComponents: comps)
            
            let queryString = try model.queryParameter(option: queryOption).escaped()
            XCTAssertEqual(queryString, "`dateComponents` = '-838:59:59'")
        }
        
        do {
            // MySQL TIME type
            // with nanosecond
            var comps = DateComponents()
            comps.hour = -838
            comps.minute = 59
            comps.second = 59
            comps.nanosecond = 1234567
            let model = ModelWithDateComponents(dateComponents: comps)
            
            let queryString = try model.queryParameter(option: queryOption).escaped()
            XCTAssertEqual(queryString, "`dateComponents` = '-838:59:59.001235'")
        }
        
        do {
            // MySQL DATETIME, TIMESTAMP type
            var comps = DateComponents()
            comps.year = 9999
            comps.month = 12
            comps.day = 31
            comps.hour = 23
            comps.minute = 59
            comps.second = 59
            let model = ModelWithDateComponents(dateComponents: comps)
            
            let queryString = try model.queryParameter(option: queryOption).escaped()
            XCTAssertEqual(queryString, "`dateComponents` = '9999-12-31 23:59:59'")
        }
        
        do {
            // MySQL DATETIME, TIMESTAMP type
            // with nanosecond
            var comps = DateComponents()
            comps.year = 9999
            comps.month = 12
            comps.day = 31
            comps.hour = 23
            comps.minute = 59
            comps.second = 59
            comps.nanosecond = 1234567
            let model = ModelWithDateComponents(dateComponents: comps)
            
            let queryString = try model.queryParameter(option: queryOption).escaped()
            XCTAssertEqual(queryString, "`dateComponents` = '9999-12-31 23:59:59.001235'")
        }
        
    }
    
    func testDataAndURLType() throws {
        
        do {
            let dataModel = ModelWithData(data: Data([0x12, 0x34, 0x56, 0xff, 0x00]))
            let queryString = try dataModel.queryParameter(option: queryOption).escaped()
            XCTAssertEqual(queryString,
                           "`data` = x'123456ff00'")
        }
        
        do {
            let urlModel = ModelWithURL(url: URL(string: "https://apple.com/iphone")!)
            let queryString = try urlModel.queryParameter(option: queryOption).escaped()
            XCTAssertEqual(queryString,
                           "`url` = 'https://apple.com/iphone'")
        }
        
        do {
            let param: QueryParameter = URL(string: "https://apple.com/iphone")!
            let queryString = try param.queryParameter(option: queryOption).escaped()
            XCTAssertEqual(queryString,
                           "'https://apple.com/iphone'")
        }
    }

    func testDecimalType() throws {
        let decimalModel = ModelWithDecimal(value: Decimal(1.2345e100))
        let queryString = try decimalModel.queryParameter(option: queryOption).escaped()
        XCTAssertEqual(queryString,
                       "`value` = '12345000000000010240000000000000000000000000000000000000000000000000000000000000000000000000000000000'")
    }
    
    private enum UserType: String, Codable {
        case user = "user"
        case admin = "admin"
    }
    
    private struct CodableModel: Codable, QueryParameter {
        let id: UserID
        let name: String
        let userType: UserType
    }
    
    private struct CodableModelWithAutoincrement: Codable, QueryParameter {
        let id: AutoincrementID<UserID>
        let name: String
        let userType: UserType
    }
    
    func testCodableIDType() throws {
        
        
        let expectedResult = Set(arrayLiteral: "`id` = 123", "`name` = 'test4456'", "`userType` = 'user'")
        
        do {
            let parameter: QueryParameter = CodableModel(id: UserID(123),
                                                         name: "test4456",
                                                         userType: .user)
            
            let result = try parameter.queryParameter(option: queryOption).escaped()
            
            XCTAssertEqual(Set(result.split(separator: ",").map(String.init).map({ $0.trimmingCharacters(in: .whitespaces) })), expectedResult)
        }
        
        do {
            let parameter: QueryParameter = CodableModelWithAutoincrement(id: AutoincrementID(UserID(123)),
                                                                          name: "test4456",
                                                                          userType: .user)
            
            let result = try parameter.queryParameter(option: queryOption).escaped()
            XCTAssertEqual(Set(result.split(separator: ",").map(String.init).map({ $0.trimmingCharacters(in: .whitespaces) })), expectedResult)
        }
        
    }
    
    func testCodableIDType_AutoincrementNoID() throws {
        
        
        let expectedResult = Set(arrayLiteral: "`name` = 'test4456'", "`userType` = 'user'")
        
        let parameter: QueryParameter = CodableModelWithAutoincrement(id: .noID,
                                                                      name: "test4456",
                                                                      userType: .user)
        
        let result = try parameter.queryParameter(option: queryOption).escaped()
        
        XCTAssertEqual(Set(result.split(separator: ",").map(String.init).map({ $0.trimmingCharacters(in: .whitespaces) })), expectedResult)
        
    }
}


================================================
FILE: Tests/MySQLTests/QueryTests.swift
================================================
//
//  QueryTests.swift
//  MySQL
//
//  Created by ito on 12/20/15.
//  Copyright © 2015 Yusuke Ito. All rights reserved.
//

import XCTest
@testable import MySQL
import Foundation

protocol QueryTestType: MySQLTestType {
    func dropTestTable() throws
}

extension QueryTestType {
    func dropTestTable() throws {
        let conn = try pool.getConnection()
        _ = try conn.query("DROP TABLE IF EXISTS \(constants.tableName)")
    }
}

extension Row {
    
    fileprivate struct SimpleUser: Codable, Equatable {
        let id: UInt
        let name: String
        let age: Int
    }
    
    fileprivate enum UserType: String, Codable {
        case user = "user"
        case admin = "admin"
    }
    
    fileprivate struct User: Codable, QueryParameter, Equatable {
        let id: AutoincrementID<UserID>
        
        let name: String
        let age: Int
        let createdAt: Date
        
        let createdAtDateComponentsOptional: DateComponents?
        
        let nameOptional: String?
        let ageOptional: Int?
        let createdAtOptional: Date?
        
        let done: Bool
        let doneOptional: Bool?
        
        let userType: UserType
        
        private enum CodingKeys: String, CodingKey {
            case id
            case name
            case age
            case createdAt = "created_at"
            
            case createdAtDateComponentsOptional = "created_at_datecomponents_Optional"
            case nameOptional = "name_Optional"
            case ageOptional = "age_Optional"
            case createdAtOptional = "created_at_Optional"
            case done
            case doneOptional = "done_Optional"
            case userType = "user_type"
        }
    }
}

final class QueryTests: XCTestCase, QueryTestType {
    
    var constants: TestConstantsType!
    var pool: ConnectionPool!
    
    override func setUp() {
        super.setUp()
        
        prepare()
        try! createTestTable()
    }
    
    func createTestTable() throws {
        try dropTestTable()
        
        let conn = try pool.getConnection()
        let query = """
            CREATE TABLE `\(constants.tableName)` (
            `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
            `name` varchar(50) NOT NULL DEFAULT '',
            `age` int(11) NOT NULL,
            `created_at` datetime NOT NULL DEFAULT '2001-01-01 00:00:00',
            `created_at_datecomponents_Optional` datetime(6) DEFAULT NULL,
            `name_Optional` varchar(50) DEFAULT NULL,
            `age_Optional` int(11) DEFAULT NULL,
            `created_at_Optional` datetime DEFAULT NULL,
            `done` tinyint(1) NOT NULL DEFAULT 0,
            `done_Optional` tinyint(1) DEFAULT NULL,
            `user_type` varchar(255) NOT NULL DEFAULT '',
            PRIMARY KEY (`id`)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
            """
        
        _ = try conn.query(query)
    }
    
    private var someDate: Date {
        return try! Date(sqlDate: "2015-12-27 16:54:00", timeZone: pool.option.timeZone)
    }
    
    private var anotherDate: Date {
        return Date(timeIntervalSinceReferenceDate: 60*60*24*67)
    }
    
    func testInsertRowCodable() throws {
        
        typealias User = Row.User
        
        let name = "name 's"
        let age = 25
        
        let dateComponents = DateComponents(year: 2012, month: 3, day: 4, hour: 5, minute: 6, second: 7, nanosecond: 890_000_000)
        
        let userNil = User(id: .noID, name: name, age: age, createdAt: someDate, createdAtDateComponentsOptional: dateComponents, nameOptional: nil, ageOptional: nil, createdAtOptional: nil, done: false, doneOptional: nil, userType: .user)
        let status: QueryStatus = try pool.execute { conn in
            try conn.query("INSERT INTO ?? SET ? ", [constants.tableName, userNil])
        }
        XCTAssertEqual(status.insertedID, 1)
        
        let userFill = User(id: .ID(UserID(134)), name: name, age: age, createdAt: someDate, createdAtDateComponentsOptional: dateComponents, nameOptional: "fuga", ageOptional: 50, createdAtOptional: anotherDate, done: true, doneOptional: false, userType: .admin)
        let status2: QueryStatus = try pool.execute { conn in
            try conn.query("INSERT INTO ?? SET ? ", [constants.tableName, userFill])
        }
        XCTAssertEqual(status2.insertedID, 134)
        
        let rows:[User] = try pool.execute { conn in
            try conn.query("SELECT id,name,age,created_at,created_at_datecomponents_Optional,name_Optional,age_Optional,created_at_Optional,done,done_Optional,user_type FROM ?? ORDER BY id ASC", [constants.tableName])
        }
        
        XCTAssertEqual(rows.count, 2)
        
        // first row
        XCTAssertEqual(rows[0].id.id, UserID(Int(status.insertedID)))
        XCTAssertEqual(rows[0].name, name)
        XCTAssertEqual(rows[0].age, age)
        XCTAssertEqual(rows[0].createdAt, someDate)
        
        XCTAssertNil(rows[0].nameOptional)
        XCTAssertNil(rows[0].ageOptional)
        XCTAssertNil(rows[0].createdAtOptional)
        
        XCTAssertFalse(rows[0].done)
        XCTAssertNil(rows[0].doneOptional)
        
        XCTAssertEqual(rows[0].userType, .user)
        
        XCTAssertEqual(rows[1], userFill)
    }
    
    func testTransaction() throws {
        
        let user = Row.User(id: .noID, name: "name", age: 11, createdAt: someDate, createdAtDateComponentsOptional: nil, nameOptional: nil, ageOptional: nil, createdAtOptional: nil, done: false, doneOptional: nil, userType: .user)
        let status: QueryStatus = try pool.transaction { conn in
            try conn.query("INSERT INTO ?? SET ? ", [constants.tableName, user])
        }
        XCTAssertEqual(status.insertedID, 1)
    }
    
    
    func testEmojiInserting() throws {
        
        typealias User = Row.User
        
        
        let now = Date()
        let user = User(id: .noID, name: "日本語123🍣🍺あいう", age: 123, createdAt: now, createdAtDateComponentsOptional: nil, nameOptional: nil, ageOptional: nil, createdAtOptional: nil, done: false, doneOptional: nil, userType: .user)
        let status: QueryStatus = try pool.execute { conn in
            try conn.query("INSERT INTO ?? SET ? ", [constants.tableName, user])
        }
        
        let rows: [User] = try pool.execute{ conn in
            try conn.query("SELECT id,name,age,created_at,name_Optional,age_Optional,created_at_Optional,done,done_Optional,user_type FROM ?? WHERE id = ?", [constants.tableName, status.insertedID])
        }
        XCTAssertEqual(rows.count, 1)
        XCTAssertEqual(rows[0].name, user.name)
        XCTAssertEqual(rows[0].age, user.age)
    }
    
    
    func testBulkInsert() throws {
        
        //let now = Date()
        let users = (1...3).map({ row in
            Row.SimpleUser(id: UInt(10+row), name: "name\(row)", age: row)
        })
    
        let usersParam: [QueryParameterArray] = users.map { user in
            QueryParameterArray([user.id, user.name, user.age])
        }
        
        _ = try pool.execute { conn in
            try conn.query("INSERT INTO ??(id,name,age) VALUES ? ", [constants.tableName, QueryParameterArray(usersParam)])
        }
        
        let fetchedUsers: [Row.SimpleUser] = try pool.execute { conn in
            try conn.query("SELECT id,name,age FROM ?? ORDER BY id DESC", [constants.tableName])
        }
        XCTAssertEqual(fetchedUsers.count, 3)
        
        for index in (0..<3) {
            XCTAssertEqual(fetchedUsers[index], users.reversed()[index])
        }
    }
    
}



================================================
FILE: Tests/MySQLTests/QueryURLTypeTests.swift
================================================
//
//  QueryURLTypeTests.swift
//  MySQLTests
//
//  Created by Yusuke Ito on 5/1/18.
//

import XCTest
@testable import MySQL
import Foundation

extension Row {
    fileprivate struct URLRow: Codable, QueryParameter, Equatable {
        let url: URL
        let urlOptional: URL?
        private enum CodingKeys: String, CodingKey {
            case url = "url"
            case urlOptional = "url_Optional"
        }
    }
}


final class QueryURLTypeTests: XCTestCase, QueryTestType {
    var constants: TestConstantsType!
    var pool: ConnectionPool!
    
    override func setUp() {
        super.setUp()
        
        prepare()
        try! createURLTestTable()
    }
    
    private func createURLTestTable() throws {
        try dropTestTable()
        
        let conn = try pool.getConnection()
        let query = """
        CREATE TABLE `\(constants.tableName)` (
        `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
        `url` mediumtext NOT NULL,
        `url_Optional` mediumtext,
        PRIMARY KEY (`id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
        """
        
        _ = try conn.query(query)
    }
    
    
    
    func testURLType() throws {
        
        let urlRow1 = Row.URLRow(url: URL(string: "https://apple.com/iphone")!, urlOptional: nil)
        let urlRow2 = Row.URLRow(url: URL(string: "https://apple.com/iphone")!, urlOptional: URL(string: "https://apple.com/ipad")!)
        
        try pool.execute { conn in
            _ = try conn.query("INSERT INTO ?? SET ? ", [constants.tableName, urlRow1])
            _ = try conn.query("INSERT INTO ?? SET ? ", [constants.tableName, urlRow2])
        }
        
        let rows: [Row.URLRow] = try pool.execute {
            try $0.query("SELECT * FROM ?? ORDER BY id ASC", [constants.tableName])
        }
        
        XCTAssertEqual(rows[0], urlRow1)
        XCTAssertEqual(rows[1], urlRow2)
    }
    
    func testURLInvalid() throws {
        
        try pool.execute { conn in
            _ = try conn.query("INSERT INTO ?? SET `url` = ''", [constants.tableName])
        }
        
        do {
            let _: [Row.URLRow] = try pool.execute {
                try $0.query("SELECT * FROM ?? ORDER BY id ASC", [constants.tableName])
            }
        } catch let error as DecodingError {
            switch error {
            case .dataCorrupted(let context):
                print(context)
            // expected error
            default:
                XCTFail("unexpected error \(error)")
            }
        } catch {
            XCTFail("unexpected error \(error)")
        }
    }
    
}


================================================
FILE: Tests/MySQLTests/XCTestManifests.swift
================================================
import XCTest

extension BlobQueryTests {
    static let __allTests = [
        ("testBlobAndTextOnBinCollation", testBlobAndTextOnBinCollation),
        ("testEscapeBlob", testEscapeBlob),
        ("testInsertForCombinedUnicodeCharacter", testInsertForCombinedUnicodeCharacter),
        ("testJSONColumnValue", testJSONColumnValue),
    ]
}

extension ConnectionPoolTests {
    static let __allTests = [
        ("testExecutionBlock", testExecutionBlock),
        ("testGetConnection", testGetConnection),
        ("testThreadingConnectionPool", testThreadingConnectionPool),
    ]
}

extension ConnectionTests {
    static let __allTests = [
        ("testConnect2", testConnect2),
        ("testConnect", testConnect),
        ("testDefaultConnectionOption", testDefaultConnectionOption),
    ]
}

extension DateTests {
    static let __allTests = [
        ("testDateComponents", testDateComponents),
        ("testSQLCalendar", testSQLCalendar),
        ("testSQLDate", testSQLDate),
    ]
}

extension EscapeTests {
    static let __allTests = [
        ("testArrayType", testArrayType),
        ("testAutoincrement", testAutoincrement),
        ("testBasicTypes", testBasicTypes),
        ("testDictionary", testDictionary),
        ("testNestedArray", testNestedArray),
        ("testStringEscape", testStringEscape),
    ]
}

extension QueryDecimalTypeTests {
    static let __allTests = [
        ("testDecimalType_largerValue", testDecimalType_largerValue),
        ("testDecimalType", testDecimalType),
    ]
}

extension QueryFormatterTests {
    static let __allTests = [
        ("testBasicFormatting", testBasicFormatting),
        ("testLikeEscape", testLikeEscape),
        ("testPlaceholder", testPlaceholder),
        ("testStringUtil", testStringUtil),
    ]
}

extension QueryParameterTests {
    static let __allTests = [
        ("testAutoincrementType", testAutoincrementType),
        ("testCodableIDType_AutoincrementNoID", testCodableIDType_AutoincrementNoID),
        ("testCodableIDType", testCodableIDType),
        ("testDataAndURLType", testDataAndURLType),
        ("testDateComponentsType", testDateComponentsType),
        ("testDecimalType", testDecimalType),
        ("testEnumType", testEnumType),
        ("testIDType", testIDType),
        ("testIDTypeInContainer", testIDTypeInContainer),
    ]
}

extension QueryTests {
    static let __allTests = [
        ("testBulkInsert", testBulkInsert),
        ("testEmojiInserting", testEmojiInserting),
        ("testInsertRowCodable", testInsertRowCodable),
        ("testTransaction", testTransaction),
    ]
}

extension QueryURLTypeTests {
    static let __allTests = [
        ("testURLInvalid", testURLInvalid),
        ("testURLType", testURLType),
    ]
}

#if !os(macOS)
public func __allTests() -> [XCTestCaseEntry] {
    return [
        testCase(BlobQueryTests.__allTests),
        testCase(ConnectionPoolTests.__allTests),
        testCase(ConnectionTests.__allTests),
        testCase(DateTests.__allTests),
        testCase(EscapeTests.__allTests),
        testCase(QueryDecimalTypeTests.__allTests),
        testCase(QueryFormatterTests.__allTests),
        testCase(QueryParameterTests.__allTests),
        testCase(QueryTests.__allTests),
        testCase(QueryURLTypeTests.__allTests),
    ]
}
#endif


================================================
FILE: Tests/SQLFormatterTests/SQLFormatterTests.swift
================================================
//
//  SQLFormatterTests.swift
//  SQLFormatterTests
//
//  Created by Yusuke Ito on 4/5/16.
//  Copyright © 2016 Yusuke Ito. All rights reserved.
//

import XCTest
@testable import SQLFormatter


class SQLFormattingTests: XCTestCase {
    
    func testDummy() throws {
        XCTAssertTrue(true)
    }
}


================================================
FILE: Tests/SQLFormatterTests/XCTestManifests.swift
================================================
import XCTest

extension SQLFormattingTests {
    static let __allTests = [
        ("testDummy", testDummy),
    ]
}

#if !os(macOS)
public func __allTests() -> [XCTestCaseEntry] {
    return [
        testCase(SQLFormattingTests.__allTests),
    ]
}
#endif
Download .txt
gitextract_zidf83u4/

├── .circleci/
│   └── config.yml
├── .gitignore
├── LICENSE.md
├── Package.swift
├── Package@swift-5.swift
├── README.md
├── Sources/
│   ├── MySQL/
│   │   ├── AutoincrementID.swift
│   │   ├── Blob.swift
│   │   ├── Connection.swift
│   │   ├── ConnectionPool.swift
│   │   ├── Date.swift
│   │   ├── Error.swift
│   │   ├── IDType.swift
│   │   ├── Query.swift
│   │   ├── QueryParameter-Data.swift
│   │   ├── QueryParameterType.swift
│   │   ├── RawRepresentableParameter.swift
│   │   ├── Result-SQLRawStringDecodable.swift
│   │   ├── Result.swift
│   │   ├── Sync.swift
│   │   └── Transaction.swift
│   ├── SQLFormatter/
│   │   ├── Error.swift
│   │   └── QueryFormatter.swift
│   └── cmysql/
│       ├── macos.pc
│       ├── module.modulemap
│       └── shim.h
└── Tests/
    ├── LinuxMain.swift
    ├── MySQLTests/
    │   ├── BlobTests.swift
    │   ├── ConnectionPoolTests.swift
    │   ├── ConnectionTests.swift
    │   ├── DateTests.swift
    │   ├── EscapeTests.swift
    │   ├── Model.swift
    │   ├── MySQLConnection.swift
    │   ├── QueryDecimalTypeTests.swift
    │   ├── QueryFormatterTests.swift
    │   ├── QueryParameterTests.swift
    │   ├── QueryTests.swift
    │   ├── QueryURLTypeTests.swift
    │   └── XCTestManifests.swift
    └── SQLFormatterTests/
        ├── SQLFormatterTests.swift
        └── XCTestManifests.swift
Download .txt
SYMBOL INDEX (1 symbols across 1 files)

FILE: Sources/cmysql/shim.h
  type my_bool (line 7) | typedef int my_bool;
Condensed preview — 42 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (145K chars).
[
  {
    "path": ".circleci/config.yml",
    "chars": 2693,
    "preview": "version: 2\n\n\njobs:\n  mac-swift5.3:\n    macos:\n      xcode: \"12.3.0\"\n    steps:\n      - checkout\n      - run: brew tap no"
  },
  {
    "path": ".gitignore",
    "chars": 332,
    "preview": "# OS X Finder\n.DS_Store\n\n# Xcode per-user config\n*.mode1\n*.mode1v3\n*.mode2v3\n*.perspective\n*.perspectivev3\n*.pbxuser\n#*."
  },
  {
    "path": "LICENSE.md",
    "chars": 1057,
    "preview": "Copyright (c) 2015-18 Yusuke Ito\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this s"
  },
  {
    "path": "Package.swift",
    "chars": 785,
    "preview": "// swift-tools-version:4.0\nimport PackageDescription\n\nlet package = Package(\n    name: \"MySQL\",\n    products: [\n        "
  },
  {
    "path": "Package@swift-5.swift",
    "chars": 933,
    "preview": "// swift-tools-version:5.0\nimport PackageDescription\n\nlet package = Package(\n    name: \"mysql-swift\",\n    products: [\n  "
  },
  {
    "path": "README.md",
    "chars": 4062,
    "preview": "mysql-swift\n===========\n\n**This library is obsolete and not maintained. Use [MySQLNIO](https://github.com/vapor/mysql-ni"
  },
  {
    "path": "Sources/MySQL/AutoincrementID.swift",
    "chars": 2305,
    "preview": "//\n//  AutoincrementID.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 6/27/16.\n//  Copyright © 2016 Yusuke Ito. All rig"
  },
  {
    "path": "Sources/MySQL/Blob.swift",
    "chars": 1796,
    "preview": "//\n//  Blob.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 4/22/16.\n//  Copyright © 2016 Yusuke Ito. All rights reserve"
  },
  {
    "path": "Sources/MySQL/Connection.swift",
    "chars": 4362,
    "preview": "//\n//  Database.swift\n//  MySQL\n//\n//  Created by ito on 2015/10/24.\n//  Copyright © 2015年 Yusuke Ito. All rights reserv"
  },
  {
    "path": "Sources/MySQL/ConnectionPool.swift",
    "chars": 4965,
    "preview": "//\n//  ConnectionPool.swift\n//  MySQL\n//\n//  Created by ito on 12/24/15.\n//  Copyright © 2015 Yusuke Ito. All rights res"
  },
  {
    "path": "Sources/MySQL/Date.swift",
    "chars": 7599,
    "preview": "//\n//  Date.swift\n//  MySQL\n//\n//  Created by ito on 12/16/15.\n//  Copyright © 2015 Yusuke Ito. All rights reserved.\n//\n"
  },
  {
    "path": "Sources/MySQL/Error.swift",
    "chars": 943,
    "preview": "//\n//  Error.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 12/14/15.\n//  Copyright © 2015 Yusuke Ito. All rights reser"
  },
  {
    "path": "Sources/MySQL/IDType.swift",
    "chars": 4654,
    "preview": "//\n//  IDType.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 6/27/16.\n//  Copyright © 2016 Yusuke Ito. All rights reser"
  },
  {
    "path": "Sources/MySQL/Query.swift",
    "chars": 8335,
    "preview": "//\n//  Connection.swift\n//  MySQL\n//\n//  Created by ito on 2015/10/24.\n//  Copyright © 2015年 Yusuke Ito. All rights rese"
  },
  {
    "path": "Sources/MySQL/QueryParameter-Data.swift",
    "chars": 603,
    "preview": "//\n//  QueryParameter-Data.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 4/29/18.\n//\n\nimport Foundation\n\npublic protoc"
  },
  {
    "path": "Sources/MySQL/QueryParameterType.swift",
    "chars": 14380,
    "preview": "//\n//  QueryParameterType.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 12/28/15.\n//  Copyright © 2015 Yusuke Ito. All"
  },
  {
    "path": "Sources/MySQL/RawRepresentableParameter.swift",
    "chars": 739,
    "preview": "//\n//  RawRepresentableParameter.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 4/21/16.\n//  Copyright © 2016 Yusuke It"
  },
  {
    "path": "Sources/MySQL/Result-SQLRawStringDecodable.swift",
    "chars": 4279,
    "preview": "//\n//  ResultTypes.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 12/28/15.\n//  Copyright © 2015 Yusuke Ito. All rights"
  },
  {
    "path": "Sources/MySQL/Result.swift",
    "chars": 11234,
    "preview": "//\n//  Result.swift\n//  MySQL\n//\n//  Created by ito on 12/10/15.\n//  Copyright © 2015 Yusuke Ito. All rights reserved.\n/"
  },
  {
    "path": "Sources/MySQL/Sync.swift",
    "chars": 1103,
    "preview": "//\n//  Sync.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 1/12/16.\n//  Copyright © 2016 Yusuke Ito. All rights reserve"
  },
  {
    "path": "Sources/MySQL/Transaction.swift",
    "chars": 1177,
    "preview": "//\n//  Connection-Transaction.swift\n//  MySQL\n//\n//  Created by ito on 12/24/15.\n//  Copyright © 2015 Yusuke Ito. All ri"
  },
  {
    "path": "Sources/SQLFormatter/Error.swift",
    "chars": 288,
    "preview": "//\n//  Error.swift\n//  SQLFormatter\n//\n//  Created by Yusuke Ito on 4/5/16.\n//  Copyright © 2016 Yusuke Ito. All rights "
  },
  {
    "path": "Sources/SQLFormatter/QueryFormatter.swift",
    "chars": 4744,
    "preview": "//\n//  Query.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 12/14/15.\n//  Copyright © 2015 Yusuke Ito. All rights reser"
  },
  {
    "path": "Sources/cmysql/macos.pc",
    "chars": 220,
    "preview": "prefix=/usr/local/opt/mysql\nexec_prefix=${prefix}\nlibdir=${exec_prefix}/lib\nincludedir=${prefix}/include\nName: MySQL\nDes"
  },
  {
    "path": "Sources/cmysql/module.modulemap",
    "chars": 83,
    "preview": "module CMySQL [system] {\n    header \"shim.h\"\n    link \"mysqlclient\"\n    export *\n}\n"
  },
  {
    "path": "Sources/cmysql/shim.h",
    "chars": 149,
    "preview": "#ifndef __CMYSQL_SHIM_H__\n#define __CMYSQL_SHIM_H__\n\n#include <mysql/mysql.h>\n\n#if LIBMYSQL_VERSION_ID >= 80000\ntypedef "
  },
  {
    "path": "Tests/LinuxMain.swift",
    "chars": 180,
    "preview": "import XCTest\n\nimport MySQLTests\nimport SQLFormatterTests\n\nvar tests = [XCTestCaseEntry]()\ntests += MySQLTests.__allTest"
  },
  {
    "path": "Tests/MySQLTests/BlobTests.swift",
    "chars": 5289,
    "preview": "//\n//  SQLTypeTests.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 4/21/16.\n//  Copyright © 2016 Yusuke Ito. All rights"
  },
  {
    "path": "Tests/MySQLTests/ConnectionPoolTests.swift",
    "chars": 3908,
    "preview": "//\n//  ConnectionPoolTests.swift\n//  MySQL\n//\n//  Created by ito on 12/24/15.\n//  Copyright © 2015 Yusuke Ito. All right"
  },
  {
    "path": "Tests/MySQLTests/ConnectionTests.swift",
    "chars": 1047,
    "preview": "//\n//  ConnectionTest.swift\n//  MySQL\n//\n//  Created by ito on 12/20/15.\n//  Copyright © 2015 Yusuke Ito. All rights res"
  },
  {
    "path": "Tests/MySQLTests/DateTests.swift",
    "chars": 4147,
    "preview": "//\n//  DateTests.swift\n//  MySQL\n//\n//  Created by ito on 12/20/15.\n//  Copyright © 2015 Yusuke Ito. All rights reserved"
  },
  {
    "path": "Tests/MySQLTests/EscapeTests.swift",
    "chars": 5127,
    "preview": "//\n//  EscapeTests.swift\n//  MySQL\n//\n//  Created by ito on 12/20/15.\n//  Copyright © 2015 Yusuke Ito. All rights reserv"
  },
  {
    "path": "Tests/MySQLTests/Model.swift",
    "chars": 490,
    "preview": "//\n//  Model.swift\n//  MySQL\n//\n//  Created by ito on 12/20/15.\n//  Copyright © 2015 Yusuke Ito. All rights reserved.\n//"
  },
  {
    "path": "Tests/MySQLTests/MySQLConnection.swift",
    "chars": 1520,
    "preview": "//\n//  MySQLTests.swift\n//  MySQLTests\n//\n//  Created by ito on 2015/10/24.\n//  Copyright © 2015年 Yusuke Ito. All rights"
  },
  {
    "path": "Tests/MySQLTests/QueryDecimalTypeTests.swift",
    "chars": 2300,
    "preview": "//\n//  QueryDecimalTypeTests.swift\n//  MySQLTests\n//\n//  Created by Yusuke Ito on 5/1/18.\n//\n\nimport XCTest\n@testable im"
  },
  {
    "path": "Tests/MySQLTests/QueryFormatterTests.swift",
    "chars": 2175,
    "preview": "//\n//  QueryFormatterTests.swift\n//  MySQL\n//\n//  Created by ito on 12/20/15.\n//  Copyright © 2015 Yusuke Ito. All right"
  },
  {
    "path": "Tests/MySQLTests/QueryParameterTests.swift",
    "chars": 12456,
    "preview": "//\n//  QueryParameterTests.swift\n//  MySQL\n//\n//  Created by Yusuke Ito on 4/21/16.\n//  Copyright © 2016 Yusuke Ito. All"
  },
  {
    "path": "Tests/MySQLTests/QueryTests.swift",
    "chars": 7646,
    "preview": "//\n//  QueryTests.swift\n//  MySQL\n//\n//  Created by ito on 12/20/15.\n//  Copyright © 2015 Yusuke Ito. All rights reserve"
  },
  {
    "path": "Tests/MySQLTests/QueryURLTypeTests.swift",
    "chars": 2629,
    "preview": "//\n//  QueryURLTypeTests.swift\n//  MySQLTests\n//\n//  Created by Yusuke Ito on 5/1/18.\n//\n\nimport XCTest\n@testable import"
  },
  {
    "path": "Tests/MySQLTests/XCTestManifests.swift",
    "chars": 3306,
    "preview": "import XCTest\n\nextension BlobQueryTests {\n    static let __allTests = [\n        (\"testBlobAndTextOnBinCollation\", testBl"
  },
  {
    "path": "Tests/SQLFormatterTests/SQLFormatterTests.swift",
    "chars": 307,
    "preview": "//\n//  SQLFormatterTests.swift\n//  SQLFormatterTests\n//\n//  Created by Yusuke Ito on 4/5/16.\n//  Copyright © 2016 Yusuke"
  },
  {
    "path": "Tests/SQLFormatterTests/XCTestManifests.swift",
    "chars": 259,
    "preview": "import XCTest\n\nextension SQLFormattingTests {\n    static let __allTests = [\n        (\"testDummy\", testDummy),\n    ]\n}\n\n#"
  }
]

About this extraction

This page contains the full source code of the novi/mysql-swift GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 42 files (133.4 KB), approximately 32.6k tokens, and a symbol index with 1 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!