SQL Adapter conformance
Clone or download
Andrew J Wagner
Andrew J Wagner Fixed ability to set a column to null in an update
If a value was nil previously the valuesByField dictionary
was being left without that key. Thise code now explicitly
inserts in an optional as a value.
Latest commit 0e743f1 Mar 2, 2017

README.md

SQL

Swift Zewo Platform License Slack Travis Codebeat

SQL provides

  • Base conformance for SQL database adapters
  • Typesafe table representations and queries (select, insert, join, etc.)
  • A powerful, non-intrusive ORM

Installation

The SQL module is bundled with the SQL adapters of Zewo

import PackageDescription

let package = Package(
    dependencies: [
        .Package(url: "https://github.com/Zewo/SQL.git", majorVersion: 0, minor: 14),
    ]
)

Usage

Use this package with one of the supported drivers listed above.

Connecting to a database

let info = Connection.ConnectionInfo(uri: URL("postgres://localhost:5432/database_name")!)!
let connection = PostgreSQL.Connection(info: info)
try connection.open()

Executing raw queries

try connection.execute("SELECT * FROM artists")
let result = try connection.execute("SELECT * FROM artists WHERE name = %@", parameters: "Josh Rouse")

Getting results from queries

let result = try connection.execute("SELECT * FROM artists")

for row in result {
	let name: String = try row.value("name")
	let genre: String? = try row.value("genre")
	print(name)
}

In the above example, an error will be thrown if name and genre is not present in the rows returned. An error will also be thrown if a name is NULL in any row, as the inferred type is non-optional. Note how genre will allow for a NULL value.

Tables

You can define tables as such:

struct Artist : TableProtocol {
    enum Field : String, TableField {
        static let tableName = "artists"

        case id
        case name
        case genre
    }
}
Artist.select(where: Artist.Field.name == "Josh Rouse")
Artist.insert([.name : "AC/DC"])
Artist.update([.name : "AC/DC"]).filtered(Artist.Field.genre == "Rock")
Artist.delete(where: Artist.Field.genre == "Rock")
try connection.execute(Artist.select(where: Artist.Field.name == "Josh Rouse"))

Models

Models provide more ORM-like functionality than tables. You can define models like so:

struct Artist {
    var name: String
    var genre: String
}

extension Artist : ModelProtocol {
    // Just like `Table`
    enum Field: String, ModelField {
        // notice how we define the "id" field
        // but don't have it as a property
        case id
        case name
        case genre

        // Specify a table name
        static let tableName = "artists"

        // Specify which field is primary
        static let primaryKey = Field.id
    }

    // Specify what type the primary key is (usually int or string)
    typealias PrimaryKey = Int

    // The values returned here will be persisted
    // primary key is inserted automatically
    func serialize() -> [Field : ValueConvertible?] {
        return [
            .name: name,
            .genre: genre
        ]
    }

    // Provide an initializer for the model taking a row
    // a little generic but dont let it scare you
    init<Row: RowProtocol>(row: TableRow<Artist, Row>) throws {
        try self.init(
            name: row.value(.name),
            genre: row.value(.genre)
        )
    }
}
// note how we operate on Entity<Artist> rather than just Artist.
// there also exists a type PersistedEntity<Artist>, which has a primary key
// and methods such as refresh and update
let rockArtists = try Entity<Artist>.fetch(where: Artist.Field.genre == "Rock", connection: connection)

for var artist in rockArtists {
    artist.model.genre = "Rock 'n Roll"
    // since artist is of type PersistedEntity<Artist> (has a primary key),
    // we can save it, replacing the previous record
    artist.save(connection: connection)
}

let newArtist = Artist(name: "Elijah Blake", genre: "Hip-hop")
let persistedArtist = try Entity(model: newArtist).create(connection: connection)
print("id of new artist: \(persistedArtist.primaryKey)")

Support

If you need any help you can join our Slack and go to the #help channel. Or you can create a Github issue in our main repository. When stating your issue be sure to add enough details, specify what module is causing the problem and reproduction steps.

Community

Slack

The entire Zewo code base is licensed under MIT. By contributing to Zewo you are contributing to an open and engaged community of brilliant Swift programmers. Join us on Slack to get to know us!

License

This project is released under the MIT license. See LICENSE for details.