Skip to content

Commit

Permalink
feat(example-todo-list): leverage temporary resolvers
Browse files Browse the repository at this point in the history
Instead of overriding the find* methods, we can now leverage the `registerInclusionResolver` method with temporary resolvers

Co-authored-by: Agnes <[email protected]>
  • Loading branch information
nabdelgadir and Agnes committed Sep 12, 2019
1 parent ae462b4 commit 31dd7bf
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 255 deletions.
151 changes: 55 additions & 96 deletions docs/site/tutorials/todo-list/todo-list-tutorial-repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,70 +87,52 @@ export class TodoListRepository extends DefaultCrudRepository<
### Inclusion of Related Models
To get the related `Todo` object for each `TodoList`, we have to override the
`find` and `findById` functions.
To get the related `Todo` objects for each `TodoList`, we can use register a
custom
[`InclusionResolver`](https://loopback.io/doc/en/lb4/apidocs.repository.inclusionresolver.html)
in the `TodoList` repository.
First add the following imports:
First, add the following import:
```ts
import {Filter, Options} from '@loopback/repository';
import {TodoListWithRelations} from '../models';
import {InclusionResolver} from '@loopback/repository';
```
Add the following two functions after the constructor:
{% include code-caption.html content="src/repositories/todo-list.repository.ts" %}
Next, in the constructor, add the following custom resolver:
```ts
async find(
filter?: Filter<TodoList>,
options?: Options,
): Promise<TodoListWithRelations[]> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = {...filter, include: undefined};
const result = await super.find(filter, options);
// poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
// and use `inq` operator to fetch related todos in fewer DB queries
// this is a temporary implementation, please see
// https://github.com/strongloop/loopback-next/issues/3195
if (include && include.length && include[0].relation === 'todos') {
await Promise.all(
result.map(async r => {
r.todos = await this.todos(r.id).find();
}),
);
}
return result;
export class TodoListRepository extends DefaultCrudRepository</*..*/> {
// ...
constructor(
//db, relation factories setup
// add the following code to build a custom resolver
const todosResolver: InclusionResolver<TodoList, Todo> = async todoLists => {
const todos: Todo[][] = [];
for (const todoList of todoLists) {
const todo = await this.todos(todoList.id).find();
todos.push(todo);
}
return todos;
};
// the resolver needs to be registered before using
this.registerInclusionResolver('todos', todosResolver);
)
}
```
async findById(
id: typeof TodoList.prototype.id,
filter?: Filter<TodoList>,
options?: Options,
): Promise<TodoListWithRelations> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = {...filter, include: undefined};
const result = await super.findById(id, filter, options);
// poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
// and use `inq` operator to fetch related todos in fewer DB queries
// this is a temporary implementation, please see
// https://github.com/strongloop/loopback-next/issues/3195
if (include && include.length && include[0].relation === 'todos') {
result.todos = await this.todos(result.id).find();
}
After that, we need to register this resolver to the repository class, which we
can do as follows:
return result;
}
```ts
this.registerInclusionResolver('todos', todosResolver);
```
{% include note.html content="
This is a temporary implementation until we implement our relation resolvers. See [GitHub issue #3450](https://github.com/strongloop/loopback-next/issues/3450) for details.
" %}
Now when you get a `TodoList`, a `todos` property will be included that contains
your related `Todo`s, for example:
Expand All @@ -174,53 +156,30 @@ Let's do the same on the `TodoRepository`:
{% include code-caption.html content="src/repositories/todo.repository.ts" %}
```ts
async find(
filter?: Filter<Todo>,
options?: Options,
): Promise<TodoWithRelations[]> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = {...filter, include: undefined};

const result = await super.find(filter, options);

// poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
// and use `inq` operator to fetch related todo-lists in fewer DB queries
// this is a temporary implementation, please see
// https://github.com/strongloop/loopback-next/issues/3195
if (include && include.length && include[0].relation === 'todoList') {
await Promise.all(
result.map(async r => {
r.todoList = await this.todoList(r.id);
}),
);
}
// .. other imports
import {InclusionResolver} from '@loopback/repository';
```
return result;
}
```ts
export class TodoRepository extends DefaultCrudRepository</*..*/> {
// ...
constructor(
//db, factories setup

async findById(
id: typeof Todo.prototype.id,
filter?: Filter<Todo>,
options?: Options,
): Promise<TodoWithRelations> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = {...filter, include: undefined};

const result = await super.findById(id, filter, options);

// poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
// and use `inq` operator to fetch related todo-lists in fewer DB queries
// this is a temporary implementation, please see
// https://github.com/strongloop/loopback-next/issues/3195
if (include && include.length && include[0].relation === 'todoList') {
result.todoList = await this.todoList(result.id);
}
// add the following code to build/register a custom resolver
const todoListResolver: InclusionResolver<Todo, TodoList> = async todos => {
const todoLists = [];

for (const todo of todos) {
const todoList = await this.todoList(todo.id);
todoLists.push(todoList);
}

return todoLists;
};

return result;
this.registerInclusionResolver('todoList', todoListResolver);
)
}
```
Expand Down
70 changes: 16 additions & 54 deletions examples/todo-list/src/repositories/todo-list-image.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,11 @@ import {Getter, inject} from '@loopback/core';
import {
BelongsToAccessor,
DefaultCrudRepository,
Filter,
Options,
InclusionResolver,
repository,
} from '@loopback/repository';
import {DbDataSource} from '../datasources';
import {
TodoList,
TodoListImage,
TodoListImageRelations,
TodoListImageWithRelations,
} from '../models';
import {TodoList, TodoListImage, TodoListImageRelations} from '../models';
import {TodoListRepository} from './todo-list.repository';

export class TodoListImageRepository extends DefaultCrudRepository<
Expand All @@ -39,55 +33,23 @@ export class TodoListImageRepository extends DefaultCrudRepository<
'todoList',
todoListRepositoryGetter,
);
}

