Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow using options object in EntityManager.find() #14

Merged
merged 1 commit into from
Mar 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,18 @@ carries the entity name so you do not have to pass it to every `find` and `findO

```typescript
const booksRepository = orm.em.getRepository(Book);
const books = await booksRepository.find({ author: '...' }, ['author'], { title: -1 });

// with sorting, limit and offset parameters, populating author references
const books = await booksRepository.find({ author: '...' }, ['author'], { title: QueryOrder.DESC }, 2, 1);

// or with options object
const books = await booksRepository.find({ author: '...' }, {
populate: ['author'],
limit: 1,
offset: 2,
sort: { title: QueryOrder.DESC },
});

console.log(books); // Book[]
```

Expand Down
5 changes: 3 additions & 2 deletions docs/entity-manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const orm = await MikroORM.init({
await orm.em.persist(new Entity()); // no auto-flushing now
await orm.em.flush();
await orm.em.persist(new Entity(), true); // you can still use second parameter to auto-flush
```
```

## Fetching entities with EntityManager

Expand All @@ -54,7 +54,8 @@ API:

```typescript
EntityManager.getRepository<T extends IEntity>(entityName: string): EntityRepository<T>;
EntityManager.find<T extends IEntity>(entityName: string, where?: FilterQuery<T>, populate?: string[], orderBy?: { [k: string]: 1 | -1; }, limit?: number, offset?: number): Promise<T[]>;
EntityManager.find<T extends IEntity>(entityName: string, where?: FilterQuery<T>, options?: FindOptions): Promise<T[]>;
EntityManager.find<T extends IEntity>(entityName: string, where?: FilterQuery<T>, populate?: string[], orderBy?: { [k: string]: QueryOrder }, limit?: number, offset?: number): Promise<T[]>;
EntityManager.findOne<T extends IEntity>(entityName: string, where: FilterQuery<T> | string, populate?: string[]): Promise<T>;
EntityManager.merge<T extends IEntity>(entityName: string, data: any): T;
EntityManager.getReference<T extends IEntity>(entityName: string, id: string): T;
Expand Down
18 changes: 14 additions & 4 deletions docs/repositories.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ API:
```typescript
EntityRepository.persist(entity: IEntity, flush?: boolean): Promise<void>;
EntityRepository.findOne(where: FilterQuery<IEntity> | string, populate?: string[]): Promise<IEntity>;
EntityRepository.find(where: FilterQuery<IEntity>, populate?: string[], orderBy?: { [k: string]: 1 | -1; }, limit?: number, offset?: number): Promise<IEntity[]>;
EntityRepository.findAll(populate?: string[], orderBy?: { [k: string]: 1 | -1; }, limit?: number, offset?: number): Promise<IEntity[]>;
EntityRepository.find(where: FilterQuery<IEntity>, options?: FindOptions): Promise<IEntity[]>;
EntityRepository.find(where: FilterQuery<IEntity>, populate?: string[], orderBy?: { [k: string]: QueryOrder; }, limit?: number, offset?: number): Promise<IEntity[]>;
EntityRepository.findAll(populate?: string[], orderBy?: { [k: string]: QueryOrder }, limit?: number, offset?: number): Promise<IEntity[]>;
EntityRepository.remove(where: IEntity | any): Promise<number>;
EntityRepository.flush(): Promise<void>;
EntityRepository.canPopulate(property: string): boolean;
Expand All @@ -19,10 +20,19 @@ EntityRepository.count(where?: any): Promise<number>;
Example:

```typescript
const booksRepository = orm.em.getRepository<Book>(Book);
const booksRepository = orm.em.getRepository(Book);

// with sorting, limit and offset parameters, populating author references
const books = await booksRepository.find({ author: '...' }, ['author'], { title: -1 }, 2, 1);
const books = await booksRepository.find({ author: '...' }, ['author'], { title: QueryOrder.DESC }, 2, 1);

