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

Add comment support for query builders #1878

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7127495
[PG]: select query builder comment support
ragrag Jan 28, 2024
ef16ec4
[PG]: insert query builder comment support
ragrag Jan 29, 2024
e65ef50
[PG]: update query builder comment support
ragrag Feb 10, 2024
dca63aa
[PG]: delete query builder comment support
ragrag Feb 10, 2024
b434832
[PG]: relation query builder comment support
ragrag Feb 10, 2024
411fdf1
[PG]: move tests to pg.test.ts
ragrag Feb 10, 2024
dab15e1
[SQLite]: select query builder comment supporta
ragrag Feb 10, 2024
e773b5e
[SQLite]: update query builder comment support
ragrag Feb 10, 2024
0620b5f
[SQLite]: delete query builder comment support
ragrag Feb 10, 2024
282218e
[SQLite]: insert query builder comment support
ragrag Feb 10, 2024
99baa22
[SQLite]: relation query builder comment support
ragrag Feb 10, 2024
748895e
[SQLite]: tests for query builder 'comment'
ragrag Feb 10, 2024
d19738a
[PG]: tests for all drivers for query builder 'comment'
ragrag Feb 10, 2024
dcd1c05
[MySql]: select query builder comment support
ragrag Feb 10, 2024
70b4250
[MySql]: delete query builder comment support
ragrag Feb 10, 2024
5c932ed
[MySql]: insert query builder comment support
ragrag Feb 10, 2024
0306409
[MySql]: update query builder comment support
ragrag Feb 10, 2024
73b4d31
[MySql]: relation query builder comment support
ragrag Feb 10, 2024
add37ac
[MySql]: delete query builder comment support
ragrag Feb 10, 2024
db8ab11
[MySql]: planet-scale rqb comment support
ragrag Feb 10, 2024
c326c21
[MySql]: tests for query builder 'comment'
ragrag Feb 10, 2024
b2f4396
chore: update typo in comment docs link
ragrag Feb 10, 2024
bded881
chore: fix typo
ragrag Feb 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 34 additions & 10 deletions drizzle-orm/src/mysql-core/dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Param, type QueryWithTypings, SQL, sql, type SQLChunk, View } from '~/s
import { Subquery, SubqueryConfig } from '~/subquery.ts';
import { getTableName, Table } from '~/table.ts';
import { orderSelectedFields, type UpdateSet } from '~/utils.ts';
import { DrizzleError, type Name, ViewBaseConfig, and, eq } from '../index.ts';
import { and, DrizzleError, eq, type Name, ViewBaseConfig } from '../index.ts';
import { MySqlColumn } from './columns/common.ts';
import type { MySqlDeleteConfig } from './query-builders/delete.ts';
import type { MySqlInsertConfig } from './query-builders/insert.ts';
Expand Down Expand Up @@ -79,14 +79,15 @@ export class MySqlDialect {
return `'${str.replace(/'/g, "''")}'`;
}

buildDeleteQuery({ table, where, returning }: MySqlDeleteConfig): SQL {
buildDeleteQuery({ table, where, returning, comment }: MySqlDeleteConfig): SQL {
const returningSql = returning
? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}`
: undefined;

const whereSql = where ? sql` where ${where}` : undefined;
const commentSql = this.buildSqlComment(comment);

return sql`delete from ${table}${whereSql}${returningSql}`;
return sql`${commentSql}delete from ${table}${whereSql}${returningSql}`;
}

buildUpdateSet(table: MySqlTable, set: UpdateSet): SQL {
Expand All @@ -106,16 +107,22 @@ export class MySqlDialect {
);
}

buildUpdateQuery({ table, set, where, returning }: MySqlUpdateConfig): SQL {
buildUpdateQuery({ table, set, where, returning, comment }: MySqlUpdateConfig): SQL {
const setSql = this.buildUpdateSet(table, set);

const returningSql = returning
? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}`
: undefined;

const whereSql = where ? sql` where ${where}` : undefined;
const commentSql = this.buildSqlComment(comment);

return sql`update ${table} set ${setSql}${whereSql}${returningSql}`;
return sql`${commentSql}update ${table} set ${setSql}${whereSql}${returningSql}`;
}

