Skip to content

Commit

Permalink
check values in column of type array - Op.in and Op.notIn operators (#14
Browse files Browse the repository at this point in the history
)

* Check values in a column that has array of values using Op.in and Op.notIn operators
* 0.3.0
  • Loading branch information
yusufshakeel authored Jan 8, 2025
1 parent 7d77f5a commit 3410443
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 30 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Minimalistic JSON database.

[![Build Status](https://github.com/yusufshakeel/minivium/actions/workflows/ci.yml/badge.svg)](https://github.com/yusufshakeel/minivium/actions/workflows/ci.yml)
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/yusufshakeel/minivium)
[![npm version](https://img.shields.io/badge/npm-0.2.4-blue.svg)](https://www.npmjs.com/package/minivium)
[![npm version](https://img.shields.io/badge/npm-0.3.0-blue.svg)](https://www.npmjs.com/package/minivium)
[![npm Downloads](https://img.shields.io/npm/dm/minivium.svg)](https://www.npmjs.com/package/minivium)

![img.webp](assets/img.webp)
Expand Down Expand Up @@ -484,6 +484,8 @@ select * from users
where email in ['yusuf@example.com'];
```

The `Op.in` operator will work for column with `string`, `string[]`, `number`, `number[]` values.

### Not in `notIn`

```js
Expand All @@ -504,6 +506,8 @@ select * from users
where email not in ['yusuf@example.com'];
```

The `Op.notIn` operator will work for column with `string`, `string[]`, `number`, `number[]` values.

### Greater than `gt`

```js
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "minivium",
"version": "0.2.4",
"version": "0.3.0",
"description": "Minimalistic JSON database.",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
Expand Down
32 changes: 22 additions & 10 deletions src/helpers/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,28 @@ import { Op } from '../core/Operators';
import { Filter, Condition } from '../types/where';

const actions: any = {
[Op.eq]: (itemValue: any, value: any) => itemValue === value,
[Op.notEq]: (itemValue: any, value: any) => itemValue !== value,
[Op.in]: (itemValue: any, value: any) => value.includes(itemValue),
[Op.notIn]: (itemValue: any, value: any) => !value.includes(itemValue),
[Op.gt]: (itemValue: any, value: any) => itemValue > value,
[Op.gte]: (itemValue: any, value: any) => itemValue >= value,
[Op.lt]: (itemValue: any, value: any) => itemValue < value,
[Op.lte]: (itemValue: any, value: any) => itemValue <= value,
[Op.between]: (itemValue: any, value: any) =>
itemValue >= value[0] && itemValue <= value[1]
[Op.eq]: (fieldValue: any, searchValue: any) => fieldValue === searchValue,
[Op.notEq]: (fieldValue: any, searchValue: any) => fieldValue !== searchValue,
[Op.in]: (needle: any | any[], haystack: any[]) => {
if (Array.isArray(needle)) {
return haystack.some(h => needle.includes(h));
} else {
return haystack.includes(needle);
}
},
[Op.notIn]: (needle: any, haystack: any[]) => {
if (Array.isArray(needle)) {
return haystack.every(h => !needle.includes(h));
} else {
return !haystack.includes(needle);
}
},
[Op.gt]: (fieldValue: any, searchValue: any) => fieldValue > searchValue,
[Op.gte]: (fieldValue: any, searchValue: any) => fieldValue >= searchValue,
[Op.lt]: (fieldValue: any, searchValue: any) => fieldValue < searchValue,
[Op.lte]: (fieldValue: any, searchValue: any) => fieldValue <= searchValue,
[Op.between]: (fieldValue: any, betweenValues: any) =>
fieldValue >= betweenValues[0] && fieldValue <= betweenValues[1]
};

const evaluateCondition =
Expand Down
6 changes: 6 additions & 0 deletions test/testdata/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,10 @@ export const usersForSorting = [
{ id: 2, firstName: 'Charlie', lastName: 'Wise', createdAt: '2025-01-01', updatedAt: '2025-01-02' },
{ id: 3, firstName: 'Alice', lastName: 'Anderson', createdAt: '2025-01-02', updatedAt: '2025-01-04' },
{ id: 4, firstName: 'Bob', lastName: 'Builder', createdAt: '2025-01-02', updatedAt: '2025-01-02' }
];

export const userMembershipForColumnWithArrayOfValues = [
{ id: 1, membership: ['red', 'green'] },
{ id: 2, membership: ['red', 'green', 'blue'] },
{ id: 3, membership: ['yellow'] }
];
91 changes: 75 additions & 16 deletions test/unit/helpers/filter.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { filter } from '../../../src/helpers/filter';
import { Op } from '../../../src/core/Operators';
import { users as data } from '../../testdata/users';
import {
users as data,
userMembershipForColumnWithArrayOfValues as dataColumnsWithArrayOfValues
} from '../../testdata/users';

describe('filter', () => {
it('should throw error for invalid operator', () => {
Expand Down Expand Up @@ -43,23 +46,79 @@ describe('filter', () => {
]);
});

it('should return matching entries by in', () => {
const result =
filter(data, { score: { [Op.in]: [30, 40] } });
expect(result).toStrictEqual([
{ id: 2, name: 'jane', score: 30, isOnline: true, status: 'active', createdAt: '2024-12-01' },
{ id: 3, name: 'tom', score: 40, isOnline: false, status: 'inactive', createdAt: '2024-12-02' },
{ id: 4, name: 'jerry', score: 30, isOnline: true, status: 'active', createdAt: '2024-12-03' }
]);
describe('in', () => {
describe('column with non-array value', () => {
it('should return matching entries by in', () => {
const result =
filter(data, { score: { [Op.in]: [30, 40] } });
expect(result).toStrictEqual([
{ id: 2, name: 'jane', score: 30, isOnline: true, status: 'active', createdAt: '2024-12-01' },
{ id: 3, name: 'tom', score: 40, isOnline: false, status: 'inactive', createdAt: '2024-12-02' },
{ id: 4, name: 'jerry', score: 30, isOnline: true, status: 'active', createdAt: '2024-12-03' }
]);
});

it('should return empty array when there is no match for the in', () => {
const result =
filter(data, { score: { [Op.in]: [100, 200] } });
expect(result).toStrictEqual([]);
});
});

describe('column with array of values', () => {
it('should return matching entries by in', () => {
const result =
filter(dataColumnsWithArrayOfValues, { membership: { [Op.in]: ['red'] } });
expect(result).toStrictEqual([
{ id: 1, membership: ['red', 'green'] },
{ id: 2, membership: ['red', 'green', 'blue'] }
]);
});

it('should return empty array when there is no match for the in', () => {
const result =
filter(dataColumnsWithArrayOfValues, { membership: { [Op.in]: ['purple'] } });
expect(result).toStrictEqual([]);
});
});
});

it('should return matching entries by notIn', () => {
const result =
filter(data, { score: { [Op.notIn]: [30, 40] } });
expect(result).toStrictEqual([
{ id: 1, name: 'john', score: 20, isOnline: false, status: 'active', createdAt: '2024-12-01' },
{ id: 5, name: 'bruce', score: 50, isOnline: true, status: 'active', createdAt: '2024-12-05' }
]);
describe('notIn', () => {
describe('column with non-array value', () => {
it('should return matching entries by notIn', () => {
const result =
filter(data, { score: { [Op.notIn]: [30, 40] } });
expect(result).toStrictEqual([
{ id: 1, name: 'john', score: 20, isOnline: false, status: 'active', createdAt: '2024-12-01' },
{ id: 5, name: 'bruce', score: 50, isOnline: true, status: 'active', createdAt: '2024-12-05' }
]);
});

it('should return empty array when there is no match for the notIn', () => {
const result =
filter(data, { score: { [Op.notIn]: [20, 30] } });
expect(result).toStrictEqual([
{ id: 3, name: 'tom', score: 40, isOnline: false, status: 'inactive', createdAt: '2024-12-02' },
{ id: 5, name: 'bruce', score: 50, isOnline: true, status: 'active', createdAt: '2024-12-05' }
]);
});
});

describe('column with array of values', () => {
it('should return matching entries by notIn', () => {
const result =
filter(dataColumnsWithArrayOfValues, { membership: { [Op.notIn]: ['red'] } });
expect(result).toStrictEqual([
{ id: 3, membership: ['yellow'] }
]);
});

it('should return empty array when there is no match for the notIn', () => {
const result =
filter(dataColumnsWithArrayOfValues, { membership: { [Op.notIn]: ['red', 'yellow'] } });
expect(result).toStrictEqual([]);
});
});
});

it('should return matching entries by gt', () => {
Expand Down

0 comments on commit 3410443

Please sign in to comment.