-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat(filter): implement ensureFields utility #6495
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| // Copyright IBM Corp. 2020. All Rights Reserved. | ||
| // Node module: @loopback/filter | ||
| // This file is licensed under the MIT License. | ||
| // License text available at https://opensource.org/licenses/MIT | ||
|
|
||
| import {expect} from '@loopback/testlab'; | ||
| import {ensureFields, Filter} from '../..'; | ||
|
|
||
| describe('ensureFields', () => { | ||
| it('does not modify a filter when it does not specify fields', () => { | ||
| const filter = {} as Filter; | ||
| const {filter: newFilter, fieldsAdded} = ensureFields(['a', 'b'], filter); | ||
|
|
||
| expect(newFilter).to.eql({}); | ||
| expect(fieldsAdded).to.eql([]); | ||
| }); | ||
|
|
||
| it('does not modify a filter when it does not exclude target fields', () => { | ||
| const filter = {fields: {a: false, b: false}} as Filter; | ||
| const {filter: newFilter, fieldsAdded} = ensureFields(['c'], filter); | ||
|
|
||
| expect(newFilter).to.eql({fields: {a: false, b: false}}); | ||
| expect(fieldsAdded).to.eql([]); | ||
| }); | ||
|
|
||
| it('does not modify a filter when target fields are not specified', () => { | ||
| const filter = {fields: {a: false, b: false}} as Filter; | ||
| const {filter: newFilter, fieldsAdded} = ensureFields([], filter); | ||
|
|
||
| expect(newFilter).to.eql({fields: {a: false, b: false}}); | ||
| expect(fieldsAdded).to.eql([]); | ||
| }); | ||
|
|
||
| it('adds omitted fields', () => { | ||
| const filter = {fields: {a: true}} as Filter; | ||
| const {filter: newFilter, fieldsAdded} = ensureFields(['b'], filter); | ||
|
|
||
| expect(newFilter).to.eql({fields: {a: true, b: true}}); | ||
| expect(fieldsAdded).to.eql(['b']); | ||
| }); | ||
|
|
||
| it('adds explicitly disabled fields', () => { | ||
| const filter = {fields: {a: true, b: false}} as Filter; | ||
| const {filter: newFilter, fieldsAdded} = ensureFields(['b'], filter); | ||
|
|
||
| expect(newFilter).to.eql({fields: {a: true, b: true}}); | ||
| expect(fieldsAdded).to.eql(['b']); | ||
| }); | ||
|
|
||
| it('removes fields clause when it only excludes fields', () => { | ||
| const filter = {fields: {a: false, b: false}} as Filter; | ||
| const {filter: newFilter, fieldsAdded} = ensureFields(['b'], filter); | ||
|
|
||
| expect(newFilter).to.eql({}); | ||
| expect(fieldsAdded).to.eql(['a', 'b']); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,75 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Copyright IBM Corp. 2020. All Rights Reserved. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Node module: @loopback/filter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // This file is licensed under the MIT License. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // License text available at https://opensource.org/licenses/MIT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import _ from 'lodash'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import {Filter, FilterBuilder} from './query'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import {AnyObject} from './types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Ensures that queries which apply the returned filter would always include | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * the target fields. To undo this effect later, fields that were disabled | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * in the original filter will be added to the pruning mask. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param targetFields - An array of fields to include | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param filter - A target filter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @returns A tuple containing amended filter and pruning mask | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function ensureFields<T extends object = AnyObject>( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| targetFields: (keyof T)[], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| filter: Filter<T>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const builder = new FilterBuilder(filter); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fields = builder.build().fields; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!fields || matchesFields(targetFields, filter)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| filter: builder.build(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fieldsAdded: [] as (keyof T)[], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const isDisablingOnly = _.size(fields) > 0 && !_.some(fields, Boolean); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
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. this is some hard to understand a suggestion could be uses every instead of some negation a vanilla version:
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fieldsAdded = (isDisablingOnly ? _.keys(fields) : []) as (keyof T)[]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| targetFields.forEach(f => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!fields[f]) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fieldsAdded.push(f); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| builder.fields(f); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const newFilter = builder.build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // if the filter only hides the fields, unset the entire fields clause | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isDisablingOnly) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| delete filter.fields; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| filter: newFilter, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fieldsAdded: _.uniq(fieldsAdded) as (keyof T)[], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } as const; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+32
to
+49
Contributor
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.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Checks whether fields array passed as an argument is a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * subset of fields picked by a target filter. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param fields - An array of fields to search in a filter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param filter - A target filter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function matchesFields<T extends object = AnyObject>( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fields: (keyof T)[], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| filter?: Filter<T>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const normalized = new FilterBuilder(filter).build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const targetFields = normalized.fields; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!targetFields) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const isDisablingOnly = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _.size(targetFields) > 0 && !_.some(targetFields, Boolean); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const f of fields) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!targetFields[f] && (f in targetFields || !isDisablingOnly)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+58
to
+75
Contributor
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.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,3 +18,4 @@ | |
| */ | ||
|
|
||
| export * from './query'; | ||
| export * from './ensure-fields'; | ||
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.