2 years ago
#314465

JacobCXDev
Composing property wrappers in Swift with Vapor + Fluent
I've implemented a system to automatically generate Fluent's Migrations by reflecting 'registered' Models, saving the boilerplate of creating them manually. To achieve this, I must allow the specification of any DatabaseSchema.FieldConstraints directly in the Model. Since I'm unable to inherit from FieldProperty, etc. as they're marked as final, this system requires that I use nested property wrappers like so:
final class User: Model {
ā¦
    @Constrained(.required)
    @Field(key: .userForename)
    var forename: String
ā¦
}
Inside the implementation of the @Constrained property wrapper, I have the following code:
@propertyWrapper
class ConstrainedProperty<T, U>: AnyConstrainedProperty where T: Fields, U: AnyProperty {
    // MARK: - Properties
    // MARK: Property Wrapper
    var projectedValue: ConstrainedProperty<T, U> { self }
    var wrappedValue: U
    // MARK: Stored
    var constraints: [DatabaseSchema.FieldConstraint]
    // MARK: - Initialisers
    init(wrappedValue: U, _ constraints: DatabaseSchema.FieldConstraint...) {
        self.wrappedValue = wrappedValue
        self.constraints = constraints
    }
}
// MARK: - Fields
extension Fields {
    typealias Constrained<T> = ConstrainedProperty<Self, T> where T: Property
}
Since wrappedValue is Optional, wrappedValue never being initialised is not an issue and the code compiles just fine. However, if I want wrappedValue not to be Optional and for it to be provided a value when the property wrapper is initialised, the Swift Evolution proposal (SE-0258) states that I should use the following code:
var wrappedValue: T
var constraints: [DatabaseSchema.FieldConstraint]
init(wrappedValue: T, _ constraints: DatabaseSchema.FieldConstraint...) {
    self.wrappedValue = wrappedValue
    self.constraints = constraints
}
(T should be FieldProperty<Model, Value> where Model == Self and Value: Codable.)
Unfortunately, the issue is that Swift complains:

It doesn't appear that Swift's passing the value of the nested property wrapper to the wrappedValue parameter of the initialiser of the outer property wrapper automatically ā I inferred from the proposal that it should; how else would property wrapper composition work š
?
swift
codable
vapor
property-wrapper
vapor-fluent
0 Answers
Your Answer