Skip to content

Commit

Permalink
fix(query-builder): cache knex QB instance to get around issues with …
Browse files Browse the repository at this point in the history
…raw fragments
  • Loading branch information
B4nan committed Jan 15, 2024
1 parent 3d8c242 commit f6e76d8
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 14 deletions.
24 changes: 17 additions & 7 deletions packages/knex/src/query/QueryBuilder.ts
Expand Up @@ -599,6 +599,11 @@ export class QueryBuilder<T extends object = AnyEntity> {
}

getKnexQuery(processVirtualEntity = true): Knex.QueryBuilder {
if (this.#query) {
return this.#query.qb;
}

this.#query = {} as any;
this.finalize();
const qb = this.getQueryBase(processVirtualEntity);
const type = this.type ?? QueryType.SELECT;
Expand All @@ -623,7 +628,7 @@ export class QueryBuilder<T extends object = AnyEntity> {
Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(type, this._onConflict!, qb), this._onConflict);

if (this.type === QueryType.TRUNCATE && this.platform.usesCascadeStatement()) {
return this.knex.raw(qb.toSQL().toNative().sql + ' cascade') as any;
return this.#query!.qb = this.knex.raw(qb.toSQL().toNative().sql + ' cascade') as any;
}

if (this.lockMode) {
Expand All @@ -633,7 +638,7 @@ export class QueryBuilder<T extends object = AnyEntity> {
this.helper.finalize(type, qb, this.mainAlias.metadata, this._data, this._returning);
this.clearRawFragmentsCache();

return qb;
return this.#query!.qb = qb;
}

/**
Expand All @@ -651,16 +656,21 @@ export class QueryBuilder<T extends object = AnyEntity> {
return this.toQuery().sql;
}

#query?: { sql: string; _sql: Knex.Sql; params: readonly unknown[] };
#query?: { sql?: string; _sql?: Knex.Sql; params?: readonly unknown[]; qb: Knex.QueryBuilder<T> };

toQuery(): { sql: string; _sql: Knex.Sql; params: readonly unknown[] } {
if (this.#query) {
return this.#query;
if (this.#query?.sql) {
return { sql: this.#query.sql, _sql: this.#query._sql!, params: this.#query.params! };
}

const sql = this.getKnexQuery().toSQL();
const query = sql.toNative();
return this.#query = { sql: query.sql, params: query.bindings ?? [], _sql: sql };

this.#query!.sql = query.sql;
this.#query!._sql = sql;
this.#query!.params = query.bindings ?? [];

return { sql: this.#query!.sql, _sql: this.#query!._sql, params: this.#query!.params };
}

/**
Expand All @@ -674,7 +684,7 @@ export class QueryBuilder<T extends object = AnyEntity> {
* Returns raw interpolated query string with all the parameters inlined.
*/
getFormattedQuery(): string {
const query = this.toQuery()._sql;
const query = this.getKnexQuery().toSQL();
return this.platform.formatQuery(query.sql, query.bindings);
}

Expand Down
14 changes: 7 additions & 7 deletions tests/features/raw-queries/GHx6.test.ts
Expand Up @@ -128,20 +128,20 @@ test('qb.joinAndSelect', async () => {
.select('*')
.leftJoinAndSelect('jobs', 'a')
.where({
[raw('similarity("u"."name", ?)', ['abc'])]: { $gte: 0.3 },
[raw('coalesce("u"."name", ?)', ['abc'])]: { $gte: 0.3 },
})
.orderBy({
[raw('similarity(u."name", ?)', ['def'])]: QueryOrder.DESC_NULLS_LAST,
[raw('coalesce(u."name", ?)', ['def'])]: QueryOrder.DESC_NULLS_LAST,
})
.limit(100)
.offset(0)
.getFormattedQuery();
expect(query).toMatch('select `u`.*, `a`.`id` as `a__id`, `a`.`DateCompleted` as `a__DateCompleted` ' +
.offset(0);
expect(query.getKnexQuery().toSQL().sql).toMatch('select `u`.*, `a`.`id` as `a__id`, `a`.`DateCompleted` as `a__DateCompleted` ' +
'from `tag` as `u` ' +
'left join `tag_jobs` as `t1` on `u`.`id` = `t1`.`tag_id` ' +
'left join `job` as `a` on `t1`.`job_id` = `a`.`id` ' +
'where `u`.`id` in (select `u`.`id` from (select `u`.`id` from `tag` as `u` left join `tag_jobs` as `t1` on `u`.`id` = `t1`.`tag_id` left join `job` as `a` on `t1`.`job_id` = `a`.`id` where similarity("u"."name", \'abc\') >= 0.3 group by `u`.`id` order by similarity(u."name", \'def\') desc nulls last limit 100) as `u`) ' +
'order by similarity(u."name", \'def\') desc nulls last');
'where `u`.`id` in (select `u`.`id` from (select `u`.`id` from `tag` as `u` left join `tag_jobs` as `t1` on `u`.`id` = `t1`.`tag_id` left join `job` as `a` on `t1`.`job_id` = `a`.`id` where coalesce("u"."name", ?) >= ? group by `u`.`id` order by coalesce(u."name", \'def\') desc nulls last limit ?) as `u`) ' +
'order by coalesce(u."name", \'def\') desc nulls last');
await query;
expect(RawQueryFragment.checkCacheSize()).toBe(0);
});

Expand Down

0 comments on commit f6e76d8

Please sign in to comment.