Skip to content

Commit

Permalink
Merge a3dcdab into c349cc8
Browse files Browse the repository at this point in the history
  • Loading branch information
gastonpereyra committed Jun 2, 2020
2 parents c349cc8 + a3dcdab commit f0b1017
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- multiple search filters

## [3.2.1] - 2020-05-19
### Fixed
- filters validation unit test fixed
Expand Down
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ module.exports = class MyApiListData extends ApiListData {
];
}

get searchFilters() {
return [
'id',
'quantity'
];
}

async formatRows(rows) {
return rows.map(row => ({ ...row, oneMoreField: true }));
}
Expand Down Expand Up @@ -147,3 +154,36 @@ module.exports = class MyApiListData extends ApiListData {

};
```

### get searchFilters()
This is used to indicate which fields will be used to mapped multiple filters (OR Type) for the same value, using only `search` as single filter.
If it don't exist or return an empty array and try to use `search` filter will return 400 status code.
Can be combined with other filters.

For example:
```js
'use strict';

const {
ApiListData
} = require('@janiscommerce/api-list');

module.exports = class MyApiListData extends ApiListData {

get searchFilters() {
return ['someField', 'otherField'];
}
};
```

* `/api/entity?filters[search]=1` with a single value.

Will filter the list for `someField: 1` or `otherField: 1`

* `/api/entity?filters[search]=fo` with a uncomplete word.

Will filter the list for `someField: fo` or `otherField: fo` and will do a parcial filter (like using `searchMapper`).

* `/api/entity?filters[search]=foo bar` with multiples words divided by white spaces.

Will filter the list for `someField: foo` or `someField: bar` or `otherField: foo` or `otherField: bar`.
2 changes: 1 addition & 1 deletion lib/api-list-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class ApiListData extends API {
...this.parents
};

this.filter = new Filter(requestFilters, this.availableFilters);
this.filter = new Filter(requestFilters, this.availableFilters, this.searchFilters);
this.paging = new Paging(this.headers);
this.sort = new Sort(this.data, this.sortableFields);

Expand Down
49 changes: 40 additions & 9 deletions lib/data-helpers/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,27 @@ const { struct } = require('superstruct');

class ListFilter {

constructor(requestFilters, availableFilters) {
constructor(requestFilters, availableFilters, searchFilters) {
this.requestFilters = requestFilters;
this.searchFilters = searchFilters || [];
this.availableFilters = availableFilters.map(filter => {
return typeof filter === 'object' ? filter : { name: filter };
});
}

struct() {

if(!this.availableFilters.length)
const filters = [...this.availableFilters];

if(this.requestFilters.search && this.searchFilters.length)
filters.push({ name: 'search' });

if(!filters.length)
return {};

const filterStruct = {};

for(const filter of this.availableFilters)
for(const filter of filters)
filterStruct[filter.name] = struct.optional('string | number | array');

return {
Expand All @@ -34,9 +40,24 @@ class ListFilter {

getParams({ filters: clientFiltersWithDefaults }) {

return this.availableFilters.filter(filter => {
const filtersParams = [
...this.getParamsFromAvailableFilters(clientFiltersWithDefaults),
...this.getParamsFromSearchFilters(clientFiltersWithDefaults)
];

if(!filtersParams.length)
return {};

return {
filters: filtersParams.length === 1 ? filtersParams[0] : filtersParams
};
}

getParamsFromAvailableFilters(clientFiltersWithDefaults) {

const availableFiltersParams = this.availableFilters.filter(filter => {
return clientFiltersWithDefaults[filter.name] !== undefined;
}).reduce(({ filters }, filter) => {
}).reduce((filters, filter) => {

const originalValue = clientFiltersWithDefaults[filter.name];

Expand All @@ -47,14 +68,24 @@ class ListFilter {
const finalName = typeof internalName === 'function' ? internalName(filter, filterValue, originalValue) : internalName;

return {
filters: {
...filters,
[finalName]: filterValue
}
...filters,
[finalName]: filterValue
};
}, {});

return Object.keys(availableFiltersParams).length ? [availableFiltersParams] : [];
}

getParamsFromSearchFilters({ search: searchOriginalValues } = {}) {
if(!searchOriginalValues)
return [];

const searchValues = searchOriginalValues.split(' ');

return this.searchFilters.map(filter => {
return searchValues.map(value => ({ [filter]: { type: 'search', value } }));
}).flat();
}
}

module.exports = ListFilter;

0 comments on commit f0b1017

Please sign in to comment.