parsejs-rails 1.2.0.1 → 1.2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  module Parsejs
2
2
  module Rails
3
- VERSION = "1.2.0.1"
3
+ VERSION = "1.2.1.0"
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * Parse JavaScript SDK
3
- * Version: 1.2.0
4
- * Built: Mon Jan 28 2013 18:16:47
3
+ * Version: 1.2.1
4
+ * Built: Mon Feb 11 2013 18:54:22
5
5
  * http://parse.com
6
6
  *
7
7
  * Copyright 2013 Parse, Inc.
@@ -13,7 +13,7 @@
13
13
  */
14
14
  (function(root) {
15
15
  root.Parse = root.Parse || {};
16
- root.Parse.VERSION = "js1.2.0";
16
+ root.Parse.VERSION = "js1.2.1";
17
17
  }(this));
18
18
 
19
19
 
@@ -1267,6 +1267,7 @@
1267
1267
  };
1268
1268
 
1269
1269
  Parse._ajaxIE8 = function(method, url, data, success, error) {
1270
+ var promise = new Parse.Promise();
1270
1271
  var xdr = new XDomainRequest();
1271
1272
  xdr.onload = function() {
1272
1273
  var response;
@@ -1276,19 +1277,25 @@
1276
1277
  if (error) {
1277
1278
  error(xdr);
1278
1279
  }
1280
+ promise.reject(e);
1279
1281
  }
1280
1282
  if (response) {
1281
1283
  if (success) {
1282
1284
  success(response, xdr);
1283
1285
  }
1286
+ promise.resolve(response);
1284
1287
  }
1285
1288
  };
1286
1289
  xdr.onerror = xdr.ontimeout = function() {
1287
- error(xdr);
1290
+ if (error) {
1291
+ error(xdr);
1292
+ }
1293
+ promise.reject(xdr);
1288
1294
  };
1289
1295
  xdr.onprogress = function() {};
1290
1296
  xdr.open(method, url);
1291
1297
  xdr.send(data);
1298
+ return promise;
1292
1299
  };
1293
1300
 
1294
1301
  Parse._ajax = function(method, url, data, success, error) {
@@ -1296,6 +1303,7 @@
1296
1303
  return Parse._ajaxIE8(method, url, data, success, error);
1297
1304
  }
1298
1305
 
1306
+ var promise = new Parse.Promise();
1299
1307
  var handled = false;
1300
1308
 
1301
1309
  var xhr = new Parse.XMLHttpRequest();
@@ -1314,22 +1322,26 @@
1314
1322
  if (error) {
1315
1323
  error(xhr);
1316
1324
  }
1325
+ promise.reject(e);
1317
1326
  }
1318
1327
  if (response) {
1319
1328
  if (success) {
1320
- success(response, xhr);
1329
+ success(response, xhr.status, xhr);
1321
1330
  }
1331
+ promise.resolve(response, xhr.status, xhr);
1322
1332
  }
1323
1333
  } else {
1324
1334
  if (error) {
1325
1335
  error(xhr);
1326
1336
  }
1337
+ promise.reject(xhr);
1327
1338
  }
1328
1339
  }
1329
1340
  };
1330
1341
  xhr.open(method, url, true);
1331
1342
  xhr.setRequestHeader("Content-Type", "text/plain"); // avoid pre-flight.
1332
1343
  xhr.send(data);
1344
+ return promise;
1333
1345
  };
1334
1346
 
1335
1347
  // A self-propagating extend function.
@@ -1358,14 +1370,14 @@
1358
1370
  }
1359
1371
 
1360
1372
 
1361
- if (route !== "classes" &&
1362
- route !== "push" &&
1363
- route !== "users" &&
1364
- route !== "login" &&
1373
+ if (route !== "batch" &&
1374
+ route !== "classes" &&
1365
1375
  route !== "functions" &&
1366
- route !== "requestPasswordReset") {
1367
- throw "First argument must be one of classes, users, functions, or " +
1368
- "login, not '" + route + "'.";
1376
+ route !== "login" &&
1377
+ route !== "push" &&
1378
+ route !== "requestPasswordReset" &&
1379
+ route !== "users") {
1380
+ throw "Bad route: '" + route + "'.";
1369
1381
  }
1370
1382
 
1371
1383
  var url = Parse.serverURL;
@@ -1401,7 +1413,8 @@
1401
1413
  }
1402
1414
  var data = JSON.stringify(dataObject);
1403
1415
 
