Code Monkey home page Code Monkey logo

mysql-swift's Introduction

mysql-swift

This library is obsolete and not maintained. Use MySQLNIO instead.

Platform Linux, macOS CircleCI

MySQL client library for Swift. This is inspired by Node.js' 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.

// 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 or cmysql-mariadb.

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

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

Ubuntu

$ sudo apt-get install libmariadbclient-dev

Installation

Swift Package Manager

  • Add mysql-swift to Package.swift of your project.
// 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.
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

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

mysql-swift's People

Contributors

floresrobles avatar florianreinhart avatar novi avatar patrick-zippenfenig avatar popaaaandrei avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mysql-swift's Issues

Carthage issues

I am a OS X user and have some weird issues installing mysql-swift via carthage. I uploaded the log of the errors to [pastebin[(http://pastebin.com/K3aYiQgN). Do you know a solution to this or could you give me some hints how I can dive into the problem to solve it?

Cartfile:

github "novi/mysql-swift" "master"

More date and time types support

I have updated this implementation on pull request #93.

Date type in Swift is recommended way to treat typical date and time type TIMESTAMP, DATETIME in MySQL commonly used for creation date, updates date.

Date only supports TIMESTAMP, DATETIME MySQL types.

DateComponents type in Swift is just container for representing SELECT ed string from databases into it.
YEAR, TIME, DATE, TIMESTAMP, DATETIME column can be parsed into DateComponents. And used as query parameters for these types in MySQL as well.

DateComponents doesn't respect or treat for timeZone and calendar on itself by this library. But Date does respect time zone on ConnectionOption.timeZone.

Check more details on its tests and another one.


This is original proposal:

We could implement this:

  • treat MySQL TIMESTAMP and DATETIME as SQLDate(and NSDate)
  • DATE as SQLDate(NSDate) with YYYY-MM-DD 00:00:00
  • TIME as String
  • YEAR as Int

TIME type has range of '-838:59:59.000000' to '838:59:59.000000’, we couldn’t treat as NSDate. So we support it with String type for now.

(https://dev.mysql.com/doc/refman/5.6/en/datetime.html)

Related #24.

MySQL has 0000-00-00 date value for representing dummy date or empty date, or sometimes null.
We could support such case in this library by following JDBC zeroDateTimeBehavior. (#24)

Connecting to database

Hello,

I have an error while trying to connect to the database.

connectionError("Lost connection to MySQL server at \'waiting for initial communication packet\', system error: 60 \"Operation timed out\"")

What I might be doing wrong?

Here is my ConnectionOption (I had to hide my addresses etc):

struct Options : ConnectionOption {
    let host: String = "xxxxxx"
    let port: Int = xxxx
    let user: String = "username"
    let password: String = "xxxxx"
    let database: String = "xxxxxx"
    let timeout: Int = 10
    let omitDetailsOnError : Bool = false
}

and here is how I call the execute:

do {
            let status: QueryStatus = try pool.execute { conn in
                try conn.query("SELECT * FROM users;") // And also it returns result to outside execute block
            }
            print(status.description)
        } catch let error {
            print("Error occurred:\n \(error)")
        }

Not compiling with Swift 4

I have imported all the files inside "Sources", into my Xcode project.
Xcode's giving me multiple errors:

private var mysql_: UnsafeMutablePointer<MYSQL>? // Use of undeclared type 'MYSQL'

Same for mysql_init, MYSQL_OPT_CONNECT_TIMEOUT, my_bool, mysql_real_connect, MYSQL_OPT_RECONNECT , etc. ...

Am I missing something? Thanks!

installing with mariadb and swift 3 pre Problem

Having a problem install

root@igentik:/home/ecnxdev/swift/test2# swift build -Xcc -fblocks -Xlinker -ldispatch -L /usr/lib
error: unknown command: -L
enter `/usr/local/swift/usr/bin/swift-build --help' for usage information
root@igentik:/home/ecnxdev/swift/test2# swift build -Xcc -fblocks -Xlinker -ldispatch
note: you may be able to install mariadb using your system-packager:

apt-get install libmariadbclient-dev

note: you may be able to install mariadb using your system-packager:

apt-get install libmariadbclient-dev

note: you may be able to install mariadb using your system-packager:

apt-get install libmariadbclient-dev

note: you may be able to install mariadb using your system-packager:

apt-get install libmariadbclient-dev

root@igentik:/home/ecnxdev/swift/test2# apt-get install libmariadbclient-dev
Reading package lists... Done
Building dependency tree
Reading state information... Done
libmariadbclient-dev is already the newest version (5.5.36-1).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
root@igentik:/home/ecnxdev/swift/test2# swift
Welcome to Swift version 3.0 (swift-3.0-PREVIEW-2). Type :help for assistance.

Make RawRepresentable types automatically conform to QueryParameter

It would be nice to use enums, OptionSets and other RawRepresentable types directly as query parameters.

This could make use of conditional conformance introduced in Swift 4.1. The following code will not compile and complain that an extension for a protocol cannot have an inheritance clause: Extension of protocol 'RawRepresentable' cannot have an inheritance clause. However, it should explain my idea. I guess mysql-swift needs some special internal handling of RawRepresentables to make this work.

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

Full Codable support and version 0.9.0

I'm planning following changes on next minor(actually major) version 0.9.0.

  • Change row decoder to Swift.Decoder(Decodable) #74 #72
  • Implement query parameter encoder for Swift.Encodable #72
  • JSON column support #85
  • Decimal type support #86

Current row decoder QueryRowResultType and parameter type QueryParameterDictionaryType will be deprecated or support dropped.

And will maintain 0.8.x for a period of time on 0.8-branch.

Related #58 #68.

Building with Xcode

As mentioned in the docs, building on macOS requires specifying the C header/library paths to the linker. Can these flags be passed to the linker through Xcode as well? Building from within Xcode would be a huge plus for this connector.

segmentation fault

環境

OS : Ubuntu 14.04
DB : 10.0.27-MariaDB-1~trusty
コンパイラ : swift 3.0 release
mysql-swift : 0.5.0

サンプル

struct Article: QueryRowResultType{
    var id: Int
    var title: String
    var content: String
    var isPublished: Bool
    var createdAt: SQLDate

    static func decodeRow(r: QueryRowResult) throws -> Article {
        return try Article(
            id: r <| "id",
            title: r <| "title",
            content: r <| "content",
            isPublished: r <| "is_published",
            createdAt: r <| "created_at"
        )
    }
}

class ArticleAccessor{
    class func loadPage(page: Int) -> [Article]{
        do{
            let articles: [Article] = try DB.connectionPool().execute { conn in
                try conn.query("SELECT * FROM articles LIMIT ?, ?", [10 * page, 10])
            }

            return articles
        }catch{
            return []
        }
    }
}

class DB{
    struct DataBaseOption: ConnectionOption{
        let host: String
        let port: Int
        let user: String
        let password: String
        let database: String
    }

    private static let options = DataBaseOption(host: "localhost", port: 3306, user: "root", password: "root", database: "hoge")

    class func connectionPool() -> ConnectionPool{
        return ConnectionPool(options: options)
    }
}

DB構成

+--------------+----------------+------+-----+-------------------+----------------+
| Field        | Type           | Null | Key | Default           | Extra          |
+--------------+----------------+------+-----+-------------------+----------------+
| id           | int(11)        | NO   | PRI | NULL              | auto_increment |
| title        | varchar(100)   | YES  |     | NULL              |                |
| content      | varchar(10000) | YES  |     | NULL              |                |
| is_published | tinyint(1)     | NO   |     | NULL              |                |
| created_at   | timestamp      | NO   |     | CURRENT_TIMESTAMP |                |
+--------------+----------------+------+-----+-------------------+----------------+

上記のようなコードをコンパイルし実行すると「segmentation fault」でアプリが落ちてしまいます。
試しにSQLDateプロパティを除いてコンパイル&実行すると正常に動作します。また、OSX(10.11.5)のMySQL 5.7.12で同じ構成をとるとSQLDateプロパティが含まれている状態でも正常に動作するようです。

mysql-swift 0.2.7を使用していた時は問題なかったようなのですが、こちら何か原因がわかりますでしょうか。

Swift 3 warnings, operator precedence deprecation

I have fixed some warnings in XCode 8. Would you like me to make a PR? It's not much, just some @noescape and unused results.

Another warning is for the deprecated operator declaration.

warning: operator should no longer be declared with body; use a precedence group instead
infix operator <| { associativity left precedence 150 }
                  ^
warning: operator should no longer be declared with body; use a precedence group instead
infix operator <|? { associativity left precedence 150 }
                   ^

As discussed in swift-evolution a possible fix would be

// Before
infix operator <|  {  associativity left precedence 150 }

// After
precedencegroup ComparisonPrecedence {
  associativity: left
  higherThan: LogicalConjunctionPrecedence
}
infix operator <| : ComparisonPrecedence

I don't know what you had in mind when you put 150, but I'm thinking that it should have the precedence around AdditivePrecedence.

Andrei

Handle the "count(*)" query

let count: UInt = try conn.query("SELECT count(*) FROM users WHERE age > ? ",  [16])
// or
let count: QueryStatus = try conn.query("SELECT count(*) FROM users WHERE age > ? ",  [16])

Hi @novi , how to handle the count(*) queries? Thank you in advance for your help!

Compile error with swift 2016-01-25 snapshot

Just switched the the swift compiler to the current delevoper snapshot 2016-01-25, and now my simple playground project with a simple mysql query won't compile anymore.

Build log snippet:

Compiling Swift Module 'MySQL' (13 sources)
/var/www/sbuerk/switf/swift-playground-one/Packages/mysql-swift-0.1.5/Sources/Builder.swift:11:28: error: curried function declaration syntax has been removed; use a single parameter list
public func build<A, Value>(create: (A) -> Value)(_ a: A) -> Value {

It seems it is an issue because of Removing currying func declaration syntax - Proposal: SE-0002

I have created a gist with the full log here: full_build_log

Since i'm just playing around with swift on linux (started learning 7 days ago, with ~5h free time playing) i' could not provide an PR for it ... maybe i find some time at the weekend, but don't think so ... to many projects at work at the moment.

Just wanna share that issue ...

If i could provide further informations for that, let me know it.

Rename SQLDateCalender to SQLDateCalendar

There is a typo in the name of SQLDateCalender, which should probably be called "SQLDateCalendar".
Could this be fixed ?

I could do it and then make a pull request.

Regards

Complie with Xcode failed

image

I use xcode complie my codes and dependency on your mysql-swift library

the step is :

  1. use carthage update build the framework, and drag drop to the build phases
  2. add framework search path
  3. add the moudle.map path to the import paths in build settings

finally i use your sample code, but when i call pool.execute method , it always complie error.

pelease help me, thanks.

how can add mysql-swift in package.swift v4.0

hi , I am new in swift with server side and now I don't how can add dependencies in package.swift
this is my package.swift file
let package = Package(
name: "toDoPoj",
dependencies: [

    // Dependencies declare other packages that this package depends on.
     .package(url: "https://github.com/IBM-Swift/Kitura.git", from: "1.7.9"),
     .package(url: "https://github.com/IBM-Swift/HeliumLogger.git", from: "1.7.1"),
     
     .package(url: "https://github.com/vapor/mysql-provider.git", from: "2.0.0"),
     
],
targets: [
    // Targets are the basic building blocks of a package. A target can define a module or a test suite.
    // Targets can depend on other targets in this package, and on products in packages which this package depends on.
    .target(
        name: "toDoPoj",
        dependencies: ["Kitura" , "HeliumLogger" ,  "mysql-provider" ]),
]

)
what should I write after heliumLogger ! , I am confused that what should we write in target dependenciy ? :|

Support for inserting multiple rows in a single statement

In node-mysql I can do something like this:

let users: [User] = [user1, user2, user3]
try connection.query("INSERT INTO User (id, name, age) VALUES ?", [users])

In mysql-swift I have to manually build the query string depending on the number of rows, e.g. "INSERT INTO User (id, name, age) VALUES (?,?,?), (?,?,?), (?,?,?)".

I could also be missing something. Is there another way to achieve this in mysql-swift?

[Feature request] Swift 4 Codable Encoder Decoder

Hi,
I'm currently evaluating Swift Mysql integration and was wondering if Swift 4 Codable protocol would be possible to integrate?

struct User: Codable {
  let id: Int
  let userName: String
  let age: Int?

  // Generated automatically by the compiler if not specified
  private enum CodingKeys: String, CodingKey {
    case id
    case userName = "user_name"
    case age
  }
  
  // Generated automatically by the compiler if not specified
  func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(id, forKey: . id)
    try container.encode(userName, forKey: . userName)
    try container.encode(age, forKey: . age)
  }

 // Generated automatically by the compiler if not specified
  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    id = try container.decode(Int.self, forKey: .id)
    userName = try container.decode(String.self, forKey: .userName)
    age = try container.decode(Int.self, forKey: .age)
  }
}

CodingKeys encode and decode are generated automatically. Reference https://www.mikeash.com/pyblog/friday-qa-2017-07-14-swiftcodable.html

An mysql ORM could now implement the necessary encode and decode container for arrays of objects. It looks similar to your current implementation.
Would such an integration be possible?

Regards,
Patrick

Floating point numbers lose precision

The age-old floating point issues bit me once again...

Note: This most definitely also applies to Float, but I have just tested with Double.

When Swift formats a Double as a String it rounds the number, e.g. an internal representation of 7.7087009966199993 has a String value of 7.70870099662. When you create a Double from that String, you get back 7.7087009966200002. This is closer to 7.70870099662 than 7.7087009966199993, so it is the right thing to do here.

mysql-swift uses the String initializer to convert numbers to strings and hands it off to MySQL client. I believe the server then decodes that string in much the same way Swift does: The string 7.70870099662 is converted to the double value 7.7087009966200002.

JSONEncoder/JSONDecoder does not observe these issues and formats the double value as 7.7087009966199993. We should probably look into the Codable implementation of Double and figure out how they encode floating point values.

I have created a sample implementation to reproduce the issue:

CREATE TABLE `DoubleTable` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `doubleField` double NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
import Foundation
import MySQL

struct MySQLOptions: MySQL.ConnectionOption {
    init() { }
    let host = "127.0.0.1"
    let port = 3306
    let user = "doubleUser"
    let password = "doubleUser"
    let database = "DoubleDatabase"
    let timeZone = TimeZone(identifier: "UTC")!
    let encoding = Connection.Encoding.UTF8MB4
    let timeout = 10
    let reconnect = true
    let omitDetailsOnError = false
}

struct DoubleStruct: Codable {
    let id: UInt32
    let doubleField: Double
}

let pool = ConnectionPool(options: MySQLOptions())

try! pool.execute { connection in
    // Write a double value to the database
    print("Writing double value to database")
    let doubleStruct1 = DoubleStruct(id: 0, doubleField: 7.7087009966199993)
    var query = "INSERT INTO DoubleTable (doubleField) VALUES (?)"
    let result = try connection.query(query, [doubleStruct1.doubleField])
    print("Created row with id \(result.insertedID) and double field \(doubleStruct1.doubleField). Memory dump follows below.")
    dump(doubleStruct1.doubleField)
    
    // Read the same double value from the database
    query = "SELECT id, doubleField FROM DoubleTable WHERE id = ?"
    let doubleStructs: [DoubleStruct] = try connection.query(query, [UInt32(result.insertedID)])
    let doubleStruct2 = doubleStructs.first!
    print("Read row with id \(doubleStruct2.id) and double field \(doubleStruct2.doubleField). Their internal values are\(doubleStruct1.doubleField == doubleStruct2.doubleField ? "" : " not") equal. Dump of the read value follows.")
    dump(doubleStruct2.doubleField)
    
    // Encode and decode as JSON
    print("\nNow encoding as JSON")
    let jsonEncoder = JSONEncoder()
    let jsonDecoder = JSONDecoder()
    let json1 = try jsonEncoder.encode(doubleStruct1)
    let json2 = try jsonEncoder.encode(doubleStruct2)
    print(String(decoding: json1, as: UTF8.self))
    print(String(decoding: json2, as: UTF8.self))
    let doubleStruct1a = try jsonDecoder.decode(DoubleStruct.self, from: json1)
    let doubleStruct2a = try jsonDecoder.decode(DoubleStruct.self, from: json2)
    print("JSON double values for struct 1 are\(doubleStruct1.doubleField == doubleStruct1a.doubleField ? "" : " not") equal. Dump follows.")
    dump(doubleStruct1.doubleField)
    dump(doubleStruct1a.doubleField)
    print("JSON double values for struct 2 are\(doubleStruct2.doubleField == doubleStruct2a.doubleField ? "" : " not") equal. Dump follows.")
    dump(doubleStruct2.doubleField)
    dump(doubleStruct2a.doubleField)
    
    // Convert to string and back
    print("\nNow encoding as string")
    let string1 = String(doubleStruct1.doubleField)
    let doubleFromString = Double(string1)!
    print("Encoding and decoding from string. Values are\(doubleStruct1.doubleField == doubleFromString ? "" : " not") equal. Dump follows")
    dump(doubleStruct1.doubleField)
    dump(doubleFromString)
}

Library not found

Please help,

when using this command "swift build -Xlinker -L/usr/local/lib -Xcc -I/usr/local/include -Xcc -I/usr/local/include/mysql" from terminal the project builds successfully.

But when building via xcode it gives me error
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Sorry found the solution :)

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.