Socket
Socket
Sign inDemoInstall

algolia-search-builder

Package Overview
Dependencies
0
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.0 to 1.1.0

build/operators/equal-factory.d.ts

187

build/index.js

@@ -8,9 +8,15 @@ (function (global, factory) {

class Operator {
constructor(operator) {
this.operator = operator;
}
}
class LogicalOperator extends Operator {
constructor(values) {
super();
constructor(values, operator) {
super(operator);
this.values = values;
}
validate() {
this.values.forEach((operator) => operator.validate());
}
}

@@ -20,4 +26,4 @@

class NumericOperator extends Operator {
constructor(fieldName, value) {
super();
constructor(fieldName, value, operator) {
super(operator);
this.fieldName = fieldName;

@@ -27,3 +33,5 @@ this.value = value;

validate() {
return true;
if (typeof this.value !== 'number') {
throw new Error(`The ${this.operator} accepts numeric values only`);
}
}

@@ -34,4 +42,4 @@ }

class RangeOperator extends Operator {
constructor(fieldName, value) {
super();
constructor(fieldName, value, operator) {
super(operator);
this.fieldName = fieldName;

@@ -41,3 +49,5 @@ this.value = value;

validate() {
return true;
const allAreNumeric = this.value.every((number) => typeof number === 'number');
if (!allAreNumeric)
throw new Error(`The ${this.operator} accepts only array of numeric values`);
}

@@ -48,2 +58,6 @@ }

class AndOperator extends LogicalOperator {
constructor(values) {
super(values, 'and');
this.values = values;
}
exec() {

@@ -54,5 +68,2 @@ return this.values

}
validate() {
return true;
}
}

@@ -62,2 +73,7 @@

class BetweenOperator extends RangeOperator {
constructor(fieldName, value) {
super(fieldName, value, 'between');
this.fieldName = fieldName;
this.value = value;
}
exec() {

@@ -69,5 +85,15 @@ return `${this.fieldName}: ${this.value[0]} TO ${this.value[1]}`;

/* eslint-disable class-methods-use-this */
class EqualOperator extends Operator {
class NumericEqual extends NumericOperator {
constructor(fieldName, value) {
super();
super(fieldName, value, 'eq');
}
exec() {
return `${this.fieldName} = ${this.value}`;
}
}
/* eslint-disable class-methods-use-this */
class NonNumericEqual extends Operator {
constructor(fieldName, value) {
super('eq');
this.fieldName = fieldName;

@@ -77,5 +103,3 @@ this.value = value;

exec() {
// The equal operator "=" is only allowed with number else ":" should be used
const [operator, newValue] = typeof this.value === 'number' ? ['=', this.value] : [':', `"${this.value}"`];
return `${this.fieldName} ${operator} ${newValue}`;
return `${this.fieldName} : "${this.value}"`;
}

@@ -87,4 +111,15 @@ validate() {

const EqualFactory = (fieldName, value) => {
if (typeof value === 'number')
return new NumericEqual(fieldName, value);
return new NonNumericEqual(fieldName, value);
};
/* eslint-disable class-methods-use-this */
class GreaterThanOrEqualOperator extends NumericOperator {
constructor(fieldName, value) {
super(fieldName, value, '>=');
this.fieldName = fieldName;
this.value = value;
}
exec() {

@@ -97,2 +132,7 @@ return `${this.fieldName} >= ${this.value}`;

class GreaterThanOperator extends NumericOperator {
constructor(fieldName, value) {
super(fieldName, value, '>');
this.fieldName = fieldName;
this.value = value;
}
exec() {

@@ -105,2 +145,7 @@ return `${this.fieldName} > ${this.value}`;

class LessThanOrEqualOperator extends NumericOperator {
constructor(fieldName, value) {
super(fieldName, value, '<=');
this.fieldName = fieldName;
this.value = value;
}
exec() {

@@ -113,2 +158,7 @@ return `${this.fieldName} <= ${this.value}`;

class LessThanOperator extends NumericOperator {
constructor(fieldName, value) {
super(fieldName, value, '<=');
this.fieldName = fieldName;
this.value = value;
}
exec() {

@@ -120,3 +170,37 @@ return `${this.fieldName} < ${this.value}`;

/* eslint-disable constructor-super */
class InOperator extends Operator {
constructor(value) {
super('in');
this.value = value;
}
exec() {
// In operator resembles and and exactly
const andOperator = new AndOperator(this.value);
return andOperator.exec();
}
validate() {
return true;
}
}
/* eslint-disable class-methods-use-this */
class TagOperator extends Operator {
constructor(value) {
super('_tags');
this.value = value;
}
exec() {
return `_tags : "${this.value}"`;
}
validate() {
return true;
}
}
/* eslint-disable constructor-super */
class OrOperator extends LogicalOperator {
constructor(values) {
super(values, 'or');
this.values = values;
}
exec() {

@@ -130,10 +214,43 @@ const orQuery = this.values

validate() {
return true;
// So far algolia doesn't support ands inside of ors
const hasAnd = this.values.some((value) => value instanceof AndOperator);
if (hasAnd)
throw new Error(`The ${this.operator} can not contain an and operator`);
// A list of or-ed commands cannot have mix of tags, facet search and numeric operators
const numericOperationsBucket = [NumericOperator, InOperator, BetweenOperator];
const facetOperationsBucket = [NonNumericEqual];
const tagsOperationsBucket = [TagOperator];
const operationsBuckets = [numericOperationsBucket, facetOperationsBucket, tagsOperationsBucket];
const operationsBucketSet = new Set();
this.values.forEach((operator) => {
operationsBuckets.forEach((bucket) => {
bucket.forEach((operatorType) => {
if (operator instanceof operatorType)
operationsBucketSet.add(bucket);
});
});
});
if (operationsBucketSet.size > 1) {
throw new Error(`The ${this.operator} cannot contain a mix of numeric, facet and tags operations`);
}
super.validate();
}
}
/* eslint-disable class-methods-use-this */
class NotEqualOperator extends NumericOperator {
constructor(fieldName, value) {
super(fieldName, value, '!=');
this.fieldName = fieldName;
this.value = value;
}
exec() {
return `${this.fieldName} != ${this.value}`;
}
}
/* eslint-disable constructor-super */
class NotOperator extends Operator {
constructor(values) {
super();
super('not');
this.values = values;

@@ -149,22 +266,8 @@ }

validate() {
return true;
const hasLogicalOperator = this.values.some((operator) => operator instanceof LogicalOperator);
if (hasLogicalOperator)
throw new Error(`The ${this.operator} can not contain logical operators (and, or)`);
}
}
/* eslint-disable constructor-super */
class InOperator extends Operator {
constructor(value) {
super();
this.value = value;
}
exec() {
// In operator resembles and and exactly
const andOperator = new AndOperator(this.value);
return andOperator.exec();
}
validate() {
return true;
}
}
class AlgoliaQueryParser {

@@ -206,7 +309,11 @@ constructor(query) {

case 'in': {
const equalOperators = value.map((arrayValue) => new EqualOperator(parentFieldName, arrayValue));
const equalOperators = value.map((arrayValue) => EqualFactory(parentFieldName, arrayValue));
return new InOperator(equalOperators);
}
case 'eq':
return new EqualOperator(parentFieldName, value);
return EqualFactory(parentFieldName, value);
case 'ne':
return new NotEqualOperator(parentFieldName, value);
case '_tags':
return new TagOperator(value);
// The key is an attribute name not an operator

@@ -216,6 +323,9 @@ default: {

if (typeof value !== 'object') {
return new EqualOperator(fieldName, value);
return EqualFactory(fieldName, value);
}
const queryKeys = Object.keys(value);
const operations = queryKeys.map((operator) => this.parseQuery(operator, value[operator], fieldName));
// if The operations size is one no need to wrap it inside and and operator
if (operations.length === 1)
return operations[0];
return new AndOperator(operations);

@@ -233,2 +343,3 @@ }

const rootOperator = this.buildQueryTree();
rootOperator.validate();
return rootOperator.exec();

@@ -235,0 +346,0 @@ }

declare abstract class Operator {
protected readonly operator: string;
constructor(operator: string);
abstract exec(): string;

@@ -3,0 +5,0 @@ abstract validate(): void;

import Operator from './base';
declare abstract class LogicalOperator extends Operator {
protected values: Operator[];
constructor(values: Operator[]);
constructor(values: Operator[], operator: string);
validate(): void;
}
export default LogicalOperator;
//# sourceMappingURL=logical-operator.d.ts.map

@@ -5,6 +5,6 @@ import Operator from './base';

protected value: number;
constructor(fieldName: string, value: number);
validate(): boolean;
constructor(fieldName: string, value: number, operator: string);
validate(): void;
}
export default NumericOperator;
//# sourceMappingURL=numeric-operator.d.ts.map

@@ -5,6 +5,6 @@ import Operator from './base';

protected value: [number, number];
constructor(fieldName: string, value: [number, number]);
validate(): boolean;
constructor(fieldName: string, value: [number, number], operator: string);
validate(): void;
}
export default RangeOperator;
//# sourceMappingURL=range-operator.d.ts.map

@@ -1,7 +0,8 @@

import { LogicalOperator } from './abstract';
import { LogicalOperator, Operator } from './abstract';
declare class AndOperator extends LogicalOperator {
protected values: Operator[];
constructor(values: Operator[]);
exec(): string;
validate(): boolean;
}
export default AndOperator;
//# sourceMappingURL=and.d.ts.map
import { RangeOperator } from './abstract';
declare class BetweenOperator extends RangeOperator {
protected fieldName: string;
protected value: [number, number];
constructor(fieldName: string, value: [number, number]);
exec(): string;

@@ -4,0 +7,0 @@ }

import NumericOperator from './abstract/numeric-operator';
declare class GreaterThanOrEqualOperator extends NumericOperator {
protected fieldName: string;
protected value: number;
constructor(fieldName: string, value: number);
exec(): string;

@@ -4,0 +7,0 @@ }

import NumericOperator from './abstract/numeric-operator';
declare class GreaterThanOperator extends NumericOperator {
protected fieldName: string;
protected value: number;
constructor(fieldName: string, value: number);
exec(): string;

@@ -4,0 +7,0 @@ }

export { default as AndOperator } from './and';
export { default as BetweenOperator } from './between';
export { default as EqualOperator } from './equal';
export { default as NumericEqual } from './numeric-equal';
export { default as NonNumericEqual } from './no-numeric-equal';
export { default as EqualFactory } from './equal-factory';
export { default as GreaterThanOrEqualOperator } from './greater-than-or-equal';

@@ -5,0 +7,0 @@ export { default as GreaterThanOperator } from './greater-than';

import NumericOperator from './abstract/numeric-operator';
declare class LessThanOrEqualOperator extends NumericOperator {
protected fieldName: string;
protected value: number;
constructor(fieldName: string, value: number);
exec(): string;

@@ -4,0 +7,0 @@ }

import NumericOperator from './abstract/numeric-operator';
declare class LessThanOperator extends NumericOperator {
protected fieldName: string;
protected value: number;
constructor(fieldName: string, value: number);
exec(): string;

@@ -4,0 +7,0 @@ }

import NumericOperator from './abstract/numeric-operator';
declare class NotEqualOperator extends NumericOperator {
protected fieldName: string;
protected value: number;
constructor(fieldName: string, value: number);
exec(): string;

@@ -4,0 +7,0 @@ }

@@ -6,5 +6,5 @@ import { Operator } from './abstract';

exec(): string;
validate(): boolean;
validate(): void;
}
export default NotOperator;
//# sourceMappingURL=not.d.ts.map

@@ -1,7 +0,9 @@

import { LogicalOperator } from './abstract';
import { LogicalOperator, Operator } from './abstract';
declare class OrOperator extends LogicalOperator {
protected values: Operator[];
constructor(values: Operator[]);
exec(): string;
validate(): boolean;
validate(): void;
}
export default OrOperator;
//# sourceMappingURL=or.d.ts.map
export declare type Equal = {
/**
* Used to match **numeric** values with given field
*
* ```json
* { field: { eq: 3 } }
* ```
* OR
* ```json
* { field: 3 }
* ```
*/
'eq': Number;
};
export declare type NotEqual = {
/**
* Used to find documents withe the provided field **not equal** to the provided **numeric** value
*
* ```json
* { field: { ne: 3 } }
* ```
*/
'ne': Number;
};
export declare type GreaterThan = {
/**
* Used to find documents with the provided field **greater than** the provided **numeric** value
*
* ```json
* { field: { gt: 3 } }
* ```
*/
'gt': Number;
};
export declare type GreaterThanOrEqual = {
/**
* Used to find documents with the provided field **greater than or equal** the provided **numeric** value
*
* ```json
* { field: { gte: 3 } }
* ```
*/
'gte': Number;
};
export declare type SmallerThan = {
/**
* Used to find documents with the provided field **smaller than** the provided **numeric** value
*
* ```json
* { field: { lt: 3 } }
* ```
*/
'lt': Number;
};
export declare type SmallerThanOrEqual = {
/**
* Used to find documents with the provided field **smaller than or equal** the provided **numeric** value
*
* ```json
* { field: { lte: 3 } }
* ```
*/
'lte': Number;
};
export declare type NumericOperation = Equal | NotEqual | GreaterThan | GreaterThanOrEqual | SmallerThan | SmallerThanOrEqual;
export declare type NonNumericEqual = {
/**
* Used to find documents with the provided field **equal** the provided **string** value
*
* ```json
* { field: { eq: "string" } }
* ```
*/
'eq': string;
};
export declare type Between = {
/**
* Used to find documents with the provided field **between** the provided **numeric** pair of values
*
* ```json
* { field: { between: [1,10] } }
* ```
*/
'between': [Number, Number];
};
export declare type In = {
/**
* Used to find documents with the provided field **in** the provided **numeric** values
*
* ```json
* { field: { in: [1,2,3] } }
* ```
*/
'in': (number | string)[];
};
export declare type FieldOperations = NumericOperation | Between | In;
export declare type FieldOperations = NumericOperation | Between | In | NonNumericEqual;
export declare type Not = {
/**
* Used to find documents that **don't match** the provided query
*
* ```json
* { field: { not: { eq: 3 } } }
* ```
*
* ### Notes
* - Cannot negate a disjunction or conjunction of a group of queries:
* ```json
* { field: { not: { or: [{ eq: 1 }, { eq: 2 } ] } } }
* ```
*
* Check this [link](https://www.algolia.com/doc/api-reference/api-parameters/filters/)
* for more info about algolia filter constraints
*/
'not': FieldOperations;

@@ -34,7 +120,36 @@ };

export declare type Or = {
/**
* Used to find documents that **match at least one** of the provided queries
*
* ```json
* { or: [ { field1: 3 }, {field2: 4} ] }
* ```
*
* ### Notes
* - Cannot mix between facet, numeric and tags filters
* ```json
* {
* or :
* [
* { field1: 3 }, // numeric query
* { field2: "string"}, // facet query
* { _tags:"tag" }, // tag query
* ]
* }
* ```
* Check this [link](https://www.algolia.com/doc/api-reference/api-parameters/filters/)
* for more info about algolia filter constraints
*/
'or': FieldsObjectQuery[];
};
export declare type And = {
/**
* Used to find documents that **match all** of the provided queries
*
* ```json
* { and: [ { field1: 3 }, {field2: 4} ] }
* ```
*/
'and': (FieldsObjectQuery | Or)[];
};
//# sourceMappingURL=operators.d.ts.map

@@ -0,1 +1,16 @@

### 1.1.0 (2021-03-28)
##### Documentation Changes
* **readme:** update the README file to reflect the new ne operator and the query validation ([5a012410](https://github.com/khaledosama999/algolia-filter-query-builder/commit/5a0124106c281ef654b53fd9845b3b7c2cd96f32))
* **types:** update the Types JSDocs so they are easy to use ([0f35a9a7](https://github.com/khaledosama999/algolia-filter-query-builder/commit/0f35a9a777502b67aef25967821ad1322a745654))
##### New Features
* **operators:** make each operator a standlone class to facilitate query parsing and validation ([64df1237](https://github.com/khaledosama999/algolia-filter-query-builder/commit/64df12373369688791a36e168cd2928c4ea5fdaa))
##### Tests
* **operator and query parser:** add tests for the new operator classes and the query parser ([550c8d89](https://github.com/khaledosama999/algolia-filter-query-builder/commit/550c8d89114d1bac879499be151559599ed26896))
## 1.0.0 (2021-03-26)

@@ -2,0 +17,0 @@

{
"name": "algolia-search-builder",
"version": "1.0.0",
"version": "1.1.0",
"description": "A query parser for algolia filters",

@@ -5,0 +5,0 @@ "repository": {

@@ -15,2 +15,3 @@ # Algolia Filters Query Builder

* [eq](#eq)
* [ne](#ne)
* [gt](#gt)

@@ -55,8 +56,14 @@ * [gte](#gte)

```json
{ x : { eq : 3 } }
{ x: { eq: 3 } }
```
- #### ne
Checks if a field is not equal to the given value
```json
{ x: { ne: 3 } }
```
- #### gt
Checks if a field is greater than the given value
```json
{ x : { gt : 3 } }
{ x: { gt: 3 } }
```

@@ -66,3 +73,3 @@ - #### gte

```json
{ x : { gte: 3 } }
{ x: { gt: 3 } }
```

@@ -72,3 +79,3 @@ - #### lt

```json
{ x : { lt : 3 } }
{ x: { lt: 3 } }
```

@@ -78,3 +85,3 @@ - #### lte

```json
{ x : { lte: 3 } }
{ x: { lt: 3 } }
```

@@ -84,8 +91,8 @@ - #### between

```json
{ x : { between : [1,2] } }
{ x: { between: [1,2] } }
```
- #### in
**** - #### in
Checks if a field is in the array of given values (can contain strings or number)
```json
{ x : { in : [1,2,3] } }
{ x: { in: [1,2,3] } }
```

@@ -96,3 +103,3 @@ - ### Logical

```json
{ x : { not : { between :[ 1 , 2] } } }
{ x: { not: { between:[ 1 , 2] } } }
```

@@ -102,6 +109,6 @@ - #### or

```json
{ or :
{ or:
[
{ x : { eq :1 } },
{ y : { eq :2 } },
{ x: { eq:1 } },
{ y: { eq:2 } },
]

@@ -113,6 +120,6 @@ }

```json
{ and :
{ and:
[
{ x : { eq :1 } },
{ y : { eq :2 } },
{ x: { eq:1 } },
{ y: { eq:2 } },
]

@@ -146,3 +153,3 @@ }

- The validity of the filter query is **your** response the builder only (for now) transforms it to a string. To find out algolia filters constraint check this [link](http://algolia.com/doc/api-reference/api-parameters/filters).
- The query builder validates the query after parsing and before returning the query string the limitations and constraints of the query builder are mostly related to the limitations given by [algolia](https://www.algolia.com/doc/api-reference/api-parameters/filters/#boolean-operators)

@@ -149,0 +156,0 @@ - To use `_tags` for filtering just add the a custom field with name `_tags` and pass it the value

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc