Nested array/set filtering
Given the following model:
class MyModel: Model {
static let schema = ""
@ID(key: .id)
var id: UUID?
@OptionalField(key: "field")
var field: Set<String>?
required init() { }
}
Running this filter does not compile:
let db: Database = { fatalError() }()
let a = Set(["a"])
MyModel.query(on: db).filter(\.$field ~~ a) // Does not work
MyModel.query(on: db).filter(\.$field ~~ ["a"]) // Does not work
MyModel.query(on: db).filter(\.$field, .subset(inverse: false), a) // It works
MyModel.query(on: db).filter(\.$field, .subset(inverse: false), ["a"]) // It works
I think here
The correct constraints are:
public func ~~ <Model, Field, Values>(lhs: KeyPath<Model, Field>, rhs: Values) -> ModelValueFilter<Model>
where Model: FluentKit.Model,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped: Collection & Codable,
Values: Collection,
Values.Element == Field.Value.Wrapped.Element
instead of:
public func ~~ <Model, Field, Values>(lhs: KeyPath<Model, Field>, rhs: Values) -> ModelValueFilter<Model>
where Model: FluentKit.Model,
Field: FieldProtocol,
Field.Value: OptionalType,
Field.Value.Wrapped: Codable,
Values: Collection,
Values.Element == Field.Value.Wrapped
{
Same bug seem to apply to other operators as well.
Sorry, deleted original comment as I'm realizing I misread and this has not been fixed.
Fluent doesn't yet support filtering on nested array and dictionary fields. I'm not sure exactly how this would work either since underlying driver support varies greatly.
For Postgres at least, you should be able to use the @> operator. Read more here: https://www.postgresql.org/docs/9.2/functions-array.html
Leaving this issue open as an enhancement to track nested array filtering.
Sorry, deleted original comment as I'm realizing I misread and this has not been fixed.
Fluent doesn't yet support filtering on nested array and dictionary fields. I'm not sure exactly how this would work either since underlying driver support varies greatly.
For Postgres at least, you should be able to use the
@>operator. Read more here: https://www.postgresql.org/docs/9.2/functions-array.htmlLeaving this issue open as an enhancement to track nested array filtering.
Why it could not be supported with custom operators ?
// Examaple
try await SomeModel
.query(on: db)
.filter(\.$stringsArrayField, .custom("&&"), "'{\"one\", \"two\"}'")
.all()
@ypotsiah in this instance he means custom Swift operators, so something like .filter(\.$stringsArrayField @> "'{\"one\", \"two\"}'"). You can do this by passing in your own custom operator as shown in your snippet
@ypotsiah in this instance he means custom Swift operators, so something like
.filter(\.$stringsArrayField @> "'{\"one\", \"two\"}'"). You can do this by passing in your own custom operator as shown in your snippet
@0xTim Unfortunately, my snippet is not compilable. Because existing implementation is:
@discardableResult
public func filter<Field>(
_ field: KeyPath<Model, Field>,
_ method: DatabaseQuery.Filter.Method,
_ value: Field.Value
) -> Self
where Field: QueryableProperty, Field.Model == Model
{
self.filter(.extendedPath(
Model.path(for: field),
schema: Model.schemaOrAlias,
space: Model.spaceIfNotAliased
), method, Field.queryValue(value))
}
To use custom values I have to implement something like that in my own QueryBuilder extension:
extension QueryBuilder {
@discardableResult
public func customFilter<Field>(
_ field: KeyPath<Model, Field>,
_ method: DatabaseQuery.Filter.Method,
_ value: DatabaseQuery.Value
) -> Self
where Field: QueryableProperty, Field.Model == Model
{
self.filter(.extendedPath(
Model.path(for: field),
schema: Model.schemaOrAlias,
space: Model.alias == nil ? Model.space : nil
), method, value)
}
}
So maybe better to have it "out of the box" in Fluent? If somebody would like to use custom part of query - it seems good addition instead of create full query with SQLKit after casting database to SQLDatabase.
I'm going to defer to @gwynne here as this kind of change is probably out of scope for Fluent 4 (though there very well may a way to do this already, worst case SQLKit) but useful to add to the requests for Fluent 5