// Builds a SQL comment and removes /* and */ occurences
private buildSqlComment(comment?: string) {
return comment ? sql.raw(`/* ${comment.replace(/\/\*|\*\//g, '')} */`) : undefined;
}

/**
Expand Down Expand Up @@ -195,6 +202,7 @@ export class MySqlDialect {
offset,
lockingClause,
distinct,
comment,
setOperators,
}: MySqlSelectConfig,
): SQL {
Expand Down Expand Up @@ -323,8 +331,10 @@ export class MySqlDialect {
}
}

const commentSql = this.buildSqlComment(comment);

const finalQuery =
sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`;
sql`${commentSql}${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`;

if (setOperators.length > 0) {
return this.buildSetOperations(finalQuery, setOperators);
Expand Down Expand Up @@ -394,7 +404,7 @@ export class MySqlDialect {
return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`;
}

buildInsertQuery({ table, values, ignore, onConflict }: MySqlInsertConfig): SQL {
buildInsertQuery({ table, values, ignore, onConflict, comment }: MySqlInsertConfig): SQL {
// const isSingleValue = values.length === 1;
const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = [];
const columns: Record<string, MySqlColumn> = table[Table.Symbol.Columns];
Expand Down Expand Up @@ -431,7 +441,9 @@ export class MySqlDialect {

const onConflictSql = onConflict ? sql` on duplicate key ${onConflict}` : undefined;

return sql`insert${ignoreSql} into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}`;
const commentSql = this.buildSqlComment(comment);

return sql`${commentSql}insert${ignoreSql} into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}`;
}

sqlToQuery(sql: SQL): QueryWithTypings {
Expand Down Expand Up @@ -464,7 +476,7 @@ export class MySqlDialect {
joinOn?: SQL;
}): BuildRelationalQueryResult<MySqlTable, MySqlColumn> {
let selection: BuildRelationalQueryResult<MySqlTable, MySqlColumn>['selection'] = [];
let limit, offset, orderBy: MySqlSelectConfig['orderBy'], where;
let limit, offset, orderBy: MySqlSelectConfig['orderBy'], where, comment;
const joins: MySqlSelectJoinConfig[] = [];

if (config === true) {
Expand Down Expand Up @@ -554,6 +566,10 @@ export class MySqlDialect {
}
}

if (config.comment) {
comment = config.comment;
}

// Transform `fieldsSelection` into `selection`
// `fieldsSelection` shouldn't be used after this point
for (const { tsKey, value } of fieldsSelection) {
Expand Down Expand Up @@ -714,6 +730,7 @@ export class MySqlDialect {
limit,
offset,
orderBy,
comment,
setOperators: [],
});
} else {
Expand All @@ -729,6 +746,7 @@ export class MySqlDialect {
limit,
offset,
orderBy,
comment,
setOperators: [],
});
}
Expand Down Expand Up @@ -762,7 +780,7 @@ export class MySqlDialect {
joinOn?: SQL;
}): BuildRelationalQueryResult<MySqlTable, MySqlColumn> {
let selection: BuildRelationalQueryResult<MySqlTable, MySqlColumn>['selection'] = [];
let limit, offset, orderBy: MySqlSelectConfig['orderBy'] = [], where;
let limit, offset, orderBy: MySqlSelectConfig['orderBy'] = [], where, comment;

if (config === true) {
const selectionEntries = Object.entries(tableConfig.columns);
Expand Down Expand Up @@ -851,6 +869,10 @@ export class MySqlDialect {
}
}

if (config.comment) {
comment = config.comment;
}

// Transform `fieldsSelection` into `selection`
// `fieldsSelection` shouldn't be used after this point
for (const { tsKey, value } of fieldsSelection) {
Expand Down Expand Up @@ -1006,6 +1028,7 @@ export class MySqlDialect {
limit,
offset,
orderBy,
comment,
setOperators: [],
});
} else {
Expand All @@ -1020,6 +1043,7 @@ export class MySqlDialect {
limit,
offset,
orderBy,
comment,
setOperators: [],
});
}
Expand Down
42 changes: 32 additions & 10 deletions drizzle-orm/src/mysql-core/query-builders/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface MySqlDeleteConfig {
where?: SQL | undefined;
table: MySqlTable;
returning?: SelectedFieldsOrdered;
comment?: string;
}

export type MySqlDeletePrepare<T extends AnyMySqlDeleteBase> = PreparedQueryKind<
Expand Down Expand Up @@ -97,40 +98,61 @@ export class MySqlDeleteBase<
this.config = { table };
}

/**
/**
* Adds a `where` clause to the query.
*
*
* Calling this method will delete only those rows that fulfill a specified condition.
*
*
* See docs: {@link https://orm.drizzle.team/docs/delete}
*
*
* @param where the `where` clause.
*
*
* @example
* You can use conditional operators and `sql function` to filter the rows to be deleted.
*
*
* ```ts
* // Delete all cars with green color
* db.delete(cars).where(eq(cars.color, 'green'));
* // or
* db.delete(cars).where(sql`${cars.color} = 'green'`)
* ```
*
*
* You can logically combine conditional operators with `and()` and `or()` operators:
*
*
* ```ts
* // Delete all BMW cars with a green color
* db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW')));
*
*
* // Delete all cars with the green or blue color
* db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue')));
* ```
*/
*/
where(where: SQL | undefined): MySqlDeleteWithout<this, TDynamic, 'where'> {
this.config.where = where;
return this as any;
}

