Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter joined ModelAlias(es) by shared properties #431

Closed
jerrycanco opened this issue May 18, 2021 · 0 comments · Fixed by #593 · May be fixed by #432
Closed

Filter joined ModelAlias(es) by shared properties #431

jerrycanco opened this issue May 18, 2021 · 0 comments · Fixed by #593 · May be fixed by #432
Labels
enhancement New feature or request

Comments

@jerrycanco
Copy link

Existing Problem
Fluent queries do not permit conditional filtering by properties shared among joined ModelAlias(es). Currently, you can only create a filter such as this on the originally queried model. For example, this is currently possible:

final class HomeTeam: ModelAlias {
    static let name = "home_teams"
    let model = Team()
}
final class AwayTeam: ModelAlias {
    static let name = "away_teams"
    let model = Team()
}
 
/// Find games that were popular enough for the crowd to be larger
/// than the number of players playing it.        
Match.query(on: self.database)
    .join(HomeTeam.self, on: \Match.$homeTeam.$id == \HomeTeam.$id)
    .join(AwayTeam.self, on: \Match.$awayTeam.$id == \AwayTeam.$id)
    /// You can currently conditionally filter the originally 
    /// queried Model type if types match (in this case,  
    /// crowd size and total players would be of type Int)
    .filter(\Match.$crowd, .greaterThan, \Match.$totalPlayers)
    .all()

Proposed Solution
Query builders would allow conditional filtering of joined ModelAliases. The call site would look something like:

Match.query(on: self.database)
    .join(HomeTeam.self, on: \Match.$homeTeam.$id == \HomeTeam.$id)
    .join(AwayTeam.self, on: \Match.$awayTeam.$id == \AwayTeam.$id)
    /// Here you can filter a ModelAlias according to properties shared with 
    /// another ModelAlias of the same original Model type.
    .filter(\HomeTeam.$score, .greaterThan, \AwayTeam.$score)
    .all()

To achieve this, I imagine a modification of QueryBuilder+Filter.swift whereby existing filter methods are combined something similar to below to allow conditional filtering on Joined types:

    /// Please note this code is for demonstration only 
    /// and is not functional.
    @discardableResult
    public func filter<Left, Right>(
        _ lhsField: KeyPath<FirstModelAlias, Left>,
        _ method: DatabaseQuery.Filter.Method,
        _ rhsField: KeyPath<SecondModelAlias, Right>
    ) -> Self
        where Left: QueryableProperty,
            Left.Model == FirstModelAlias,
            Right: QueryableProperty,
            Right.Model == SecondModelAlias
    {
        self.filter(FirstModelAlias.path(for: lhsField), method, SecondModelAlias.path(for: rhsField))
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
1 participant