1404
- Parse._ajax(method, url, data, options.success, options.error);
1416
+ options = options || {};
1417
+ return Parse._ajax(method, url, data, options.success, options.error);
1405
1418
  };
1406
1419
 
1407
1420
  // Helper function to get a value from a Backbone object as a property
@@ -3157,7 +3170,7 @@
3157
3170
  * promise will succeed, with the result being an array with the results of
3158
3171
  * all the input promises.
3159
3172
  * @param {Array} promises a list of promises to wait for.
3160
- * @return {Parse.Promise} the new promise
3173
+ * @return {Parse.Promise} the new promise.
3161
3174
  */
3162
3175
  when: function(promises) {
3163
3176
  // Allow passing in Promises as separate arguments instead of an Array.
@@ -3209,6 +3222,22 @@
3209
3222
  });
3210
3223
 
3211
3224
  return promise;
3225
+ },
3226
+
3227
+ /**
3228
+ * Runs the given asyncFunction repeatedly, as long as the predicate
3229
+ * function returns a truthy value. Stops repeating if asyncFunction returns
3230
+ * a rejected promise.
3231
+ * @param {Function} predicate should return false when ready to stop.
3232
+ * @param {Function} asyncFunction should return a Promise.
3233
+ */
3234
+ _continueWhile: function(predicate, asyncFunction) {
3235
+ if (predicate()) {
3236
+ return asyncFunction().then(function() {
3237
+ return Parse.Promise._continueWhile(predicate, asyncFunction);
3238
+ });
3239
+ }
3240
+ return Parse.Promise.as();
3212
3241
  }
3213
3242
  });
3214
3243
 
@@ -3229,6 +3258,8 @@
3229
3258
  _.each(this._resolvedCallbacks, function(resolvedCallback) {
3230
3259
  resolvedCallback.apply(this, results);
3231
3260
  });
3261
+ this._resolvedCallbacks = [];
3262
+ this._rejectedCallbacks = [];
3232
3263
  },
3233
3264
 
3234
3265
  /**
@@ -3245,6 +3276,8 @@
3245
3276
  _.each(this._rejectedCallbacks, function(rejectedCallback) {
3246
3277
  rejectedCallback(error);
3247
3278
  });
3279
+ this._resolvedCallbacks = [];
3280
+ this._rejectedCallbacks = [];
3248
3281
  },
3249
3282
 
3250
3283
  /**
@@ -3315,7 +3348,66 @@
3315
3348
  }
3316
3349
 
3317
3350
  return promise;
3351
+ },
3352
+
3353
+ /**
3354
+ * Run the given callbacks after this promise is fulfilled.
3355
+ * @param optionsOrCallback {} A Backbone-style options callback, or a
3356
+ * callback function. If this is an options object and contains a "model"
3357
+ * attributes, that will be passed to error callbacks as the first argument.
3358
+ * @return {Parse.Promise} A promise that will be resolved after the
3359
+ * callbacks are run, with the same result as this.
3360
+ */
3361
+ _thenRunCallbacks: function(optionsOrCallback) {
3362
+ var options;
3363
+ if (_.isFunction(optionsOrCallback)) {
3364
+ var callback = optionsOrCallback;
3365
+ options = {
3366
+ success: function(result) {
3367
+ callback(result, null);
3368
+ },
3369
+ error: function(error) {
3370
+ callback(null, error);
3371
+ }
3372
+ };
3373
+ } else {
3374
+ options = _.clone(optionsOrCallback);
3375
+ }
3376
+ options = options || {};
3377
+
3378
+ return this.then(function(result) {
3379
+ if (options.success) {
3380
+ options.success(result);
3381
+ }
3382
+ return result;
3383
+ }, function(error) {
3384
+ if (options.error) {
3385
+ if (options.model) {
3386
+ options.error(options.model, error);
3387
+ } else {
3388
+ options.error(error);
3389
+ }
3390
+ }
3391
+ return Parse.Promise.error(error);
3392
+ });
3393
+ },
3394
+
3395
+ /**
3396
+ * Adds a callback function that should be called regardless of whether
3397
+ * this promise failed or succeeded. The callback will be given either the
3398
+ * array of results for its first argument, or the error as its second,
3399
+ * depending on whether this Promise was rejected or resolved. Returns a
3400
+ * new Promise, like "then" would.
3401
+ * @param {Function} continuation the callback.
3402
+ */
3403
+ _continueWith: function(continuation) {
3404
+ return this.then(function() {
3405
+ return continuation(arguments, null);
3406
+ }, function(error) {
3407
+ return continuation(null, error);
3408
+ });
3318
3409
  }
