Skip to content

Commit

Permalink
MySQL2 tests for RQBv2, workarounds for MySQL limitations on lateral …
Browse files Browse the repository at this point in the history
…joins and `json_arrayagg()`'s `order by` order preservation, removed unused code, added error throw to incomplete RQBv2 feature `.through()`
  • Loading branch information
Sukairo-02 committed Jan 8, 2025
1 parent 38fedf0 commit b4f992e
Show file tree
Hide file tree
Showing 5 changed files with 6,996 additions and 351 deletions.
29 changes: 21 additions & 8 deletions drizzle-orm/src/mysql-core/dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,13 @@ export class MySqlDialect {
columnIdentifiers.push(
sql`${table[column.tsName as keyof typeof table]} as ${sql.identifier(column.tsName)}`,
);

selection.push(
{
key: column.tsName,
field: column.column,
},
);
}

return columnIdentifiers.length
Expand All @@ -1245,6 +1252,7 @@ export class MySqlDialect {
mode,
errorPath,
depth,
isNested,
}: {
tables: Record<string, MySqlTable>;
schema: TablesRelationalConfig;
Expand All @@ -1256,6 +1264,7 @@ export class MySqlDialect {
mode: 'first' | 'many';
errorPath?: string;
depth?: number;
isNested?: boolean;
},
): BuildRelationalQueryResult {
const selection: BuildRelationalQueryResult['selection'] = [];
Expand Down Expand Up @@ -1290,8 +1299,6 @@ export class MySqlDialect {

return sql.join(
withEntries.map(([k, join]) => {
selectionArr.push(sql`${sql.identifier(k)}.${sql.identifier('r')} as ${sql.identifier(k)}`);

if (is(tableConfig.relations[k]!, AggregatedField)) {
const relation = tableConfig.relations[k]!;
relation.onTable(table);
Expand All @@ -1302,9 +1309,12 @@ export class MySqlDialect {
field: relation,
});

return sql`, lateral(${query}) as ${sql.identifier(k)}`;
selectionArr.push(sql`(${query}) as ${sql.identifier(k)}`);
return;
}

selectionArr.push(sql`${sql.identifier(k)}.${sql.identifier('r')} as ${sql.identifier(k)}`);

const relation = tableConfig.relations[k]! as Relation;
const isSingle = is(relation, One);
const targetTable = aliasedTable(relation.targetTable, `d${currentDepth + 1}`);
Expand All @@ -1321,6 +1331,7 @@ export class MySqlDialect {
relationWhere: relationFilter,
errorPath: `${currentPath.length ? `${currentPath}.` : ''}${k}`,
depth: currentDepth + 1,
isNested: true,
});

selection.push({
Expand All @@ -1337,11 +1348,9 @@ export class MySqlDialect {
sql`, `,
);

return sql`, lateral(select ${
isSingle
? sql`json_object(${jsonColumns}) as ${sql.identifier('r')}`
: sql`coalesce(json_arrayagg(json_object(${jsonColumns})), json_array()) as ${sql.identifier('r')}`
} from (${innerQuery.sql}) as ${sql.identifier('t')}) as ${sql.identifier(k)}`;
return sql`, lateral(select ${sql`coalesce(json_arrayagg(json_object(${jsonColumns})), json_array()) as ${
sql.identifier('r')
}`} from (${innerQuery.sql}) as ${sql.identifier('t')}) as ${sql.identifier(k)}`;
}),
);
})()
Expand All @@ -1353,6 +1362,10 @@ export class MySqlDialect {
message: `No fields selected for table "${tableConfig.tsName}"${currentPath ? ` ("${currentPath}")` : ''}`,
});
}
// json_arrayagg() ignores order by clause otherwise
if (isNested && order) {
selectionArr.push(sql`row_number() over (order by ${order})`);
}
const selectionSet = sql.join(selectionArr, sql`, `);

const query = sql`select ${selectionSet} from ${
Expand Down
27 changes: 1 addition & 26 deletions drizzle-orm/src/mysql2/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,33 +141,8 @@ export class MySql2PreparedQuery<T extends MySqlPreparedQueryConfig, TIsRqbV2 ex

this.logger.logQuery(this.rawQuery.sql, params);

const { client, rawQuery, customResultMapper, returningIds, generatedIds } = this;
const { client, rawQuery, customResultMapper } = this;
const res = await client.query<any>(rawQuery, params);
const insertId = res[0].insertId;
const affectedRows = res[0].affectedRows;
// for each row, I need to check keys from
if (returningIds) {
const returningResponse = [];
let j = 0;
for (let i = insertId; i < insertId + affectedRows; i++) {
for (const column of returningIds) {
const key = returningIds[0]!.path[0]!;
if (is(column.field, Column)) {
// @ts-ignore
if (column.field.primary && column.field.autoIncrement) {
returningResponse.push({ [key]: i });
}
if (column.field.defaultFn && generatedIds) {
// generatedIds[rowIdx][key]
returningResponse.push({ [key]: generatedIds[j]![key] });
}
}
}
j++;
}

return (customResultMapper as (rows: Record<string, unknown>[]) => T['execute'])(returningResponse);
}

const rows = res[0];

Expand Down
13 changes: 8 additions & 5 deletions drizzle-orm/src/relations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,11 @@ export function mapRelationalRow(
const field = selectionItem.field!;

if (is(field, Table)) {
// MySQL's lateral joins act only as inner joins, thus must have null responses on single relations be casted as arrays to preserve rows
if (!selectionItem.isArray && Array.isArray(row[selectionItem.key])) {
row[selectionItem.key] = (row[selectionItem.key] as Array<any>)[0] ?? null;
}

const currentPath = `${path ? `${path}.` : ''}${selectionItem.key}`;

if (row[selectionItem.key] === null) {
Expand Down Expand Up @@ -719,8 +724,8 @@ export class RelationsBuilderColumn<

through(column: RelationsBuilderColumnBase<string, TData>): Omit<this, 'through'> {
this._.through = column;

return this;
throw new Error('Not implemented');
// return this;
}

getSQL(): SQL {
Expand Down Expand Up @@ -763,9 +768,7 @@ export type RelationsFilter<TColumns extends Record<string, Column>> =
RAW?: (
table: Simplify<
& AnyTable<{ columns: TColumns }>
& {
[K in keyof TColumns]: TColumns[K];
}
& TColumns
>,
operators: Operators,
) => SQL;
Expand Down
Loading

0 comments on commit b4f992e

Please sign in to comment.