Skip to content

Commit

Permalink
feat(core): add groupBy, having and schema to CountOptions
Browse files Browse the repository at this point in the history
  • Loading branch information
B4nan committed Sep 24, 2020
1 parent 0a9ef65 commit d3c3858
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 15 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/EntityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {
where = await this.applyFilters(entityName, where, options.filters ?? {}, 'read');
this.validator.validateParams(where);

return this.driver.count(entityName, where, this.transactionContext);
return this.driver.count(entityName, where, options, this.transactionContext);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/drivers/DatabaseDriver.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EntityManagerType, FindOneOptions, FindOptions, IDatabaseDriver } from './IDatabaseDriver';
import { CountOptions, EntityManagerType, FindOneOptions, FindOptions, IDatabaseDriver } from './IDatabaseDriver';
import { EntityData, EntityMetadata, EntityProperty, FilterQuery, AnyEntity, Dictionary, Primary, PopulateOptions } from '../typings';
import { MetadataStorage } from '../metadata';
import { Connection, QueryResult, Transaction } from '../connections';
Expand Down Expand Up @@ -35,7 +35,7 @@ export abstract class DatabaseDriver<C extends Connection> implements IDatabaseD

abstract async nativeDelete<T extends AnyEntity<T>>(entityName: string, where: FilterQuery<T>, ctx?: Transaction): Promise<QueryResult>;

abstract async count<T extends AnyEntity<T>>(entityName: string, where: FilterQuery<T>, ctx?: Transaction): Promise<number>;
abstract async count<T extends AnyEntity<T>>(entityName: string, where: FilterQuery<T>, options?: CountOptions<T>, ctx?: Transaction): Promise<number>;

