Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 35 additions & 21 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,32 @@ const arrayHave = (v) => { return v.split(' ').map(v => { return isNaN(v) ? `{${
* (replacing _.set() to avoid importing all of underscore)
*/
const deepPropSet = (obj, dotPath, key, val) => {
const props = dotPath.split('.')
let here = obj
props.forEach((prop, i) => {
here = (here[prop] = here[prop] || {})
})
here[key] = val

if(dotPath.split('.').length > 1) {
obj[`$${dotPath}$`] = {
[key]: val
}
} else {
obj[`${dotPath}`] = {
[key]: val
}
}
}

/** @class
*
* @description Used to parse query strings and produce sort / filter objects
* for sequelize querying
*/
class SequelizeQueryStringParser {
class SequelizeQueryStringParser {
/** @constructor
*
* @param {Object} sequelize - the user's `require('sequelize')`
* @param {Object} opts - extra options to determine behaviour
* @param {Boolean} opts.symbolic - whether to use symbolic Ops
* or (deprecated) string Ops
*/
constructor (sequelize, opts={}) {
constructor(sequelize, opts = {}) {
this.sequelize = sequelize
this.symbolic = opts.symbolic || false
if (opts.symbolic && !sequelize) {
Expand All @@ -50,9 +54,9 @@ class SequelizeQueryStringParser {
* @param {Boolean} opts.symbolic - will be set to true regardless of passed value
* @returns an instance of `SequelizeQueryStringParser` with symbolic=true.
*/
withSymbolicOps (sequelize, opts={}) {
return new SequelizeQueryStringParser(sequelize,
Object.assign(opts, {symbolic: true}))
withSymbolicOps(sequelize, opts = {}) {
return new SequelizeQueryStringParser(sequelize,
Object.assign(opts, { symbolic: true }))
}

/** @method
Expand All @@ -70,8 +74,8 @@ class SequelizeQueryStringParser {
operators() {
const identityOps = {
valFunc: identity,
ops: ['gt', 'gte', 'lt', 'lte', 'ne', 'eq', 'not', 'like',
'notLike', 'iLike', 'notILike']
ops: ['gt', 'gte', 'lt', 'lte', 'ne', 'eq', 'not', 'like',
'notLike', 'iLike', 'notILike']
}
const arrayHaveOps = {
valFunc: arrayHave,
Expand All @@ -81,7 +85,7 @@ class SequelizeQueryStringParser {
for (var opSet of [identityOps, arrayHaveOps]) {
for (var op of opSet.ops) {
resultMap[op] = {
'op': (this.symbolic ? this.sequelize.Op[op] : `$${op}`),
'op': (this.symbolic ? this.sequelize.Op[op] : `$${op}`),
'valFunc': opSet.valFunc
}
}
Expand All @@ -99,21 +103,21 @@ class SequelizeQueryStringParser {
* @returns {Object} the where clause for building the corresponding
* Sequelize query
*/
find (expression) {
find(expression) {
let where = {}
if (expression.match(/(([\w|.]+)\s(\w+)\s([\w|\s|%|_]+),?)+/)) {
if (expression.match(/(([\w|.]+)(\s|%20)(\w+)(\s|%20)([\w|\s|%|_]+)?)+/)) {
let parts = (expression).split(',')
const operators = this.operators()
for (let i = 0; i < parts.length; i++) {
// build a regexp to match filter expressions
const lhs = '[\\w|.]+'
const op = '\\w+'
const rhs = `[A-Za-z0-9.+@:/()%_\\s\\-\\xAA\\xB5\\xBA${utf8letters}]+`
const expressionRegExp = new RegExp(`(${lhs})\\s+(${op})\\s+(${rhs})`)
const expressionRegExp = new RegExp(`(${lhs})(\\s|%20)+(${op})(\\s|%20)+(${rhs})`)
if (parts[i].match(expressionRegExp)) {
let prop = RegExp.$1
let op = RegExp.$2
let value = RegExp.$3
let op = RegExp.$3
let value = RegExp.$5
if (!operators[op]) {
throw new Error(`Invalid operator ${op}`)
}
Expand Down Expand Up @@ -141,7 +145,8 @@ class SequelizeQueryStringParser {
* @returns {Array} the order clause for building the corresponding Sequelize
* query
*/
sort (expression, sequelize) {
sort(expression, sequelize) {

// maintain backward-compatibility with v0.x.x, where users supply
// their own sequelize object as the second param of sort()
sequelize = sequelize || this.sequelize
Expand All @@ -152,7 +157,16 @@ class SequelizeQueryStringParser {
if (exp.length === 2) {
let prop = exp[0]
let ord = exp[1].toUpperCase()
if (ord.match(/ASC|DESC/i)) {

let nests = prop.split('.')

if (nests.length > 1) {
prop = nests
if (ord.match(/ASC|DESC/i)) {
prop.push(ord.toUpperCase())
order.push(prop)
}
} else if (ord.match(/ASC|DESC/i)) {
order.push([prop, ord.toUpperCase()])
}
}
Expand Down