├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── config └── index.js ├── index.js ├── package.json ├── src ├── builder-abstract.js ├── helper.js ├── order-builder.js ├── search-builder.js └── where-builder.js └── test ├── data ├── condition.js ├── order-builder │ └── index.js └── where-builder │ ├── between.js │ ├── equal.js │ ├── gt.js │ ├── gte.js │ ├── iLike.js │ ├── iRegexp.js │ ├── in.js │ ├── is.js │ ├── like.js │ ├── lt.js │ ├── lte.js │ ├── ne.js │ ├── not.js │ ├── notBetween.js │ ├── notILike.js │ ├── notIRegexp.js │ ├── notIn.js │ ├── notLike.js │ ├── notRegexp.js │ └── regexp.js └── index.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "rules": { 4 | "no-underscore-dangle": 0, 5 | "no-console": "off", 6 | "linebreak-style": 0 7 | }, 8 | "plugins": [ 9 | "mocha" 10 | ] 11 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | .vscode 4 | .idea -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 - present, Serhii Mukhin (segemun) sergeymukhin21@gmail.com 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 🚨 This package has moved! It is now maintained under [@SequelizeSearchBuilder](https://github.com/SequelizeSearchBuilder). 2 | 3 | # Sequelize Search Builder 4 | ## About 5 | This is a lightweight library to convert search request (e.g. HTTP) to Sequelize ORM query. 6 | 7 | ## Installation 8 | ```bash 9 | npm install --save sequelize-search-builder 10 | ``` 11 | 12 | ## Usage 13 | Example based on Express framework. 14 | 15 | Direct generation of where/order/limit/offset query 16 | ```javascript 17 | const router = require('express').Router(), 18 | models = require('../models'), 19 | searchBuilder = require('sequelize-search-builder'); 20 | 21 | router.get('/search', async (req, res, next) => { 22 | // Set req.query param to Search Builder constructor 23 | const search = new searchBuilder(models.Sequelize, req.query), 24 | whereQuery = search.getWhereQuery(), 25 | orderQuery = search.getOrderQuery(), 26 | limitQuery = search.getLimitQuery(), 27 | offsetQuery = search.getOffsetQuery(); 28 | 29 | res.json({ 30 | data: await models.product.findAll({ 31 | include: [{ all: true, nested: true, duplicating: false }], 32 | where: whereQuery, 33 | order: orderQuery, 34 | limit: limitQuery, 35 | offset: offsetQuery, 36 | logging: console.log, 37 | }) 38 | }); 39 | }); 40 | ``` 41 | Full query generation example (getFullQuery method) 42 | ```javascript 43 | res.json({ 44 | data: await models.product.findAll(search.getFullQuery({ 45 | include: [{ all: true, nested: true, duplicating: true }], 46 | })) 47 | }); 48 | ``` 49 | 50 | You can set HTTP query string as second parameter for Seach Builder constructor (it will parse by 'qs' library to object). 51 | 52 | ## Request Examples 53 | 54 | #### Equal: 55 | ```javascript 56 | // HTTP: 57 | ?filter[name]=John&filter[surname]=Smith 58 | // req.query: 59 | { filter: { name: 'John', surname: 'Smith' } } 60 | // getWhereQuery() 61 | { name: 'John', surname: 'Smith' } 62 | ``` 63 | 64 | #### Equal (OR): 65 | ```javascript 66 | // HTTP: 67 | ?filter[name]=John&filter[surname]=Smith&filter[_condition]=or 68 | // req.query: 69 | { filter: { name: 'John', surname: 'Smith', _condition: 'or', } } 70 | // getWhereQuery() 71 | { [Symbol(or)]: {name: 'John', surname: 'Smith'} } 72 | ``` 73 | 74 | #### Conditions: 75 | ```javascript 76 | // HTTP: 77 | filter[age][gt]=100&filter[age][lt]=10&filter[age][_condition]=or&filter[name][iLike]=%john%&filter[_condition]=or 78 | // req.query 79 | { 80 | filter: { 81 | age: { 82 | gt: 100, 83 | lt: 10, 84 | _condition: 'or', 85 | }, 86 | name: { 87 | iLike: '%john%', 88 | }, 89 | _condition: 'or', 90 | }, 91 | } 92 | // getWhereQuery() 93 | { 94 | [Op.or]: { 95 | [Op.or]: [{ 96 | age: { 97 | [Op.gt]: 100, 98 | }, 99 | }, { 100 | age: { 101 | [Op.lt]: 10, 102 | }, 103 | }], 104 | name: { 105 | [Op.like]: '%john%', 106 | }, 107 | }, 108 | } 109 | ``` 110 | 111 | If _condition parameter is absent - "and" will be used by default 112 | 113 | #### Order: 114 | ```javascript 115 | // HTTP: 116 | ?filter[name]=desc 117 | // req.query: 118 | { order: { name: 'desc' } } 119 | // getOrderQuery() 120 | [ [ 'name', 'desc' ] ] 121 | ``` 122 | 123 | You can find more examples in the tests of the project (test/index.js) 124 | 125 | Git repository with DB tests: https://github.com/SequelizeSearchBuilder/sequelize-search-builder-db-tests 126 | 127 | ## Allowed query conditions 128 | | Request Option|Sequelize Symbol |Description | 129 | |---------------|-------------------------|------------| 130 | | eq (=) | = (no Symbol) | Equal 131 | | gt | Op.gt | Greater than 132 | | gte | Op.gte | Greater than or equal 133 | | lt | Op.lt | Less than 134 | | lte | Op.lte | Less than or equal 135 | | ne | Op.ne | Not equal 136 | | between | Op.between | Between [value1, value2] 137 | | notBetween | Op.notBetween | Not Between [value1, value2] 138 | | in | Op.in | In value list [value1, value2, ...] 139 | | notIn | Op.notIn | Not in value list [value1, value2, ...] 140 | | like | Op.like | Like search (%value, value%, %value%) 141 | | notLike | Op.notLike | Not like search (%value, value%, %value%) 142 | | is | Op.is | is (used to check for NULL and boolean values) 143 | | not | Op.not | not (used to check for NULL and boolean values) 144 | | iLike | Op.iLike | case insensitive LIKE (PG only) 145 | | notILike | Op.notILike | case insensitive NOT LIKE (PG only) 146 | | regexp | Op.regexp | Regexp (MySQL and PG only) 147 | | notRegexp | Op.notRegexp | Not Regexp (MySQL and PG only) 148 | | iRegexp | Op.iRegexp | iRegexp (case insensitive) (PG only) 149 | | notIRegexp | Op.notIRegexp | notIRegexp (case insensitive) (PG only) 150 | 151 | ## Configuration 152 | 153 | You can redefine configuration variables in rc file 154 | 155 | Just create .sequelize-search-builderrc file in root folder of your project 156 | 157 | Or use setter for 'config' parameter (setConfig) 158 | 159 | RC file example: 160 | 161 | ```javascript 162 | { 163 | "logging": false, 164 | "fields": { 165 | "filter" : "filter", 166 | "order" : "order", 167 | "limit" : "limit", 168 | "offset" : "offset" 169 | }, 170 | "default-limit": 10 171 | } 172 | ``` 173 | 174 | Setter example: 175 | 176 | ```javascript 177 | new searchBuilder(models.Sequelize, req.query) 178 | .setConfig({ 179 | logging: true, 180 | }); 181 | ``` 182 | 183 | ## Front-End 184 | You can use [Sequelize Search Builder Client](http://github.com/SequelizeSearchBuilder/sequelize-search-builder-client) module for the generation request http search string on the client side. 185 | 186 | ## Contribute 187 | You are Welcome =) 188 | Keep in mind: 189 | ```sh 190 | npm run test 191 | ``` 192 | ```sh 193 | ./node_modules/.bin/eslint . 194 | ``` 195 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | logging: false, 3 | 4 | fields: { 5 | filter: 'filter', 6 | order: 'order', 7 | limit: 'limit', 8 | offset: 'offset', 9 | }, 10 | 11 | 'default-limit': 10, 12 | }; 13 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * sequelize-search-builder 3 | * Copyright(c) 2019 - present, Serhii Mukhin (segemun) 4 | * Contacts: sergeymukhin21@gmail.com 5 | * MIT Licensed 6 | */ 7 | 8 | module.exports = require('./src/search-builder'); 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sequelize-search-builder", 3 | "description": "Minimalist library for parsing search request to sequelize query", 4 | "version": "0.13.2", 5 | "author": "Serhii Mukhin (segemun) ", 6 | "main": "index.js", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/SequelizeSearchBuilder/sequelize-search-builder.git" 11 | }, 12 | "keywords": [ 13 | "sequelize-search-builder", 14 | "search-builder", 15 | "query-builder", 16 | "http", 17 | "sequelize", 18 | "express", 19 | "web", 20 | "rest", 21 | "restful", 22 | "api", 23 | "search", 24 | "query", 25 | "http-query", 26 | "query-string", 27 | "query-parse", 28 | "parse", 29 | "convert", 30 | "request", 31 | "request-convert" 32 | ], 33 | "files": [ 34 | "LICENSE", 35 | "Readme.md", 36 | "index.js", 37 | "src/", 38 | "config/" 39 | ], 40 | "dependencies": { 41 | "lodash.merge": "^4.6.2", 42 | "qs": "^6.9.0", 43 | "rc": "^1.2.8", 44 | "sequelize": "^5.19.2" 45 | }, 46 | "devDependencies": { 47 | "chai": "^4.2.0", 48 | "eslint": "^8.2.0", 49 | "eslint-config-airbnb-base": "^15.0.0", 50 | "eslint-plugin-import": "^2.14.0", 51 | "eslint-plugin-mocha": "^5.2.0", 52 | "lodash.isequal": "^4.5.0", 53 | "mocha": "^5.2.0" 54 | }, 55 | "scripts": { 56 | "test": "mocha --exit" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/builder-abstract.js: -------------------------------------------------------------------------------- 1 | const rc = require('rc'); 2 | const qs = require('qs'); 3 | const merge = require('lodash.merge'); 4 | const defaultConfig = require('../config'); 5 | 6 | const config = rc('sequelize-search-builder', defaultConfig); 7 | 8 | class BuilderAbstract { 9 | /** 10 | * @param {Object} Sequelize 11 | * @param {(Object|string)} request 12 | */ 13 | constructor(Sequelize, request = {}) { 14 | if (new.target === BuilderAbstract) { 15 | throw new TypeError('Cannot construct BuilderAbstract instances directly'); 16 | } 17 | 18 | this.Sequelize = Sequelize; 19 | this.request = BuilderAbstract.prepareRequest(request); 20 | this.setConfig(config); 21 | } 22 | 23 | /** 24 | * Set Builder configs 25 | * 26 | * @param {Object} value - config options 27 | * 28 | * @returns {this} 29 | */ 30 | setConfig(value) { 31 | if (value !== null && typeof value === 'object') { 32 | this.config = merge(this.config, value); 33 | } else { 34 | console.error('Config parameter should be an object'); 35 | } 36 | 37 | return this; 38 | } 39 | 40 | /** 41 | * Transform request to request object 42 | * @param {(Object|string)} request 43 | * 44 | * @returns {Object} 45 | */ 46 | static prepareRequest(request = {}) { 47 | if (typeof request === 'string') { 48 | return qs.parse(request, { ignoreQueryPrefix: true }); 49 | } 50 | 51 | return request || {}; 52 | } 53 | } 54 | 55 | module.exports = BuilderAbstract; 56 | -------------------------------------------------------------------------------- /src/helper.js: -------------------------------------------------------------------------------- 1 | const rc = require('rc'); 2 | const defaultConfig = require('../config'); 3 | 4 | const config = rc('sequelize-search-builder', defaultConfig); 5 | 6 | const helpers = { 7 | isComparableField: (key) => key[0] !== '_', 8 | 9 | getFieldKey: (key) => { 10 | let result = key; 11 | if (key.indexOf('.') !== -1) { 12 | result = `$${key}$`; 13 | } 14 | 15 | return result; 16 | }, 17 | 18 | getEqualOp: (key, value) => { 19 | const query = { 20 | [key]: value, 21 | }; 22 | 23 | return query; 24 | }, 25 | 26 | log: (mode, message) => { 27 | if (config.logging) { 28 | console[mode](message); 29 | } 30 | }, 31 | }; 32 | 33 | module.exports = helpers; 34 | -------------------------------------------------------------------------------- /src/order-builder.js: -------------------------------------------------------------------------------- 1 | const BuilderAbstract = require('./builder-abstract'); 2 | 3 | class OrderBuilder extends BuilderAbstract { 4 | getQuery() { 5 | const { request } = this; 6 | const query = []; 7 | 8 | Object.keys(request).forEach((key) => { 9 | const value = key.split('.'); 10 | value.push(request[key]); 11 | query.push(value); 12 | }); 13 | 14 | return query; 15 | } 16 | } 17 | 18 | module.exports = OrderBuilder; 19 | -------------------------------------------------------------------------------- /src/search-builder.js: -------------------------------------------------------------------------------- 1 | const BuilderAbstract = require('./builder-abstract'); 2 | const WhereBuilder = require('./where-builder'); 3 | const OrderBuilder = require('./order-builder'); 4 | 5 | const constructors = { 6 | filter: WhereBuilder, 7 | order: OrderBuilder, 8 | }; 9 | 10 | class SearchBuilder extends BuilderAbstract { 11 | /** 12 | * Get object with sequelize where conditions 13 | * @returns {(Object|null)} sequelize where query 14 | */ 15 | getWhereQuery() { 16 | return this.getQueryByType('filter'); 17 | } 18 | 19 | /** 20 | * Get object with sequelize order conditions 21 | * @returns {(Object|null)} sequelize order query 22 | */ 23 | getOrderQuery() { 24 | return this.getQueryByType('order'); 25 | } 26 | 27 | /** 28 | * Get object with sequelize conditions by type 29 | * @param {string} type 30 | * @returns {(Object|null)} sequelize query 31 | */ 32 | getQueryByType(type) { 33 | const request = this.request[this.config.fields[type]]; 34 | return SearchBuilder 35 | .prepareResponse(new constructors[type](this.Sequelize, request) 36 | .setConfig(this.config) 37 | .getQuery()); 38 | } 39 | 40 | /** 41 | * Get string with limit value 42 | * @returns {(int|null)} limit value 43 | */ 44 | getLimitQuery() { 45 | return SearchBuilder.prepareIntegerQuery(this.request[this.config.fields.limit]) || this.config['default-limit'] || null; 46 | } 47 | 48 | /** 49 | * Get string with offset value 50 | * @returns {(int|null)} offset value 51 | */ 52 | getOffsetQuery() { 53 | return SearchBuilder.prepareIntegerQuery(this.request[this.config.fields.offset]) || null; 54 | } 55 | 56 | /** 57 | * Get object with all sequelize conditions (where, order, limit, offset) 58 | * @param {Object} target object for extending 59 | * @returns {Object} sequelize queries with all conditions 60 | */ 61 | getFullQuery(target = {}) { 62 | return { 63 | ...target, 64 | where: this.getWhereQuery(), 65 | order: this.getOrderQuery(), 66 | limit: this.getLimitQuery(), 67 | offset: this.getOffsetQuery(), 68 | }; 69 | } 70 | 71 | /** 72 | * Prepare sequelize query for response 73 | * @param {Object} sequelize query 74 | * @returns {(Object|null)} sequelize query 75 | */ 76 | static prepareResponse(query) { 77 | return (Object.keys(query).length === 0 78 | && Object.getOwnPropertySymbols(query).length === 0) ? null : query; 79 | } 80 | 81 | /** 82 | * Prepare integer response (limit and offset values) 83 | * @param {string} string value 84 | * @returns {(int|null)} integer value 85 | */ 86 | static prepareIntegerQuery(query) { 87 | const intQuery = parseInt(query, 10); 88 | return (Number.isInteger(intQuery) && intQuery >= 0) ? intQuery : null; 89 | } 90 | } 91 | 92 | module.exports = SearchBuilder; 93 | -------------------------------------------------------------------------------- /src/where-builder.js: -------------------------------------------------------------------------------- 1 | /* eslint class-methods-use-this: ["error", { "exceptMethods": ["_getConditionQuery"] }] */ 2 | 3 | const { Op } = require('sequelize'); 4 | const BuilderAbstract = require('./builder-abstract'); 5 | const helper = require('./helper'); 6 | 7 | const allowedConditions = ['gt', 'gte', 'lt', 'lte', 'ne', 'like', 'notLike', 'iLike', 'notILike', 'regexp', 'notRegexp', 'iRegexp', 'notIRegexp', 'is', 'not']; 8 | const allowedConditionsArray = ['between', 'notBetween', 'in', 'notIn']; 9 | 10 | class WhereBuilder extends BuilderAbstract { 11 | getQuery() { 12 | const { request } = this; 13 | const query = {}; 14 | 15 | Object.keys(request).forEach((key) => { 16 | const fieldValue = request[key]; 17 | const fieldKey = helper.getFieldKey(key); 18 | 19 | if (helper.isComparableField(fieldKey)) { 20 | if (Array.isArray(fieldValue) || typeof fieldValue === 'string' || typeof fieldValue === 'number') { 21 | Object.assign(query, helper.getEqualOp(fieldKey, fieldValue)); 22 | } else if (typeof fieldValue === 'object') { 23 | Object.assign(query, this._getFieldQuery(fieldKey, fieldValue)); 24 | } 25 | } 26 | }); 27 | return this._getConditionQuery(query, request); 28 | } 29 | 30 | _getConditionQuery(query, request) { 31 | let conditionQuery = {}; 32 | if (typeof request._condition === 'string' && typeof query === 'object' && Object.keys(query).length !== 0) { 33 | conditionQuery = { 34 | [Op[request._condition]]: query, 35 | }; 36 | } else if (Array.isArray(query) && query.length > 1) { 37 | conditionQuery = { 38 | [Op.and]: query, 39 | }; 40 | } else { 41 | conditionQuery = query; 42 | } 43 | 44 | return conditionQuery; 45 | } 46 | 47 | _getFieldQuery(fieldKey, values) { 48 | const fieldQuery = []; 49 | 50 | Object.keys(values) 51 | .filter(helper.isComparableField) 52 | .forEach((key) => { 53 | const value = values[key]; 54 | 55 | if (key === 'eq') { 56 | fieldQuery.push( 57 | helper.getEqualOp(fieldKey, value), 58 | ); 59 | } else if (allowedConditions.includes(key) 60 | || (allowedConditionsArray.includes(key) && Array.isArray(value))) { 61 | if (['is', 'not'].includes(key) && value === 'null') { 62 | fieldQuery.push({ 63 | [fieldKey]: { 64 | [Op[key]]: null, 65 | }, 66 | }); 67 | } else { 68 | fieldQuery.push({ 69 | [fieldKey]: { 70 | [Op[key]]: value, 71 | }, 72 | }); 73 | } 74 | } else { 75 | helper.log('error', `${key} operator is missing`); 76 | } 77 | }); 78 | 79 | return fieldQuery.length > 1 ? this._getConditionQuery(fieldQuery, values) : fieldQuery[0]; 80 | } 81 | } 82 | 83 | module.exports = WhereBuilder; 84 | -------------------------------------------------------------------------------- /test/data/condition.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Condition with one field with _condition AND parameter', 6 | request: { 7 | key: { 8 | gt: 10, 9 | lt: 100, 10 | _condition: 'and', 11 | }, 12 | }, 13 | expected: { 14 | [Op.and]: [ 15 | { 16 | key: { 17 | [Op.gt]: 10, 18 | }, 19 | }, 20 | { 21 | key: { 22 | [Op.lt]: 100, 23 | }, 24 | }, 25 | ], 26 | }, 27 | }, 28 | { 29 | it: 'Condition with one field with _condition AND parameter (string)', 30 | request: 'filter[key][gt]=10&filter[key][lt]=100&filter[key][_condition]=and', 31 | expected: { 32 | [Op.and]: [ 33 | { 34 | key: { 35 | [Op.gt]: '10', 36 | }, 37 | }, 38 | { 39 | key: { 40 | [Op.lt]: '100', 41 | }, 42 | }, 43 | ], 44 | }, 45 | }, 46 | { 47 | it: 'Condition with one field without _condition AND parameter', 48 | request: { 49 | key: { 50 | gt: 10, 51 | lt: 100, 52 | }, 53 | }, 54 | expected: { 55 | [Op.and]: [ 56 | { 57 | key: { 58 | [Op.gt]: 10, 59 | }, 60 | }, 61 | { 62 | key: { 63 | [Op.lt]: 100, 64 | }, 65 | }, 66 | ], 67 | }, 68 | }, 69 | { 70 | it: 'Condition with one field without _condition AND parameter (string)', 71 | request: 'filter[key][gt]=10&filter[key][lt]=100&filter[key]', 72 | expected: { 73 | [Op.and]: [ 74 | { 75 | key: { 76 | [Op.gt]: '10', 77 | }, 78 | }, 79 | { 80 | key: { 81 | [Op.lt]: '100', 82 | }, 83 | }, 84 | ], 85 | }, 86 | }, 87 | { 88 | it: 'Condition with one field with _condition OR parameter', 89 | request: { 90 | key: { 91 | gt: 10, 92 | lt: 100, 93 | _condition: 'or', 94 | }, 95 | }, 96 | expected: { 97 | [Op.or]: [ 98 | { 99 | key: { 100 | [Op.gt]: 10, 101 | }, 102 | }, 103 | { 104 | key: { 105 | [Op.lt]: 100, 106 | }, 107 | }, 108 | ], 109 | }, 110 | }, 111 | { 112 | it: 'Condition with several fields with _condition OR parameter', 113 | request: { 114 | key1: { 115 | gt: 10, 116 | lt: 100, 117 | _condition: 'or', 118 | }, 119 | key2: { 120 | like: '%value%', 121 | }, 122 | _condition: 'or', 123 | }, 124 | expected: { 125 | [Op.or]: { 126 | [Op.or]: [{ 127 | key1: { 128 | [Op.gt]: 10, 129 | }, 130 | }, { 131 | key1: { 132 | [Op.lt]: 100, 133 | }, 134 | }], 135 | key2: { 136 | [Op.like]: '%value%', 137 | }, 138 | }, 139 | }, 140 | }, 141 | { 142 | it: 'Condition with several fields with _condition OR parameter (string)', 143 | request: 'filter[key1][gt]=10&filter[key1][lt]=100&filter[key1][_condition]=or&filter[key2][like]=%value%&filter[_condition]=or', 144 | expected: { 145 | [Op.or]: { 146 | [Op.or]: [{ 147 | key1: { 148 | [Op.gt]: '10', 149 | }, 150 | }, { 151 | key1: { 152 | [Op.lt]: '100', 153 | }, 154 | }], 155 | key2: { 156 | [Op.like]: '%value%', 157 | }, 158 | }, 159 | }, 160 | }, 161 | ]; 162 | -------------------------------------------------------------------------------- /test/data/order-builder/index.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | it: 'Order by one field (order[key]=value)', 4 | request: { 5 | key: 'value', 6 | }, 7 | expected: [ 8 | ['key', 'value'], 9 | ], 10 | }, 11 | ]; 12 | -------------------------------------------------------------------------------- /test/data/where-builder/between.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Between operator simple (key[between][]=1&key[between][]=2)', 6 | request: { 7 | key: { 8 | between: [1, 2], 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.between]: [1, 2], 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Between simple with association (key.key[between][]=1&key.key[between][]=2)', 19 | request: { 20 | 'key.key': { 21 | between: [1, 2], 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.between]: [1, 2], 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Between operator multi (key1[between][]=1&key1[between][]=2&key2[between][]=1&key2[between][]=2)', 32 | request: { 33 | key1: { 34 | between: [1, 2], 35 | }, 36 | key2: { 37 | between: [1, 2], 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.between]: [1, 2], 43 | }, 44 | key2: { 45 | [Op.between]: [1, 2], 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/equal.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Equal simple (key=value)', 6 | request: { 7 | key: 'value', 8 | }, 9 | expected: { 10 | key: 'value', 11 | }, 12 | }, 13 | { 14 | it: 'Equal simple with association (key.key=value)', 15 | request: { 16 | 'key.key': 'value', 17 | }, 18 | expected: { 19 | '$key.key$': 'value', 20 | }, 21 | }, 22 | { 23 | it: 'Equal multi (key1=value1&key2=value2)', 24 | request: { 25 | key1: 'value1', 26 | key2: 'value2', 27 | }, 28 | expected: { 29 | key1: 'value1', 30 | key2: 'value2', 31 | }, 32 | }, 33 | { 34 | it: 'Equal array (key1=value1&key1=value2)', 35 | request: { 36 | key1: ['value1', 'value2'], 37 | }, 38 | expected: { 39 | key1: ['value1', 'value2'], 40 | }, 41 | }, 42 | { 43 | it: 'Equal operator simple (key[eq]=value)', 44 | request: { 45 | key: { 46 | eq: 'value', 47 | }, 48 | }, 49 | expected: { 50 | key: 'value', 51 | }, 52 | }, 53 | { 54 | it: 'Equal with OR condition (key1=value1&key2=value2&_condition=or)', 55 | request: { 56 | _condition: 'or', 57 | key1: 'value1', 58 | key2: 'value2', 59 | }, 60 | expected: { 61 | [Op.or]: { 62 | key1: 'value1', 63 | key2: 'value2', 64 | }, 65 | }, 66 | }, 67 | { 68 | it: 'Equal with AND condition (key1=value1&key2=value2&_condition=and)', 69 | request: { 70 | _condition: 'or', 71 | key1: 'value1', 72 | key2: 'value2', 73 | }, 74 | expected: { 75 | [Op.or]: { 76 | key1: 'value1', 77 | key2: 'value2', 78 | }, 79 | }, 80 | }, 81 | { 82 | it: 'Equal operator simple with association (key.key[eq]=value)', 83 | request: { 84 | 'key.key': { 85 | eq: 'value', 86 | }, 87 | }, 88 | expected: { 89 | '$key.key$': 'value', 90 | }, 91 | }, 92 | { 93 | it: 'Equal operator multi (key1[eq]=value1&key2[eq]=value2)', 94 | request: { 95 | key1: { 96 | eq: 'value1', 97 | }, 98 | key2: { 99 | eq: 'value2', 100 | }, 101 | }, 102 | expected: { 103 | key1: 'value1', 104 | key2: 'value2', 105 | }, 106 | }, 107 | { 108 | it: 'Equal operator array (key1[eq]=value1&key1[eq]=value2)', 109 | request: { 110 | key1: { 111 | eq: ['value1', 'value2'], 112 | }, 113 | }, 114 | expected: { 115 | key1: ['value1', 'value2'], 116 | }, 117 | }, 118 | { 119 | it: 'Equal operator with OR condition (key1[eq]=value1&key2[eq]=value2&_condition=or)', 120 | request: { 121 | _condition: 'or', 122 | key1: { 123 | eq: 'value1', 124 | }, 125 | key2: { 126 | eq: 'value2', 127 | }, 128 | }, 129 | expected: { 130 | [Op.or]: { 131 | key1: 'value1', 132 | key2: 'value2', 133 | }, 134 | }, 135 | }, 136 | { 137 | it: 'Equal operator with AND condition (key1[eq]=value1&key2[eq]=value2&_condition=and)', 138 | request: { 139 | _condition: 'and', 140 | key1: { 141 | eq: 'value1', 142 | }, 143 | key2: { 144 | eq: 'value2', 145 | }, 146 | }, 147 | expected: { 148 | [Op.and]: { 149 | key1: 'value1', 150 | key2: 'value2', 151 | }, 152 | }, 153 | }, 154 | { 155 | it: '(string request) Equal operator with AND condition (?filter[key1][eq]=value1&filter[key2][eq]=value2&filter[_condition]=and)', 156 | request: 'filter[key1][eq]=value1&filter[key2][eq]=value2&filter[_condition]=and', 157 | expected: { 158 | [Op.and]: { 159 | key1: 'value1', 160 | key2: 'value2', 161 | }, 162 | }, 163 | }, 164 | { 165 | it: '(string request) Equal simple (?key=value)', 166 | request: 'filter[key]=value', 167 | expected: { 168 | key: 'value', 169 | }, 170 | }, 171 | { 172 | it: '(string request) Equal simple (?key=value)', 173 | request: '?filter[key]=value', 174 | expected: { 175 | key: 'value', 176 | }, 177 | }, 178 | { 179 | it: 'Equal simple (key=value)', 180 | request: null, 181 | expected: null, 182 | }, 183 | ]; 184 | -------------------------------------------------------------------------------- /test/data/where-builder/gt.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Gt operator simple (key[gt]=value)', 6 | request: { 7 | key: { 8 | gt: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.gt]: 'value', 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Gt simple with association (key.key[gt]=value)', 19 | request: { 20 | 'key.key': { 21 | gt: 'value', 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.gt]: 'value', 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Gt operator multi (key1[gt]=value1&key2[gt]=value2)', 32 | request: { 33 | key1: { 34 | gt: 'value1', 35 | }, 36 | key2: { 37 | gt: 'value2', 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.gt]: 'value1', 43 | }, 44 | key2: { 45 | [Op.gt]: 'value2', 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/gte.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Gte operator simple (key[gte]=value)', 6 | request: { 7 | key: { 8 | gte: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.gte]: 'value', 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Gte simple with association (key.key[gte]=value)', 19 | request: { 20 | 'key.key': { 21 | gte: 'value', 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.gte]: 'value', 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Gte operator multi (key1[gte]=value1&key2[gte]=value2)', 32 | request: { 33 | key1: { 34 | gte: 'value1', 35 | }, 36 | key2: { 37 | gte: 'value2', 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.gte]: 'value1', 43 | }, 44 | key2: { 45 | [Op.gte]: 'value2', 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/iLike.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Like operator simple (key[iLike]=value)', 6 | request: { 7 | key: { 8 | iLike: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.iLike]: 'value', 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Like simple with association (key.key[iLike]=value)', 19 | request: { 20 | 'key.key': { 21 | iLike: 'value', 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.iLike]: 'value', 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Like operator multi (key1[iLike]=value1&key2[iLike]=value2)', 32 | request: { 33 | key1: { 34 | iLike: 'value1', 35 | }, 36 | key2: { 37 | iLike: 'value2', 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.iLike]: 'value1', 43 | }, 44 | key2: { 45 | [Op.iLike]: 'value2', 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/iRegexp.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'iRegexp operator simple (key[regexp]=value)', 6 | request: { 7 | key: { 8 | iRegexp: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.iRegexp]: 'value', 14 | }, 15 | }, 16 | }, 17 | ]; 18 | -------------------------------------------------------------------------------- /test/data/where-builder/in.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'In operator simple (key[in][]=1&key[in][]=2)', 6 | request: { 7 | key: { 8 | in: [1, 2], 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.in]: [1, 2], 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'In simple with association (key.key[in][]=1&key.key[in][]=2)', 19 | request: { 20 | 'key.key': { 21 | in: [1, 2], 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.in]: [1, 2], 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'In operator multi (key1[in][]=1&key1[in][]=2&key2[in][]=1&key2[in][]=2&key2[in][]=3)', 32 | request: { 33 | key1: { 34 | in: [1, 2], 35 | }, 36 | key2: { 37 | in: [1, 2, 3], 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.in]: [1, 2], 43 | }, 44 | key2: { 45 | [Op.in]: [1, 2, 3], 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/is.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Is for null (key[is]=null)', 6 | request: { 7 | key: { 8 | is: 'null', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.is]: null, 14 | }, 15 | }, 16 | }, 17 | ]; 18 | -------------------------------------------------------------------------------- /test/data/where-builder/like.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Like operator simple (key[like]=value)', 6 | request: { 7 | key: { 8 | like: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.like]: 'value', 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Like simple with association (key.key[like]=value)', 19 | request: { 20 | 'key.key': { 21 | like: 'value', 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.like]: 'value', 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Like operator multi (key1[like]=value1&key2[like]=value2)', 32 | request: { 33 | key1: { 34 | like: 'value1', 35 | }, 36 | key2: { 37 | like: 'value2', 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.like]: 'value1', 43 | }, 44 | key2: { 45 | [Op.like]: 'value2', 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/lt.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Lt operator simple (key[lt]=value)', 6 | request: { 7 | key: { 8 | lt: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.lt]: 'value', 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Lt simple with association (key.key[lt]=value)', 19 | request: { 20 | 'key.key': { 21 | lt: 'value', 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.lt]: 'value', 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Lt operator multi (key1[lt]=value1&key2[lt]=value2)', 32 | request: { 33 | key1: { 34 | lt: 'value1', 35 | }, 36 | key2: { 37 | lt: 'value2', 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.lt]: 'value1', 43 | }, 44 | key2: { 45 | [Op.lt]: 'value2', 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/lte.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Lte operator simple (key[lte]=value)', 6 | request: { 7 | key: { 8 | lte: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.lte]: 'value', 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Lte simple with association (key.key[lte]=value)', 19 | request: { 20 | 'key.key': { 21 | lte: 'value', 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.lte]: 'value', 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Lte operator multi (key1[lte]=value1&key2[lte]=value2)', 32 | request: { 33 | key1: { 34 | lte: 'value1', 35 | }, 36 | key2: { 37 | lte: 'value2', 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.lte]: 'value1', 43 | }, 44 | key2: { 45 | [Op.lte]: 'value2', 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/ne.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Ne operator simple (key[ne]=value)', 6 | request: { 7 | key: { 8 | ne: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.ne]: 'value', 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Ne simple with association (key.key[ne]=value)', 19 | request: { 20 | 'key.key': { 21 | ne: 'value', 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.ne]: 'value', 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Ne operator multi (key1[ne]=value1&key2[ne]=value2)', 32 | request: { 33 | key1: { 34 | ne: 'value1', 35 | }, 36 | key2: { 37 | ne: 'value2', 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.ne]: 'value1', 43 | }, 44 | key2: { 45 | [Op.ne]: 'value2', 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/not.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Not for null (key[not]=null)', 6 | request: { 7 | key: { 8 | not: 'null', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.not]: null, 14 | }, 15 | }, 16 | }, 17 | ]; 18 | -------------------------------------------------------------------------------- /test/data/where-builder/notBetween.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Not Between operator simple (key[notBetween][]=1&key[notBetween][]=2)', 6 | request: { 7 | key: { 8 | notBetween: [1, 2], 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.notBetween]: [1, 2], 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Not Between simple with association (key.key[notBetween][]=1&key.key[notBetween][]=2)', 19 | request: { 20 | 'key.key': { 21 | notBetween: [1, 2], 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.notBetween]: [1, 2], 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Not Between operator multi (key1[notBetween][]=1&key1[notBetween][]=2&key2[notBetween][]=1&key2[notBetween][]=2)', 32 | request: { 33 | key1: { 34 | notBetween: [1, 2], 35 | }, 36 | key2: { 37 | notBetween: [1, 2], 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.notBetween]: [1, 2], 43 | }, 44 | key2: { 45 | [Op.notBetween]: [1, 2], 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/notILike.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Not Like operator simple (key[notILike]=value)', 6 | request: { 7 | key: { 8 | notILike: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.notILike]: 'value', 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Not Like simple with association (key.key[notILike]=value)', 19 | request: { 20 | 'key.key': { 21 | notILike: 'value', 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.notILike]: 'value', 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Not Like operator multi (key1[notILike]=value1&key2[notILike]=value2)', 32 | request: { 33 | key1: { 34 | notILike: 'value1', 35 | }, 36 | key2: { 37 | notILike: 'value2', 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.notILike]: 'value1', 43 | }, 44 | key2: { 45 | [Op.notILike]: 'value2', 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/notIRegexp.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'notIRegexp operator simple (key[notIRegexp]=value)', 6 | request: { 7 | key: { 8 | notIRegexp: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.notIRegexp]: 'value', 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'notIRegexp operator simple (key[notIRegexp]=value) string', 19 | request: 'filter[key][notIRegexp]=value', 20 | expected: { 21 | key: { 22 | [Op.notIRegexp]: 'value', 23 | }, 24 | }, 25 | }, 26 | ]; 27 | -------------------------------------------------------------------------------- /test/data/where-builder/notIn.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Not In operator simple (key[notIn][]=1&key[notIn][]=2)', 6 | request: { 7 | key: { 8 | notIn: [1, 2], 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.notIn]: [1, 2], 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Not In simple with association (key.key[notIn][]=1&key.key[notIn][]=2)', 19 | request: { 20 | 'key.key': { 21 | notIn: [1, 2], 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.notIn]: [1, 2], 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Not In operator multi (key1[notIn][]=1&key1[notIn][]=2&key2[notIn][]=1&key2[notIn][]=2&key2[notIn][]=3)', 32 | request: { 33 | key1: { 34 | notIn: [1, 2], 35 | }, 36 | key2: { 37 | notIn: [1, 2, 3], 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.notIn]: [1, 2], 43 | }, 44 | key2: { 45 | [Op.notIn]: [1, 2, 3], 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/notLike.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Not Like operator simple (key[notLike]=value)', 6 | request: { 7 | key: { 8 | notLike: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.notLike]: 'value', 14 | }, 15 | }, 16 | }, 17 | { 18 | it: 'Not Like simple with association (key.key[notLike]=value)', 19 | request: { 20 | 'key.key': { 21 | notLike: 'value', 22 | }, 23 | }, 24 | expected: { 25 | '$key.key$': { 26 | [Op.notLike]: 'value', 27 | }, 28 | }, 29 | }, 30 | { 31 | it: 'Not Like operator multi (key1[notLike]=value1&key2[notLike]=value2)', 32 | request: { 33 | key1: { 34 | notLike: 'value1', 35 | }, 36 | key2: { 37 | notLike: 'value2', 38 | }, 39 | }, 40 | expected: { 41 | key1: { 42 | [Op.notLike]: 'value1', 43 | }, 44 | key2: { 45 | [Op.notLike]: 'value2', 46 | }, 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /test/data/where-builder/notRegexp.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Not Regexp operator simple (key[notRegexp]=value)', 6 | request: { 7 | key: { 8 | notRegexp: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.notRegexp]: 'value', 14 | }, 15 | }, 16 | }, 17 | ]; 18 | -------------------------------------------------------------------------------- /test/data/where-builder/regexp.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize'); 2 | 3 | module.exports = [ 4 | { 5 | it: 'Regexp operator simple (key[regexp]=value)', 6 | request: { 7 | key: { 8 | regexp: 'value', 9 | }, 10 | }, 11 | expected: { 12 | key: { 13 | [Op.regexp]: 'value', 14 | }, 15 | }, 16 | }, 17 | ]; 18 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | /* global describe it */ 2 | const isEqual = require('lodash.isequal'); 3 | const { expect } = require('chai'); 4 | const Sequelize = require('sequelize'); 5 | const SearchBuilder = require('../src/search-builder'); 6 | 7 | // Datasets 8 | const equalData = require('./data/where-builder/equal'); 9 | const gtData = require('./data/where-builder/gt'); 10 | const gteData = require('./data/where-builder/gte'); 11 | const ltData = require('./data/where-builder/lt'); 12 | const lteData = require('./data/where-builder/lte'); 13 | const neData = require('./data/where-builder/ne'); 14 | const betweenData = require('./data/where-builder/between'); 15 | const notBetweenData = require('./data/where-builder/notBetween'); 16 | const inData = require('./data/where-builder/in'); 17 | const notInData = require('./data/where-builder/notIn'); 18 | const likeData = require('./data/where-builder/like'); 19 | const notLikeData = require('./data/where-builder/notLike'); 20 | const iLikeData = require('./data/where-builder/iLike'); 21 | const notILikeData = require('./data/where-builder/notILike'); 22 | const regexpData = require('./data/where-builder/regexp'); 23 | const notRegexpData = require('./data/where-builder/notRegexp'); 24 | const iRegexpData = require('./data/where-builder/iRegexp'); 25 | const notIRegexpData = require('./data/where-builder/notIRegexp'); 26 | const isData = require('./data/where-builder/is'); 27 | const notData = require('./data/where-builder/not'); 28 | 29 | const conditionData = require('./data/condition'); 30 | 31 | const orderData = require('./data/order-builder'); 32 | 33 | function compareDataset(row, request, expected, methodName) { 34 | it(row.it, (done) => { 35 | const searchBuilder = new SearchBuilder(Sequelize, request); 36 | const query = searchBuilder[methodName](); 37 | 38 | expect(isEqual(query, expected)).to.equal(true); 39 | done(); 40 | }); 41 | } 42 | 43 | function compareWhereDataset(row) { 44 | const request = (typeof row.request === 'object') ? { filter: row.request } : row.request; 45 | compareDataset(row, request, row.expected, 'getWhereQuery'); 46 | } 47 | 48 | function compareOrderDataset(row) { 49 | const request = (typeof row.request === 'object') ? { order: row.request } : row.request; 50 | compareDataset(row, request, row.expected, 'getOrderQuery'); 51 | } 52 | 53 | describe('SearchBuilder', () => { 54 | describe('WhereBuilder', () => { 55 | describe('Equal operator (=, eq)', () => { 56 | equalData.forEach(compareWhereDataset); 57 | }); 58 | describe('Gt operator', () => { 59 | gtData.forEach(compareWhereDataset); 60 | }); 61 | describe('Gte operator', () => { 62 | gteData.forEach(compareWhereDataset); 63 | }); 64 | describe('Lt operator', () => { 65 | ltData.forEach(compareWhereDataset); 66 | }); 67 | describe('Lte operator', () => { 68 | lteData.forEach(compareWhereDataset); 69 | }); 70 | describe('Ne operator', () => { 71 | neData.forEach(compareWhereDataset); 72 | }); 73 | describe('Between operator', () => { 74 | betweenData.forEach(compareWhereDataset); 75 | }); 76 | describe('Not Between operator', () => { 77 | notBetweenData.forEach(compareWhereDataset); 78 | }); 79 | describe('In operator', () => { 80 | inData.forEach(compareWhereDataset); 81 | }); 82 | describe('Not In operator', () => { 83 | notInData.forEach(compareWhereDataset); 84 | }); 85 | describe('Like operator', () => { 86 | likeData.forEach(compareWhereDataset); 87 | }); 88 | describe('Not Like operator', () => { 89 | notLikeData.forEach(compareWhereDataset); 90 | }); 91 | describe('iLike operator', () => { 92 | iLikeData.forEach(compareWhereDataset); 93 | }); 94 | describe('Not iLike operator', () => { 95 | notILikeData.forEach(compareWhereDataset); 96 | }); 97 | describe('Regexp operator', () => { 98 | regexpData.forEach(compareWhereDataset); 99 | }); 100 | describe('Not Regexp operator', () => { 101 | notRegexpData.forEach(compareWhereDataset); 102 | }); 103 | describe('iRegexp operator', () => { 104 | iRegexpData.forEach(compareWhereDataset); 105 | }); 106 | describe('notIRegexp operator', () => { 107 | notIRegexpData.forEach(compareWhereDataset); 108 | }); 109 | describe('is operator', () => { 110 | isData.forEach(compareWhereDataset); 111 | }); 112 | describe('not operator', () => { 113 | notData.forEach(compareWhereDataset); 114 | }); 115 | }); 116 | 117 | describe('Conditions', () => { 118 | conditionData.forEach(compareWhereDataset); 119 | }); 120 | 121 | describe('OrderBuilder', () => { 122 | orderData.forEach(compareOrderDataset); 123 | }); 124 | 125 | describe('LimitBuilder', () => { 126 | compareDataset({ it: 'Test limit' }, { limit: 100 }, 100, 'getLimitQuery'); 127 | compareDataset({ it: 'Test limit default' }, {}, 10, 'getLimitQuery'); 128 | compareDataset({ it: 'Test limit string' }, { limit: '100' }, 100, 'getLimitQuery'); 129 | compareDataset({ it: 'Test limit string' }, { limit: 'string' }, 10, 'getLimitQuery'); 130 | compareDataset({ it: 'Test limit string' }, { limit: '100_string' }, 100, 'getLimitQuery'); 131 | }); 132 | 133 | describe('OffsetBuilder', () => { 134 | compareDataset({ it: 'Test offset' }, { offset: 10 }, 10, 'getOffsetQuery'); 135 | compareDataset({ it: 'Test limit string' }, { offset: '100' }, 100, 'getOffsetQuery'); 136 | compareDataset({ it: 'Test limit string' }, { offset: 'string' }, null, 'getOffsetQuery'); 137 | compareDataset({ it: 'Test limit string' }, { offset: '100_string' }, 100, 'getOffsetQuery'); 138 | }); 139 | 140 | describe('Config setter', () => { 141 | it('Test custom configs', (done) => { 142 | const expected = { 143 | where: { key1: 'value1' }, 144 | order: [['key1', 'desc']], 145 | limit: 100, 146 | offset: null, 147 | }; 148 | 149 | const expectedDefaultConfigs = { 150 | where: null, 151 | order: [['key1', 'desc']], 152 | limit: 10, 153 | offset: null, 154 | }; 155 | 156 | const query = { 157 | f: { key1: 'value1' }, 158 | order: { key1: 'desc' }, 159 | }; 160 | 161 | const config = { 162 | fields: { filter: 'f' }, 163 | 'default-limit': 100, 164 | }; 165 | 166 | let searchBuilder = new SearchBuilder(Sequelize, query); 167 | searchBuilder.setConfig(config); 168 | expect(isEqual(searchBuilder.getFullQuery(), expected)).to.equal(true); 169 | 170 | searchBuilder = new SearchBuilder(Sequelize, query); 171 | expect(isEqual(searchBuilder.getFullQuery(), expectedDefaultConfigs)).to.equal(true); 172 | done(); 173 | }); 174 | }); 175 | }); 176 | --------------------------------------------------------------------------------