Releases: vapor/fluent-kit
FluentKit 1.0.0 Beta 1
- Added a new
@OptionalParent
relation where the child's parent ID is optional. (#78) filter
operators now support comparing two columns. (#79)- Added a new protocol
ModelAlias
for handling queries that join a given table more than once. (#75)
final class Match: Model {
...
@Parent(key: "home_team_id")
var homeTeam: Team
@Parent(key: "away_team_id")
var awayTeam: Team
}
final class Team: Model {
...
@Children(from: \.$homeTeam)
var homeMatches: [Match]
@Children(from: \.$awayTeam)
var awayMatches: [Match]
}
struct HomeTeam: ModelAlias {
typealias Model = Team
static var alias: String { "home_teams" }
}
struct AwayTeam: ModelAlias {
typealias Model = Team
static var alias: String { "away_teams" }
}
let matches = try Match.query(on: self.database)
.join(HomeTeam.self, on: \Match.$homeTeam == \Team.$id)
.join(AwayTeam.self, on: \Match.$awayTeam == \Team.$id)
.filter(HomeTeam.self, \Team.$name == "a")
.all().wait()
for match in matches {
let home = try match.joined(HomeTeam.self)
let away = try match.joined(AwayTeam.self)
print(match.name)
print("home: \(home.name)")
print("away: \(away.name)")
}
Database
can now specify anEventLoopPreference
andLogger
. (#84)
This is in line with changes to how Vapor 4.0.0 Beta 1 handles services.
FluentKit 1.0.0 Alpha 3.1
- Fixes a bug causing
@Parent.query
and@Parent.get
to filter on the wrong column. (#68)
Notes: Previously these methods would attempt to filter the related parent by the child's key. They now filter on the parent's key (identifier).
FluentKit 1.0.0 Alpha 3
@Field
and@Parent
properties now require akey
String
Notes: The reflection logic required to automatically infer keys was complex and computation heavy. Requiring the user to supply keys simplifies a lot of the internal logic. This also allows Fluent to provide clearer error messages. Moreover, this change increases the consistency of large models where there are more likely to be label / key mismatches.
@Children
now requires the labelfrom:
- New
@ID
property replaces@Field
for model identifiers.
Notes:
ID
is a special field that holds additional information like whether or not the model has been saved to the database yet and a reference to the DB output for decoding joins. By limiting this property to one-per-model, Fluent reduces the overall size of models.
@ID
property has a newGenerator
parameter with three options:
public enum ID.Generator {
case user
case random
case database
}
Notes: This change makes Fluent's supported ID generation methods more clear. You can now explicitly choose whether you want to supply user-generated IDs, have Fluent generate random IDs, or let your database generate the ID. These options work in conjunction with Fluent's
RandomGeneratable
protocol andSchemaBuilder
's default constraints respectively.
-
Model.ID
has been renamed toModel.IDValue
to avoid conflicting with the new@ID
property. -
New
@Siblings
property that connects two models in a many-to-many relation. This relation requires a third "pivot" model that has two@Parent
properties to the models that will be related. The pivot model can have additional fields and relations if desired.
Example model with siblings relation:
final class Tag: Model {
static let schema = "tags"
@ID(key: "id")
var id: Int?
@Field(key: "name")
var name: String
@Siblings(through: PlanetTag.self, from: \.$tag, to: \.$planet)
var planets: [Planet]
init() { }
init(id: Int? = nil, name: String) {
self.id = id
self.name = name
}
}
Example pivot model:
final class PlanetTag: Model {
static let schema = "planet+tag"
@ID(key: "id")
var id: Int?
@Parent(key: "planet_id")
var planet: Planet
@Parent(key: "tag_id")
var tag: Tag
init() { }
init(planetID: Int, tagID: Int) {
self.$planet.id = planetID
self.$tag.id = tagID
}
}
SoftDeletable
andTimestampable
have been replaced by a new@Timestamp
property with three possible triggers.
public enum Timestamp.Trigger {
case create
case update
case delete
}
Notes: This change allows for more flexibility in which timestamps each model should have and how to name them. For example, you are no longer required to have both
createdAt
andupdatedAt
timestamps. In order to make a model soft-deletable, simply add a@Timestamp
property with thedelete
trigger.
QueryBuilder.withSoftDeleted
has been renamed towithDeleted
.
Notes: With the removal of the
SoftDeletable
protocol, this more concise name better matches the@Timestamp
's.delete
trigger name.
SchemaBuilder
is now decoupled fromModel
(#59)
Example model and associated migration:
final class Planet: Model {
static let schema = "planets"
@ID(key: "id")
var id: Int?
@Field(key: "name")
var name: String
@Parent(key: "galaxy_id")
var galaxy: Galaxy
@Siblings(through: PlanetTag.self, from: \.$planet, to: \.$tag)
var tags: [Tag]
init() { }
init(id: Int? = nil, name: String, galaxyID: Galaxy.IDValue) {
self.id = id
self.name = name
self.$galaxy.id = galaxyID
}
}
struct PlanetMigration: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
return database.schema("planets")
.field("id", .int, .identifier(auto: true))
.field("name", .string, .required)
.field("galaxy_id", .int, .required)
.create()
}
func revert(on database: Database) -> EventLoopFuture<Void> {
return database.schema("planets").delete()
}
}
Notes: Decoupling migrations from models is an important step for making Fluent more reliable and predictable for production use cases and team development.
Model.entity
andModel.name
have been combined toModel.schema
Notes:
entity
was vague and the difference betweenname
andentity
was not clear. Combining these properties and using the nameschema
makes the relation to the string used bySchemaBuilder
more clear.
FluentKit 1.0.0 Alpha 2
New:
Model
has been combined withRow
and makes use of Swift 5.1's property wrappers:
final class Planet: Model {
@Field var id: Int?
@Field var name: String
@Parent var galaxy: Galaxy
init() { }
init(id: Int? = nil, name: String, galaxyID: Galaxy.ID) {
self.id = id
self.name = name
self.$galaxy.id = galaxyID
}
}
final class Galaxy: Model {
@Field var id: Int?
@Field var name: String
@Children(\.$galaxy) var planets: [Planet]
init() { }
init(id: Int? = nil, name: String) {
self.id = id
self.name = name
}
}
- Migrations are now required for all models and auto migrations have been temporarily disabled:
struct GalaxyMigration: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
return Galaxy.schema(on: database)
.field(\.$id, .int, .identifier(auto: true))
.field(\.$name, .string, .required)
.create()
}
func revert(on database: Database) -> EventLoopFuture<Void> {
return Galaxy.schema(on: database).delete()
}
}
struct PlanetMigration: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
return Planet.schema(on: database)
.field(\.$id, .int, .identifier(auto: true))
.field(\.$name, .string, .required)
.field("galaxy_id", .int, .required)
.create()
}
func revert(on database: Database) -> EventLoopFuture<Void> {
return Planet.schema(on: database).delete()
}
}
FluentKit 1.0.0 Alpha 1.3
FluentKit 1.0.0 Alpha 1.2
FluentKit 1.0.0 Alpha 1.1
Fixed:
- Added support for Fluent-generated IDs (like
UUID
)
FluentKit 1.0.0 Alpha 1
More information on Vapor 4 alpha releases:
https://medium.com/@codevapor/vapor-4-alpha-1-releases-begin-94a4bc79dd9a
API Docs:
https://api.vapor.codes/fluent-kit/master/FluentKit/index.html