Skip to content

Commit 8566734

Browse files
committed
deleteObject in db adapter
1 parent 83f6175 commit 8566734

File tree

4 files changed

+108
-78
lines changed

4 files changed

+108
-78
lines changed

spec/ParseHooks.spec.js

Lines changed: 37 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -37,50 +37,43 @@ describe('Hooks', () => {
3737
});
3838
});
3939

40-
it("should CRUD a function registration", (done) => {
41-
// Create
42-
Parse.Hooks.createFunction("My-Test-Function", "http://someurl").then((res) => {
43-
expect(res.functionName).toBe("My-Test-Function");
44-
expect(res.url).toBe("http://someurl")
45-
// Find
46-
return Parse.Hooks.getFunction("My-Test-Function");
47-
}, (err) => {
48-
fail(err);
49-
done();
50-
}).then((res) => {
51-
expect(res).not.toBe(null);
52-
expect(res).not.toBe(undefined);
53-
expect(res.url).toBe("http://someurl");
54-
// delete
55-
return Parse.Hooks.updateFunction("My-Test-Function", "http://anotherurl");
56-
}, (err) => {
57-
fail(err);
58-
done();
59-
}).then((res) => {
60-
expect(res.functionName).toBe("My-Test-Function");
61-
expect(res.url).toBe("http://anotherurl")
62-
63-
return Parse.Hooks.deleteFunction("My-Test-Function");
64-
}, (err) => {
65-
fail(err);
66-
done();
67-
}).then((res) => {
68-
// Find again! but should be deleted
69-
return Parse.Hooks.getFunction("My-Test-Function");
70-
}, (err) => {
71-
fail(err);
72-
done();
73-
}).then((res) => {
74-
fail("Should not succeed")
75-
done();
76-
}, (err) => {
77-
expect(err).not.toBe(null);
78-
expect(err).not.toBe(undefined);
79-
expect(err.code).toBe(143);
80-
expect(err.error).toBe("no function named: My-Test-Function is defined")
81-
done();
82-
})
83-
});
40+
it("should CRUD a function registration", (done) => {
41+
// Create
42+
Parse.Hooks.createFunction("My-Test-Function", "http://someurl")
43+
.then(response => {
44+
expect(response.functionName).toBe("My-Test-Function");
45+
expect(response.url).toBe("http://someurl")
46+
// Find
47+
return Parse.Hooks.getFunction("My-Test-Function")
48+
}).then(response => {
49+
expect(response.url).toBe("http://someurl");
50+
return Parse.Hooks.updateFunction("My-Test-Function", "http://anotherurl");
51+
})
52+
.then((res) => {
53+
expect(res.functionName).toBe("My-Test-Function");
54+
expect(res.url).toBe("http://anotherurl")
55+
// delete
56+
return Parse.Hooks.deleteFunction("My-Test-Function")
57+
})
58+
.then((res) => {
59+
// Find again! but should be deleted
60+
return Parse.Hooks.getFunction("My-Test-Function")
61+
.then((res) => {
62+
fail("Failed to delete hook")
63+
done();
64+
return Promise.resolve();
65+
}, (err) => {
66+
expect(err.code).toBe(143);
67+
expect(err.error).toBe("no function named: My-Test-Function is defined")
68+
done();
69+
return Promise.resolve();
70+
})
71+
})
72+
.catch(error => {
73+
fail(error);
74+
done();
75+
})
76+
});
8477

