Skip to content

Commit

Permalink
Relax restrictions on ModelAlias use and join conditions (#593)
Browse files Browse the repository at this point in the history
* Future-proof a couple declarations
* Relax the generic requirements on the field/field, array, and string operators from Model to Schema so ModelAliases can be used.
* Enable SQL embedding and arbitrary value comparisons in Fluent join operators.
  • Loading branch information
gwynne authored Feb 1, 2024
1 parent 0a2b448 commit 3ae5187
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 38 deletions.
6 changes: 6 additions & 0 deletions Sources/FluentBenchmark/Tests/JoinTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ extension FluentBenchmarker {
.all().wait()

XCTAssertFalse(planets.isEmpty)

let morePlanets = try Planet.query(on: self.database)
.join(Star.self, on: \Planet.$star.$id == \Star.$id && \Star.$name != "Sun")
.all().wait()

XCTAssertEqual(morePlanets.count, 1)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/FluentKit/Database/Database+Logging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,5 @@ extension LoggingOverrideDatabase: SQLDatabase where D: SQLDatabase {
self.database.execute(sql: query, onRow)
}
var dialect: SQLDialect { self.database.dialect }
var version: SQLDatabaseReportedVersion? { self.database.version }
var version: (any SQLDatabaseReportedVersion)? { self.database.version }
}
2 changes: 1 addition & 1 deletion Sources/FluentKit/Operators/FieldOperators.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public func !=~ <Left, Right, LeftField, RightField>(
}

public struct ModelFieldFilter<Left, Right>
where Left: FluentKit.Model, Right: FluentKit.Model
where Left: FluentKit.Schema, Right: FluentKit.Schema
{
public init<LeftField, RightField>(
_ lhs: KeyPath<Left, LeftField>,
Expand Down
12 changes: 6 additions & 6 deletions Sources/FluentKit/Operators/ValueOperators+Array.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// MARK: Field.Value

public func ~~ <Model, Field, Values>(lhs: KeyPath<Model, Field>, rhs: Values) -> ModelValueFilter<Model>
where Model: FluentKit.Model,
where Model: FluentKit.Schema,
Field: QueryableProperty,
Values: Collection,
Values.Element == Field.Value
Expand All @@ -10,7 +10,7 @@ public func ~~ <Model, Field, Values>(lhs: KeyPath<Model, Field>, rhs: Values) -
}

public func ~~ <Model, Field, Values>(lhs: KeyPath<Model, Field>, rhs: Values) -> ModelValueFilter<Model>
where Model: FluentKit.Model,
where Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped: Codable,
Expand All @@ -21,7 +21,7 @@ public func ~~ <Model, Field, Values>(lhs: KeyPath<Model, Field>, rhs: Values) -
}

public func !~ <Model, Field, Values>(lhs: KeyPath<Model, Field>, rhs: Values) -> ModelValueFilter<Model>
where Model: FluentKit.Model,
where Model: FluentKit.Schema,
Field: QueryableProperty,
Values: Collection,
Values.Element == Field.Value
Expand All @@ -30,7 +30,7 @@ public func !~ <Model, Field, Values>(lhs: KeyPath<Model, Field>, rhs: Values) -
}

public func !~ <Model, Field, Values>(lhs: KeyPath<Model, Field>, rhs: Values) -> ModelValueFilter<Model>
where Model: FluentKit.Model,
where Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped: Codable,
Expand All @@ -43,13 +43,13 @@ public func !~ <Model, Field, Values>(lhs: KeyPath<Model, Field>, rhs: Values) -
// MARK: DatabaseQuery.Value

public func ~~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where Model: FluentKit.Model, Field: QueryableProperty
where Model: FluentKit.Schema, Field: QueryableProperty
{
.init(lhs, .subset(inverse: false), rhs)
}

public func !~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where Model: FluentKit.Model, Field: QueryableProperty
where Model: FluentKit.Schema, Field: QueryableProperty
{
.init(lhs, .subset(inverse: true), rhs)
}
48 changes: 24 additions & 24 deletions Sources/FluentKit/Operators/ValueOperators+String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

