-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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(repository): implement inclusionResolver for hasMany relation #3595
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -314,3 +314,95 @@ certain properties from the JSON/OpenAPI spec schema built for the `requestBody` | |
payload. See its [GitHub | ||
issue](https://github.com/strongloop/loopback-next/issues/1179) to follow the discussion. | ||
" %} | ||
|
||
## Querying related models | ||
|
||
LoopBack 4 has the concept of an `inclusion resolver` in relations, which helps | ||
to query data through an `include` filter. An inclusion resolver is a function | ||
that can fetch target models for the given list of source model instances. | ||
LoopBack 4 creates a different inclusion resolver for each relation type. | ||
|
||
Use the relation between `Customer` and `Order` we show above, a `Customer` has | ||
many `Order`s. | ||
|
||
After setting up the relation in the repository class, the inclusion resolver | ||
allows users to retrieve all customers along with their related orders through | ||
the following code: | ||
|
||
```ts | ||
customerRepo.find({include: [{relation: 'orders'}]}); | ||
``` | ||
|
||
### Enable/disable the inclusion resolvers: | ||
|
||
- Base repository classes have a public property `inclusionResolvers`, which | ||
maintains a map containing inclusion resolvers for each relation. | ||
- The `inclusionResolver` of a certain relation is built when the source | ||
repository class calls the `createHasManyRepositoryFactoryFor` function in the | ||
constructor with the relation name. | ||
- Call `registerInclusionResolver` to add the resolver of that relation to the | ||
`inclusionResolvers` map. (As we realized in LB3, not all relations are | ||
allowed to be traversed. Users can decide to which resolvers can be added.) | ||
|
||
The following code snippet shows how to register the inclusion resolver for the | ||
has-many relation 'orders': | ||
|
||
```ts | ||
export class CustomerRepository extends DefaultCrudRepository { | ||
products: HasManyRepositoryFactory<Order, typeof Customer.prototype.id>; | ||
|
||
constructor( | ||
dataSource: juggler.DataSource, | ||
orderRepositoryGetter: Getter<OrderRepository>, | ||
) { | ||
super(Customer, dataSource); | ||
|
||
// we already have this line to create a HasManyRepository factory | ||
this.orders = this.createHasManyRepositoryFactoryFor( | ||
'orders', | ||
orderRepositoryGetter, | ||
); | ||
|
||
// add this line to register inclusion resolver | ||
this.registerInclusion('orders', this.orders.inclusionResolver); | ||
} | ||
} | ||
``` | ||
|
||
- We can simply include the relation in queries via `find()`, `findOne()`, and | ||
`findById()` methods. Example: | ||
|
||
```ts | ||
customerRepository.find({include: [{relation: 'orders'}]}); | ||
``` | ||
|
||
which returns: | ||
|
||
```ts | ||
[ | ||
{ | ||
id: 1, | ||
name: 'Thor', | ||
orders: [ | ||
{name: 'Mjolnir', customerId: 1}, | ||
{name: 'Rocket Raccoon', customerId: 1}, | ||
], | ||
}, | ||
{ | ||
id: 2, | ||
name: 'Captain', | ||
orders: [{name: 'Shield', customerId: 2}], | ||
}, | ||
]; | ||
``` | ||
|
||
- You can delete a relation from `inclusionResolvers` to disable the inclusion | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this doing exactly? It is not clear to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to show the way to disable a certain inclusion resolver. Because not all models are traversable. |
||
for a certain relation. e.g | ||
`customerRepository.inclusionResolvers.delete('orders')` | ||
|
||
{% include note.html content=" | ||
Inclusion with custom scope: | ||
Besides specifying the relation name to include, it's also possible to specify additional scope constraints. | ||
However, this feature is not supported yet. Check our GitHub issue for more information: | ||
[Include related models with a custom scope](https://github.com/strongloop/loopback-next/issues/3453). | ||
" %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if we can make it even simpler as we can use
orders
to get the inclusionResolver (this['orders'].inclusionResolver
).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I think it's doable.
Let me land this PR and open a new one for it.