-
-
Notifications
You must be signed in to change notification settings - Fork 861
[Pg] Add support for left and inner lateral join in postgres #1079
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
[Pg] Add support for left and inner lateral join in postgres #1079
Conversation
@alexvuka1 could you please resolve conflicts? Also I'll let @dankochetov to take from here as well. Need his eyes here |
46925c6
to
a1a8ede
Compare
@alexvuka1 1 last thing needed from you. Please sign all commits |
739c4ff
to
014b164
Compare
09a3d73
to
d0d3b2b
Compare
@dankochetov just a kind reminder that it's waiting for the review. I'd love to have it move upstream! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change the PR target to the beta branch (you'll probably have merge conflicts)
Signed-off-by: Alex Vukadinov <[email protected]>
Signed-off-by: Alex Vukadinov <[email protected]>
209819b
to
47b48f1
Compare
Rebased and changed target to beta branch. |
In the mean time before this commit is merged, is there a way to use custom join in drizzle now? |
Any update on this? Would love to convert a few lateral subqueries using the raw sql builder to use the query builder. |
@dankochetov Just checking to see what the status on this might be :) would love to start leveraging |
+1 |
can we merge this? |
+1 |
@dankochetov Wondering if there are further changes needed to this, as many of us would love to start using this as soon as possible. |
I hope to use it soon in the project with drizzle. |
@dankochetov would be awesome to merge this. |
Any update on this? |
+1 |
1 similar comment
+1 |
@dankochetov @AndriiSherman curious where this might fit into the roadmap? |
Yes, this is one step for Drizzle to cover the full SQL spectrum. It's much needed to be able to build related objects. |
Hey guys, what's the status with this PR? |
Just adding our 👍 / request for an update on this PR to the list! We would definitely benefit from pulling this in. |
+1 here - I'd use this immediately also! |
+1 Same |
Yes, this would be very helpful for optimizing some larger queries that are composed of multiple parts. Not everything can be easily turned into relational queries, so I'm hopeful this will be merged soon! |
Would love a status update! Does this PR need work? Is a custom join method possible? I can see how it might be a lot of work to get "custom joins" working with TypeScript if someone were to try using lateral in a custom join for example. Are we waiting on someone to add lateral to the rest of the supported databases? |
+1 |
@AndriiSherman @dankochetov circling back to this... this would still be very helpful. Would really appreciate understanding where this falls in the roadmap |
I'm not sure why this PR hasn't been merged. These changes are exposing a functionality that is already supported by drizzle and that is used on the query builder. For anyone who needs lateral query support now, here is a patch based on the changes contained in this PR. All credits to @alexvuka1. Click here to see the patchdiff --git a/pg-core/query-builders/select.d.ts b/pg-core/query-builders/select.d.ts
index 2a4ebd99c56baf1ed5264844e5d332130f1bfe0b..92f1165027cd23eafb84ac4bcec29f8b9cced478 100644
--- a/pg-core/query-builders/select.d.ts
+++ b/pg-core/query-builders/select.d.ts
@@ -98,7 +98,16 @@ export declare abstract class PgSelectQueryBuilderBase<THKT extends PgSelectHKTB
* .leftJoin(pets, eq(users.id, pets.ownerId))
* ```
*/
- leftJoin: PgSelectJoinFn<this, TDynamic, "left">;
+ leftJoin: PgSelectJoinFn<this, TDynamic, "left", false>;
+ /**
+ * For each row of the table, include
+ * values from a matching row of the joined
+ * subquery, if there is a matching row. If not,
+ * all of the columns of the joined subquery
+ * will be set to null. The lateral keyword allows
+ * access to columns after the FROM statement.
+ */
+ leftJoinLateral: PgSelectJoinFn<this, TDynamic, "left", true>;
/**
* Executes a `right join` operation by adding another table to the current query.
*
@@ -126,7 +135,7 @@ export declare abstract class PgSelectQueryBuilderBase<THKT extends PgSelectHKTB
* .rightJoin(pets, eq(users.id, pets.ownerId))
* ```
*/
- rightJoin: PgSelectJoinFn<this, TDynamic, "right">;
+ rightJoin: PgSelectJoinFn<this, TDynamic, "right", false>;
/**
* Executes an `inner join` operation, creating a new table by combining rows from two tables that have matching values.
*
@@ -154,7 +163,14 @@ export declare abstract class PgSelectQueryBuilderBase<THKT extends PgSelectHKTB
* .innerJoin(pets, eq(users.id, pets.ownerId))
* ```
*/
- innerJoin: PgSelectJoinFn<this, TDynamic, "inner">;
+ innerJoin: PgSelectJoinFn<this, TDynamic, "inner", false>;
+ /**
+ * For each row of the table, the joined subquery
+ * needs to have a matching row, or it will
+ * be excluded from results. The lateral keyword allows
+ * access to columns after the FROM statement.
+ */
+ innerJoinLateral: PgSelectJoinFn<this, TDynamic, "inner", true>;
/**
* Executes a `full join` operation by combining rows from two tables into a new table.
*
@@ -182,7 +198,7 @@ export declare abstract class PgSelectQueryBuilderBase<THKT extends PgSelectHKTB
* .fullJoin(pets, eq(users.id, pets.ownerId))
* ```
*/
- fullJoin: PgSelectJoinFn<this, TDynamic, "full">;
+ fullJoin: PgSelectJoinFn<this, TDynamic, "full", false>;
private createSetOperator;
/**
* Adds `union` set operator to the query.
diff --git a/pg-core/query-builders/select.js b/pg-core/query-builders/select.js
index ae18634ef1ca087222f9be341eccf7c08594b40c..614b6049de6d8fe72537e2ff9e26f69eb3cb1045 100644
--- a/pg-core/query-builders/select.js
+++ b/pg-core/query-builders/select.js
@@ -97,7 +97,7 @@ class PgSelectQueryBuilderBase extends TypedQueryBuilder {
this.tableName = getTableLikeName(table);
this.joinsNotNullableMap = typeof this.tableName === "string" ? { [this.tableName]: true } : {};
}
- createJoin(joinType) {
+ createJoin(joinType, lateral = false) {
return (table, on) => {
const baseTableName = this.tableName;
const tableName = getTableLikeName(table);
@@ -126,7 +126,7 @@ class PgSelectQueryBuilderBase extends TypedQueryBuilder {
if (!this.config.joins) {
this.config.joins = [];
}
- this.config.joins.push({ on, table, joinType, alias: tableName });
+ this.config.joins.push({ on, table, joinType, alias: tableName, lateral });
if (typeof tableName === "string") {
switch (joinType) {
case "left": {
@@ -184,6 +184,17 @@ class PgSelectQueryBuilderBase extends TypedQueryBuilder {
* ```
*/
leftJoin = this.createJoin("left");
+
+ /**
+ * For each row of the table, include
+ * values from a matching row of the joined
+ * subquery, if there is a matching row. If not,
+ * all of the columns of the joined subquery
+ * will be set to null. The lateral keyword allows
+ * access to columns after the FROM statement.
+ */
+ leftJoinLateral = this.createJoin("left", true);
+
/**
* Executes a `right join` operation by adding another table to the current query.
*
@@ -240,6 +251,15 @@ class PgSelectQueryBuilderBase extends TypedQueryBuilder {
* ```
*/
innerJoin = this.createJoin("inner");
+
+ /**
+ * For each row of the table, the joined subquery
+ * needs to have a matching row, or it will
+ * be excluded from results. The lateral keyword allows
+ * access to columns after the FROM statement.
+ */
+ innerJoinLateral = this.createJoin("inner", true);
+
/**
* Executes a `full join` operation by combining rows from two tables into a new table.
*
diff --git a/pg-core/query-builders/select.types.d.ts b/pg-core/query-builders/select.types.d.ts
index 8c5ef9c39bbbf0f999b3ddc39f8f57a3648aab81..24a8187fcc9a031ad18a324249713d02d073dd49 100644
--- a/pg-core/query-builders/select.types.d.ts
+++ b/pg-core/query-builders/select.types.d.ts
@@ -51,7 +51,7 @@ export interface PgSelectConfig {
}[];
}
export type PgSelectJoin<T extends AnyPgSelectQueryBuilder, TDynamic extends boolean, TJoinType extends JoinType, TJoinedTable extends PgTable | Subquery | PgViewBase | SQL, TJoinedName extends GetSelectTableName<TJoinedTable> = GetSelectTableName<TJoinedTable>> = T extends any ? PgSelectWithout<PgSelectKind<T['_']['hkt'], T['_']['tableName'], AppendToResult<T['_']['tableName'], T['_']['selection'], TJoinedName, TJoinedTable extends Table ? TJoinedTable['_']['columns'] : TJoinedTable extends Subquery ? Assume<TJoinedTable['_']['selectedFields'], SelectedFields> : never, T['_']['selectMode']>, T['_']['selectMode'] extends 'partial' ? T['_']['selectMode'] : 'multiple', AppendToNullabilityMap<T['_']['nullabilityMap'], TJoinedName, TJoinType>, T['_']['dynamic'], T['_']['excludedMethods']>, TDynamic, T['_']['excludedMethods']> : never;
-export type PgSelectJoinFn<T extends AnyPgSelectQueryBuilder, TDynamic extends boolean, TJoinType extends JoinType> = <TJoinedTable extends PgTable | Subquery | PgViewBase | SQL, TJoinedName extends GetSelectTableName<TJoinedTable> = GetSelectTableName<TJoinedTable>>(table: TJoinedTable, on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined) => PgSelectJoin<T, TDynamic, TJoinType, TJoinedTable, TJoinedName>;
+export type PgSelectJoinFn<T extends AnyPgSelectQueryBuilder, TDynamic extends boolean, TJoinType extends JoinType, TIsLateral extends boolean> = <TJoinedTable extends (TIsLateral extends true ? Subquery | SQL : PgTable | Subquery | PgViewBase | SQL), TJoinedName extends GetSelectTableName<TJoinedTable> = GetSelectTableName<TJoinedTable>>(table: TJoinedTable, on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined) => PgSelectJoin<T, TDynamic, TJoinType, TJoinedTable, TJoinedName>;
export type SelectedFieldsFlat = SelectedFieldsFlatBase<PgColumn>;
export type SelectedFields = SelectedFieldsBase<PgColumn, PgTable>;
export type SelectedFieldsOrdered = SelectedFieldsOrderedBase<PgColumn>;
Edit: |
Another related PR is #1669, which adds support for CROSS JOIN. Still waiting for both. 🙏🏼🙏🏼🙏🏼 |
+1 |
…to feature/drizzle-teamGH-420-join-lateral-support
…izzle-orm into feature/drizzle-teamGH-420-join-lateral-support
* Add support for cross join (#1669) * Add cross join support * Add cross join tests * Updated docs links (docs TBD) * Merged cross join function types into join function types, fixed missing cases for `cross` join type, ordered `crossJoin` test queries * `onIndex` support for `MySQL` `crossJoin`, fixed lack of `onIndex` param description in JSDoc, additional tests, disabled test case failing due to driver's issue --------- Co-authored-by: Sukairo-02 <[email protected]> * Export `PgTextBuilderInitial` type (#1286) * MySQL: Removed .fullJoin() from MySQL Api (#1351) Added new type MySqlJoinType which excludes the option for full joins and is used in the MySQL query builder createJoin function instead of the regular JoinType. Also removed two MySQL select type-tests which included the fullJoin function Co-authored-by: Sukairo-02 <[email protected]> * [Pg] Add support for left and inner lateral join in postgres (#1079) * feat: added support for left and inner lateral join in postgres Signed-off-by: Alex Vukadinov <[email protected]> * chore: updated method descriptions on the new joins Signed-off-by: Alex Vukadinov <[email protected]> * GH-420 allowing sql inside lateral joins and revert package.json * GH-420 reverted package.json empty line at the end * Changed JSDoc [WIP], reversed check --------- Signed-off-by: Alex Vukadinov <[email protected]> Co-authored-by: Sukairo-02 <[email protected]> * Completed `left`, `inner`, `cross` lateral joins in `postgresql`, `mysql`, `gel`, `singlestore`, disabled implicit `schema.table` prefixes in column selections on single table selections for `gel` due to possible errors in subqueries on column name matches in inner and outer queries, added\altered related tests * [SingleStore] Add Connection Attributes and Fix Options (#4417) * add connection attributes to SingleStore driver connection * fix allowing connection strings/options rather than external pool --------- Co-authored-by: Andrii Sherman <[email protected]> * Fix for #2654, related tests (#4353) * Dprint * Bumped version, added changelog, fixed broken test case * fix(3554) Correct spelling of `nowait` flag (#3555) * Fixed `nowait` in `Gel`, `SingleStore`, added change to changelog * Updated changelog * Fixed broken test case * Fixed `nowait` tests in `bun-sql`, `mysql-prefixed` * Add changelog updates --------- Signed-off-by: Alex Vukadinov <[email protected]> Co-authored-by: L-Mario564 <[email protected]> Co-authored-by: Dan Imhoff <[email protected]> Co-authored-by: Itay Ben-Ami <[email protected]> Co-authored-by: Alex Vukadinov <[email protected]> Co-authored-by: Mitchell Adair <[email protected]> Co-authored-by: Andrii Sherman <[email protected]> Co-authored-by: Jacob Elder <[email protected]>
No description provided.