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

Feat: Set operations (union / intersect / except) support #1218

Merged
merged 36 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
26db589
(Mysql) Initial implementation of Set Operations support
Angelelz Sep 14, 2023
2899623
Initial implementation of Set Operations support for postgres
Angelelz Sep 14, 2023
943945a
Progress on type for only union in Mysql. More work needed
Angelelz Sep 14, 2023
06ed8de
Added generic types to mysql Set Operation to generate type errors if…
Angelelz Sep 15, 2023
273a884
Added support to pass multiple arguments to the standalone set operat…
Angelelz Sep 16, 2023
4c2f929
Added function support to the set operators methods in mysql
Angelelz Sep 17, 2023
c842f4d
(Mysql) fixed set operator function accepting only one parameter
Angelelz Sep 17, 2023
a21e386
(mysql) added type tests for the set operators
Angelelz Sep 17, 2023
8def9d6
[MySql] fixed type issue with the rest parameters passed to the set o…
Angelelz Sep 20, 2023
907605a
Added test for mysql implementation of set operators
Angelelz Sep 20, 2023
3893876
[Pg] Completed implementation of set operations
Angelelz Sep 21, 2023
87479a7
[Pg] Added type tests for the set operators
Angelelz Sep 21, 2023
4e371fb
[Pg] Added integration tests for the set operators
Angelelz Sep 21, 2023
35a525d
[SQLite] Completed implementation of set operators
Angelelz Sep 21, 2023
e555c09
[SQLite] Added type tests
Angelelz Sep 21, 2023
14f996b
[SQLite] Added integration tests for all cases
Angelelz Sep 21, 2023
8808a1f
[All] Completed implementation with requested changes
Angelelz Sep 23, 2023
9281dc2
[All] code cleanup and eslint rules fix
Angelelz Sep 24, 2023
7618db5
[All] Added offset
Angelelz Sep 24, 2023
85be035
[All] added `.as()` method to create subqueries from set operations. …
Angelelz Sep 24, 2023
256a292
[All] Moved the query construction logic to the each dialect
Angelelz Sep 24, 2023
1bcd418
Merge branch 'beta' into feat-union
Angelelz Oct 6, 2023
d38f3b4
[All] Resolved merge conflicts. Need to fix types
Angelelz Oct 6, 2023
152aa37
[SQLite] fixed types, addressed comments and added new type tests
Angelelz Oct 14, 2023
3c925d6
[SQLite] deleted commented code and improved error readability
Angelelz Oct 14, 2023
e763b29
[MySql] fixed types, addressed comments and added new type tests
Angelelz Oct 14, 2023
0b1d5ae
[Pg] fixed types, addressed comments and added new type tests, fixed …
Angelelz Oct 15, 2023
f4794c6
Merge branch 'beta' into feat-union
Angelelz Oct 15, 2023
57889e1
[All] fix typescript errors
Angelelz Oct 15, 2023
8fcd2d4
[MySql] Simplification by removing intermediary clases and making the…
Angelelz Oct 20, 2023
c8117b1
[Pg] Simplification by removing intermediary clases and making the qu…
Angelelz Oct 20, 2023
c7846b9
[SQLite] Simplification by removing intermediary clases and making th…
Angelelz Oct 20, 2023
1128c12
[MySql] Types simplification from review and fixed tests for western …
Angelelz Oct 31, 2023
99b2a3c
[Pg] Types simplification from review
Angelelz Oct 31, 2023
af5387f
[SQLite] Types simplification from review
Angelelz Oct 31, 2023
a83ea7d
[MySql] fixed failing tests based on query order
Angelelz Oct 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions drizzle-orm/src/libsql/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,15 @@ import {
} from '~/relations.ts';
import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts';
import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts';
import type {
SQLiteDelete,
SQLiteInsert,
SQLiteSelect,
SQLiteUpdate,
} from '~/sqlite-core/index.ts';
import type { SQLiteDelete, SQLiteInsert, SQLiteSelect, SQLiteUpdate } from '~/sqlite-core/index.ts';
import type { SQLiteRelationalQuery } from '~/sqlite-core/query-builders/query.ts';
import type { SQLiteRaw } from '~/sqlite-core/query-builders/raw.ts';
import { type DrizzleConfig } from '~/utils.ts';
import { LibSQLSession } from './session.ts';