async find(
filter?: Filter<TodoListImage>,
options?: Options,
): Promise<TodoListImageWithRelations[]> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = {...filter, include: undefined};

const result = await super.find(filter, options);

// poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
// and use `inq` operator to fetch related todo-lists in fewer DB queries
// this is a temporary implementation, please see
// https://github.com/strongloop/loopback-next/issues/3195
if (include && include.length && include[0].relation === 'todoList') {
await Promise.all(
result.map(async r => {
// eslint-disable-next-line require-atomic-updates
r.todoList = await this.todoList(r.id);
}),
);
}

return result;
}

async findById(
id: typeof TodoListImage.prototype.id,
filter?: Filter<TodoListImage>,
options?: Options,
): Promise<TodoListImageWithRelations> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = {...filter, include: undefined};
// this is a temporary implementation until
// https://github.com/strongloop/loopback-next/issues/3450 is landed
const todoListResolver: InclusionResolver<
TodoListImage,
TodoList
> = async images => {
const todoLists = [];

const result = await super.findById(id, filter, options);
for (const image of images) {
const todoList = await this.todoList(image.id);
todoLists.push(todoList);
}

// poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
// and use `inq` operator to fetch related todo-lists in fewer DB queries
// this is a temporary implementation, please see
// https://github.com/strongloop/loopback-next/issues/3195
if (include && include.length && include[0].relation === 'todoList') {
result.todoList = await this.todoList(result.id);
}
return todoLists;
};

return result;
this.registerInclusionResolver('todoList', todoListResolver);
}
}
92 changes: 36 additions & 56 deletions examples/todo-list/src/repositories/todo-list.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,13 @@
import {Getter, inject} from '@loopback/core';
import {
DefaultCrudRepository,
Filter,
HasManyRepositoryFactory,
HasOneRepositoryFactory,
InclusionResolver,
juggler,
Options,
repository,
} from '@loopback/repository';
import {
Todo,
TodoList,
TodoListImage,
TodoListRelations,
TodoListWithRelations,
} from '../models';
import {Todo, TodoList, TodoListImage, TodoListRelations} from '../models';
import {TodoListImageRepository} from './todo-list-image.repository';
import {TodoRepository} from './todo.repository';

Expand Down Expand Up @@ -49,62 +42,49 @@ export class TodoListRepository extends DefaultCrudRepository<
'todos',
todoRepositoryGetter,
);

// this is a temporary implementation until
// https://github.com/strongloop/loopback-next/issues/3450 is landed
const todosResolver: InclusionResolver<
TodoList,
Todo
> = async todoLists => {
const todos: Todo[][] = [];
for (const todoList of todoLists) {
const todo = await this.todos(todoList.id).find();
todos.push(todo);
}

return todos;
};

this.registerInclusionResolver('todos', todosResolver);

this.image = this.createHasOneRepositoryFactoryFor(
'image',
todoListImageRepositoryGetter,
);
}

public findByTitle(title: string) {
return this.findOne({where: {title}});
}
// this is a temporary implementation until
// https://github.com/strongloop/loopback-next/issues/3450 is landed
const imageResolver: InclusionResolver<
TodoList,
TodoListImage
> = async todoLists => {
const images = [];

async find(
filter?: Filter<TodoList>,
options?: Options,
): Promise<TodoListWithRelations[]> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = {...filter, include: undefined};
const result = await super.find(filter, options);
for (const todoList of todoLists) {
const image = await this.image(todoList.id).get();
images.push(image);
}

// poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
// and use `inq` operator to fetch related todos in fewer DB queries
// this is a temporary implementation, please see
// https://github.com/strongloop/loopback-next/issues/3195
if (include && include.length && include[0].relation === 'todos') {
await Promise.all(
result.map(async r => {
// eslint-disable-next-line require-atomic-updates
r.todos = await this.todos(r.id).find();
}),
);
}
return images;
};

return result;
this.registerInclusionResolver('image', imageResolver);
}

async findById(
id: typeof TodoList.prototype.id,
filter?: Filter<TodoList>,
options?: Options,
): Promise<TodoListWithRelations> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = {...filter, include: undefined};

const result = await super.findById(id, filter, options);

// poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
// and use `inq` operator to fetch related todos in fewer DB queries
// this is a temporary implementation, please see
// https://github.com/strongloop/loopback-next/issues/3195
if (include && include.length && include[0].relation === 'todos') {
result.todos = await this.todos(result.id).find();
}

return result;
public findByTitle(title: string) {
return this.findOne({where: {title}});
}
}
Loading

0 comments on commit 31dd7bf

Please sign in to comment.