Skip to content

Commit 53e88f1

Browse files
jeremypiednoeldplewis
authored andcommitted
Adding Mongodb element to add arrayMatches the parse-community#4762 (parse-community#4766)
* Adding elemMatch and nor * lint * adding test * adding edge test * postgres support * clean up * empty test
1 parent aef5bb9 commit 53e88f1

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

spec/ParseQuery.spec.js

+103
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,109 @@ describe('Parse.Query testing', () => {
754754
});
755755
});
756756

757+
it('containedBy pointer array', (done) => {
758+
const objects = Array.from(Array(10).keys()).map((idx) => {
759+
const obj = new Parse.Object('Object');
760+
obj.set('key', idx);
761+
return obj;
762+
});
763+
764+
const parent = new Parse.Object('Parent');
765+
const parent2 = new Parse.Object('Parent');
766+
const parent3 = new Parse.Object('Parent');
767+
768+
Parse.Object.saveAll(objects).then(() => {
769+
// [0, 1, 2]
770+
parent.set('objects', objects.slice(0, 3));
771+
772+
const shift = objects.shift();
773+
// [2, 0]
774+
parent2.set('objects', [objects[1], shift]);
775+
776+
// [1, 2, 3, 4]
777+
parent3.set('objects', objects.slice(1, 4));
778+
779+
return Parse.Object.saveAll([parent, parent2, parent3]);
780+
}).then(() => {
781+
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
782+
const pointers = objects.map(object => object.toPointer());
783+
784+
// Return all Parent where all parent.objects are contained in objects
785+
return rp.get({
786+
url: Parse.serverURL + "/classes/Parent",
787+
json: {
788+
where: {
789+
objects: {
790+
$containedBy: pointers
791+
}
792+
}
793+
},
794+
headers: {
795+
'X-Parse-Application-Id': Parse.applicationId,
796+
'X-Parse-Javascript-Key': Parse.javaScriptKey
797+
}
798+
});
799+
}).then((results) => {
800+
expect(results.results[0].objectId).not.toBeUndefined();
801+
expect(results.results[0].objectId).toBe(parent3.id);
802+
expect(results.results.length).toBe(1);
803+
done();
804+
});
805+
});
806+
807+
808+
it('containedBy number array', (done) => {
809+
const options = Object.assign({}, masterKeyOptions, {
810+
body: {
811+
where: { numbers: { $containedBy: [1, 2, 3, 4, 5, 6, 7, 8, 9] } },
812+
}
813+
});
814+
const obj1 = new TestObject({ numbers: [0, 1, 2] });
815+
const obj2 = new TestObject({ numbers: [2, 0] });
816+
const obj3 = new TestObject({ numbers: [1, 2, 3, 4] });
817+
Parse.Object.saveAll([obj1, obj2, obj3]).then(() => {
818+
return rp.get(Parse.serverURL + "/classes/TestObject", options);
819+
}).then((results) => {
820+
expect(results.results[0].objectId).not.toBeUndefined();
821+
expect(results.results[0].objectId).toBe(obj3.id);
822+
expect(results.results.length).toBe(1);
823+
done();
824+
});
825+
});
826+
827+
it('containedBy empty array', (done) => {
828+
const options = Object.assign({}, masterKeyOptions, {
829+
body: {
830+
where: { numbers: { $containedBy: [] } },
831+
}
832+
});
833+
const obj1 = new TestObject({ numbers: [0, 1, 2] });
834+
const obj2 = new TestObject({ numbers: [2, 0] });
835+
const obj3 = new TestObject({ numbers: [1, 2, 3, 4] });
836+
Parse.Object.saveAll([obj1, obj2, obj3]).then(() => {
837+
return rp.get(Parse.serverURL + "/classes/TestObject", options);
838+
}).then((results) => {
839+
expect(results.results.length).toBe(0);
840+
done();
841+
});
842+
});
843+
844+
it('containedBy invalid query', (done) => {
845+
const options = Object.assign({}, masterKeyOptions, {
846+
body: {
847+
where: { objects: { $containedBy: 1234 } },
848+
}
849+
});
850+
const obj = new TestObject();
851+
obj.save().then(() => {
852+
return rp.get(Parse.serverURL + "/classes/TestObject", options);
853+
}).then(done.fail).catch((error) => {
854+
equal(error.error.code, Parse.Error.INVALID_JSON);
855+
equal(error.error.error, 'bad $containedBy: should be an array');
856+
done();
857+
});
858+
});
859+
757860
const BoxedNumber = Parse.Object.extend({
758861
className: "BoxedNumber"
759862
});

src/Adapters/Storage/Mongo/MongoTransform.js

+16
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@ function transformQueryKeyValue(className, key, value, schema) {
290290
if (transformedConstraint.$text) {
291291
return {key: '$text', value: transformedConstraint.$text};
292292
}
293+
if (transformedConstraint.$elemMatch) {
294+
return { key: '$nor', value: [{ [key]: transformedConstraint }] };
295+
}
293296
return {key, value: transformedConstraint};
294297
}
295298

@@ -797,6 +800,19 @@ function transformConstraint(constraint, field) {
797800
answer[key] = s;
798801
break;
799802

803+
case '$containedBy': {
804+
const arr = constraint[key];
805+
if (!(arr instanceof Array)) {
806+
throw new Parse.Error(
807+
Parse.Error.INVALID_JSON,
808+
`bad $containedBy: should be an array`
809+
);
810+
}
811+
answer.$elemMatch = {
812+
$nin: arr.map(transformer)
813+
};
814+
break;
815+
}
800816
case '$options':
801817
answer[key] = constraint[key];
802818
break;

src/Adapters/Storage/Postgres/PostgresStorageAdapter.js

+14
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,20 @@ const buildWhereClause = ({ schema, query, index }): WhereClause => {
446446
index += 1;
447447
}
448448

449+
if (fieldValue.$containedBy) {
450+
const arr = fieldValue.$containedBy;
451+
if (!(arr instanceof Array)) {
452+
throw new Parse.Error(
453+
Parse.Error.INVALID_JSON,
454+
`bad $containedBy: should be an array`
455+
);
456+
}
457+
458+
patterns.push(`$${index}:name <@ $${index + 1}::jsonb`);
459+
values.push(fieldName, JSON.stringify(arr));
460+
index += 2;
461+
}
462+
449463
if (fieldValue.$text) {
450464
const search = fieldValue.$text.$search;
451465
let language = 'english';

0 commit comments

Comments
 (0)