diff --git a/src/ParseObject.js b/src/ParseObject.js
index a10999ff3..5f78cb191 100644
--- a/src/ParseObject.js
+++ b/src/ParseObject.js
@@ -56,7 +56,8 @@ type SaveParams = {
};
type SaveOptions = FullOptions & {
- cascadeSave?: boolean
+ cascadeSave?: boolean;
+ context?: AttributeMap;
}
// Mapping of class names to constructors, so we can populate objects from the
@@ -1179,6 +1180,7 @@ class ParseObject {
*
sessionToken: A valid session token, used for making a request on
* behalf of a specific user.
* cascadeSave: If `false`, nested objects will not be saved (default is `true`).
+ * context: A dictionary that is accessible in Cloud Code `beforeSave` and `afterSave` triggers.
*
*
*
@@ -1192,6 +1194,7 @@ class ParseObject {
* sessionToken: A valid session token, used for making a request on
* behalf of a specific user.
* cascadeSave: If `false`, nested objects will not be saved (default is `true`).
+ * context: A dictionary that is accessible in Cloud Code `beforeSave` and `afterSave` triggers.
*
*
* @return {Promise} A promise that is fulfilled when the save
@@ -1251,6 +1254,9 @@ class ParseObject {
if (options.hasOwnProperty('installationId') && typeof options.installationId === 'string') {
saveOptions.installationId = options.installationId;
}
+ if (options.hasOwnProperty('context') && typeof options.context === 'object') {
+ saveOptions.context = options.context;
+ }
const controller = CoreManager.getObjectController();
const unsaved = options.cascadeSave !== false ? unsavedChildren(this) : null;
return controller.save(unsaved, saveOptions).then(() => {
diff --git a/src/RESTController.js b/src/RESTController.js
index 1b3006a6d..82e3d3195 100644
--- a/src/RESTController.js
+++ b/src/RESTController.js
@@ -21,6 +21,7 @@ export type RequestOptions = {
batchSize?: number;
include?: any;
progress?: any;
+ context?: any;
};
export type FullOptions = {
@@ -222,6 +223,13 @@ const RESTController = {
}
}
+ // Add context
+ const context = options.context;
+ if (context !== undefined) {
+ payload._context = context;
+ delete options.context;
+ }
+
if (method !== 'POST') {
payload._method = method;
method = 'POST';
diff --git a/src/__tests__/ParseObject-test.js b/src/__tests__/ParseObject-test.js
index cc917da61..e055a9d0e 100644
--- a/src/__tests__/ParseObject-test.js
+++ b/src/__tests__/ParseObject-test.js
@@ -1219,6 +1219,26 @@ describe('ParseObject', () => {
});
});
+ it('accepts context on save', async () => {
+ // Mock XHR
+ CoreManager.getRESTController()._setXHR(
+ mockXHR([{
+ status: 200,
+ response: { objectId: 'newattributes' }
+ }])
+ );
+ // Spy on REST controller
+ const controller = CoreManager.getRESTController();
+ jest.spyOn(controller, 'ajax');
+ // Save object
+ const context = {a: "a"};
+ const obj = new ParseObject('Item');
+ await obj.save(null, {context});
+ // Validate
+ const jsonBody = JSON.parse(controller.ajax.mock.calls[0][2]);
+ expect(jsonBody._context).toEqual(context);
+ });
+
it('interpolates delete operations', (done) => {
CoreManager.getRESTController()._setXHR(
mockXHR([{