Last active
June 14, 2020 03:01
-
-
Save m-barthelemy/63ae5917383263b435cd61651dceb6e0 to your computer and use it in GitHub Desktop.
Extensions for using KeyPaths in Vapor4 Fluent migrations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Vapor | |
import Fluent | |
// Example models | |
final class Organization: Model, Content { | |
static var schema = "organizations" | |
@ID (key: .id) | |
var id: UUID? | |
@Field (key: "name") | |
var name: String? | |
@Children(for: \.$organization) | |
var users: [User] | |
init() {} | |
} | |
final class User: Model, Content { | |
static var schema = "users" | |
@ID (key: .id) | |
var id: UUID? | |
@Field (key: "name") | |
var name: String? | |
@Field (key: "email") | |
var email: String? | |
@OptionalParent (key: "org_id") | |
var organization: Organization? | |
init() {} | |
} | |
// Example migrations using the generic extensions | |
struct CreateOrgs: Migration { | |
func prepare(on database: Database) -> EventLoopFuture<Void> { | |
return database.schema(Organization.schema) | |
.id() | |
.field(\Organization.$name, .string, .required) | |
.create() | |
} | |
func revert(on database: Database) -> EventLoopFuture<Void> { | |
return database.schema(Organization.schema).delete() | |
} | |
} | |
struct CreateUsers: Migration { | |
func prepare(on database: Database) -> EventLoopFuture<Void> { | |
return database.schema(User.schema) | |
.id() | |
.field(\User.$name, .string) | |
.field(\User.$email, .string, .required) | |
.unique(on: \User.$email) | |
.foreignKey(\User.$organization.$id, references: \Organization.$id, onDelete: .cascade, onUpdate: .cascade) | |
.create() | |
} | |
func revert(on database: Database) -> EventLoopFuture<Void> { | |
return database.schema(User.schema).delete() | |
} | |
} | |
// Generic extensions allowing to use KeyPaths in migrations | |
extension SchemaBuilder { | |
public func field<T, U>( | |
_ key: KeyPath<T, U>, | |
_ dataType: DatabaseSchema.DataType, | |
_ constraints: DatabaseSchema.FieldConstraint... | |
) -> Self where T: Model, U: QueryableProperty { | |
self.field(.definition( | |
name: .key(T.path(for: key).last!), | |
dataType: dataType, | |
constraints: constraints | |
)) | |
} | |
/// Passing multiple keypaths confuses the compiler, whereas one is fine. | |
public func unique<T, U>(on fields: KeyPath<T, U>..., name: String? = nil) -> Self where T: Model, U: QueryableProperty { | |
self.constraint(.constraint( | |
.unique(fields: fields.map { .key(T.path(for: $0).last!) }), | |
name: name | |
)) | |
return self | |
} | |
public func foreignKey<T, U, V, W>( | |
_ field: KeyPath<T, V>, | |
references foreignField: KeyPath<U, W>, | |
onDelete: DatabaseSchema.ForeignKeyAction = .noAction, | |
onUpdate: DatabaseSchema.ForeignKeyAction = .noAction, | |
name: String? = nil | |
) -> Self where T:Model, U: Model, V: QueryableProperty, W: QueryableProperty { | |
self.schema.createConstraints.append(.constraint( | |
.foreignKey( | |
[.key(T.path(for: field).last!)], | |
U.schema, | |
[.key(U.path(for: foreignField).last!)], | |
onDelete: onDelete, | |
onUpdate: onUpdate | |
), | |
name: name | |
)) | |
return self | |
} | |
public func updateField<T, U>( | |
_ key: KeyPath<T, U>, | |
_ dataType: DatabaseSchema.DataType | |
) -> Self where T: Model, U: QueryableProperty { | |
self.updateField(.dataType( | |
name: .key(T.path(for: key).last!), | |
dataType: dataType | |
)) | |
} | |
} | |
extension DatabaseSchema.FieldConstraint { | |
public static func references<T, U>( | |
_ field: KeyPath<T, U>, | |
onDelete: DatabaseSchema.ForeignKeyAction = .noAction, | |
onUpdate: DatabaseSchema.ForeignKeyAction = .noAction | |
) -> Self where T: Model, U: QueryableProperty { | |
.foreignKey( | |
T.schema, | |
.key(T.path(for: field).last!), | |
onDelete: onDelete, | |
onUpdate: onUpdate | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated for FluentKit 1.0.0-rc.2