Adding Mongodb element to add arrayMatches the #4762 (#4766)

* Adding elemMatch and nor

* lint

* adding test

* adding edge test

* postgres support

* clean up

* empty test
This commit is contained in:
Jérémy Piednoel
2018-05-18 09:35:50 -04:00
committed by Diamond Lewis
parent ad244d6654
commit c0f86ae1d1
3 changed files with 133 additions and 0 deletions

View File

@@ -754,6 +754,109 @@ describe('Parse.Query testing', () => {
});
});
it('containedBy pointer array', (done) => {
const objects = Array.from(Array(10).keys()).map((idx) => {
const obj = new Parse.Object('Object');
obj.set('key', idx);
return obj;
});
const parent = new Parse.Object('Parent');
const parent2 = new Parse.Object('Parent');
const parent3 = new Parse.Object('Parent');
Parse.Object.saveAll(objects).then(() => {
// [0, 1, 2]
parent.set('objects', objects.slice(0, 3));
const shift = objects.shift();
// [2, 0]
parent2.set('objects', [objects[1], shift]);
// [1, 2, 3, 4]
parent3.set('objects', objects.slice(1, 4));
return Parse.Object.saveAll([parent, parent2, parent3]);
}).then(() => {
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
const pointers = objects.map(object => object.toPointer());
// Return all Parent where all parent.objects are contained in objects
return rp.get({
url: Parse.serverURL + "/classes/Parent",
json: {
where: {
objects: {
$containedBy: pointers
}
}
},
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-Javascript-Key': Parse.javaScriptKey
}
});
}).then((results) => {
expect(results.results[0].objectId).not.toBeUndefined();
expect(results.results[0].objectId).toBe(parent3.id);
expect(results.results.length).toBe(1);
done();
});
});
it('containedBy number array', (done) => {
const options = Object.assign({}, masterKeyOptions, {
body: {
where: { numbers: { $containedBy: [1, 2, 3, 4, 5, 6, 7, 8, 9] } },
}
});
const obj1 = new TestObject({ numbers: [0, 1, 2] });
const obj2 = new TestObject({ numbers: [2, 0] });
const obj3 = new TestObject({ numbers: [1, 2, 3, 4] });
Parse.Object.saveAll([obj1, obj2, obj3]).then(() => {
return rp.get(Parse.serverURL + "/classes/TestObject", options);
}).then((results) => {
expect(results.results[0].objectId).not.toBeUndefined();
expect(results.results[0].objectId).toBe(obj3.id);
expect(results.results.length).toBe(1);
done();
});
});
it('containedBy empty array', (done) => {
const options = Object.assign({}, masterKeyOptions, {
body: {
where: { numbers: { $containedBy: [] } },
}
});
const obj1 = new TestObject({ numbers: [0, 1, 2] });
const obj2 = new TestObject({ numbers: [2, 0] });
const obj3 = new TestObject({ numbers: [1, 2, 3, 4] });
Parse.Object.saveAll([obj1, obj2, obj3]).then(() => {
return rp.get(Parse.serverURL + "/classes/TestObject", options);
}).then((results) => {
expect(results.results.length).toBe(0);
done();
});
});
it('containedBy invalid query', (done) => {
const options = Object.assign({}, masterKeyOptions, {
body: {
where: { objects: { $containedBy: 1234 } },
}
});
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_JSON);
equal(error.error.error, 'bad $containedBy: should be an array');
done();
});
});
const BoxedNumber = Parse.Object.extend({
className: "BoxedNumber"
});

View File

@@ -290,6 +290,9 @@ function transformQueryKeyValue(className, key, value, schema) {
if (transformedConstraint.$text) {
return {key: '$text', value: transformedConstraint.$text};
}
if (transformedConstraint.$elemMatch) {
return { key: '$nor', value: [{ [key]: transformedConstraint }] };
}
return {key, value: transformedConstraint};
}
@@ -797,6 +800,19 @@ function transformConstraint(constraint, field) {
answer[key] = s;
break;
case '$containedBy': {
const arr = constraint[key];
if (!(arr instanceof Array)) {
throw new Parse.Error(
Parse.Error.INVALID_JSON,
`bad $containedBy: should be an array`
);
}
answer.$elemMatch = {
$nin: arr.map(transformer)
};
break;
}
case '$options':
answer[key] = constraint[key];
break;

View File

@@ -446,6 +446,20 @@ const buildWhereClause = ({ schema, query, index }): WhereClause => {
index += 1;
}
if (fieldValue.$containedBy) {
const arr = fieldValue.$containedBy;
if (!(arr instanceof Array)) {
throw new Parse.Error(
Parse.Error.INVALID_JSON,
`bad $containedBy: should be an array`
);
}
patterns.push(`$${index}:name <@ $${index + 1}::jsonb`);
values.push(fieldName, JSON.stringify(arr));
index += 2;
}
if (fieldValue.$text) {
const search = fieldValue.$text.$search;
let language = 'english';