My recent tinkering has been with Vapor, and while I mostly like their Fluent ORM, it has some rough edges and semi-undocumented behavior. At some point, I’ll feel confident enough in what I’ve learned through trial and error (combined with reading the source code – open source!) to actually make some contributions to the documentation, but for now, I’m going to throw some of the things I struggled with up here.
If you’re using a migration to add a column, and specifically want it to be non-null, you’ll need a default value. My first approach was to do a three-step migration, adding the column as nullable, then filling the default value on all rows, and then setting the column to be non-null, but that didn’t feel right. Eventually, though, I figured out how to express a DEFAULT
constraint in Fluent:
let defaultValueConstraint = SQLColumnConstraintAlgorithm.default(/* your default value here */)
Then, in your actual schema builder call:
.field("column_name", /* your type */, .sql(defaultValueConstraint), .required)
Note that SQLColumnConstraintAlgorithm
isn’t available from the Fluent module, you’ll need to import SQLKit
first.
And here, a full worked example:
import Vapor
import Fluent
import SQLKit
struct DemoMigration: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
let defaultValueConstraint = SQLColumnConstraintAlgorithm.default(false)
return database.schema(DemoModel.schema)
.field(DemoModel.FieldKeys.hasBeenTouched, .bool, .sql(defaultValueConstraint), .required)
.update()
}
func revert(on database: Database) -> EventLoopFuture<Void> {
database.schema(DemoModel.schema)
.deleteField(DemoModel.FieldKeys.hasBeenTouched)
.update()
}
}
(For context, I’m in the habit of having a static var schema: String { "demo_model" }
and a struct FieldKeys { static var hasBeenTouched: FieldKey { "has_been_touched" } }
within each of my Fluent models – it keeps everything nice and organized, and avoids having stringly-typed issues all over the place.)