Skip to content

Commit

Permalink
chore(context): rename binding sorter to comparator
Browse files Browse the repository at this point in the history
  • Loading branch information
raymondfeng committed May 9, 2019
1 parent e3eac7b commit 5be908f
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 41 deletions.
2 changes: 1 addition & 1 deletion docs/site/Context.md
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ should be able to pick up these new routes without restarting.
To support the dynamic tracking of such artifacts registered within a context
chain, we introduce `ContextObserver` interface and `ContextView` class that can
be used to watch a list of bindings matching certain criteria depicted by a
`BindingFilter` function and an optional `BindingSorter` function to sort
`BindingFilter` function and an optional `BindingComparator` function to sort
matched bindings.

```ts
Expand Down
4 changes: 2 additions & 2 deletions docs/site/Decorators_inject.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ class MyControllerWithValues {
```

To sort matched bindings found by the binding filter function, `@inject` honors
`bindingSorter` in `metadata`:
`bindingComparator` in `metadata`:

```ts
class MyControllerWithValues {
constructor(
@inject(binding => binding.tagNames.includes('foo'), {
bindingSorter: (a, b) => {
bindingComparator: (a, b) => {
// Sort by value of `foo` tag
return a.tagMap.foo.localCompare(b.tagMap.foo);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import {expect} from '@loopback/testlab';
import {
Context,
ContextView,
createSorterByGroup,
filterByTag,
Getter,
inject,
compareBindingsByGroup,
} from '../..';

let app: Context;
Expand All @@ -36,10 +36,10 @@ describe('@inject.* to receive multiple values matching a filter', async () => {
expect(await getter()).to.eql([3, 7, 5]);
});

it('injects as getter with bindingSorter', async () => {
it('injects as getter with bindingComparator', async () => {
class MyControllerWithGetter {
@inject.getter(workloadMonitorFilter, {
bindingSorter: createSorterByGroup('name'),
bindingComparator: compareBindingsByGroup('name'),
})
getter: Getter<number[]>;
}
Expand Down Expand Up @@ -76,11 +76,11 @@ describe('@inject.* to receive multiple values matching a filter', async () => {
expect(inst.values).to.eql([3, 5]);
});

it('injects as values with bindingSorter', async () => {
it('injects as values with bindingComparator', async () => {
class MyControllerWithBindingSorter {
constructor(
@inject(workloadMonitorFilter, {
bindingSorter: createSorterByGroup('name'),
bindingComparator: compareBindingsByGroup('name'),
})
public values: number[],
) {}
Expand All @@ -93,13 +93,13 @@ describe('@inject.* to receive multiple values matching a filter', async () => {
expect(inst.values).to.eql([5, 3]);
});

it('throws error if bindingSorter is provided without a filter', () => {
it('throws error if bindingComparator is provided without a filter', () => {
expect(() => {
// tslint:disable-next-line:no-unused
class ControllerWithInvalidInject {
constructor(
@inject('my-key', {
bindingSorter: createSorterByGroup('name'),
bindingComparator: compareBindingsByGroup('name'),
})
public values: number[],
) {}
Expand All @@ -126,10 +126,10 @@ describe('@inject.* to receive multiple values matching a filter', async () => {
expect(await view.values()).to.eql([3, 5]);
});

it('injects as a view with bindingSorter', async () => {
it('injects as a view with bindingComparator', async () => {
class MyControllerWithView {
@inject.view(workloadMonitorFilter, {
bindingSorter: createSorterByGroup('name'),
bindingComparator: compareBindingsByGroup('name'),
})
view: ContextView<number[]>;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/context/src/__tests__/unit/binding-sorter.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import {expect} from '@loopback/testlab';
import {Binding, sortBindingsByGroup} from '../..';

describe('BindingSorter', () => {
describe('BindingComparator', () => {
const orderedGroups = ['log', 'auth'];
const groupTagName = 'group';
let bindings: Binding<unknown>[];
Expand Down
4 changes: 2 additions & 2 deletions packages/context/src/__tests__/unit/context-view.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
BindingScope,
Context,
ContextView,
createSorterByGroup,
compareBindingsByGroup,
createViewGetter,
filterByTag,
} from '../..';
Expand All @@ -31,7 +31,7 @@ describe('ContextView', () => {
const view = new ContextView(
server,
filterByTag('foo'),
createSorterByGroup('foo', ['b', 'a']),
compareBindingsByGroup('foo', ['b', 'a']),
);
expect(view.bindings).to.eql([bindings[1], bindings[0]]);
});
Expand Down
32 changes: 22 additions & 10 deletions packages/context/src/binding-sorter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,28 @@
import {Binding} from './binding';

/**
* Compare function to sort bindings
* Compare function to sort an array of bindings.
* It is used by `Array.prototype.sort()`.
*/
export type BindingSorter = (
bindingA: Readonly<Binding<unknown>>,
bindingB: Readonly<Binding<unknown>>,
) => number;
export interface BindingComparator {
/**
* Compare two bindings
* @param bindingA First binding
* @param bindingB Second binding
* @returns A number to determine order of bindingA and bindingB
* - 0 leaves bindingA and bindingB unchanged
* - <0 bindingA comes before bindingB
* - >0 bindingA comes after bindingB
*/
(
bindingA: Readonly<Binding<unknown>>,
bindingB: Readonly<Binding<unknown>>,
): number;
}

/**
* Creates a binding sorter to sort bindings by tagged group name. Two bindings
* are compared as follows:
* Creates a binding compare function to sort bindings by tagged group name.
* Two bindings are compared as follows:
*
* 1. Get the `group` value from binding tags, if not present, default to `''`
* 2. If both bindings have `group` values in `orderedGroups`, honor the order
Expand All @@ -28,10 +40,10 @@ export type BindingSorter = (
* @param groupTagName Name of the tag for group
* @param orderedGroups An array of group names as predefined orders
*/
export function createSorterByGroup(
export function compareBindingsByGroup(
groupTagName: string = 'group',
orderedGroups: string[] = [],
): BindingSorter {
): BindingComparator {
return (a: Readonly<Binding<unknown>>, b: Readonly<Binding<unknown>>) => {
const g1: string = a.tagMap[groupTagName] || '';
const g2: string = b.tagMap[groupTagName] || '';
Expand Down Expand Up @@ -60,5 +72,5 @@ export function sortBindingsByGroup(
groupTagName?: string,
orderedGroups?: string[],
) {
return bindings.sort(createSorterByGroup(groupTagName, orderedGroups));
return bindings.sort(compareBindingsByGroup(groupTagName, orderedGroups));
}
14 changes: 7 additions & 7 deletions packages/context/src/context-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {EventEmitter} from 'events';
import {promisify} from 'util';
import {Binding} from './binding';
import {BindingFilter} from './binding-filter';
import {BindingSorter} from './binding-sorter';
import {BindingComparator} from './binding-sorter';
import {Context} from './context';
import {
ContextEventType,
Expand Down Expand Up @@ -44,7 +44,7 @@ export class ContextView<T = unknown> extends EventEmitter
constructor(
protected readonly context: Context,
public readonly filter: BindingFilter,
public readonly sorter?: BindingSorter,
public readonly sorter?: BindingComparator,
) {
super();
}
Expand Down Expand Up @@ -163,23 +163,23 @@ export class ContextView<T = unknown> extends EventEmitter
* Create a context view as a getter
* @param ctx Context object
* @param bindingFilter A function to match bindings
* @param bindingSorter A function to sort matched bindings
* @param bindingComparator A function to sort matched bindings
* @param session Resolution session
*/
export function createViewGetter<T = unknown>(
ctx: Context,
bindingFilter: BindingFilter,
bindingSorterOrSession?: BindingSorter | ResolutionSession,
bindingSorterOrSession?: BindingComparator | ResolutionSession,
session?: ResolutionSession,
): Getter<T[]> {
let bindingSorter: BindingSorter | undefined = undefined;
let bindingComparator: BindingComparator | undefined = undefined;
if (typeof bindingSorterOrSession === 'function') {
bindingSorter = bindingSorterOrSession;
bindingComparator = bindingSorterOrSession;
} else if (bindingSorterOrSession instanceof ResolutionSession) {
session = bindingSorterOrSession;
}

const view = new ContextView<T>(ctx, bindingFilter, bindingSorter);
const view = new ContextView<T>(ctx, bindingFilter, bindingComparator);
view.open();
return view.asGetter(session);
}
4 changes: 2 additions & 2 deletions packages/context/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {v1 as uuidv1} from 'uuid';
import {Binding, BindingTag} from './binding';
import {BindingFilter, filterByKey, filterByTag} from './binding-filter';
import {BindingAddress, BindingKey} from './binding-key';
import {BindingSorter} from './binding-sorter';
import {BindingComparator} from './binding-sorter';
import {
ContextEventObserver,
ContextEventType,
Expand Down Expand Up @@ -444,7 +444,7 @@ export class Context extends EventEmitter {
* @param filter A function to match bindings
* @param sorter A function to sort matched bindings
*/
createView<T = unknown>(filter: BindingFilter, sorter?: BindingSorter) {
createView<T = unknown>(filter: BindingFilter, sorter?: BindingComparator) {
const view = new ContextView<T>(this, filter, sorter);
view.open();
return view;
Expand Down
12 changes: 6 additions & 6 deletions packages/context/src/inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
isBindingAddress,
} from './binding-filter';
import {BindingAddress} from './binding-key';
import {BindingSorter} from './binding-sorter';
import {BindingComparator} from './binding-sorter';
import {BindingCreationPolicy, Context} from './context';
import {ContextView, createViewGetter} from './context-view';
import {ResolutionSession} from './resolution-session';
Expand Down Expand Up @@ -60,7 +60,7 @@ export interface InjectionMetadata {
/**
* Optional sorter for matched bindings
*/
bindingSorter?: BindingSorter;
bindingComparator?: BindingComparator;
/**
* Other attributes
*/
Expand Down Expand Up @@ -118,7 +118,7 @@ export function inject(
resolve = resolveValuesByFilter;
}
const injectionMetadata = Object.assign({decorator: '@inject'}, metadata);
if (injectionMetadata.bindingSorter && !resolve) {
if (injectionMetadata.bindingComparator && !resolve) {
throw new Error('Binding sorter is only allowed with a binding filter');
}
return function markParameterOrPropertyAsInjected(
Expand Down Expand Up @@ -544,7 +544,7 @@ function resolveValuesByFilter(
const view = new ContextView(
ctx,
bindingFilter,
injection.metadata.bindingSorter,
injection.metadata.bindingComparator,
);
return view.resolve(session);
}
Expand All @@ -567,7 +567,7 @@ function resolveAsGetterByFilter(
return createViewGetter(
ctx,
bindingFilter,
injection.metadata.bindingSorter,
injection.metadata.bindingComparator,
session,
);
}
Expand All @@ -585,7 +585,7 @@ function resolveAsContextView(ctx: Context, injection: Readonly<Injection>) {
const view = new ContextView(
ctx,
bindingFilter,
injection.metadata.bindingSorter,
injection.metadata.bindingComparator,
);
view.open();
return view;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/extension-point.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function extensions(extensionPointName?: string) {
return createViewGetter(
ctx,
bindingFilter,
injection.metadata.bindingSorter,
injection.metadata.bindingComparator,
session,
);
});
Expand Down

0 comments on commit 5be908f

Please sign in to comment.