Code Monkey home page Code Monkey logo

swiftmysql's Introduction

SwiftMysql

Build Status

A pure Swift Client implementing the MySQL protocol. this is not depend on libmysql.

Features

  • Thread safe
  • Pooling connections
  • Prepared statements
  • Transactions
  • JSON Data Type in MySQL 5.7
  • Streaming query rows
  • Non-Blocking Querying

Instllation

let package = Package(
    name: "MyApp",
    dependencies: [
        .package(url: "https://github.com/noppoMan/SwiftMysql.git", .upToNextMajor(from: "0.1.0"))
    ],
)

Basic querying

let url = URL(string: "mysql://localhost:3306")
let con = try Connection(url: url!, user: "root", password: "password", database: "swift_mysql")

let result = try con.query("selct * from users")
if let rows = result.asRows() {
    for row in rows {
      print(row) // ["id": 1, "name": "Luke", "email": "[email protected]"]
    }
}

Prepared statements

You can easy to use prepared statement as following.

let url = URL(string: "mysql://localhost:3306")
let con = try Connection(url: url!, user: "root", password: "password", database: "swift_mysql")

let result = try con.query("selct * from books where published_at > ? and category_id = ?", [2017, 3])
if let rows = result.asRows() {
    for row in rs {
      print(row)
    }
}

Pooling connections

Rather than creating and managing connections one-by-one, this module also provides built-in connection pooling using ConnectionPool(url:user:database:minPoolSize:maxPoolSize)

let pool = try ConnectionPool(
    url: URL(string: "mysql://localhost:3306")!,
    user: "root",
    database: "swift_mysql",
    minPoolSize: 3,
    maxPoolSize: 10
)

try pool.query("select * from users") // the connection is released after finishing query.

failedToGetConnectionFromPool Error

failedToGetConnectionFromPool will be thrown when the number of connections that are used in internally reaches maxPoolSize, and then query is called. But It's recoverable, all developers can retry to perform query as like following.

do {
    try pool.query("select * from users")
} catch ConnectionPoolError.failedToGetConnectionFromPool {
    // may need to wait a moment...

    // try again.
    try pool.query("select * from users")
}

Transactions

Simple transaction support is available at the connection level

Commit

If the program that in transaction block is finished without throwing error, transaction should be committed automatically.

try con.transaction {
    $0.query("insert into users (name, email), value (\"Foo\", \"[email protected]\")")
}

Rollback

if the error is thrown in transaction block, rollback should be performed.

try con.transaction {
    throw FooError
}

Streaming query rows

Sometimes you may want to select large quantities of rows and process each of them as they are received. This can be done like this

let result = try con.query("selct * from large_tables")
if let resultFetcher = result.asResultSet() {
    print(resultFetcher.columns) // [String]

    // resultFetcher.rows is a infinity Sequence
    // you can loop it until the Mysql sends EOF packet.
    for row in resultFetcher.rows {
        print(row)
    }
}

Terminating connections

once call close method, the Mysql connection is terminated safely.

try con.close()

Non-Blocking Querying

SwiftMysql supports Non-Blocking querying with AsyncConnection. Non-Blocking means event-driven non-blocking I/O using OS native asynchronous system calls (epoll/kqueue). It doesn't concurrent execution by worker threads.

Currently all of non-blocking features are not thread safe. So you should use them on the single thread.

Non-Blocking Querying with AsyncConnection

You can asynchronously connect to the mysql with AsyncConnection(url:user:password:database:queue),

Once call initializer of AsyncConnection, connection is automatically opened on a specified thread(queue). Then, all of your operations(query) are queued and processed in order. The thread will create event loop on the own thread to observe the file descriptor of the connection.

import Foundation
import SwiftMysql

let url = URL(string: "mysql://localhost:3306")!
let con = try SwiftMysql.AsyncConnection(
    url: url,
    user: "root",
    password: nil,
    database: "swift_mysql"
)

con.onConnect {
    print("connected to \(url)")
}

con.onError { error in
    print("Error: \(error)")
}

con.query("select * from users where id = 1") { result in
    if let error = result.asError() {
        print(error)
        return
    }

    result.asRows {
        print($0) // [["id": 1, "name": "Jack....]]
    }
}

con.query("select * from users where id = 2") { result in
    if let error = result.asError() {
        print(error)
        return
    }

    result.asRows {
        print($0) // [["id": 2, "name": "Tonny....]]
    }
}

RunLoop.main.run()

Event Loop Thread

If you didn't care the thread for running event loop, it's automatically determined by DispatchQueue(attributes: .serial) internally.

Or you can provide it by queue label of initializer like following.

let url = URL(string: "mysql://localhost:3306")!
let con = try SwiftMysql.AsyncConnection(
    url: url,
    user: "root",
    password: nil,
    database: "swift_mysql",
    queue: DispatchQueue.main
)

con.connect {
    print(Thread.current == Thread.main) // true
}

con.query("...") { _ in
    print(Thread.current == Thread.main) // true
}

Event Driven Query rows and fields

You can improve memory efficiency for fetching records to use ResultSetEvent.

ResultSetEvent provides two methods to fetch fields and rows streamly.

  • onFields: onFields is called when the all fields packets are received.
  • onRow: onRow is called when the per row packets are received.
con.query("select * from users limit ?", bindParams: [100]) { result in
    let rs = result.asResultSet() // get ResultSetEvent

    rs.onFields { fields in
        print(fields) // ["id", "name", "age"...]
    }

    event.onRow { row in
        print(row) // [[1, "Jack", 35...]]
    }
}

Pooling connections

Also you can use pooling connections for non-blocking querying with AsyncConnectionPool. The usage is roughly same as sync version. The number of connections using at the same time are reached maxPoolSize, the next query queue should wait for a connection is available.

let pool = try AsyncConnectionPool(
    url: url,
    user: "root",
    database: "swift_mysql",
    minPoolSize: 2,
    maxPoolSize: 10
)

pool.onReady {
    print("The initial connections are ready")
}

pool.onNewConnectionIsReady {
    print("new Connection is ready")
}

// Uses a existing connection
pool.query("select * from users where id = ?", bindParams: [1]) { result in
    result.asRows()
    // connection will be released automatically,
    // when the all of packets of this query are received.
}

// Uses a existing connection
pool.query("select * from users where id = ?", bindParams: [2]) { result in
    result.asRows()
}

// May create a new connection asynchronously.
// Depends on the timing of first query finished.
pool.query("select * from users where id = ?", bindParams: [3]) { result in
    result.asRows()
}

Transactions

pool.transaction { error, con in
    con?.query("insert into ....") { result in
        if let error = result.asError() {
            con?.rollback { _ in
                done(error)
            }
            return
        }

        con?.query("update users set name = ....") { result in
          if let error = result.asError() {
              con?.rollback { _ in
                  done(error)
              }
              return
          }

          con?.commit { _ in
              done(nil)
          }
        }
    }
}

License

SwiftMysql is released under the MIT license. See LICENSE for details.

swiftmysql's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

firdausyusofs

swiftmysql's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.