3410
+
3319
3411
  });
3320
3412
 
3321
3413
  }(this));
@@ -3399,52 +3491,6 @@
3399
3491
  * @property {String} id The objectId of the Parse Object.
3400
3492
  */
3401
3493
 
3402
- /**
3403
- * Internal function for saveAll. This calls func on every item in list,
3404
- * and adds the results to results. When it's done, optionsOrCallback is
3405
- * called with the accumulated results. See saveAll for more info.
3406
- *
3407
- * @param list - A list of Parse.Object.
3408
- * @param func - function(Parse.Object, callback);
3409
- * @param optionsOrCallback - See saveAll.
3410
- */
3411
- var _doAll = function(list, func, optionsOrCallback) {
3412
- var options;
3413
- if (_.isFunction(optionsOrCallback)) {
3414
- var callback = optionsOrCallback;
3415
- options = {
3416
- success: function(list) { callback(list, null); },
3417
- error: function(e) { callback(null, e); }
3418
- };
3419
- } else {
3420
- options = optionsOrCallback;
3421
- }
3422
- options = options || {};
3423
-
3424
- var results = [];
3425
- var promise = new Parse.Promise.as();
3426
- _.each(list, function(item) {
3427
- promise = promise.then(function() {
3428
- return func(item);
3429
- }).then(function(result) {
3430
- results.push(result);
3431
- });
3432
- });
3433
-
3434
- promise = promise.then(function() {
3435
- if (options.success) {
3436
- options.success(results);
3437
- }
3438
- }, function(error) {
3439
- if (options.error) {
3440
- options.error(error);
3441
- }
3442
- return Parse.Promise.error(error);
3443
- });
3444
-
3445
- return promise;
3446
- };
3447
-
3448
3494
  /**
3449
3495
  * Saves the given list of Parse.Object.
3450
3496
  * If any error is encountered, stops and calls the error handler.
@@ -3471,18 +3517,10 @@
3471
3517
  * </pre>
3472
3518
  *
3473
3519
  * @param {Array} list A list of <code>Parse.Object</code>.
3474
- * @param {Object} optionsOrCallback A Backbone-style callback object.
3520
+ * @param {Object} options A Backbone-style callback object.
3475
3521
  */
3476
- Parse.Object.saveAll = function(list, optionsOrCallback) {
3477
- return _doAll(list, function(obj, options) {
3478
- return obj.save(null, options);
3479
- }, optionsOrCallback);
3480
- };
3481
-
3482
- Parse.Object._signUpAll = function(list, optionsOrCallback) {
3483
- return _doAll(list, function(obj, options) {
3484
- return obj.signUp(null, options);
3485
- }, optionsOrCallback);
3522
+ Parse.Object.saveAll = function(list, options) {
3523
+ return Parse.Object._deepSaveAsync(list)._thenRunCallbacks(options);
3486
3524
  };
3487
3525
 
3488
3526
  // Attach all inheritable methods to the Parse.Object prototype.
@@ -3676,20 +3714,6 @@
3676
3714
  this._opSetQueue.push({});
3677
3715
  },
3678
3716
 
