Awesome
SQL
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
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.