// or with options object
const books = await booksRepository.find({ author: '...' }, {
populate: ['author'],
limit: 1,
offset: 2,
sort: { title: QueryOrder.DESC },
});

console.log(books); // Book[]
```

Expand Down
18 changes: 14 additions & 4 deletions lib/EntityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { RequestContext } from './utils/RequestContext';
import { FilterQuery } from './drivers/DatabaseDriver';
import { IDatabaseDriver } from './drivers/IDatabaseDriver';
import { IPrimaryKey } from './decorators/PrimaryKey';
import { QueryBuilder } from './QueryBuilder';
import { QueryBuilder, QueryOrder } from './QueryBuilder';
import { Cascade, EntityClass, EntityData, IEntity, IEntityType, ReferenceType } from './decorators/Entity';
import { EntityHelper } from './utils/EntityHelper';
import { EntityLoader } from './EntityLoader';
Expand Down Expand Up @@ -64,10 +64,13 @@ export class EntityManager {
return new QueryBuilder(entityName, this.metadata, this.getConnection());
}

async find<T extends IEntityType<T>>(entityName: string | EntityClass<T>, where = {} as FilterQuery<T>, populate: string[] = [], orderBy: { [k: string]: 1 | -1 } = {}, limit?: number, offset?: number): Promise<T[]> {
async find<T extends IEntityType<T>>(entityName: string | EntityClass<T>, where?: FilterQuery<T>, options?: FindOptions): Promise<T[]>;
async find<T extends IEntityType<T>>(entityName: string | EntityClass<T>, where?: FilterQuery<T>, populate?: string[], orderBy?: { [k: string]: 1 | -1 }, limit?: number, offset?: number): Promise<T[]>;
async find<T extends IEntityType<T>>(entityName: string | EntityClass<T>, where = {} as FilterQuery<T>, populate?: string[] | FindOptions, orderBy?: { [k: string]: 1 | -1 }, limit?: number, offset?: number): Promise<T[]> {
entityName = Utils.className(entityName);
this.validator.validateParams(where);
const results = await this.driver.find(entityName, where, populate, orderBy, limit, offset);
const options = Utils.isObject<FindOptions>(populate) ? populate : { populate, orderBy, limit, offset };
const results = await this.driver.find(entityName, where, options.populate || [], options.orderBy || {}, options.limit, options.offset);

if (results.length === 0) {
return [];
Expand All @@ -80,7 +83,7 @@ export class EntityManager {
ret.push(entity);
}

await this.entityLoader.populate(entityName, ret, populate);
await this.entityLoader.populate(entityName, ret, options.populate || []);

return ret;
}
Expand Down Expand Up @@ -312,3 +315,10 @@ export class EntityManager {
}

}

export interface FindOptions {
populate?: string[];
orderBy?: { [k: string]: QueryOrder };
limit?: number;
offset?: number;
}
9 changes: 6 additions & 3 deletions lib/EntityRepository.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { EntityManager } from './EntityManager';
import { EntityManager, FindOptions } from './EntityManager';
import { RequestContext } from './utils/RequestContext';
import { FilterQuery } from './drivers/DatabaseDriver';
import { IPrimaryKey } from './decorators/PrimaryKey';
import { EntityClass, EntityData, IEntityType } from './decorators/Entity';
import { QueryOrder } from './QueryBuilder';

export class EntityRepository<T extends IEntityType<T>> {

Expand All @@ -17,8 +18,10 @@ export class EntityRepository<T extends IEntityType<T>> {
return this.em.findOne<T>(this.entityName, where, populate);
}

async find(where: FilterQuery<T> | IPrimaryKey, populate: string[] = [], orderBy: { [k: string]: 1 | -1 } = {}, limit?: number, offset?: number): Promise<T[]> {
return this.em.find<T>(this.entityName, where as FilterQuery<T>, populate, orderBy, limit, offset);
async find(where: FilterQuery<T> | IPrimaryKey, options?: FindOptions): Promise<T[]>;
async find(where: FilterQuery<T> | IPrimaryKey, populate?: string[], orderBy?: { [k: string]: QueryOrder }, limit?: number, offset?: number): Promise<T[]>;
async find(where: FilterQuery<T> | IPrimaryKey, populate: string[] | FindOptions = [], orderBy: { [k: string]: QueryOrder } = {}, limit?: number, offset?: number): Promise<T[]> {
return this.em.find<T>(this.entityName, where as FilterQuery<T>, populate as string[], orderBy, limit, offset);
}

async findAll(populate: string[] = [], orderBy: { [k: string]: 1 | -1 } = {}, limit?: number, offset?: number): Promise<T[]> {
Expand Down
1 change: 1 addition & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './EntityManager';
export * from './utils/RequestContext';
export * from './utils/EntityHelper';
export * from './Collection';
export * from './QueryBuilder';
export * from './drivers/IDatabaseDriver';
export * from './drivers/DatabaseDriver';
export * from './naming-strategy/NamingStrategy';
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { IEntityType } from '../decorators/Entity';

export class Utils {

static isObject(o: any): o is Record<string, any> {
static isObject<T = Record<string, any>>(o: any): o is T {
return !!o && typeof o === 'object' && !Array.isArray(o);
}

Expand Down
21 changes: 20 additions & 1 deletion tests/EntityManager.mongo.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ObjectID } from 'mongodb';
import { Collection, EntityManager, MikroORM } from '../lib';
import { Collection, EntityManager, MikroORM, QueryOrder } from '../lib';
import { EntityProperty } from '../lib/decorators/Entity';
import { Author, Book, BookTag, Publisher, PublisherType, Test } from './entities';
import { AuthorRepository } from './repositories/AuthorRepository';
Expand Down Expand Up @@ -132,6 +132,25 @@ describe('EntityManagerMongo', () => {
expect(lastBook[0].title).toBe('My Life on The Wall, part 1');
expect(lastBook[0].author).toBeInstanceOf(Author);
expect(lastBook[0].author.isInitialized()).toBe(true);

const lastBook2 = await booksRepository.find({ author: jon.id }, {
populate: ['author'],
orderBy: { title: QueryOrder.DESC },
limit: 2,
offset: 2,
});
expect(lastBook2.length).toBe(1);
expect(lastBook[0]).toBe(lastBook2[0]);

const lastBook3 = await orm.em.find(Book, { author: jon.id }, {
populate: ['author'],
orderBy: { title: QueryOrder.DESC },
limit: 2,
offset: 2,
});
expect(lastBook3.length).toBe(1);
expect(lastBook[0]).toBe(lastBook3[0]);

await orm.em.getRepository(Book).remove(lastBook[0]._id);
});

Expand Down
12 changes: 12 additions & 0 deletions tests/EntityRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,16 @@ describe('EntityRepository', () => {
expect(methods.aggregate.mock.calls[0]).toEqual([Publisher, [{ foo: 'bar' }]]);
});

test('find() supports calling with options object', async () => {
const options = {
populate: ['test'],
orderBy: { test: -1 },
limit: 123,
offset: 321,
};
methods.find.mock.calls = [];
await repo.find({ foo: 'bar' }, options);
expect(methods.find.mock.calls[0]).toEqual([Publisher, { foo: 'bar' }, options, {}, undefined, undefined]);
});

});
3 changes: 1 addition & 2 deletions tests/QueryBuilder.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Author2, Book2, BookTag2, Publisher2, PublisherType, Test2 } from './entities-sql';
import { QueryOrder } from '../lib/QueryBuilder';
import { initORMMySql } from './bootstrap';
import { MikroORM } from '../lib';
import { MikroORM, QueryOrder } from '../lib';

/**
* @class QueryBuilderTest
Expand Down