Getting Started
Alchemy includes Rune, an object-relational mapper (ORM) to make it simple to interact with your database. With Rune, each database table has a correspondingModel type that is used to interact with that table. Use this Model type for querying, inserting, updating or deleting from the table.
Creating a Model
To get started, implement the Model protocol. All it requires is anid property. Each property of your Model will correspond to a table column with the same name, converted to snake_case.
Model APIs rely heavily on Swift’s Codable. Please avoid overriding the compiler synthesized func encode(to: Encoder) and init(from: Decoder) functions. You might be able to get away with it but it could cause issues under the hood. You can however, add custom CodingKeys if you like, just be aware of the impact it will have on the keyMappingStrategy described below.
Custom Table Names
By default, your model will correspond to a table with the name of your model type, pluralized. For custom table names, you can override the statictableName: String property.
Custom Key Mappings
As mentioned, by default allModel property names will be converted to snake_case, when mapping to corresponding table columns. You may change this behavior via the keyMapping: DatabaseKeyMapping. You could set it to .useDefaultKeys to use the verbatim CodingKeys of the Model object, or .custom((String) -> String) to provide a custom mapping closure.
Model Field Types
Basic Types
Models support most basic Swift types such asString, Bool, Int, Double, UUID, Date. Under the hood, these are mapped to relevant types on the concrete Database you are using.
Advanced Types
Models also support some more advanced Swift types, such asenums and JSON.
Enums
String or Int backed Swift enums are allowed as fields on a Model, as long as they conform to ModelEnum.
JSON
Models require all properties to beCodable, so any property that isn’t one of the types listed above will be stored as JSON.
Custom JSON Encoders
By default,JSON properties are encoded using a default JSONEncoder() and stored in the table column. You can use a custom JSONEncoder by overriding the static Model.jsonEncoder.
Custom JSON Decoders
Likewise, you can provide a customJSONDecoder for decoding data from JSON columns.
Decoding from SQLRow
Models may be “decoded” from a SQLRow that was the result of a raw query or query builder query. The Model’s properties will be mapped to their relevant columns, factoring in any custom keyMappingStrategy. This will throw an error if there is an issue while decoding, such as a missing column.
SQLRow.decode(_ type:) because the typed ORM queries described in the next section decode it for you.
Model Querying
To add some type safety to query builder queries, you can initiate a typed query off of aModel with the static .query function.
ModelQuery<M: Model> is a subclass of the generic Query, with a few functions for running and automatically decoding M from a query.
All Models
.allModels() returns all Models that matched the query.
First Model
.firstModel() returns an EventLoopFuture<M?> containing the first Model that matched the query, if it exists.
.unwrapFirstModel(or error: Error).
Quick Lookups
There are also two functions for quickly looking up aModel.
ensureNotExists(where:error:) does a query to ensure that a Model matching the provided where clause doesn’t exist. If it does, it throws the provided error.
unwrapFirstWhere(_:error:) is essentially the opposite, finding the first Model that matches the provided where clause or throwing an error if one doesn’t exist.
Model CRUD
There are also convenience functions around creating, fetching, and deletingModels.
Get All
Fetch all records of aModel with the all() function.
Save
Save aModel to the database, either inserting it or updating it depending on if it has a nil id.
Delete
Delete an existingModel from the database with delete().
Sync
Fetch an up to date copy of thisModel.
Bulk Operations
You can also do bulk inserts or deletes on[Model].