3679
- /**
3680
- * If any save has been started since the current one running, process the
3681
- * next one in the queue.
3682
- */
3683
- _processSaveQueue: function() {
3684
- if (this._saveQueue && this._saveQueue.length > 0) {
3685
- var nextSave = _.first(this._saveQueue);
3686
- this._saveQueue = _.rest(this._saveQueue);
3687
- nextSave();
3688
- } else {
3689
- this._saving = false;
3690
- }
3691
- },
3692
-
3693
3717
  /**
3694
3718
  * Called when a save fails because of an error. Any changes that were part
3695
3719
  * of the save need to be merged with changes made after the save. This
@@ -3716,7 +3740,7 @@
3716
3740
  nextChanges[key] = op1;
3717
3741
  }
3718
3742
  });
3719
- this._processSaveQueue();
3743
+ this._saving = this._saving - 1;
3720
3744
  },
3721
3745
 
3722
3746
  /**
@@ -3734,7 +3758,7 @@
3734
3758
  self._serverData[key] = Parse._decode(key, value);
3735
3759
  });
3736
3760
  this._rebuildAllEstimatedData();
3737
- this._processSaveQueue();
3761
+ this._saving = this._saving - 1;
3738
3762
  },
3739
3763
 
3740
3764
  /**
@@ -4078,6 +4102,13 @@
4078
4102
  return json;
4079
4103
  },
4080
4104
 
4105
+ /**
4106
+ * Returns true if this object can be serialized for saving.
4107
+ */
4108
+ _canBeSerialized: function() {
4109
+ return Parse.Object._canBeSerializedAsValue(this.attributes);
4110
+ },
4111
+
4081
4112
  /**
4082
4113
  * Fetch the model from the server. If the server's representation of the
4083
4114
  * model differs from its current attributes, they will be overriden,
@@ -4200,9 +4231,12 @@
4200
4231
 
4201
4232
  // If there is any unsaved child, save it first.
4202
4233
  model._refreshCache();
4234
+
4235
+
4236
+
4203
4237
  var unsavedChildren = Parse.Object._findUnsavedChildren(model.attributes);
4204
4238
  if (unsavedChildren.length > 0) {
4205
- return Parse.Object.saveAll(unsavedChildren).then(function() {
4239
+ return Parse.Object._deepSaveAsync(this.attributes).then(function() {
4206
4240
  return model.save(null, oldOptions);
4207
4241
  }, function(error) {
4208
4242
  if (options.error) {
@@ -4243,8 +4277,10 @@
4243
4277
  newOptions);
4244
4278
 
4245
4279
  this._startSave();
4280
+ this._saving = (this._saving || 0) + 1;
4246
4281
 
4247
- var doSave = function() {
4282
+ this._allPreviousSaves = this._allPreviousSaves || Parse.Promise.as();
4283
+ this._allPreviousSaves._continueWith(function() {
4248
4284
  var method = model.id ? 'PUT' : 'POST';
4249
4285
 
4250
4286
  var json = model._getSaveJSON();
@@ -4256,19 +4292,15 @@
4256
4292
  route = "users";
4257
4293
  className = null;
4258
4294
  }
4259
- Parse._request(route, className, model.id, method, json, newOptions);
4295
+ var request =
4296
+ Parse._request(route, className, model.id, method, json, newOptions);
4260
4297
  if (newOptions.wait) {
4261
4298
  model.set(current, setOptions);
4262
4299
  }
4263
- };
4300
+ return request;
4264
4301
 
4265
- if (this._saving) {
4266
- this._saveQueue = this._saveQueue || [];
4267
- this._saveQueue.push(doSave);
4268
- } else {
4269
- this._saving = true;
4270
- doSave();
4271
- }
4302
+ });
4303
+ this._allPreviousSaves = promise;
4272
4304
 
4273
4305
  return promise;
4274
4306
  },
@@ -4333,7 +4365,7 @@
4333
4365
  output.updatedAt = output.createdAt;
4334
4366
  }
4335
4367
  if (status) {
4336
- this._existed = (status.status !== 201);
4368
+ this._existed = (status !== 201);
4337
4369
  }
4338
4370
  return output;
4339
4371
  },
@@ -4689,6 +4721,125 @@
4689
4721
  return results;
4690
4722
  };
4691
4723
 
4724
+ Parse.Object._canBeSerializedAsValue = function(object) {
4725
+ var canBeSerializedAsValue = true;
4726
+
4727
+ if (object instanceof Parse.Object) {
4728
+ canBeSerializedAsValue = !!object.id;
4729
+
4730
+ } else if (_.isArray(object)) {
4731
+ _.each(object, function(child) {
4732
+ if (!Parse.Object._canBeSerializedAsValue(child)) {
4733
+ canBeSerializedAsValue = false;
4734
+ }
4735
+ });
4736
+
4737
+ } else if (_.isObject(object)) {
4738
+ Parse._each(object, function(child) {
4739
+ if (!Parse.Object._canBeSerializedAsValue(child)) {
4740
+ canBeSerializedAsValue = false;
4741
+ }
4742
+ });
4743
+ }
4744
+
4745
+ return canBeSerializedAsValue;
4746
+ };
4747
+
4748
+ Parse.Object._deepSaveAsync = function(object) {
4749
+ var objects = _.uniq(Parse.Object._findUnsavedChildren(object));
4750
+ var remaining = _.uniq(objects);
4751
+
4752
+ return Parse.Promise._continueWhile(function() {
4753
+ return remaining.length > 0;
4754
+ }, function() {
4755
+
4756
+ // Gather up all the objects that can be saved in this batch.
4757
+ var batch = [];
4758
+ var newRemaining = [];
4759
+ _.each(remaining, function(object) {
4760
+ // Limit batches to 20 objects.
4761
+ if (batch.length > 20) {
4762
+ newRemaining.push(object);
4763
+ return;
4764
+ }
4765
+
4766
+ if (object._canBeSerialized()) {
4767
+ batch.push(object);
4768
+ } else {
4769
+ newRemaining.push(object);
4770
+ }
4771
+ });
4772
+ remaining = newRemaining;
4773
+
4774
+ // If we can't save any objects, there must be a circular reference.
4775
+ if (batch.length === 0) {
4776
+ return Parse.Promise.error(
4777
+ new Parse.Error(Parse.Error.OTHER_CAUSE,
4778
+ "Tried to save a batch with a cycle."));
4779
+ }
4780
+
4781
+ // Reserve a spot in every object's save queue.
4782
+ var readyToStart = Parse.Promise.when(_.map(batch, function(object) {
4783
+ return object._allPreviousSaves || Parse.Promise.as();
4784
+ }));
4785
+ var batchFinished = new Parse.Promise();
4786
+ _.each(batch, function(object) {
4787
+ object._allPreviousSaves = batchFinished;
4788
+ });
4789
+
4790
+ // Save a single batch, whether previous saves succeeded or failed.
4791
+ return readyToStart._continueWith(function() {
4792
+ return Parse._request("batch", null, null, "POST", {
4793
+ requests: _.map(batch, function(object) {
4794
+ var json = object._getSaveJSON();
4795
+ var method = "POST";
4796
+
4797
+ var path = "/1/classes/" + object.className;
4798
+ if (object.id) {
4799
+ path = path + "/" + object.id;
4800
+ method = "PUT";
4801
+ }
4802
+
4803
+ object._startSave();
4804
+
4805
+ return {
4806
+ method: method,
4807
+ path: path,
4808
+ body: json
4809
+ };
4810
+ })
4811
+
4812
+ }).then(function(response, status, xhr) {
4813
+ var error;
4814
+ _.each(batch, function(object, i) {
4815
+ if (response[i].success) {
4816
+ object._finishSave(
4817
+ object.parse(response[i].success, status, xhr));
4818
+ } else {
4819
+ error = error || response[i].error;
4820
+ object._cancelSave();
4821
+ }
4822
+ });
4823
+ if (error) {
4824
+ return Parse.Promise.error(
4825
+ new Parse.Error(error.code, error.error));
4826
+ }
4827
+
4828
+ }).then(function(results) {
4829
+ batchFinished.resolve(results);
4830
+ return results;
4831
+ }, function(error) {
4832
+ batchFinished.reject(error);
4833
+ return Parse.Promise.error(error);
4834
+
4835
+ });
4836
+ });
4837
+ }).then(function() {
4838
+ return object;
4839
+
4840
+ });
4841
+ };
4842
+
4692
4843
  }(this));
4693
4844
 
4694
4845
  (function(root) {
@@ -6453,6 +6604,18 @@
6453
6604
  return this;
6454
6605
  },
6455
6606
 
6607
+ /**
6608
+ * Add a constraint to the query that requires a particular key's value to
6609
+ * contain each one of the provided list of values.
6610
+ * @param {String} key The key to check. This key's value must be an array.
6611
+ * @param {Array} values The values that will match.
6612
+ * @return {Parse.Query} Returns the query, so you can chain this call.
6613
+ */
6614
+ containsAll: function(key, values) {
6615
+ this._addCondition(key, "$all", values);
6616
+ return this;
6617
+ },
6618
+
6456
6619
 
6457
6620
  /**
6458
6621
  * Add a constraint for finding objects that contain the given key.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parsejs-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0.1
4
+ version: 1.2.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-09 00:00:00.000000000 Z
12
+ date: 2013-02-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
@@ -54,7 +54,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
54
54
  version: '0'
55
55
  segments:
56
56
  - 0
57
- hash: -2498638719657893255
57
+ hash: -832789119919337928
58
58
  required_rubygems_version: !ruby/object:Gem::Requirement
59
59
  none: false
60
60
  requirements:
@@ -63,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
63
  version: '0'
64
64
  segments:
65
65
  - 0
66
- hash: -2498638719657893255
66
+ hash: -832789119919337928
67
67
  requirements: []
68
68
  rubyforge_project:
69
69
  rubygems_version: 1.8.25