-
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): add InclusionResolver type and includeRelatedModels #3517
Conversation
2ac78a0
to
a8d066f
Compare
2467176
to
273646d
Compare
ebd6559
to
9151086
Compare
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.
😎 Great start! I left a few comments.
packages/repository/src/__tests__/unit/repositories/relation.helpers.unit.ts
Outdated
Show resolved
Hide resolved
packages/repository/src/__tests__/unit/repositories/relation.helpers.unit.ts
Outdated
Show resolved
Hide resolved
packages/repository/src/__tests__/unit/repositories/relation.helpers.unit.ts
Outdated
Show resolved
Hide resolved
packages/repository/src/__tests__/unit/repositories/relation.helpers.unit.ts
Outdated
Show resolved
Hide resolved
packages/repository/src/__tests__/unit/repositories/relation.helpers.unit.ts
Outdated
Show resolved
Hide resolved
fe33565
to
f455a65
Compare
602aa1b
to
724a09c
Compare
724a09c
to
02fe727
Compare
@@ -100,6 +101,8 @@ export class DefaultCrudRepository< | |||
> implements EntityCrudRepository<T, ID, Relations> { | |||
modelClass: juggler.PersistedModelClass; | |||
|
|||
public inclusionResolvers: Map<string, InclusionResolver<T, Entity>>; |
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.
public readonly inclusionResolvers: Map<string, InclusionResolver<T, Entity>> = new Map();
/** | ||
* List of source models as returned by the first database query. | ||
*/ | ||
sourceEntities: S[], |
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 wonder if sourceEntities
needs to have a generic type S
. It's not helping the compiler much.
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.
@raymondfeng I suggested to add a generic type S
to avoid specifying the source entity's type like
const resolver: InclusionResolver = async entities => {
// you need to specify Category....
const c = entities[0] as Category;
const product: Product[] = await categoryRepo.products(c.id).find();
return [product];
};
categoryRepo.inclusionResolvers.set('products', resolver);
In the resolver function.
See the current resolver function
vs
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 see. It sounds good then.
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.
On a second thought...maybe the resolver should be written as
const hasManyResolver: InclusionResolver = async (entities: Category[]) => {
const products: Product[] = [];
for (const category of entities) {
const product = await categoryRepo.products(category.id).find();
products.push(product);
}
return products;
};
?
Then we don't need the generic type.
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.
The current signature with S
seems to be better.
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.
IIRC, generic arguments are pretty useless here. At high level, we need a registry of resolvers, mapping from relation name (e.g. products
) to a resolver. This registry cannot use generic types and has to fall back to Entity
.
That's why I am using the following definition in my spike:
I am concerned that the current design creates a false sense of safety - the resolver is implemented with the assumption that it will be called with certain S
and T
types, but in reality the code calling it will always allow any Entity
.
Having said that, I see how the stubbed resolvers are easier to implement when generic arguments are in place.
I don't have enough insight now to be able to judge what aspect is more important.
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.
Ha, I take my comment back. When I reviewed code below, I found that it is able to provide a meaningful value for S
.
public readonly inclusionResolvers: Map<
string,
InclusionResolver<T, Entity>
> = new Map();
Nice trick! I agree that we should keep the generic argument for the type of the source entity.
The remaining question is whether we need the second generic argument for the type of the target (related) entity?
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.
It would help the developer with the return type for each resolver (e.g. restricting to type Product
), but I don't think it's too important.
02fe727
to
8969d4c
Compare
8969d4c
to
50fb53f
Compare
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 reviewed the production code, will try to review the tests tomorrow.
|
||
describe('findByForeignKeys', () => { | ||
describe('relation helpers', () => { |
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.
This test file is growing quite large. Can we split it into two files please? One test file for findByForeignKeys
(this can be hopefully just a rename from relation.helpers.unit.ts
to something like find-by-foreing-key.ts
or relations-helpers/find-by-foreign.keys
, with no code changes needed), another test file for the new helper includeRelatedModels
.
/** | ||
* List of source models as returned by the first database query. | ||
*/ | ||
sourceEntities: S[], |
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.
IIRC, generic arguments are pretty useless here. At high level, we need a registry of resolvers, mapping from relation name (e.g. products
) to a resolver. This registry cannot use generic types and has to fall back to Entity
.
That's why I am using the following definition in my spike:
I am concerned that the current design creates a false sense of safety - the resolver is implemented with the assumption that it will be called with certain S
and T
types, but in reality the code calling it will always allow any Entity
.
Having said that, I see how the stubbed resolvers are easier to implement when generic arguments are in place.
I don't have enough insight now to be able to judge what aspect is more important.
/** | ||
* List of source models as returned by the first database query. | ||
*/ | ||
sourceEntities: S[], |
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.
Ha, I take my comment back. When I reviewed code below, I found that it is able to provide a meaningful value for S
.
public readonly inclusionResolvers: Map<
string,
InclusionResolver<T, Entity>
> = new Map();
Nice trick! I agree that we should keep the generic argument for the type of the source entity.
The remaining question is whether we need the second generic argument for the type of the target (related) entity?
packages/repository/src/__tests__/unit/repositories/relation.helpers.unit.ts
Outdated
Show resolved
Hide resolved
4a445c8
to
82a7a23
Compare
… helper function Add InclusionResolver type, includeRelatedModels and isInclusionAllowed helpers. Co-authored-by: Nora <[email protected]> Co-authored-by: Miroslav Bajtoš <[email protected]>
82a7a23
to
7d8e85d
Compare
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.
👍 🚢
resolves #3445
When reviewing, select
hide white space changes
would make it easier to review 😄Checklist
👉 Read and sign the CLA (Contributor License Agreement) 👈
npm test
passes on your machinepackages/cli
were updatedexamples/*
were updated👉 Check out how to submit a PR 👈