pouchdb-selector-core
Advanced tools
+100
-40
@@ -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 @@ |
+100
-40
@@ -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 @@ |
+8
-4
| { | ||
| "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", |
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
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
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
9.95%1143
11.3%6
500%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated