Skip to content

Build request with closures #1759

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

Merged
merged 41 commits into from
May 11, 2025
Merged

Build request with closures #1759

merged 41 commits into from
May 11, 2025

Conversation

groue
Copy link
Owner

@groue groue commented Apr 12, 2025

This pull request brings a new way to write query interface requests:

struct Player: Codable, Identifiable {
    var id: String
    var name: String
    var score: Int
    var isRegistered: Bool
}

extension Player: FetchableRecord, PersistableRecord {
    enum Columns {
        static let id = Column(CodingKeys.id)
        static let name = Column(CodingKeys.name)
        static let score = Column(CodingKeys.score)
        static let isRegistered = Column(CodingKeys.isRegistered)
    }
}

try dbQueue.read { db in
    // Filter, order, select, group, having now accept a closure.
    // In Swift 6.1, the closure can be written as a key path.
    let registeredPlayers = try Player
        .filter(\.isRegistered)     // NEW (Swift 6.1)
        .filter { $0.isRegistered } // NEW (Swift 6.0)
        .fetchAll(db)
    
    let highEndPlayers = try Player
        .filter { $0.score > 1000 && $0.isRegistered } // NEW
        .fetchAll(db)
    
    let bestPlayers = try Player
        .order(\.score.desc)     // NEW (Swift 6.1+)
        .order { $0.score.desc } // NEW (Swift 6.0)
        .limit(10)
        .fetchAll(db)

     let playersByScore = try Player
        .order { [ // NEW
            $0.score,
            $0.name.collating(.localizedStandardCompare),
        ] }
        .fetchAll(db)
    
    let names = try Player
        .select(\.name, as: String.self)      // NEW (Swift 6.1+)
        .select({ $0.name }, as: String.self) // NEW (Swift 6.0)
        .fetchSet(db)

    // Batch updates
    try Player.updateAll(db) { [$0.score += 10] }
    
    // Association aggregates can be defined with a closure.
    // In Swift 6.1, the closure can be written as a key path.
    let teams = try Team
        .annotated(with: Team.players.max(\.score))     // NEW (Swift 6.1+)
        .annotated(with: Team.players.max { $0.score }) // NEW (Swift 6.0)
}

TODO:

  • enum Columns: String, ColumnExpression { ... }: those do not support the key path syntax, because SE-0438 did not ship with support for enums. We now discourage those enums, because we don't know when the language will improve.
  • Update documentation
  • Update DocC
  • Improve table aliases, so that alias[Foo.Columns.name] can be replaced with alias.name

@groue groue force-pushed the dev/expression-builder branch 2 times, most recently from 507a715 to 02df897 Compare April 12, 2025 18:02
@freak4pc
Copy link
Contributor

Love the syntax 👏

@groue groue force-pushed the dev/expression-builder branch from a27cf10 to c967436 Compare April 26, 2025 15:32
groue added 26 commits May 10, 2025 09:36
so that we can use the new SQLExpressionBuilder
Don't use key paths in tests because they are Swift 6.1+ only
We now recommend:

    enum Columns {
        static let id = Column("id")
        static let title = Column("title")
        static let latitude = Column("latitude")
        static let longitude = Column("longitude")
    }

Instead of the previous recommendation:

    enum Columns: String, ColumnExpression {
        case id, title, latitude, longitude
    }

This is because SE-0438 does not support Metatype Keypaths for enums. A request like `Place.order(\.title)` does not compile with a String enum.
@groue groue force-pushed the dev/expression-builder branch from 56b757c to 4301413 Compare May 10, 2025 07:36
@groue groue force-pushed the dev/expression-builder branch from f476807 to fac0c22 Compare May 10, 2025 12:52
@groue groue force-pushed the dev/expression-builder branch from d1f34c2 to 2316fb3 Compare May 11, 2025 09:12
@groue groue changed the base branch from master to development May 11, 2025 09:13
@groue groue force-pushed the dev/expression-builder branch from 3454e40 to 034b241 Compare May 11, 2025 11:10
@groue groue merged commit 7c2cbfe into development May 11, 2025
8 checks passed
@groue groue deleted the dev/expression-builder branch May 11, 2025 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants