Skip to content
This repository was archived by the owner on Jan 26, 2021. It is now read-only.

Commit 455f448

Browse files
committed
Merge pull request #92 from philikon/mutation_abort
Add ability for aborting mutation batches
2 parents 5e062d4 + 8bec64c commit 455f448

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

src/MutationBatch.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,26 @@ import type { ParseRequestOptions } from './MutationExecutor';
3030
class MutationBatch {
3131
static maxBatchSize: number;
3232

33+
_aborted: boolean;
34+
_dispatched: boolean;
3335
_requests: Array<ParseRequestOptions>;
3436
_promises: Array<Parse.Promise>;
35-
addRequest: (options: ParseRequestOptions) => Parse.Promise;
3637

3738
constructor() {
39+
this._aborted = false;
40+
this._dispatched = false;
3841
this._requests = [];
3942
this._promises = [];
40-
this.addRequest = this.addRequest.bind(this);
4143
}
4244

4345
getNumberOfRequests(): number {
4446
return this._requests.length;
4547
}
4648

4749
addRequest(options: ParseRequestOptions): Parse.Promise {
50+
if (this._aborted || this._dispatched) {
51+
throw new Error('Cannot add a request to aborted or dispatched batch.');
52+
}
4853
if (this.getNumberOfRequests() === MutationBatch.maxBatchSize) {
4954
throw new Error('Cannot batch more than ' + MutationBatch.maxBatchSize +
5055
' requests at a time.');
@@ -56,6 +61,10 @@ class MutationBatch {
5661
}
5762

5863
dispatch(): Parse.Promise {
64+
if (this._aborted || this._dispatched) {
65+
throw new Error('Cannot dispatch an already dispatched or aborted batch.');
66+
}
67+
this._dispatched = true;
5968
var requests = this._requests.map((req) => {
6069
var path = '/1/' + req.route;
6170
if (req.className) {
@@ -90,6 +99,12 @@ class MutationBatch {
9099
return Parse.Promise.error(error);
91100
});
92101
}
102+
103+
abort() {
104+
this._aborted = true;
105+
var error = new Error('Batch was aborted.');
106+
this._promises.forEach((promise) => promise.reject(error));
107+
}
93108
}
94109
MutationBatch.maxBatchSize = 50;
95110

src/MutationExecutor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function execute(
121121
var className = (typeof target === 'string') ? target : target.className;
122122
var objectId = (typeof target === 'string') ? '' : target.objectId;
123123
var payload;
124-
var request = batch ? batch.addRequest : sendRequest;
124+
var request = batch ? batch.addRequest.bind(batch) : sendRequest;
125125
switch (mutation.action) {
126126
case 'CREATE':
127127
return request({

src/__tests__/MutationBatch-test.js

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,13 @@ describe('MutationBatch', function() {
142142
expect(thirdPromiseResult).toBe(null);
143143
expect(thirdPromiseError).toEqual(expectedThirdError);
144144
expect(batchPromiseResolved).toBe(true);
145+
146+
// Once dispatched, the batch cannot be dispatched or aborted anymore.
147+
expect(function() { batch.dispatch(); }).toThrow();
148+
expect(function() { batch.abort(); }).toThrow();
145149
});
146150

147-
it('resolves promises even when request fails', function() {
151+
it('rejects promises when the entire request fails', function() {
148152
Parse.XMLHttpRequest = testXHR(
149153
function() {},
150154
function() {},
@@ -189,6 +193,49 @@ describe('MutationBatch', function() {
189193
expect(firstPromiseError).toBe(secondPromiseError);
190194
expect(batchPromiseError).toBe(firstPromiseError);
191195
expect(batchPromiseSuccess).toBe(false);
196+
197+
// Once dispatched, the batch cannot be dispatched or aborted anymore.
198+
expect(function() { batch.dispatch(); }).toThrow();
199+
expect(function() { batch.abort(); }).toThrow();
200+
});
201+
202+
it('rejects promises when the mutation is aborted', function() {
203+
var batch = new MutationBatch();
204+
var firstPromise = batch.addRequest({
205+
method: 'DELETE',
206+
route: 'classes',
207+
className: 'MadeUpClassName',
208+
objectId: 'randomId',
209+
});
210+
var secondPromise = batch.addRequest({
211+
method: 'CREATE',
212+
route: 'classes',
213+
className: 'MadeUpClassName',
214+
data: {some: 'fields', and: 'stuff'},
215+
});
216+
217+
var firstPromiseResult = null;
218+
var firstPromiseError = null;
219+
var secondPromiseResult = null;
220+
var secondPromiseError = null;
221+
firstPromise.then(
222+
function(result) { firstPromiseResult = result; },
223+
function(error) { firstPromiseError = error; }
224+
);
225+
secondPromise.then(
226+
function(result) { secondPromiseResult = result; },
227+
function(error) { secondPromiseError = error; }
228+
);
229+
batch.abort()
230+
231+
expect(firstPromiseResult).toBe(null);
232+
expect(secondPromiseResult).toBe(null);
233+
expect(firstPromiseError instanceof Error).toBe(true);
234+
expect(secondPromiseError instanceof Error).toBe(true);
235+
236+
// Once aborted, the batch cannot be dispatched or aborted anymore.
237+
expect(function() { batch.dispatch(); }).toThrow();
238+
expect(function() { batch.abort(); }).toThrow();
192239
});
193240

194241
});

0 commit comments

Comments
 (0)