createEntityManager<D extends IDatabaseDriver = IDatabaseDriver>(useContext?: boolean): D[typeof EntityManagerType] {
return new EntityManager(this.config, this, this.metadata, useContext) as unknown as EntityManager<D>;
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/drivers/IDatabaseDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export interface IDatabaseDriver<C extends Connection = Connection> {

syncCollection<T, O>(collection: Collection<T, O>, ctx?: Transaction): Promise<void>;

count<T extends AnyEntity<T>>(entityName: string, where: FilterQuery<T>, ctx?: Transaction): Promise<number>;
count<T extends AnyEntity<T>>(entityName: string, where: FilterQuery<T>, options?: CountOptions<T>, ctx?: Transaction): Promise<number>;

aggregate(entityName: string, pipeline: any[]): Promise<any[]>;

Expand Down Expand Up @@ -102,6 +102,9 @@ export interface FindOneOrFailOptions<T, P extends Populate<T> = Populate<T>> ex

export interface CountOptions<T> {
filters?: Dictionary<boolean | Dictionary> | string[] | boolean;
schema?: string;
groupBy?: string | string[];
having?: QBFilterQuery<T>;
}

export interface UpdateOptions<T> {
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/entity/EntityRepository.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EntityManager } from '../EntityManager';
import { EntityData, EntityName, AnyEntity, Primary, Populate, Loaded, New, FilterQuery } from '../typings';
import { QueryOrderMap } from '../enums';
import { FindOneOptions, FindOneOrFailOptions, FindOptions } from '../drivers/IDatabaseDriver';
import { CountOptions, FindOneOptions, FindOneOrFailOptions, FindOptions } from '../drivers/IDatabaseDriver';
import { IdentifiedReference, Reference } from './Reference';

export class EntityRepository<T extends AnyEntity<T>> {
Expand Down Expand Up @@ -124,8 +124,8 @@ export class EntityRepository<T extends AnyEntity<T>> {
return this.em.assign(entity, data);
}

async count(where: FilterQuery<T> = {}): Promise<number> {
return this.em.count<T>(this.entityName, where);
async count(where: FilterQuery<T> = {}, options: CountOptions<T> = {}): Promise<number> {
return this.em.count<T>(this.entityName, where, options);
}

}
10 changes: 7 additions & 3 deletions packages/knex/src/AbstractSqlDriver.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { QueryBuilder as KnexQueryBuilder, Raw, Transaction as KnexTransaction, Value } from 'knex';
import {
AnyEntity, Collection, Configuration, Constructor, DatabaseDriver, Dictionary, EntityData, EntityManager, EntityManagerType, EntityMetadata, EntityProperty, QueryFlag,
FilterQuery, FindOneOptions, FindOptions, IDatabaseDriver, LockMode, Primary, QueryOrderMap, QueryResult, ReferenceType, Transaction, Utils, PopulateOptions, LoadStrategy,
AnyEntity, Collection, Configuration, Constructor, DatabaseDriver, Dictionary, EntityData, EntityManager, EntityManagerType,
EntityMetadata, EntityProperty, QueryFlag, FilterQuery, FindOneOptions, FindOptions, IDatabaseDriver, LockMode, Primary,
QueryOrderMap, QueryResult, ReferenceType, Transaction, Utils, PopulateOptions, LoadStrategy, CountOptions,
} from '@mikro-orm/core';
import { AbstractSqlConnection } from './AbstractSqlConnection';
import { AbstractSqlPlatform } from './AbstractSqlPlatform';
Expand Down Expand Up @@ -162,11 +163,14 @@ export abstract class AbstractSqlDriver<C extends AbstractSqlConnection = Abstra
}
}

async count(entityName: string, where: any, ctx?: Transaction<KnexTransaction>): Promise<number> {
async count<T extends AnyEntity<T>>(entityName: string, where: any, options: CountOptions<T> = {}, ctx?: Transaction<KnexTransaction>): Promise<number> {
const pks = this.metadata.find(entityName)!.primaryKeys;
const qb = this.createQueryBuilder(entityName, ctx, !!ctx)
.unsetFlag(QueryFlag.CONVERT_CUSTOM_TYPES)
.count(pks, true)
.groupBy(options.groupBy!)
.having(options.having!)
.withSchema(options.schema)
.where(where);
const res = await this.rethrow(qb.execute('get', false));

Expand Down
4 changes: 2 additions & 2 deletions packages/mongodb/src/MongoDriver.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ClientSession, ObjectId } from 'mongodb';
import {
DatabaseDriver, EntityData, AnyEntity, FilterQuery, EntityMetadata, EntityProperty, Configuration, Utils, ReferenceType, FindOneOptions, FindOptions,
QueryResult, Transaction, IDatabaseDriver, EntityManager, EntityManagerType, Dictionary, PopulateOptions,
QueryResult, Transaction, IDatabaseDriver, EntityManager, EntityManagerType, Dictionary, PopulateOptions, CountOptions,
} from '@mikro-orm/core';
import { MongoConnection } from './MongoConnection';
import { MongoPlatform } from './MongoPlatform';
Expand Down Expand Up @@ -42,7 +42,7 @@ export class MongoDriver extends DatabaseDriver<MongoConnection> {
return this.mapResult<T>(res[0], this.metadata.find(entityName)!);
}

async count<T extends AnyEntity<T>>(entityName: string, where: FilterQuery<T>, ctx?: Transaction<ClientSession>): Promise<number> {
async count<T extends AnyEntity<T>>(entityName: string, where: FilterQuery<T>, options: CountOptions<T>, ctx?: Transaction<ClientSession>): Promise<number> {
where = this.renameFields(entityName, where);
return this.rethrow(this.getConnection('read').countDocuments(entityName, where, ctx));
}
Expand Down
18 changes: 15 additions & 3 deletions tests/DatabaseDriver.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import {
Configuration, Connection, DatabaseDriver, EntityData, EntityManager, EntityRepository, FilterQuery, FindOneOptions, FindOptions, LockMode,
Platform, QueryResult, Transaction,
Configuration,
Connection,
CountOptions,
DatabaseDriver,
EntityData,
EntityManager,
EntityRepository,
FilterQuery,
FindOneOptions,
FindOptions,
LockMode,
Platform,
QueryResult,
Transaction,
} from '@mikro-orm/core';

class Platform1 extends Platform { }
Expand All @@ -14,7 +26,7 @@ class Driver extends DatabaseDriver<Connection> {
super(config, dependencies);
}

async count<T>(entityName: string, where: FilterQuery<T>, ctx: Transaction | undefined): Promise<number> {
async count<T>(entityName: string, where: FilterQuery<T>, options: CountOptions<T>, ctx: Transaction | undefined): Promise<number> {
return Promise.resolve(0);
}

Expand Down
6 changes: 6 additions & 0 deletions tests/EntityManager.mysql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ describe('EntityManagerMySql', () => {
expect(driver.getPlatform().denormalizePrimaryKey(1)).toBe(1);
expect(driver.getPlatform().denormalizePrimaryKey('1')).toBe('1');
await expect(driver.find<BookTag2>(BookTag2.name, { books: { $in: ['1'] } })).resolves.not.toBeNull();
await expect(driver.count(BookTag2.name, {})).resolves.toBe(1);
await expect(driver.ensureIndexes()).rejects.toThrowError('MySqlDriver does not use ensureIndexes');

const conn = driver.getConnection();
Expand Down Expand Up @@ -424,6 +425,11 @@ describe('EntityManagerMySql', () => {
expect(count).toBe(authors.length);
const count2 = await orm.em.count(Author2);
expect(count2).toBe(authors.length);
const count3 = await orm.em.getRepository(Author2).count({}, {
groupBy: ['termsAccepted'],
having: { termsAccepted: false },
});
expect(count3).toBe(authors.length);

// identity map test
authors.shift(); // shift the god away, as that entity is detached from IM
Expand Down

0 comments on commit d3c3858

Please sign in to comment.