public func ~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value == String
{
Expand All @@ -11,7 +11,7 @@ public func ~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelV

public func ~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped == String
Expand All @@ -21,7 +21,7 @@ public func ~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelV

public func ~~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value == String
{
Expand All @@ -30,7 +30,7 @@ public func ~~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelV

public func ~~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped == String
Expand All @@ -40,7 +40,7 @@ public func ~~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelV

public func =~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value == String
{
Expand All @@ -49,7 +49,7 @@ public func =~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelV

public func =~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped == String
Expand All @@ -59,7 +59,7 @@ public func =~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelV

public func !~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value == String
{
Expand All @@ -68,7 +68,7 @@ public func !~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> Model

public func !~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped == String
Expand All @@ -78,7 +78,7 @@ public func !~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> Model

public func !~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value == String
{
Expand All @@ -87,7 +87,7 @@ public func !~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelV

public func !~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped == String
Expand All @@ -97,7 +97,7 @@ public func !~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelV

public func !=~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value == String
{
Expand All @@ -106,7 +106,7 @@ public func !=~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> Model

public func !=~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped == String
Expand All @@ -118,7 +118,7 @@ public func !=~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: String) -> Model

public func ~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: CustomStringConvertible
{
Expand All @@ -127,7 +127,7 @@ public func ~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Val

public func ~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped: CustomStringConvertible
Expand All @@ -137,7 +137,7 @@ public func ~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Val

public func ~~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: CustomStringConvertible
{
Expand All @@ -146,7 +146,7 @@ public func ~~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Val

public func ~~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped: CustomStringConvertible
Expand All @@ -156,7 +156,7 @@ public func ~~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Val

public func =~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: CustomStringConvertible
{
Expand All @@ -165,7 +165,7 @@ public func =~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Val

public func =~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped: CustomStringConvertible
Expand All @@ -175,7 +175,7 @@ public func =~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Val

public func !~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: CustomStringConvertible
{
Expand All @@ -184,7 +184,7 @@ public func !~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Va

public func !~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped: CustomStringConvertible
Expand All @@ -194,7 +194,7 @@ public func !~= <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Va

public func !~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: CustomStringConvertible
{
Expand All @@ -203,7 +203,7 @@ public func !~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Val

public func !~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped: CustomStringConvertible
Expand All @@ -213,7 +213,7 @@ public func !~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Val

public func !=~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: CustomStringConvertible
{
Expand All @@ -222,7 +222,7 @@ public func !=~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Va

public func !=~ <Model, Field>(lhs: KeyPath<Model, Field>, rhs: DatabaseQuery.Value) -> ModelValueFilter<Model>
where
Model: FluentKit.Model,
Model: FluentKit.Schema,
Field: QueryableProperty,
Field.Value: OptionalType,
Field.Value.Wrapped: CustomStringConvertible
Expand Down
35 changes: 31 additions & 4 deletions Sources/FluentKit/Query/Builder/QueryBuilder+Join.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ extension QueryBuilder {
self.query.joins.append(join)
return self
}

}

// MARK: Local == Foreign
Expand Down Expand Up @@ -139,21 +138,41 @@ public func != <Foreign, ForeignField, Local, LocalField>(

// MARK: Filter && combinator

/// a ==/!= b && c ==/!= d
/// `a ==/!= b && c ==/!= d`
public func && (lhs: ComplexJoinFilter, rhs: ComplexJoinFilter) -> ComplexJoinFilterGroup {
.init(filters: [lhs, rhs])
}

/// (a == b && c != d) && e != f
/// `a ==/!= b && c >/< 1`
public func && <Model: Schema> (lhs: ComplexJoinFilter, rhs: ModelValueFilter<Model>) -> ComplexJoinFilterGroup {
.init(filters: [lhs, .init(rhs)])
}

/// `c >/< 1 && a ==/!= b`
public func && <Model: Schema> (lhs: ModelValueFilter<Model>, rhs: ComplexJoinFilter) -> ComplexJoinFilterGroup {
.init(filters: [.init(lhs), rhs])
}

/// `(a == b && c != d) && e != f`
public func && (lhs: ComplexJoinFilterGroup, rhs: ComplexJoinFilter) -> ComplexJoinFilterGroup {
.init(filters: lhs.filters + [rhs])
}

// e != f && (a == b && c != d)
/// `(a == b && c != d) && e < 1`
public func && <Model: Schema>(lhs: ComplexJoinFilterGroup, rhs: ModelValueFilter<Model>) -> ComplexJoinFilterGroup {
.init(filters: lhs.filters + [.init(rhs)])
}

/// `e != f && (a == b && c != d)`
public func && (lhs: ComplexJoinFilter, rhs: ComplexJoinFilterGroup) -> ComplexJoinFilterGroup {
.init(filters: [lhs] + rhs.filters)
}

/// `e > 1 && (a == b && c != d)`
public func && <Model: Schema>(lhs: ModelValueFilter<Model>, rhs: ComplexJoinFilterGroup) -> ComplexJoinFilterGroup {
.init(filters: [.init(lhs)] + rhs.filters)
}

// MARK: - Struct definitions

/// This wrapper type allows the compiler to better constrain the overload set for global operators, reducing
Expand All @@ -165,6 +184,14 @@ public struct ComplexJoinFilter {
self.filter = filter
}

init<Model: Schema>(_ filter: ModelValueFilter<Model>) {
self.init(filter: .value(
.extendedPath(filter.path, schema: Model.schemaOrAlias, space: Model.spaceIfNotAliased),
filter.method,
filter.value
))
}

init<Left, LField, Right, RField>(
_ lhs: KeyPath<Left, LField>, _ method: DatabaseQuery.Filter.Method, _ rhs: KeyPath<Right, RField>
) where Left: Schema, Right: Schema, LField: QueryableProperty, RField: QueryableProperty, LField.Value == RField.Value {
Expand Down
14 changes: 14 additions & 0 deletions Sources/FluentSQL/DatabaseQuery+SQL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ extension DatabaseQuery.Filter {
}
}

extension DatabaseQuery.Join {
public static func sql(raw: String) -> Self {
.sql(SQLRaw(raw))
}

public static func sql(embed: SQLQueryString) -> Self {
.sql(embed)
}

public static func sql(_ expression: SQLExpression) -> Self {
.custom(expression)
}
}

extension DatabaseQuery.Sort {
public static func sql(raw: String) -> Self {
.sql(SQLRaw(raw))
Expand Down
4 changes: 2 additions & 2 deletions Sources/FluentSQL/SQLQueryConverter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,9 @@ private struct EncodableDatabaseInput: Encodable {
let input: [FieldKey: DatabaseQuery.Value]

func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: SomeCodingKey.self)
var container = encoder.container(keyedBy: FluentKit.SomeCodingKey.self)
for (key, value) in self.input {
try container.encode(EncodableDatabaseValue(value: value), forKey: SomeCodingKey(stringValue: key.description))
try container.encode(EncodableDatabaseValue(value: value), forKey: FluentKit.SomeCodingKey(stringValue: key.description))
}
}
}
Expand Down

0 comments on commit 3ae5187

Please sign in to comment.