export type BatchParameters =
| SQLiteUpdate<any, 'async', ResultSet, any>
| SQLiteSelect<any, 'async', ResultSet, any, any>
| SQLiteSelect<any, 'async', ResultSet, any, any, any>
| SQLiteDelete<any, 'async', ResultSet, any>
| Omit<SQLiteDelete<any, 'async', ResultSet, any>, 'where'>
| Omit<SQLiteUpdate<any, 'async', ResultSet, any>, 'where'>
Expand Down
49 changes: 49 additions & 0 deletions drizzle-orm/src/mysql-core/dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { MySqlColumn } from './columns/common.ts';
import type { MySqlDeleteConfig } from './query-builders/delete.ts';
import type { MySqlInsertConfig } from './query-builders/insert.ts';
import type { Join, MySqlSelectConfig, SelectedFieldsOrdered } from './query-builders/select.types.ts';
import type { MySqlSetOperatorConfig } from './query-builders/set-operators.ts';
import type { MySqlUpdateConfig } from './query-builders/update.ts';
import type { MySqlSession } from './session.ts';
import { MySqlTable } from './table.ts';
Expand Down Expand Up @@ -334,6 +335,54 @@ export class MySqlDialect {
return sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`;
}

buildSetOperationQuery({
operator,
isAll,
leftSelect,
rightSelect,
limit,
orderBy,
offset,
}: MySqlSetOperatorConfig): SQL {
const leftChunk = sql`(${leftSelect.getSQL()}) `;
const rightChunk = sql`(${rightSelect.getSQL()})`;

let orderBySql;
if (orderBy && orderBy.length > 0) {
const orderByValues: SQL<unknown>[] = [];

// The next bit is necessary because the sql operator replaces ${table.column} with `table`.`column`
// which is invalid MySql syntax, Table from one of the SELECTs cannot be used in global ORDER clause
for (const orderByUnit of orderBy) {
if (is(orderByUnit, MySqlColumn)) {
orderByValues.push(sql.raw(orderByUnit.name));
Angelelz marked this conversation as resolved.
Show resolved Hide resolved
} else if (is(orderByUnit, SQL)) {
for (let i = 0; i < orderByUnit.queryChunks.length; i++) {
Angelelz marked this conversation as resolved.
Show resolved Hide resolved
const chunk = orderByUnit.queryChunks[i];

if (is(chunk, MySqlColumn)) {
orderByUnit.queryChunks[i] = sql.raw(chunk.name);
}
}

orderByValues.push(sql`${orderByUnit}`);
} else {
orderByValues.push(sql`${orderByUnit}`);
}
}

orderBySql = sql` order by ${sql.join(orderByValues, sql`, `)} `;
}

const limitSql = limit ? sql` limit ${limit}` : undefined;

const operatorChunk = sql.raw(`${operator} ${isAll ? 'all ' : ''}`);

const offsetSql = offset ? sql` offset ${offset}` : undefined;

return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`;
}

buildInsertQuery({ table, values, ignore, onConflict }: MySqlInsertConfig): SQL {
// const isSingleValue = values.length === 1;
const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = [];
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/query-builders/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export * from './insert.ts';
export * from './query-builder.ts';
export * from './select.ts';
export * from './select.types.ts';
export * from './set-operators.ts';
export * from './update.ts';
11 changes: 7 additions & 4 deletions drizzle-orm/src/mysql-core/query-builders/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import type {
import type { SubqueryWithSelection } from '~/mysql-core/subquery.ts';
import type { MySqlTable } from '~/mysql-core/table.ts';
import { MySqlViewBase } from '~/mysql-core/view.ts';
import { TypedQueryBuilder } from '~/query-builders/query-builder.ts';
import type {
BuildSubquerySelection,
GetSelectTableName,
Expand All @@ -37,6 +36,7 @@ import type {
MySqlSelectQueryBuilderHKT,
SelectedFields,
} from './select.types.ts';
import { MySqlSetOperatorBuilder } from './set-operators.ts';

type CreateMySqlSelectFromBuilderMode<
TBuilderMode extends 'db' | 'qb',
Expand Down Expand Up @@ -128,9 +128,12 @@ export abstract class MySqlSelectQueryBuilder<
TSelectMode extends SelectMode,
TNullabilityMap extends Record<string, JoinNullability> = TTableName extends string ? Record<TTableName, 'not-null'>
: {},
> extends TypedQueryBuilder<
BuildSubquerySelection<TSelection, TNullabilityMap>,
SelectResult<TSelection, TSelectMode, TNullabilityMap>[]
> extends MySqlSetOperatorBuilder<
TTableName,
TSelection,
TSelectMode,
PreparedQueryHKTBase,
TNullabilityMap
> {
static readonly [entityKind]: string = 'MySqlSelectQueryBuilder';

Expand Down
Loading