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

Support the use of unions in subqueries #178

Merged
merged 3 commits into from
May 17, 2024
Merged

Support the use of unions in subqueries #178

merged 3 commits into from
May 17, 2024

Conversation

gwynne
Copy link
Member

@gwynne gwynne commented May 17, 2024

These changes are now available in 3.30.0

Adds support for the use of UNION queries within subqueries. Unfortunately, thanks to iffy design choices on my part in the original SQLUnion implementation, the usage is slightly awkward. Example usage:

try await db.update("foos")
    .set(SQLIdentifier("bar_id"), to: SQLSubquery
        .union { $0
            .column("id")
            .from("bars")
            .where("baz", .notEqual, "bamf")
        }
        .union(all: { $0
            .column("id")
            .from("bars")
            .where("baz", .equal, "bop")
        })
        .finish()
    )
    .run()

This generates the following query:

UPDATE "foos"
SET "bar_id" = (
        SELECT "id" FROM "bars" WHERE "baz" <> "bamf"
    UNION ALL
        SELECT "id" FROM "bars" WHERE "baz" = "bop"
)

Unfortunately, it is not possible to chain .union() when using SQLSubquery.select(_:); the call chain must start with SQLSubquery.union(_:).

… to bad design choices in the original union support (my bad), this turns out to be mildly annoying to actually use and extremely painful to follow in the actual implementation.
@gwynne gwynne added enhancement New feature or request semver-minor Contains new APIs labels May 17, 2024
@gwynne gwynne requested review from 0xTim, MahdiBM and ptoffy May 17, 2024 18:19
Copy link

codecov bot commented May 17, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (9afdc96) to head (9b9f663).

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #178   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           97        98    +1     
  Lines         2551      2565   +14     
=========================================
+ Hits          2551      2565   +14     
Files Coverage Δ
.../Builders/Implementations/SQLSubqueryBuilder.swift 100.00% <100.00%> (ø)
...Kit/Builders/Implementations/SQLUnionBuilder.swift 100.00% <100.00%> (ø)
...it/Builders/Prototypes/SQLCommonUnionBuilder.swift 100.00% <100.00%> (ø)
...urces/SQLKit/Expressions/Clauses/SQLSubquery.swift 100.00% <100.00%> (ø)

... and 1 file with indirect coverage changes

@gwynne
Copy link
Member Author

gwynne commented May 17, 2024

API breakage notes:

  • The change from SQLSelectBuilder to any SQLSubqueryClauseBuilder in the parameters for the SQSelectBuilder extension methods is an API break but has no actual effect, as SQLSelectBuilder provides no API that the protocol doesn't (or at least, none that can be used in the relevant context).
  • The removed methods on SQLUnionBuilder are now provided as extension methods on the SQLCommonUnionBuilder protocol instead.

Copy link

@MahdiBM MahdiBM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're sure about the API breakage.

@gwynne
Copy link
Member Author

gwynne commented May 17, 2024

I am, actually 🙂. Look at the definition of SQLSelectBuilder. The only method of its own it defines is an initializer, and the SQLQueryBuilder and SQLQueryFetcher methods aren't callable within sub-builder closures (they're all asynchronous; there's nowhere to go with an ELF (anyone calling .wait() in that context frankly deserves what they get) and you can't await in a non-async closure).

@gwynne gwynne merged commit 25d8170 into main May 17, 2024
11 of 12 checks passed
@gwynne gwynne deleted the unions-in-subqueries branch May 17, 2024 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request semver-minor Contains new APIs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants