pouchdb-selector-core
Advanced tools
Comparing version 7.2.2 to 7.3.0
@@ -37,9 +37,9 @@ import { clone } from 'pouchdb-utils'; | ||
var ch = fieldName[i]; | ||
if (ch === '.') { | ||
if (i > 0 && fieldName[i - 1] === '\\') { // escaped delimiter | ||
current = current.substring(0, current.length - 1) + '.'; | ||
} else { // not escaped, so delimiter | ||
fields.push(current); | ||
current = ''; | ||
} | ||
if (i > 0 && fieldName[i - 1] === '\\' && (ch === '$' || ch === '.')) { | ||
// escaped delimiter | ||
current = current.substring(0, current.length - 1) + ch; | ||
} else if (ch === '.') { | ||
// When `.` is not escaped (above), it is a field delimiter | ||
fields.push(current); | ||
current = ''; | ||
} else { // normal character | ||
@@ -74,2 +74,3 @@ current += ch; | ||
var res = {}; | ||
var first = {$or: true, $nor: true}; | ||
@@ -84,7 +85,28 @@ selectors.forEach(function (selector) { | ||
if (isCombinationalField(field)) { | ||
// or, nor | ||
if (matcher instanceof Array) { | ||
res[field] = matcher.map(function (m) { | ||
return mergeAndedSelectors([m]); | ||
if (first[field]) { | ||
first[field] = false; | ||
res[field] = matcher; | ||
return; | ||
} | ||
var entries = []; | ||
res[field].forEach(function (existing) { | ||
Object.keys(matcher).forEach(function (key) { | ||
var m = matcher[key]; | ||
var longest = Math.max(Object.keys(existing).length, Object.keys(m).length); | ||
var merged = mergeAndedSelectors([existing, m]); | ||
if (Object.keys(merged).length <= longest) { | ||
// we have a situation like: (a :{$eq :1} || ...) && (a {$eq: 2} || ...) | ||
// merging would produce a $eq 2 when actually we shouldn't ever match against these merged conditions | ||
// merged should always contain more values to be valid | ||
return; | ||
} | ||
entries.push(merged); | ||
}); | ||
}); | ||
res[field] = entries; | ||
} else { | ||
// not | ||
res[field] = mergeAndedSelectors([matcher]); | ||
@@ -105,2 +127,4 @@ } | ||
return mergeEq(value, fieldMatchers); | ||
} else if (operator === "$regex") { | ||
return mergeRegex(value, fieldMatchers); | ||
} | ||
@@ -204,2 +228,12 @@ fieldMatchers[operator] = value; | ||
// combine $regex values into one array | ||
function mergeRegex(value, fieldMatchers) { | ||
if ('$regex' in fieldMatchers) { | ||
// a value could match multiple regexes | ||
fieldMatchers.$regex.push(value); | ||
} else { // doesn't exist yet | ||
fieldMatchers.$regex = [value]; | ||
} | ||
} | ||
//#7458: execute function mergeAndedSelectors on nested $and | ||
@@ -283,6 +317,11 @@ function mergeAndedSelectorsNested(obj) { | ||
matcher = {$eq: matcher}; | ||
} else if ('$ne' in matcher && !wasAnded) { | ||
// I put these in an array, since there may be more than one | ||
// but in the "mergeAnded" operation, I already take care of that | ||
matcher.$ne = [matcher.$ne]; | ||
} else if (!wasAnded) { | ||
// These values must be placed in an array because these operators can be used multiple times on the same field | ||
// when $and is used, mergeAndedSelectors takes care of putting them into arrays, otherwise it's done here: | ||
if ('$ne' in matcher) { | ||
matcher.$ne = [matcher.$ne]; | ||
} | ||
if ('$regex' in matcher) { | ||
matcher.$regex = [matcher.$regex]; | ||
} | ||
} | ||
@@ -364,5 +403,29 @@ result[field] = matcher; | ||
if (typeof matcher === 'object') { | ||
return Object.keys(matcher).every(function (userOperator) { | ||
var userValue = matcher[userOperator]; | ||
return match(userOperator, doc, userValue, parsedField, docFieldValue); | ||
return Object.keys(matcher).every(function (maybeUserOperator) { | ||
var userValue = matcher[ maybeUserOperator ]; | ||
// explicit operator | ||
if (maybeUserOperator.indexOf("$") === 0) { | ||
return match(maybeUserOperator, doc, userValue, parsedField, docFieldValue); | ||
} else { | ||
var subParsedField = parseField(maybeUserOperator); | ||
if ( | ||
docFieldValue === undefined && | ||
typeof userValue !== "object" && | ||
subParsedField.length > 0 | ||
) { | ||
// the field does not exist, return or getFieldFromDoc will throw | ||
return false; | ||
} | ||
var subDocFieldValue = getFieldFromDoc(docFieldValue, subParsedField); | ||
if (typeof userValue === "object") { | ||
// field value is an object that might contain more operators | ||
return matchSelector(userValue, doc, parsedField, subDocFieldValue); | ||
} | ||
// implicit operator | ||
return match("$eq", doc, userValue, subParsedField, subDocFieldValue); | ||
} | ||
}); | ||
@@ -396,2 +459,3 @@ } | ||
if (!matchers[userOperator]) { | ||
/* istanbul ignore next */ | ||
throw new Error('unknown operator "' + userOperator + | ||
@@ -413,20 +477,10 @@ '" - should be one of $eq, $lte, $lt, $gt, $gte, $exists, $ne, $in, ' + | ||
function modField(docFieldValue, userValue) { | ||
if (typeof docFieldValue !== "number" || | ||
parseInt(docFieldValue, 10) !== docFieldValue) { | ||
return false; | ||
} | ||
var divisor = userValue[0]; | ||
var mod = userValue[1]; | ||
if (divisor === 0) { | ||
throw new Error('Bad divisor, cannot divide by zero'); | ||
} | ||
if (parseInt(divisor, 10) !== divisor ) { | ||
throw new Error('Divisor is not an integer'); | ||
} | ||
if (parseInt(mod, 10) !== mod ) { | ||
throw new Error('Modulus is not an integer'); | ||
} | ||
if (parseInt(docFieldValue, 10) !== docFieldValue) { | ||
return false; | ||
} | ||
return docFieldValue % divisor === mod; | ||
@@ -438,6 +492,8 @@ } | ||
if (docFieldValue instanceof Array) { | ||
return docFieldValue.indexOf(val) > -1; | ||
return docFieldValue.some(function (docFieldValueItem) { | ||
return collate(val, docFieldValueItem) === 0; | ||
}); | ||
} | ||
return docFieldValue === val; | ||
return collate(val, docFieldValue) === 0; | ||
}); | ||
@@ -448,3 +504,5 @@ } | ||
return userValue.every(function (val) { | ||
return docFieldValue.indexOf(val) > -1; | ||
return docFieldValue.some(function (docFieldValueItem) { | ||
return collate(val, docFieldValueItem) === 0; | ||
}); | ||
}); | ||
@@ -479,6 +537,2 @@ } | ||
} | ||
throw new Error(userValue + ' not supported as a type.' + | ||
'Please use one of object, string, array, number, boolean or null.'); | ||
} | ||
@@ -576,3 +630,5 @@ | ||
'$size': function (doc, userValue, parsedField, docFieldValue) { | ||
return fieldExists(docFieldValue) && arraySize(docFieldValue, userValue); | ||
return fieldExists(docFieldValue) && | ||
Array.isArray(docFieldValue) && | ||
arraySize(docFieldValue, userValue); | ||
}, | ||
@@ -585,3 +641,7 @@ | ||
'$regex': function (doc, userValue, parsedField, docFieldValue) { | ||
return fieldExists(docFieldValue) && regexMatch(docFieldValue, userValue); | ||
return fieldExists(docFieldValue) && | ||
typeof docFieldValue == "string" && | ||
userValue.every(function (regexValue) { | ||
return regexMatch(docFieldValue, regexValue); | ||
}); | ||
}, | ||
@@ -588,0 +648,0 @@ |
140
lib/index.js
@@ -41,9 +41,9 @@ 'use strict'; | ||
var ch = fieldName[i]; | ||
if (ch === '.') { | ||
if (i > 0 && fieldName[i - 1] === '\\') { // escaped delimiter | ||
current = current.substring(0, current.length - 1) + '.'; | ||
} else { // not escaped, so delimiter | ||
fields.push(current); | ||
current = ''; | ||
} | ||
if (i > 0 && fieldName[i - 1] === '\\' && (ch === '$' || ch === '.')) { | ||
// escaped delimiter | ||
current = current.substring(0, current.length - 1) + ch; | ||
} else if (ch === '.') { | ||
// When `.` is not escaped (above), it is a field delimiter | ||
fields.push(current); | ||
current = ''; | ||
} else { // normal character | ||
@@ -78,2 +78,3 @@ current += ch; | ||
var res = {}; | ||
var first = {$or: true, $nor: true}; | ||
@@ -88,7 +89,28 @@ selectors.forEach(function (selector) { | ||
if (isCombinationalField(field)) { | ||
// or, nor | ||
if (matcher instanceof Array) { | ||
res[field] = matcher.map(function (m) { | ||
return mergeAndedSelectors([m]); | ||
if (first[field]) { | ||
first[field] = false; | ||
res[field] = matcher; | ||
return; | ||
} | ||
var entries = []; | ||
res[field].forEach(function (existing) { | ||
Object.keys(matcher).forEach(function (key) { | ||
var m = matcher[key]; | ||
var longest = Math.max(Object.keys(existing).length, Object.keys(m).length); | ||
var merged = mergeAndedSelectors([existing, m]); | ||
if (Object.keys(merged).length <= longest) { | ||
// we have a situation like: (a :{$eq :1} || ...) && (a {$eq: 2} || ...) | ||
// merging would produce a $eq 2 when actually we shouldn't ever match against these merged conditions | ||
// merged should always contain more values to be valid | ||
return; | ||
} | ||
entries.push(merged); | ||
}); | ||
}); | ||
res[field] = entries; | ||
} else { | ||
// not | ||
res[field] = mergeAndedSelectors([matcher]); | ||
@@ -109,2 +131,4 @@ } | ||
return mergeEq(value, fieldMatchers); | ||
} else if (operator === "$regex") { | ||
return mergeRegex(value, fieldMatchers); | ||
} | ||
@@ -208,2 +232,12 @@ fieldMatchers[operator] = value; | ||
// combine $regex values into one array | ||
function mergeRegex(value, fieldMatchers) { | ||
if ('$regex' in fieldMatchers) { | ||
// a value could match multiple regexes | ||
fieldMatchers.$regex.push(value); | ||
} else { // doesn't exist yet | ||
fieldMatchers.$regex = [value]; | ||
} | ||
} | ||
//#7458: execute function mergeAndedSelectors on nested $and | ||
@@ -287,6 +321,11 @@ function mergeAndedSelectorsNested(obj) { | ||
matcher = {$eq: matcher}; | ||
} else if ('$ne' in matcher && !wasAnded) { | ||
// I put these in an array, since there may be more than one | ||
// but in the "mergeAnded" operation, I already take care of that | ||
matcher.$ne = [matcher.$ne]; | ||
} else if (!wasAnded) { | ||
// These values must be placed in an array because these operators can be used multiple times on the same field | ||
// when $and is used, mergeAndedSelectors takes care of putting them into arrays, otherwise it's done here: | ||
if ('$ne' in matcher) { | ||
matcher.$ne = [matcher.$ne]; | ||
} | ||
if ('$regex' in matcher) { | ||
matcher.$regex = [matcher.$regex]; | ||
} | ||
} | ||
@@ -368,5 +407,29 @@ result[field] = matcher; | ||
if (typeof matcher === 'object') { | ||
return Object.keys(matcher).every(function (userOperator) { | ||
var userValue = matcher[userOperator]; | ||
return match(userOperator, doc, userValue, parsedField, docFieldValue); | ||
return Object.keys(matcher).every(function (maybeUserOperator) { | ||
var userValue = matcher[ maybeUserOperator ]; | ||
// explicit operator | ||
if (maybeUserOperator.indexOf("$") === 0) { | ||
return match(maybeUserOperator, doc, userValue, parsedField, docFieldValue); | ||
} else { | ||
var subParsedField = parseField(maybeUserOperator); | ||
if ( | ||
docFieldValue === undefined && | ||
typeof userValue !== "object" && | ||
subParsedField.length > 0 | ||
) { | ||
// the field does not exist, return or getFieldFromDoc will throw | ||
return false; | ||
} | ||
var subDocFieldValue = getFieldFromDoc(docFieldValue, subParsedField); | ||
if (typeof userValue === "object") { | ||
// field value is an object that might contain more operators | ||
return matchSelector(userValue, doc, parsedField, subDocFieldValue); | ||
} | ||
// implicit operator | ||
return match("$eq", doc, userValue, subParsedField, subDocFieldValue); | ||
} | ||
}); | ||
@@ -400,2 +463,3 @@ } | ||
if (!matchers[userOperator]) { | ||
/* istanbul ignore next */ | ||
throw new Error('unknown operator "' + userOperator + | ||
@@ -417,20 +481,10 @@ '" - should be one of $eq, $lte, $lt, $gt, $gte, $exists, $ne, $in, ' + | ||
function modField(docFieldValue, userValue) { | ||
if (typeof docFieldValue !== "number" || | ||
parseInt(docFieldValue, 10) !== docFieldValue) { | ||
return false; | ||
} | ||
var divisor = userValue[0]; | ||
var mod = userValue[1]; | ||
if (divisor === 0) { | ||
throw new Error('Bad divisor, cannot divide by zero'); | ||
} | ||
if (parseInt(divisor, 10) !== divisor ) { | ||
throw new Error('Divisor is not an integer'); | ||
} | ||
if (parseInt(mod, 10) !== mod ) { | ||
throw new Error('Modulus is not an integer'); | ||
} | ||
if (parseInt(docFieldValue, 10) !== docFieldValue) { | ||
return false; | ||
} | ||
return docFieldValue % divisor === mod; | ||
@@ -442,6 +496,8 @@ } | ||
if (docFieldValue instanceof Array) { | ||
return docFieldValue.indexOf(val) > -1; | ||
return docFieldValue.some(function (docFieldValueItem) { | ||
return pouchdbCollate.collate(val, docFieldValueItem) === 0; | ||
}); | ||
} | ||
return docFieldValue === val; | ||
return pouchdbCollate.collate(val, docFieldValue) === 0; | ||
}); | ||
@@ -452,3 +508,5 @@ } | ||
return userValue.every(function (val) { | ||
return docFieldValue.indexOf(val) > -1; | ||
return docFieldValue.some(function (docFieldValueItem) { | ||
return pouchdbCollate.collate(val, docFieldValueItem) === 0; | ||
}); | ||
}); | ||
@@ -483,6 +541,2 @@ } | ||
} | ||
throw new Error(userValue + ' not supported as a type.' + | ||
'Please use one of object, string, array, number, boolean or null.'); | ||
} | ||
@@ -580,3 +634,5 @@ | ||
'$size': function (doc, userValue, parsedField, docFieldValue) { | ||
return fieldExists(docFieldValue) && arraySize(docFieldValue, userValue); | ||
return fieldExists(docFieldValue) && | ||
Array.isArray(docFieldValue) && | ||
arraySize(docFieldValue, userValue); | ||
}, | ||
@@ -589,3 +645,7 @@ | ||
'$regex': function (doc, userValue, parsedField, docFieldValue) { | ||
return fieldExists(docFieldValue) && regexMatch(docFieldValue, userValue); | ||
return fieldExists(docFieldValue) && | ||
typeof docFieldValue == "string" && | ||
userValue.every(function (regexValue) { | ||
return regexMatch(docFieldValue, regexValue); | ||
}); | ||
}, | ||
@@ -592,0 +652,0 @@ |
{ | ||
"name": "pouchdb-selector-core", | ||
"version": "7.2.2", | ||
"version": "7.3.0", | ||
"description": "PouchDB's core selector code", | ||
@@ -9,7 +9,11 @@ "main": "./lib/index.js", | ||
"license": "Apache-2.0", | ||
"repository": "https://github.com/pouchdb/pouchdb", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/pouchdb/pouchdb.git", | ||
"directory": "packages/node_modules/pouchdb-selector-core" | ||
}, | ||
"jsnext:main": "./lib/index.es.js", | ||
"dependencies": { | ||
"pouchdb-collate": "7.2.2", | ||
"pouchdb-utils": "7.2.2" | ||
"pouchdb-collate": "7.3.0", | ||
"pouchdb-utils": "7.3.0" | ||
}, | ||
@@ -16,0 +20,0 @@ "module": "./lib/index.es.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
53030
1143
0
1
+ Addedbuffer-from@1.1.2(transitive)
+ Addedpouchdb-binary-utils@7.3.0(transitive)
+ Addedpouchdb-collate@7.3.0(transitive)
+ Addedpouchdb-collections@7.3.0(transitive)
+ Addedpouchdb-errors@7.3.0(transitive)
+ Addedpouchdb-md5@7.3.0(transitive)
+ Addedpouchdb-utils@7.3.0(transitive)
+ Addedspark-md5@3.0.2(transitive)
+ Addeduuid@8.3.2(transitive)
- Removedbuffer-from@1.1.1(transitive)
- Removedpouchdb-binary-utils@7.2.2(transitive)
- Removedpouchdb-collate@7.2.2(transitive)
- Removedpouchdb-collections@7.2.2(transitive)
- Removedpouchdb-errors@7.2.2(transitive)
- Removedpouchdb-md5@7.2.2(transitive)
- Removedpouchdb-utils@7.2.2(transitive)
- Removedspark-md5@3.0.1(transitive)
- Removeduuid@8.1.0(transitive)
Updatedpouchdb-collate@7.3.0
Updatedpouchdb-utils@7.3.0