Adding $nor operator support (#4768)

* adding nor to specialQuerykeys

* adding nor suport

* adding test

* CRLF

* adding postgres NOR

* adding nor validation

* adding NOR test

* adding test amd fixing NOR cases

* revert the nor logic
This commit is contained in:
Jérémy Piednoel
2018-05-18 15:26:33 -04:00
committed by Diamond Lewis
parent a9ebc2b9af
commit 77ed10f57b
4 changed files with 74 additions and 6 deletions

View File

@@ -2567,6 +2567,63 @@ describe('Parse.Query testing', () => {
});
});
it('$nor valid query', (done) => {
const objects = Array.from(Array(10).keys()).map((rating) => {
return new TestObject({ 'rating': rating });
});
const highValue = 5;
const lowValue = 3;
const options = Object.assign({}, masterKeyOptions, {
body: {
where: {
$nor: [
{ rating : { $gt : highValue } },
{ rating : { $lte : lowValue } },
]
},
}
});
Parse.Object.saveAll(objects).then(() => {
return rp.get(Parse.serverURL + "/classes/TestObject", options);
}).then((results) => {
expect(results.results.length).toBe(highValue - lowValue);
expect(results.results.every(res => res.rating > lowValue && res.rating <= highValue)).toBe(true);
done();
});
});
it('$nor invalid query - empty array', (done) => {
const options = Object.assign({}, masterKeyOptions, {
body: {
where: { $nor: [] },
}
});
const obj = new TestObject();
obj.save().then(() => {
return rp.get(Parse.serverURL + "/classes/TestObject", options);
}).then(done.fail).catch((error) => {
equal(error.error.code, Parse.Error.INVALID_QUERY);
done();
});
});
it('$nor invalid query - wrong type', (done) => {
const options = Object.assign({}, masterKeyOptions, {
body: {
where: { $nor: 1337 },
}
});
const obj = new TestObject();
obj.save().then(() => {
return rp.get(Parse.serverURL + "/classes/TestObject", options);
}).then(done.fail).catch((error) => {
equal(error.error.code, Parse.Error.INVALID_QUERY);
done();
});
});
it("dontSelect query", function(done) {
const RestaurantObject = Parse.Object.extend("Restaurant");
const PersonObject = Parse.Object.extend("Person");

View File

@@ -247,9 +247,9 @@ function transformQueryKeyValue(className, key, value, schema) {
case '_perishable_token':
case '_email_verify_token': return {key, value}
case '$or':
return {key: '$or', value: value.map(subQuery => transformWhere(className, subQuery, schema))};
case '$and':
return {key: '$and', value: value.map(subQuery => transformWhere(className, subQuery, schema))};
case '$nor':
return {key: key, value: value.map(subQuery => transformWhere(className, subQuery, schema))};
case 'lastUsed':
if (valueAsDate(value)) {
return {key: '_last_used', value: valueAsDate(value)}

View File

@@ -306,7 +306,7 @@ const buildWhereClause = ({ schema, query, index }): WhereClause => {
patterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue);
index += 2;
} else if (fieldName === '$or' || fieldName === '$and') {
} else if (['$or', '$nor', '$and'].includes(fieldName)) {
const clauses = [];
const clauseValues = [];
fieldValue.forEach((subQuery) => {
@@ -317,8 +317,11 @@ const buildWhereClause = ({ schema, query, index }): WhereClause => {
index += clause.values.length;
}
});
const orOrAnd = fieldName === '$or' ? ' OR ' : ' AND ';
patterns.push(`(${clauses.join(orOrAnd)})`);
const orOrAnd = fieldName === '$and' ? ' AND ' : ' OR ';
const not = fieldName === '$nor' ? ' NOT ' : '';
patterns.push(`${not}(${clauses.join(orOrAnd)})`);
values.push(...clauseValues);
}

View File

@@ -50,7 +50,7 @@ const transformObjectACL = ({ ACL, ...result }) => {
return result;
}
const specialQuerykeys = ['$and', '$or', '_rperm', '_wperm', '_perishable_token', '_email_verify_token', '_email_verify_token_expires_at', '_account_lockout_expires_at', '_failed_login_count'];
const specialQuerykeys = ['$and', '$or', '$nor', '_rperm', '_wperm', '_perishable_token', '_email_verify_token', '_email_verify_token_expires_at', '_account_lockout_expires_at', '_failed_login_count'];
const isSpecialQueryKey = key => {
return specialQuerykeys.indexOf(key) >= 0;
@@ -111,6 +111,14 @@ const validateQuery = (query: any): void => {
}
}
if (query.$nor) {
if (query.$nor instanceof Array && query.$nor.length > 0) {
query.$nor.forEach(validateQuery);
} else {
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Bad $nor format - use an array of at least 1 value.');
}
}
Object.keys(query).forEach(key => {
if (query && query[key] && query[key].$regex) {
if (typeof query[key].$options === 'string') {