This loosens the requirement on the value of a KeyPath passed to Fields.path(for:) to AnyQueryableProperty, which has no associated types or Self requirements, and can thus be treated as an existential (e.g. any AnyQueryableProperty). While existentials are best avoided when possible, in this case, the relaxed definition allows usefully operating on the resolved database field names of an arbitrary set of key paths without the use of variadic generics.
As this is a very confusing and opaque description of the behavior, here is an example of a helper method which was impossible to write before:
extension SchemaBuilder {
func fields<M: FluentKit.Model>(from _: M.Type = M.self, _ keypaths: KeyPath<M, AnyQueryableProperty>...) -> Self {
return keypaths.reduce(self) { builder, keypath in
// N.B.: Despite the name and array type, `Fields.path(for:)` never returns more than one `FieldKey` in practice.
// Implementing `figureOutDataType(for:)` is left as an exercise for the reader.
return builder.field(M.path(for: keypath).first!, figureOutDataType(for: keypath))
}
}
}
// Usage would be something like:
database.schema(M.schema)
.fields(\.$id, \.$foo, \.$bar, \$.baz)
.create()
Previously, such a helper could only have taken a single KeyPath parameter. This is admittedly a contrived example (and by design very far from a complete "automatic migration" implementation), and it's a fairly small convenience to call .fields(a,b,c,d) versus .field(a).field(b).field(c).field(d), but it's nonetheless useful. The generic constraint should never have been so strict in any event. (And field keys should not be wrapped in arrays all the time, but that's a PR for another day.)
Note: While technically the relaxed constraint is a "new" public API, the change is small enough and the difference invisible enough that I've marked this semver-patch; even for me, there's such a thing as being too pedantic about the rules 🙂.
This loosens the requirement on the value of a
KeyPath
passed toFields.path(for:)
toAnyQueryableProperty
, which has no associated types orSelf
requirements, and can thus be treated as an existential (e.g.any AnyQueryableProperty
). While existentials are best avoided when possible, in this case, the relaxed definition allows usefully operating on the resolved database field names of an arbitrary set of key paths without the use of variadic generics.As this is a very confusing and opaque description of the behavior, here is an example of a helper method which was impossible to write before:
Previously, such a helper could only have taken a single
KeyPath
parameter. This is admittedly a contrived example (and by design very far from a complete "automatic migration" implementation), and it's a fairly small convenience to call.fields(a,b,c,d)
versus.field(a).field(b).field(c).field(d)
, but it's nonetheless useful. The generic constraint should never have been so strict in any event. (And field keys should not be wrapped in arrays all the time, but that's a PR for another day.)Note: While technically the relaxed constraint is a "new" public API, the change is small enough and the difference invisible enough that I've marked this semver-patch; even for me, there's such a thing as being too pedantic about the rules 🙂.