SQL provides
- Base conformance for SQL database adapters
- Typesafe table representations and queries (select, insert, join, etc.)
- A powerful, non-intrusive ORM
The SQL module is bundled with the SQL adapters of Zewo
import PackageDescription
letpackage=Package(
dependencies:[.Package(url:"https://github.com/Zewo/SQL.git", majorVersion:0, minor:14),])Use this package with one of the supported drivers listed above.
letinfo=Connection.ConnectionInfo(uri:URL("postgres://localhost:5432/database_name")!)!
letconnection=PostgreSQL.Connection(info: info)try connection.open()try connection.execute("SELECT * FROM artists")letresult=try connection.execute("SELECT * FROM artists WHERE name = %@", parameters:"Josh Rouse")letresult=try connection.execute("SELECT * FROM artists")forrowin result {letname:String=try row.value("name")letgenre: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.
You can define tables as such:
structArtist:TableProtocol{enumField:String,TableField{staticlettableName="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 provide more ORM-like functionality than tables. You can define models like so:
structArtist{varname:Stringvargenre:String}extensionArtist:ModelProtocol{
// Just like `Table`
enumField: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
staticlettableName="artists"
// Specify which field is primary
staticletprimaryKey=Field.id
}
// Specify what type the primary key is (usually int or string)
typealiasPrimaryKey=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{tryself.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
letrockArtists=try Entity<Artist>.fetch(where:Artist.Field.genre =="Rock", connection: connection)forvar artistin 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)}letnewArtist=Artist(name:"Elijah Blake", genre:"Hip-hop")letpersistedArtist=tryEntity(model: newArtist).create(connection: connection)print("id of new artist: \(persistedArtist.primaryKey)")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.
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!
This project is released under the MIT license. See LICENSE for details.
