Skip to content

Commit

Permalink
fix(core): map property names to column names in qb.onConflict()
Browse files Browse the repository at this point in the history
Closes #4483
  • Loading branch information
B4nan committed Aug 27, 2023
1 parent 4a21c33 commit e38d126
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 16 deletions.
4 changes: 2 additions & 2 deletions packages/knex/src/AbstractSqlDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ export abstract class AbstractSqlDriver<Connection extends AbstractSqlConnection
const uniqueFields = Utils.isPlainObject(where) ? Object.keys(where) : meta!.primaryKeys;
/* istanbul ignore next */
qb.insert(data as T)
.onConflict(uniqueFields.map(p => meta?.properties[p]?.fieldNames[0] ?? p))
.onConflict(uniqueFields)
.merge(Object.keys(data).filter(f => !uniqueFields.includes(f)))
.returning(meta?.comparableProps.filter(p => !p.lazy && !p.embeddable && !(p.name in data)).map(p => p.name) ?? '*');
} else {
Expand All @@ -450,7 +450,7 @@ export abstract class AbstractSqlDriver<Connection extends AbstractSqlConnection
const uniqueFields = Utils.isPlainObject(where[0]) ? Object.keys(where[0]) : meta.primaryKeys;
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes).withSchema(this.getSchemaName(meta, options));
qb.insert(data)
.onConflict(uniqueFields.map(p => meta.properties[p]?.fieldNames[0] ?? p))
.onConflict(uniqueFields)
.merge(Object.keys(data[0]).filter(f => !uniqueFields.includes(f)))
.returning(meta.comparableProps.filter(p => !p.lazy && !p.embeddable && !(p.name in data[0])).map(p => p.name) ?? '*');
return qb.execute('run', false);
Expand Down
29 changes: 18 additions & 11 deletions packages/knex/src/query/QueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ import type { Field, JoinOptions } from '../typings';
*/
export class QueryBuilder<T extends object = AnyEntity> {

get mainAlias(): Alias {
get mainAlias(): Alias<T> {
this.ensureFromClause();
return this._mainAlias!;
}
Expand Down Expand Up @@ -110,8 +110,8 @@ export class QueryBuilder<T extends object = AnyEntity> {
private lockMode?: LockMode;
private lockTables?: string[];
private subQueries: Dictionary<string> = {};
private _mainAlias?: Alias;
private _aliases: Dictionary<Alias> = {};
private _mainAlias?: Alias<T>;
private _aliases: Dictionary<Alias<any>> = {};
private _helper?: QueryBuilderHelper;
private readonly platform = this.driver.getPlatform();
private readonly knex = this.driver.getConnection(this.connectionType).getKnex();
Expand Down Expand Up @@ -350,9 +350,16 @@ export class QueryBuilder<T extends object = AnyEntity> {
}

onConflict(fields: Field<T> | Field<T>[] = []): this {
const meta = this.mainAlias.metadata as EntityMetadata<T>;
this.ensureNotFinalized();
this._onConflict = this._onConflict || [];
this._onConflict.push({ fields: Utils.asArray(fields).map(f => f.toString()) });
this._onConflict ??= [];
this._onConflict.push({
fields: Utils.asArray(fields).flatMap(f => {
const key = f.toString();
/* istanbul ignore next */
return meta.properties[key]?.fieldNames ?? [key];
}),
});
return this;
}

Expand Down Expand Up @@ -584,7 +591,7 @@ export class QueryBuilder<T extends object = AnyEntity> {
* @internal
*/
getAliasMap(): Dictionary<string> {
return Object.fromEntries(Object.entries(this._aliases).map(([key, value]: [string, Alias]) => [key, value.entityName]));
return Object.fromEntries(Object.entries(this._aliases).map(([key, value]: [string, Alias<any>]) => [key, value.entityName]));
}

/**
Expand Down Expand Up @@ -614,13 +621,13 @@ export class QueryBuilder<T extends object = AnyEntity> {

if (method === 'all' && Array.isArray(res)) {
const map: Dictionary = {};
const mapped = res.map(r => this.driver.mapResult(r, meta, this._populate, this, map)) as unknown as U;
const mapped = res.map(r => this.driver.mapResult<T>(r, meta, this._populate, this, map)) as unknown as U;
await this.em?.storeCache(this._cache, cached!, mapped);

return mapped;
}

const mapped = this.driver.mapResult(res, meta, this._populate, this) as unknown as U;
const mapped = this.driver.mapResult(res as T, meta, this._populate, this) as unknown as U;
await this.em?.storeCache(this._cache, cached!, mapped);

return mapped;
Expand Down Expand Up @@ -1180,20 +1187,20 @@ export class QueryBuilder<T extends object = AnyEntity> {
this._populateMap[field] = this._joins[field].alias;
}

private getSchema(alias: Alias): string | undefined {
private getSchema(alias: Alias<any>): string | undefined {
const { metadata } = alias;
const metaSchema = metadata?.schema && metadata.schema !== '*' ? metadata.schema : undefined;
return this._schema ?? metaSchema ?? this.em?.config.get('schema');
}

private createAlias(entityName: string, aliasName: string, subQuery?: Knex.QueryBuilder): Alias {
private createAlias<U = unknown>(entityName: string, aliasName: string, subQuery?: Knex.QueryBuilder): Alias<U> {
const metadata = this.metadata.find(entityName)!;
const alias = { aliasName, entityName, metadata, subQuery };
this._aliases[aliasName] = alias;
return alias;
}

private createMainAlias(entityName: string, aliasName: string, subQuery?: Knex.QueryBuilder): Alias {
private createMainAlias(entityName: string, aliasName: string, subQuery?: Knex.QueryBuilder): Alias<T> {
this._mainAlias = this.createAlias(entityName, aliasName, subQuery);
this._helper = this.createQueryBuilderHelper();
return this._mainAlias;
Expand Down
6 changes: 3 additions & 3 deletions packages/knex/src/query/QueryBuilderHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class QueryBuilderHelper {

constructor(private readonly entityName: string,
private readonly alias: string,
private readonly aliasMap: Dictionary<Alias>,
private readonly aliasMap: Dictionary<Alias<any>>,
private readonly subQueries: Dictionary<string>,
private readonly knex: Knex,
private readonly driver: AbstractSqlDriver) { }
Expand Down Expand Up @@ -839,9 +839,9 @@ export class QueryBuilderHelper {

}

export interface Alias {
export interface Alias<T> {
aliasName: string;
entityName: string;
metadata?: EntityMetadata;
metadata?: EntityMetadata<T>;
subQuery?: Knex.QueryBuilder;
}

0 comments on commit e38d126

Please sign in to comment.