/**
* Adds a `comment` to the query.
*
* Calling this method will add a comment to the query.
*
* See docs: {@link https://orm.drizzle.team/docs/delete#comment}
*
* @param comment the `comment` to be added.
*
* @example
*
* ```ts
* // add a comment "action=delete-car"
* await db.delete(cars).where(eq(cars.color, 'green')).comment("action=delete-car");
* ```
*/
comment(comment: string): MySqlDeleteWithout<this, TDynamic, 'comment'> {
this.config.comment = comment;
return this as any;
}

/** @internal */
getSQL(): SQL {
return this.dialect.buildDeleteQuery(this.config);
Expand Down
36 changes: 29 additions & 7 deletions drizzle-orm/src/mysql-core/query-builders/insert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface MySqlInsertConfig<TTable extends MySqlTable = MySqlTable> {
values: Record<string, Param | SQL>[];
ignore: boolean;
onConflict?: SQL;
comment?: string;
}

export type AnyMySqlInsertConfig = MySqlInsertConfig<MySqlTable>;
Expand Down Expand Up @@ -160,25 +161,25 @@ export class MySqlInsertBase<

/**
* Adds an `on duplicate key update` clause to the query.
*
*
* Calling this method will update update the row if any unique index conflicts. MySQL will automatically determine the conflict target based on the primary key and unique indexes.
*
*
* See docs: {@link https://orm.drizzle.team/docs/insert#on-duplicate-key-update}
*
*
* @param config The `set` clause
*
*
* @example
* ```ts
* await db.insert(cars)
* .values({ id: 1, brand: 'BMW'})
* .onDuplicateKeyUpdate({ set: { brand: 'Porsche' }});
* ```
*
*
* While MySQL does not directly support doing nothing on conflict, you can perform a no-op by setting any column's value to itself and achieve the same effect:
*
*
* ```ts
* import { sql } from 'drizzle-orm';
*
*
* await db.insert(cars)
* .values({ id: 1, brand: 'BMW' })
* .onDuplicateKeyUpdate({ set: { id: sql`id` } });
Expand All @@ -192,6 +193,27 @@ export class MySqlInsertBase<
return this as any;
}

/**
* Adds a `comment` to the query.
*
* Calling this method will add a comment to the query.
*
* See docs: {@link https://orm.drizzle.team/docs/insert#comment}
*
* @param comment the `comment` to be added.
*
* @example
*
* ```ts
* // add a comment "action=insert-car"
* await db.insert(cars).values({ id: 1, brand: 'BMW' }).comment("action=insert-car");
* ```
*/
comment(comment: string): MySqlInsertWithout<this, TDynamic, 'comment'> {
this.config.comment = comment;
return this as any;
}

/** @internal */
getSQL(): SQL {
return this.dialect.buildInsertQuery(this.config);
Expand Down