Skip to content

Commit

Permalink
feat(knex): allow changing FROM clause using QueryBuilder (#3378)
Browse files Browse the repository at this point in the history
  • Loading branch information
derevnjuk committed Sep 9, 2022
1 parent 1297966 commit df7d939
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 63 deletions.
34 changes: 34 additions & 0 deletions docs/docs/query-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,40 @@ const count = await qb.getCount();

This will also remove any existing limit and offset from the query (the QB will be cloned under the hood, so calling `getCount()` does not mutate the original QB state).

## Overriding FROM clause

You can specify the table used in the `FROM` clause, replacing the current table name if one has already been specified. This is typically used to specify a sub-query expression in SQL.

```ts
const qb = em.createQueryBuilder(Book2);
qb.select('*').from(Author2).where({ id: { $gt: 2 } });

console.log(qb.getQuery());
// select `e0`.* from `author2` as `e0` where `e0`.`id` > 2;
```

You can also use sub-queries in the `FROM` like this:

```ts
const qb1 = em.createQueryBuilder(Book2).where({ id: { $lte: new Date() } }).orderBy({ id: 'DESC' }).limit(10);
const qb2 = em.createQueryBuilder(qb1.clone())
qb2.select('*').orderBy({ id: 'ASC' });

console.log(qb2.getQuery());
// select `e1`.* from (select `e0`.* from `book2` as `e0` where `e0`.`id` <= ? order by `e0`.`id` desc limit ?) as `e1` order by `e1`.`id`;
```

To set up an alias to refer to a table in a `SELECT` statement, pass the second argument as follows:

```ts
const qb1 = em.createQueryBuilder(Book2, 'b1').where({ id: { $lte: new Date() } }).orderBy({ id: 'DESC' }).limit(10);
const qb2 = em.createQueryBuilder(qb1.clone(), 'b2')
qb2.select('*').orderBy({ id: 'ASC' });

console.log(qb2.getQuery());
// select `b2`.* from (select `b1`.* from `book2` as `b1` where `b1`.`id` <= ? order by `b1`.`id` desc limit ?) as `b2` order by `b2`.`id`;
```

## Using sub-queries

You can filter using sub-queries in where conditions:
Expand Down
7 changes: 3 additions & 4 deletions packages/knex/src/AbstractSqlDriver.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import type { Knex } from 'knex';
import type {
AnyEntity, Collection, ConnectionType, Configuration, Constructor, CountOptions, DeleteOptions, Dictionary,
DriverMethodOptions, EntityData, EntityDictionary, EntityField, EntityManager, EntityMetadata, EntityProperty, FilterQuery,
DriverMethodOptions, EntityData, EntityDictionary, EntityField, EntityManager, EntityMetadata, EntityName, EntityProperty, FilterQuery,
FindOneOptions, FindOptions, IDatabaseDriver, LockOptions, NativeInsertUpdateManyOptions, NativeInsertUpdateOptions,
PopulateOptions, Primary, QueryOrderMap, QueryResult, RequiredEntityData, Transaction,
} from '@mikro-orm/core';
import { DatabaseDriver, EntityManagerType, helper, LoadStrategy, QueryFlag, QueryHelper, ReferenceType, Utils } from '@mikro-orm/core';
import type { AbstractSqlConnection } from './AbstractSqlConnection';
import type { AbstractSqlPlatform } from './AbstractSqlPlatform';
import { QueryBuilder } from './query/QueryBuilder';
import { QueryBuilder, QueryType } from './query';
import { SqlEntityManager } from './SqlEntityManager';
import type { Field } from './typings';
import { QueryType } from './query';

export abstract class AbstractSqlDriver<C extends AbstractSqlConnection = AbstractSqlConnection> extends DatabaseDriver<C> {

Expand Down Expand Up @@ -712,7 +711,7 @@ export abstract class AbstractSqlDriver<C extends AbstractSqlConnection = Abstra
}

/** @internal */
createQueryBuilder<T extends object>(entityName: string, ctx?: Transaction<Knex.Transaction>, preferredConnectionType?: ConnectionType, convertCustomTypes?: boolean): QueryBuilder<T> {
createQueryBuilder<T extends object>(entityName: EntityName<T> | QueryBuilder<T>, ctx?: Transaction<Knex.Transaction>, preferredConnectionType?: ConnectionType, convertCustomTypes?: boolean): QueryBuilder<T> {
const connectionType = this.resolveConnectionType({ ctx, connectionType: preferredConnectionType });
const qb = new QueryBuilder<T>(entityName, this.metadata, this, ctx, undefined, connectionType);

Expand Down
5 changes: 2 additions & 3 deletions packages/knex/src/SqlEntityManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Knex } from 'knex';
import type { AnyEntity, ConnectionType, Dictionary, EntityData, EntityName, EntityRepository, GetRepository, QueryResult } from '@mikro-orm/core';
import { EntityManager, Utils } from '@mikro-orm/core';
import { EntityManager } from '@mikro-orm/core';
import type { AbstractSqlDriver } from './AbstractSqlDriver';
import { QueryBuilder } from './query';
import type { SqlEntityRepository } from './SqlEntityRepository';
Expand All @@ -13,8 +13,7 @@ export class SqlEntityManager<D extends AbstractSqlDriver = AbstractSqlDriver> e
/**
* Creates a QueryBuilder instance
*/
createQueryBuilder<T extends object>(entityName: EntityName<T>, alias?: string, type?: ConnectionType): QueryBuilder<T> {
entityName = Utils.className(entityName);
createQueryBuilder<T extends object>(entityName: EntityName<T> | QueryBuilder<T>, alias?: string, type?: ConnectionType): QueryBuilder<T> {
const context = this.getContext();

return new QueryBuilder<T>(entityName, this.getMetadata(), this.getDriver(), context.getTransactionContext(), alias, type, context);
Expand Down
9 changes: 9 additions & 0 deletions packages/knex/src/query/Alias.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { Knex } from 'knex';
import type { EntityMetadata } from '@mikro-orm/core';

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

0 comments on commit df7d939

Please sign in to comment.