Skip to content

Commit

Permalink
Merge pull request #94 from novi/some-updates
Browse files Browse the repository at this point in the history
Some updates and refactoring
  • Loading branch information
novi authored Aug 29, 2018
2 parents 739befb + b599068 commit 0b25e17
Show file tree
Hide file tree
Showing 19 changed files with 264 additions and 212 deletions.
35 changes: 18 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ mysql-swift


MySQL client library for Swift.
This is inspired by Node.js' [mysql](https://github.com/felixge/node-mysql).
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 support currently. It depends libmysqlclient.
_Note:_ No asynchronous I/O support currently. It depends libmysqlclient.

```swift
// Declare a model
Expand Down Expand Up @@ -54,28 +54,29 @@ 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 `user` SET age = ? WHERE age is NULL;", [defaultAge])
try conn.query("UPDATE ?? SET age = ? WHERE age is NULL;", [tableName, defaultAge])

```

# Requirements

* Swift 4.1 or later

# Dependencies

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

## macOS

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

```
brew install https://gist.github.com/novi/dd21d48d260379e8919d9490bf5cfaec/raw/6ea4daa02d93f4ab0110ad30d87ea2b497a71cd0/cmysqlmariadb.rb
```sh
# cmysql
$ brew tap vapor/homebrew-tap && brew install cmysql
# cmysql-mariadb
$ brew install https://gist.github.com/novi/dd21d48d260379e8919d9490bf5cfaec/raw/6ea4daa02d93f4ab0110ad30d87ea2b497a71cd0/cmysqlmariadb.rb
```

## Ubuntu Linux
## Ubuntu

* Install `libmariadbclient`
* Follow [Setting up MariaDB Repositories](https://downloads.mariadb.org/mariadb/repositories/#mirror=yamagata-university) and set up your repository.
Expand All @@ -97,7 +98,7 @@ import PackageDescription
let package = Package(
...,
dependencies: [
.package(url: "https://github.com/novi/mysql-swift.git", .upToNextMinor(from: "0.9.0"))
.package(url: "https://github.com/novi/mysql-swift.git", .upToNextMajor(from: "0.9.0"))
],
targets: [
.target(
Expand All @@ -116,13 +117,13 @@ let package = Package(
## Connection & Querying

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

```swift
let options = Options(host: "your.mysql.host"...)
let pool = ConnectionPool(options: options) // Create pool with options
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 is held in this block
// The connection `conn` is held in this block
try conn.query("SELECT * FROM users;") // And it returns result to outside execute block
}
```
Expand All @@ -133,7 +134,7 @@ let rows: [User] = try pool.execute { conn in
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 val = ? WHERE key = 'latest_user_id' ", [userId]) // Store user's id that we have created the above
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
```
Expand Down
18 changes: 9 additions & 9 deletions Sources/MySQL/Blob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ extension Data: SQLRawStringDecodable {
}
}

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 = "x'"
for d in self {
let str = String(d, radix: 16)
if str.count == 1 {
buffer.append("0")
}
buffer += str
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 += "'"
return buffer
buffer.append("'")
return String(buffer)
}

public func escapedForID() -> String? {
Expand Down
47 changes: 21 additions & 26 deletions Sources/MySQL/Connection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,14 @@ import CoreFoundation
import Foundation

internal struct MySQLUtil {
internal static func getMySQLError(_ mysqlPtr: UnsafeMutablePointer<MYSQL>?) -> String {
guard let mysql = mysqlPtr else {
return "generic error"
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 ch = mysql_error(mysql) else {
return "generic error"
guard let errorString = String(validatingUTF8: strPtr) else {
return "unknown error. could not get error as string."
}
guard let str = String(validatingUTF8: ch) else {
return "generic error"
}
return str as String
return errorString
}
}

Expand Down Expand Up @@ -68,11 +65,9 @@ extension Connection {

}

extension Connection {
public enum Error: Swift.Error {
case connectionError(String)
case connectionPoolGetConnectionError
}
public enum ConnectionError: Error {
case connectionError(String)
case connectionPoolGetConnectionTimeoutError
}

public final class Connection {
Expand All @@ -81,10 +76,10 @@ public final class Connection {
private var mysql_: UnsafeMutablePointer<MYSQL>?

internal let pool: ConnectionPool
public let options: ConnectionOption
public let option: ConnectionOption

init(options: ConnectionOption, pool: ConnectionPool) {
self.options = options
internal init(option: ConnectionOption, pool: ConnectionPool) {
self.option = option
self.pool = pool
self.mysql_ = nil
}
Expand Down Expand Up @@ -115,23 +110,23 @@ public final class Connection {

do {
let timeoutPtr = UnsafeMutablePointer<Int>.allocate(capacity: 1)
timeoutPtr.pointee = options.timeout
timeoutPtr.pointee = option.timeout
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, timeoutPtr)
timeoutPtr.deallocate()
}

Connection.setReconnect(options.reconnect, mysql: mysql)
Connection.setReconnect(option.reconnect, mysql: mysql)

if mysql_real_connect(mysql,
options.host,
options.user,
options.password,
options.database,
UInt32(options.port), nil, 0) == nil {
option.host,
option.user,
option.password,
option.database,
UInt32(option.port), nil, 0) == nil {
// error
throw Error.connectionError(MySQLUtil.getMySQLError(mysql))
throw ConnectionError.connectionError(MySQLUtil.getMySQLError(mysql))
}
mysql_set_character_set(mysql, options.encoding.rawValue)
mysql_set_character_set(mysql, option.encoding.rawValue)
self.mysql_ = mysql
return mysql
}
Expand Down
Loading

0 comments on commit 0b25e17

Please sign in to comment.