8578
it("should CRUD a trigger registration", (done) => {
8679
// Create

src/Adapters/Storage/Mongo/MongoStorageAdapter.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,27 @@ export class MongoStorageAdapter {
159159
.then(collection => collection.insertOne(mongoObject));
160160
}
161161

162+
// Remove the object with the given ID. If the object does not exist, reject with OBJECT_NOT_FOUND.
163+
// If there is a different type of error, reject with INTERNAL_SERVER_ERROR and a message
164+
// that doesn't leak info to the client.
165+
deleteObject(className, objectId) {
166+
return this.adaptiveCollection(className)
167+
.then(collection => collection.deleteOne({ _id: objectId }))
168+
.then(({ deletedCount }) => {
169+
if (deletedCount === 1) {
170+
return Promise.resolve();
171+
} else {
172+
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
173+
}
174+
}, error => {
175+
throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'Database adapter error.');
176+
});
177+
}
178+
179+
//
180+
deleteObjectsByQuery(className, query) {
181+
}
182+
162183
get transform() {
163184
return transform;
164185
}

src/Controllers/DatabaseController.js

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ DatabaseController.prototype.update = function(className, query, update, {
156156
.then(() => this.adapter.adaptiveCollection(className))
157157
.then(collection => {
158158
if (!isMaster) {
159-
query = this.addPointerPermissions(schema, className, 'update', query, aclGroup);
159+
query = this.addPointerPermissions(schema, className, 'update', query, aclGroup);
160160
}
161161
if (!query) {
162162
return Promise.resolve();
@@ -284,40 +284,56 @@ DatabaseController.prototype.removeRelation = function(key, fromClassName, fromI
284284
// acl: a list of strings. If the object to be updated has an ACL,
285285
// one of the provided strings must provide the caller with
286286
// write permissions.
287-
DatabaseController.prototype.destroy = function(className, query, { acl } = {}) {
288-
var isMaster = acl !== undefined;
289-
var aclGroup = acl || [];
287+
DatabaseController.prototype.destroy = function(className, { objectId, ...query}, { acl } = {}) {
288+
const isMaster = acl !== undefined;
289+
const aclGroup = acl || [];
290290

291-
var schema;
292291
return this.loadSchema()
293-
.then(s => {
294-
schema = s;
295-
if (!isMaster) {
296-
return schema.validatePermission(className, aclGroup, 'delete');
297-
}
298-
return Promise.resolve();
299-
})
300-
.then(() => this.adapter.adaptiveCollection(className))
301-
.then(collection => {
302-
if (!isMaster) {
303-
query = this.addPointerPermissions(schema, className, 'delete', query, aclGroup);
304-
if (!query) {
305-
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
292+
.then(schemaController => {
293+
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'delete'))
294+
.then(() => {
295+
if (query !== {} || !objectId) {
296+
if (objectId) {
297+
query.objectId = objectId;
306298
}
307-
}
308-
let mongoWhere = this.transform.transformWhere(schema, className, query, {validate: !this.skipValidation});
309-
if (acl) {
310-
mongoWhere = this.transform.addWriteACL(mongoWhere, acl);
311-
}
312-
return collection.deleteMany(mongoWhere);
313-
})
314-
.then(resp => {
315-
//Check _Session to avoid changing password failed without any session.
316-
// TODO: @nlutsenko Stop relying on `result.n`
317-
if (resp.result.n === 0 && className !== "_Session") {
318-
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
299+
300+
// delete by query
301+
return this.adapter.adaptiveCollection(className)
302+
.then(collection => {
303+
if (!isMaster) {
304+
query = this.addPointerPermissions(schema, className, 'delete', query, aclGroup);
305+
if (!query) {
306+
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
307+
}
308+
}
309+
let mongoWhere = this.transform.transformWhere(schemaController, className, query, {validate: !this.skipValidation});
310+
if (acl) {
311+
mongoWhere = this.transform.addWriteACL(mongoWhere, acl);
312+
}
313+
return collection.deleteMany(mongoWhere)
314+
.then(resp => {
315+
//Check _Session to avoid changing password failed without any session.
316+
// TODO: @nlutsenko Stop relying on `result.n`
317+
if (resp.result.n === 0 && className !== "_Session") {
318+
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
319+
}
320+
});
321+
});
322+
} else {
323+
// delete by objectId
324+
return this.adapter.deleteObject(className, objectId)
325+
.catch(error => {
326+
if (className === '_Session' && error.code === Parse.Error.OBJECT_NOT_FOUND) {
327+
// When deleting sessions while changing passwords, don't throw an error.
328+
// I suspect this isn't necessary, as sessions should only be deleted by query
329+
// when changing password, but we'll see.
330+
return Promise.resolve();
331+
}
332+
throw error;
333+
});
319334
}
320335
});
336+
});
321337
};
322338

323339
// Inserts an object into the database.
@@ -612,7 +628,7 @@ DatabaseController.prototype.find = function(className, query, {
612628
.then(() => this.adapter.adaptiveCollection(className))
613629
.then(collection => {
614630
if (!isMaster) {
615-
query = this.addPointerPermissions(schema, className, op, query, aclGroup);
631+
query = this.addPointerPermissions(schema, className, op, query, aclGroup);
616632
}
617633
if (!query) {
618634
if (op == 'get') {

src/cloud-code/Parse.Hooks.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
var request = require("request");
22
const send = function(method, path, body) {
3-
3+
44
var Parse = require("parse/node").Parse;
55

66
var options = {
@@ -12,15 +12,15 @@ const send = function(method, path, body) {
1212
'Content-Type': 'application/json'
1313
},
1414
};
15-
15+
1616
if (body) {
1717
if (typeof body == "object") {
1818
options.body = JSON.stringify(body);
1919
} else {
2020
options.body = body;
2121
}
2222
}
23-
23+
2424
var promise = new Parse.Promise();
2525
request(options, function(err, response, body){
2626
if (err) {

0 commit comments

Comments
 (0)