Skip to content

Commit

Permalink
Merge pull request #1 from Avocarrot/refactor/improvements
Browse files Browse the repository at this point in the history
Refactor/improvements
  • Loading branch information
giorgosera authored Aug 2, 2016
2 parents d9a2a09 + 68f18b7 commit 9971328
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 91 deletions.
101 changes: 59 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,85 @@

## Purpose

Given an array of objects returns those that satisfy some or all desired filters.
A utility library which filters objects from an array of objects based on a set of filter conditions.

```javascript
const query = require('query-objects');

const users = [
{
firstName: 'George',
lastName: 'Eracleous',
age: 28
},
{
firstName: 'Erica',
lastName: 'Archer',
age: 50
},
{
firstName: 'Leo',
lastName: 'Andrews',
age: 20
}
];

const filters = [
{
field: 'age',
value: 30,
operator: 'lt'
},
{
field: 'firstName',
value: 'Erica',
operator: 'equals'
}
];

// Filter all users that are less than 30 years old AND their first name is Erica
const res = query(users).every(filters);

// Filter all users that are less than 30 years old OR their first name is Erica
const res = query(users).some(filters);

```

## Contents

- [Installation](#installation)
- [Filtering objects](#filtering-objects)
- [Constructing filters](#constructing-filters)
- [Usage](#usage)
- [Filters](#filters)
- [Examples](#examples)
- [Contributing](#contributing)

## Installation

```npm install filter-objects```

## Filtering objects

```filter(arr, filters, operator)```
## Usage

Returns an array of all the objects in `arr` that satisfy the `filters`. `operator` can take two values `every` or 'some'. If 'every' is used then the returned objects satisfy *every* filter or alternatively if 'some' is used then the returned objects satisfy at least one of the filters.
1. Create a query object by using `query(arr)` where `arr` is the array of objects you want to query.

## Constructing filters

`field` - The name of the property we will filter on
```javascript
const q = query(arr)
```

`value` - The value of the property we will filter on
2. Finally get the result array using:

`operator` - The filter operator. Supported operators `equals`, `contains`, `gt`, `gte`, `lt`, `lte`
```javascript
q.every(filters); //returns an array of all objects in `arr` that satisfy EVERY filter

## Examples
q.some(filters); //returns an array of all objects in `arr` that satisfy SOME of the filters
```

```javascript
const filters = [
{
field: 'foo',
value: 1,
operator: 'equals'
},
{
field: 'bar',
value: 'baz',
operator: 'equals'
}
];
## Filters

const arr = [
{
foo: 1,
bar: 'baz'
},
{
foo: 2,
bar: 'baz'
},
{
foo: 3,
bar: 'fiz'
}
];
`field` - The name of the property we will filter on

let res = filter(arr, filters, 'every');
```
`value` - The value of the property we will filter on

`operator` - The filter operator. Supported operators `equals`, `contains`, `gt`, `gte`, `lt`, `lte`

## Contributing

Expand Down
8 changes: 2 additions & 6 deletions lib/filterArr.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ const match = (filters, operator) => {
};

module.exports = (arr, filters, operator) => {
if (!Array.isArray(arr)) {
throw new Error('`arr` must be an array of objects');
}

if (!Array.isArray(filters)) {
throw new Error('`filters` must be an array of filters');
}
Expand All @@ -21,7 +17,7 @@ module.exports = (arr, filters, operator) => {
throw new Error('Invalid operator');
}

filters = filters.map(f => parseFilter(f));
const matches = match(filters, operator);
const parsedFilters = filters.map(f => parseFilter(f));
const matches = match(parsedFilters, operator);
return arr.filter(matches);
};
12 changes: 11 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
module.exports = require('./find');
const filterArr = require('./filterArr');

module.exports = (arr) => {
if (!Array.isArray(arr)) {
throw new Error('`arr` must be an array of objects');
}
return {
every: filters => filterArr(arr, filters, 'every'),
some: filters => filterArr(arr, filters, 'some'),
};
}
20 changes: 4 additions & 16 deletions lib/operators.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,10 @@ const contains = (val1, val2) => {
};

const equals = (val1, val2) => val1 === val2;

const gt = (val1, val2) => {
return val1 > val2;
};

const gte = (val1, val2) => {
return val1 >= val2;
};

const lt = (val1, val2) => {
return val1 < val2;
};

const lte = (val1, val2) => {
return val1 <= val2;
};
const gt = (val1, val2) => val1 > val2;
const gte = (val1, val2) => val1 >= val2;
const lt = (val1, val2) => val1 < val2;
const lte = (val1, val2) => val1 <= val2;

module.exports = {
contains,
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "query-objects",
"version": "0.0.1",
"description": "Given an array of objects returns those that satisfy some or all desired filters",
"version": "0.0.2",
"description": "A utility library which filters objects from an array of objects based on a set of filter conditions",
"main": "index.js",
"scripts": {
"test": "NODE_ENV=test mocha --recursive test",
Expand Down
2 changes: 1 addition & 1 deletion test/lib/filter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ describe('Filter module tests', () => {
isSatisfied({field: 'foo', value: 'bar', operator: 'equals'}, {'fiz': 'bar'}).should.be.false;
});

});
});
32 changes: 9 additions & 23 deletions test/lib/filterArr.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,60 +33,46 @@ describe('filter(arr, filters, operator) should', () => {
}
];

it('throw an error if `arr` is not an array', () => {
(() => {
filter()();
}).should.throw('`arr` must be an array of objects');

(() => {
filter(null)();
}).should.throw('`arr` must be an array of objects');

(() => {
filter(1234)();
}).should.throw('`arr` must be an array of objects');
});

it('throw an error if `filters` is not an array', () => {
(() => {
filter([])();
filter(arr);
}).should.throw('`filters` must be an array');

(() => {
filter([], null)();
filter(arr, 'this is a string');
}).should.throw('`filters` must be an array');

(() => {
filter([], 1234)();
filter(arr, 1234);
}).should.throw('`filters` must be an array');
});

it('throw an error if `filters` contains an object which is not a valid filter', () => {
(() => {
filter([], [{key: 'value'}], 'every')();
filter(arr, [{key: 'value'}], 'every');
}).should.throw('Object is not a valid filter');
});

it('throw an error if `operator` is invalid', () => {
(() => {
filter([], [], 'wrong')();
filter(arr, filters);
}).should.throw('Invalid operator');

(() => {
filter([], [], 'every')();
filter(arr, filters, 'every');
}).should.not.throw('Invalid operator');

(() => {
filter([], [], 'some')();
filter(arr, filters, 'some');
}).should.not.throw('Invalid operator');
});

it('return all the objects in `arr` which satisfy every filter in the array with filters `f` given that `operator` is `every`', () => {
it('return all the objects in `arr` which satisfy every filter in the array of `filters` given that `operator` is `every`', () => {
const expected = [arr[0]];
filter(arr, filters, 'every').should.eql(expected);
});

it('return all the objects in `arr` which satisfies at least one of the filters in the array with filters `f` given that `operator` is `some`', () => {
it('return all the objects in `arr` which satisfy at least one of the `filters` given that `operator` is `some`', () => {
const expected = [arr[0], arr[1]];
filter(arr, filters, 'some').should.eql(expected);
});
Expand Down
82 changes: 82 additions & 0 deletions test/lib/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const should = require('chai').Should();
const query = require('../../lib');

describe('Module Tests', () => {

const people = [
{
name: 'George',
lastName: 'Eracleous',
age: 28
},
{
name: 'Erica',
lastName: 'Archer',
age: 20
},
{
name: 'George',
lastName: 'Makkoulis',
age: 57
},
{
name: 'Bob',
lastName: 'Smith',
age: 32
}
];

it('query(arr) should return a query object', () => {
query([]).should.have.property('every');
query([]).should.have.property('some');
});

it('throw an error if `arr` is not an array', () => {
(() => {
query();
}).should.throw('`arr` must be an array of objects');

(() => {
query('this is a string');
}).should.throw('`arr` must be an array of objects');

(() => {
query(1234);
}).should.throw('`arr` must be an array of objects');
});

it('query(arr).every(filters) should return all results that satisfy all filters', () => {
const filters = [
{
field: 'name',
value: 'George',
operator: 'equals'
},
{
field: 'age',
value: 30,
operator: 'lt'
}
];
const expected = [people[0]];
query(people).every(filters).should.eql(expected);
});

it('query(arr).some(filters) should return all results that satisfy at least one of the filters', () => {
const filters = [
{
field: 'name',
value: 'George',
operator: 'equals'
},
{
field: 'age',
value: 30,
operator: 'lt'
}
];
const expected = [people[0], people[1], people[2]];
query(people).some(filters).should.eql(expected);
});

});

0 comments on commit 9971328

Please sign in to comment.