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(context): add support to sort bindings for @inject.* and ContextView #2848

Merged
merged 2 commits into from
May 13, 2019

Conversation

raymondfeng
Copy link
Contributor

@raymondfeng raymondfeng commented May 7, 2019

This PR introduces BindingSorter to help sort bindings discovered from contexts. Some extension points need to control the order of bound extensions. Such APIs can be used to sort life cycle observers
and global interceptors after the PR is landed.

It has two commits:

  1. Add BindingComparator interface and a utility to sort by group tag.
  2. Add support of bindingComparator for ContextView and @inject.*.

Checklist

👉 Read and sign the CLA (Contributor License Agreement) 👈

  • npm test passes on your machine
  • New tests added or existing tests modified to cover all changes
  • Code conforms with the style guide
  • API Documentation in code was updated
  • Documentation in /docs/site was updated
  • Affected artifact templates in packages/cli were updated
  • Affected example projects in examples/* were updated

👉 Check out how to submit a PR 👈

Copy link
Contributor

@jannyHou jannyHou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Mostly LGTM. I left a comment about the order of unknown group.

@raymondfeng raymondfeng requested a review from jannyHou May 7, 2019 18:05
@raymondfeng raymondfeng added Extensions feature IoC/Context @loopback/context: Dependency Injection, Inversion of Control labels May 7, 2019
@emonddr
Copy link
Contributor

emonddr commented May 8, 2019

@raymondfeng , tiny typo.

Some extension points need to control of order of bound extensions.

Some extension points need to control the order of bound extensions.

@emonddr
Copy link
Contributor

emonddr commented May 8, 2019

@raymondfeng
Question: what is it's referring to?

Such APIs can be used to sort life cycle observers and global interceptors after it's landed.
If it's refers to the life cycle observers and global interceptors, we should use they . If it refers to something else, please clarify. Thanks.

@emonddr
Copy link
Contributor

emonddr commented May 8, 2019

@raymondfeng

If you could please provide an example of when it helps that bindings are sorted. I thought bindings were stored in a hashmap and were resolved quickly. Is it more for a programmer that is writing a specific piece of logic that needs to pass through a list in a particular fashion?

Copy link
Contributor

@emonddr emonddr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Just have a few questions in the comments area.

@raymondfeng
Copy link
Contributor Author

If you could please provide an example of when it helps that bindings are sorted. I thought bindings were stored in a hashmap and were resolved quickly. Is it more for a programmer that is writing a specific piece of logic that needs to pass through a list in a particular fashion?

Bindings are stored in a Map by keys. No sorting is involved when a binding is resolved by key. The binding sorter is only allowed for @inject.* or ContextView that takes a BindingFilter function to select multiple bindings, such as:

  1. Registered life cycle observers
  2. Request body parsers
  3. Global interceptors

Copy link
Contributor

@b-admike b-admike left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got one question, otherwise LGTM.

packages/context/src/__tests__/unit/binding-sorter.unit.ts Outdated Show resolved Hide resolved
Copy link
Member

@bajtos bajtos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of allowing @inject* consumers to specify ordering of the injected bindings 👍

The implementation looks good at design level.

However, I find the naming convention rather problematic. I feel the name sorter implies the function will perform the sort, while in reality it's a compareFunction passed to Array.prototype.sort. Let's find a better name please and update all places accordingly.

docs/site/Decorators_inject.md Outdated Show resolved Hide resolved
docs/site/Decorators_inject.md Outdated Show resolved Hide resolved
packages/context/src/__tests__/unit/context-view.unit.ts Outdated Show resolved Hide resolved
packages/context/src/__tests__/unit/context-view.unit.ts Outdated Show resolved Hide resolved
packages/context/src/binding-sorter.ts Outdated Show resolved Hide resolved
packages/context/src/binding-sorter.ts Outdated Show resolved Hide resolved
packages/context/src/binding-sorter.ts Outdated Show resolved Hide resolved
packages/context/src/context-view.ts Show resolved Hide resolved
packages/context/src/inject.ts Show resolved Hide resolved
@bajtos
Copy link
Member

bajtos commented May 9, 2019

@raymondfeng How do you envision integration & interaction of this new feature with Extension Point/Extension pattern? Can code receiving a list of extension bindings use this new feature out of the box?

@raymondfeng raymondfeng changed the title feat(context): add binding sorter feat(context): add support to sort bindings for @inject.* and ContextView May 9, 2019
@raymondfeng
Copy link
Contributor Author

How do you envision integration & interaction of this new feature with Extension Point/Extension pattern? Can code receiving a list of extension bindings use this new feature out of the box?

Yes, I'll refactor some of the extension points to use this new feature in two flavors:

  1. Use bindingComparator for @extensions
  2. Use bindingComparator for ContextView or @inject.view

@raymondfeng raymondfeng force-pushed the binding-sorter branch 3 times, most recently from c25308f to 89ab031 Compare May 9, 2019 14:55
@raymondfeng raymondfeng requested a review from bajtos May 9, 2019 14:56
@raymondfeng raymondfeng force-pushed the binding-sorter branch 3 times, most recently from d7d5657 to add0552 Compare May 9, 2019 19:07
docs/site/Decorators_inject.md Show resolved Hide resolved
packages/context/src/binding-sorter.ts Outdated Show resolved Hide resolved
packages/context/src/binding-sorter.ts Outdated Show resolved Hide resolved
Copy link
Member

@bajtos bajtos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks mostly good, I have few more minor comments to consider.

No further review is necessary as far as I am concerned, but please get at least one or two more approvals from other team members.

@@ -32,7 +34,7 @@ export class RequestBodyParser {
readonly parsers: BodyParser[];

constructor(
@inject.tag(REQUEST_BODY_PARSER_TAG, {optional: true})
@inject(filterByTag(REQUEST_BODY_PARSER_TAG), {optional: true})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reasoning for this change? Is it just a stylistic refactoring, or does it introduce any changes in the externally-observed behavior, e.g. the order in which the parsers are invoked?

I am ok with the change, but would like to better understand the consequences.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's stylistic. IIRC, we would like to deprecate @inject.tag in the future and use @inject with a filter function instead.

* @param bindingComparatorOrSession A function to sort matched bindings or
* resolution session if the comparator is not needed
* @param session Resolution session if the comparator is provided
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the actual implementation should not have any tsdoc comments. We have already described the two flavors recognized by the compiler when validating places calling this method. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments are for maintainers only. I assume strong-docs or tsdocs only expose the method signatures (not implementation).

packages/context/src/inject.ts Outdated Show resolved Hide resolved
- add ability to sort bindings by tag values
- allow binding sorter on ContextView and @Inject.*
@raymondfeng raymondfeng merged commit db1c004 into master May 13, 2019
@raymondfeng raymondfeng deleted the binding-sorter branch May 13, 2019 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Extensions feature IoC/Context @loopback/context: Dependency Injection, Inversion of Control
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants