BVB Source Codes

parse-server Show ParseQuery.spec.js Source code

Return Download parse-server: download ParseQuery.spec.js Source code - Download parse-server Source code - Type:.js
  1. // This is a port of the test suite:
  2. // hungry/js/test/parse_query_test.js
  3. //
  4. // Some new tests are added.
  5. 'use strict';
  6.  
  7. const Parse = require('parse/node');
  8.  
  9. describe('Parse.Query testing', () => {
  10.   it("basic query", function(done) {
  11.     var baz = new TestObject({ foo: 'baz' });
  12.     var qux = new TestObject({ foo: 'qux' });
  13.     Parse.Object.saveAll([baz, qux], function() {
  14.       var query = new Parse.Query(TestObject);
  15.       query.equalTo('foo', 'baz');
  16.       query.find({
  17.         success: function(results) {
  18.           equal(results.length, 1);
  19.           equal(results[0].get('foo'), 'baz');
  20.           done();
  21.         }
  22.       });
  23.     });
  24.   });
  25.  
  26.   it("notEqualTo with Relation is working", function(done) {
  27.     var user = new Parse.User();
  28.     user.setPassword("asdf");
  29.     user.setUsername("zxcv");
  30.  
  31.     var user1 = new Parse.User();
  32.     user1.setPassword("asdf");
  33.     user1.setUsername("qwerty");
  34.  
  35.     var user2 = new Parse.User();
  36.     user2.setPassword("asdf");
  37.     user2.setUsername("asdf");
  38.  
  39.     var Cake = Parse.Object.extend("Cake");
  40.     var cake1 = new Cake();
  41.     var cake2 = new Cake();
  42.     var cake3 = new Cake();
  43.  
  44.  
  45.     user.signUp().then(function(){
  46.       return user1.signUp();
  47.     }).then(function(){
  48.       return user2.signUp();
  49.     }).then(function(){
  50.       var relLike1 = cake1.relation("liker");
  51.       relLike1.add([user, user1]);
  52.  
  53.       var relDislike1 = cake1.relation("hater");
  54.       relDislike1.add(user2);
  55.       return cake1.save();
  56.     }).then(function(){
  57.       var rellike2 = cake2.relation("liker");
  58.       rellike2.add([user, user1]);
  59.  
  60.       var relDislike2 = cake2.relation("hater");
  61.       relDislike2.add(user2);
  62.  
  63.       return cake2.save();
  64.     }).then(function(){
  65.       var rellike3 = cake3.relation("liker");
  66.       rellike3.add(user);
  67.  
  68.       var relDislike3 = cake3.relation("hater");
  69.       relDislike3.add([user1, user2]);
  70.       return cake3.save();
  71.     }).then(function(){
  72.       var query = new Parse.Query(Cake);
  73.       // User2 likes nothing so we should receive 0
  74.       query.equalTo("liker", user2);
  75.       return query.find().then(function(results){
  76.         equal(results.length, 0);
  77.       });
  78.     }).then(function(){
  79.       var query = new Parse.Query(Cake);
  80.       // User1 likes two of three cakes
  81.       query.equalTo("liker", user1);
  82.       return query.find().then(function(results){
  83.         // It should return 2 -> cake 1 and cake 2
  84.         equal(results.length, 2);
  85.       });
  86.     }).then(function(){
  87.       var query = new Parse.Query(Cake);
  88.       // We want to know which cake the user1 is not appreciating -> cake3
  89.       query.notEqualTo("liker", user1);
  90.       return query.find().then(function(results){
  91.         // Should return 1 -> the cake 3
  92.         equal(results.length, 1);
  93.       });
  94.     }).then(function(){
  95.       var query = new Parse.Query(Cake);
  96.       // User2 is a hater of everything so we should receive 0
  97.       query.notEqualTo("hater", user2);
  98.       return query.find().then(function(results){
  99.         equal(results.length, 0);
  100.       });
  101.     }).then(function(){
  102.       var query = new Parse.Query(Cake);
  103.       // Only cake3 is liked by user
  104.       query.notContainedIn("liker", [user1]);
  105.       return query.find().then(function(results){
  106.         equal(results.length, 1);
  107.       });
  108.     }).then(function(){
  109.       var query = new Parse.Query(Cake);
  110.       // All the users
  111.       query.containedIn("liker", [user, user1, user2]);
  112.       // Exclude user 1
  113.       query.notEqualTo("liker", user1);
  114.       // Only cake3 is liked only by user1
  115.       return query.find().then(function(results){
  116.         equal(results.length, 1);
  117.         const cake = results[0];
  118.         expect(cake.id).toBe(cake3.id);
  119.       });
  120.     }).then(function(){
  121.       var query = new Parse.Query(Cake);
  122.       // Exclude user1
  123.       query.notEqualTo("liker", user1);
  124.       // Only cake1
  125.       query.equalTo("objectId", cake1.id)
  126.       // user1 likes cake1 so this should return no results
  127.       return query.find().then(function(results){
  128.         equal(results.length, 0);
  129.       });
  130.     }).then(function(){
  131.       var query = new Parse.Query(Cake);
  132.       query.notEqualTo("hater", user2);
  133.       query.notEqualTo("liker", user2);
  134.       // user2 doesn't like any cake so this should be 0
  135.       return query.find().then(function(results){
  136.         equal(results.length, 0);
  137.       });
  138.     }).then(function(){
  139.       var query = new Parse.Query(Cake);
  140.       query.equalTo("hater", user);
  141.       query.equalTo("liker", user);
  142.       // user doesn't hate any cake so this should be 0
  143.       return query.find().then(function(results){
  144.         equal(results.length, 0);
  145.       });
  146.     }).then(function(){
  147.       done();
  148.     }).catch((err) => {
  149.       jfail(err);
  150.       done();
  151.     })
  152.   });
  153.  
  154.   it("query with limit", function(done) {
  155.     var baz = new TestObject({ foo: 'baz' });
  156.     var qux = new TestObject({ foo: 'qux' });
  157.     Parse.Object.saveAll([baz, qux], function() {
  158.       var query = new Parse.Query(TestObject);
  159.       query.limit(1);
  160.       query.find({
  161.         success: function(results) {
  162.           equal(results.length, 1);
  163.           done();
  164.         }
  165.       });
  166.     });
  167.   });
  168.  
  169.   it("containedIn object array queries", function(done) {
  170.     var messageList = [];
  171.     for (var i = 0; i < 4; ++i) {
  172.       var message = new TestObject({});
  173.       if (i > 0) {
  174.         message.set('prior', messageList[i - 1]);
  175.       }
  176.       messageList.push(message);
  177.     }
  178.  
  179.     Parse.Object.saveAll(messageList, function() {
  180.       equal(messageList.length, 4);
  181.  
  182.       var inList = [];
  183.       inList.push(messageList[0]);
  184.       inList.push(messageList[2]);
  185.  
  186.       var query = new Parse.Query(TestObject);
  187.       query.containedIn('prior', inList);
  188.       query.find({
  189.         success: function(results) {
  190.           equal(results.length, 2);
  191.           done();
  192.         },
  193.         error: function(e) {
  194.           jfail(e);
  195.           done();
  196.         }
  197.       });
  198.     }, (e) => {
  199.       jfail(e);
  200.       done();
  201.     });
  202.   });
  203.  
  204.   it("containsAll number array queries", function(done) {
  205.     var NumberSet = Parse.Object.extend({ className: "NumberSet" });
  206.  
  207.     var objectsList = [];
  208.     objectsList.push(new NumberSet({ "numbers" : [1, 2, 3, 4, 5] }));
  209.     objectsList.push(new NumberSet({ "numbers" : [1, 3, 4, 5] }));
  210.  
  211.     Parse.Object.saveAll(objectsList, function() {
  212.       var query = new Parse.Query(NumberSet);
  213.       query.containsAll("numbers", [1, 2, 3]);
  214.       query.find({
  215.         success: function(results) {
  216.           equal(results.length, 1);
  217.           done();
  218.         },
  219.         error: function(err) {
  220.           jfail(err);
  221.           done();
  222.         },
  223.       });
  224.     }).catch((err) => {
  225.       jfail(err);
  226.       done();
  227.     });
  228.   });
  229.  
  230.   it("containsAll string array queries", function(done) {
  231.     var StringSet = Parse.Object.extend({ className: "StringSet" });
  232.  
  233.     var objectsList = [];
  234.     objectsList.push(new StringSet({ "strings" : ["a", "b", "c", "d", "e"] }));
  235.     objectsList.push(new StringSet({ "strings" : ["a", "c", "d", "e"] }));
  236.  
  237.     Parse.Object.saveAll(objectsList, function() {
  238.       var query = new Parse.Query(StringSet);
  239.       query.containsAll("strings", ["a", "b", "c"]);
  240.       query.find({
  241.         success: function(results) {
  242.           equal(results.length, 1);
  243.           done();
  244.         }
  245.       });
  246.     }).catch((err) => {
  247.       jfail(err);
  248.       done();
  249.     });
  250.   });
  251.  
  252.   it("containsAll date array queries", function(done) {
  253.     var DateSet = Parse.Object.extend({ className: "DateSet" });
  254.  
  255.     function parseDate(iso8601) {
  256.       var regexp = new RegExp(
  257.         '^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})' + 'T' +
  258.           '([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})' +
  259.           '(.([0-9]+))?' + 'Z$');
  260.       var match = regexp.exec(iso8601);
  261.       if (!match) {
  262.         return null;
  263.       }
  264.  
  265.       var year = match[1] || 0;
  266.       var month = (match[2] || 1) - 1;
  267.       var day = match[3] || 0;
  268.       var hour = match[4] || 0;
  269.       var minute = match[5] || 0;
  270.       var second = match[6] || 0;
  271.       var milli = match[8] || 0;
  272.  
  273.       return new Date(Date.UTC(year, month, day, hour, minute, second, milli));
  274.     }
  275.  
  276.     var makeDates = function(stringArray) {
  277.       return stringArray.map(function(dateStr) {
  278.         return parseDate(dateStr + "T00:00:00Z");
  279.       });
  280.     };
  281.  
  282.     var objectsList = [];
  283.     objectsList.push(new DateSet({
  284.       "dates" : makeDates(["2013-02-01", "2013-02-02", "2013-02-03",
  285.         "2013-02-04"])
  286.     }));
  287.     objectsList.push(new DateSet({
  288.       "dates" : makeDates(["2013-02-01", "2013-02-03", "2013-02-04"])
  289.     }));
  290.  
  291.     Parse.Object.saveAll(objectsList, function() {
  292.       var query = new Parse.Query(DateSet);
  293.       query.containsAll("dates", makeDates(
  294.         ["2013-02-01", "2013-02-02", "2013-02-03"]));
  295.       query.find({
  296.         success: function(results) {
  297.           equal(results.length, 1);
  298.           done();
  299.         },
  300.         error: function(e) {
  301.           jfail(e);
  302.           done();
  303.         },
  304.       });
  305.     });
  306.   });
  307.  
  308.   it("containsAll object array queries", function(done) {
  309.  
  310.     var MessageSet = Parse.Object.extend({ className: "MessageSet" });
  311.  
  312.     var messageList = [];
  313.     for (var i = 0; i < 4; ++i) {
  314.       messageList.push(new TestObject({ 'i' : i }));
  315.     }
  316.  
  317.     Parse.Object.saveAll(messageList, function() {
  318.       equal(messageList.length, 4);
  319.  
  320.       var messageSetList = [];
  321.       messageSetList.push(new MessageSet({ 'messages' : messageList }));
  322.  
  323.       var someList = [];
  324.       someList.push(messageList[0]);
  325.       someList.push(messageList[1]);
  326.       someList.push(messageList[3]);
  327.       messageSetList.push(new MessageSet({ 'messages' : someList }));
  328.  
  329.       Parse.Object.saveAll(messageSetList, function() {
  330.         var inList = [];
  331.         inList.push(messageList[0]);
  332.         inList.push(messageList[2]);
  333.  
  334.         var query = new Parse.Query(MessageSet);
  335.         query.containsAll('messages', inList);
  336.         query.find({
  337.           success: function(results) {
  338.             equal(results.length, 1);
  339.             done();
  340.           }
  341.         });
  342.       });
  343.     });
  344.   });
  345.  
  346.   var BoxedNumber = Parse.Object.extend({
  347.     className: "BoxedNumber"
  348.   });
  349.  
  350.   it("equalTo queries", function(done) {
  351.     var makeBoxedNumber = function(i) {
  352.       return new BoxedNumber({ number: i });
  353.     };
  354.     Parse.Object.saveAll([0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  355.                          function() {
  356.                            var query = new Parse.Query(BoxedNumber);
  357.                            query.equalTo('number', 3);
  358.                            query.find({
  359.                              success: function(results) {
  360.                                equal(results.length, 1);
  361.                                done();
  362.                              }
  363.                            });
  364.                          });
  365.   });
  366.  
  367.   it("equalTo undefined", function(done) {
  368.     var makeBoxedNumber = function(i) {
  369.       return new BoxedNumber({ number: i });
  370.     };
  371.     Parse.Object.saveAll([0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  372.                          function() {
  373.                            var query = new Parse.Query(BoxedNumber);
  374.                            query.equalTo('number', undefined);
  375.                            query.find(expectSuccess({
  376.                              success: function(results) {
  377.                                equal(results.length, 0);
  378.                                done();
  379.                              }
  380.                            }));
  381.                          });
  382.   });
  383.  
  384.   it("lessThan queries", function(done) {
  385.     var makeBoxedNumber = function(i) {
  386.       return new BoxedNumber({ number: i });
  387.     };
  388.     Parse.Object.saveAll([0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  389.                          function() {
  390.                            var query = new Parse.Query(BoxedNumber);
  391.                            query.lessThan('number', 7);
  392.                            query.find({
  393.                              success: function(results) {
  394.                                equal(results.length, 7);
  395.                                done();
  396.                              }
  397.                            });
  398.                          });
  399.   });
  400.  
  401.   it("lessThanOrEqualTo queries", function(done) {
  402.     var makeBoxedNumber = function(i) {
  403.       return new BoxedNumber({ number: i });
  404.     };
  405.     Parse.Object.saveAll(
  406.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  407.       function() {
  408.         var query = new Parse.Query(BoxedNumber);
  409.         query.lessThanOrEqualTo('number', 7);
  410.         query.find({
  411.           success: function(results) {
  412.             equal(results.length, 8);
  413.             done();
  414.           }
  415.         });
  416.       });
  417.   });
  418.  
  419.   it("greaterThan queries", function(done) {
  420.     var makeBoxedNumber = function(i) {
  421.       return new BoxedNumber({ number: i });
  422.     };
  423.     Parse.Object.saveAll(
  424.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  425.       function() {
  426.         var query = new Parse.Query(BoxedNumber);
  427.         query.greaterThan('number', 7);
  428.         query.find({
  429.           success: function(results) {
  430.             equal(results.length, 2);
  431.             done();
  432.           }
  433.         });
  434.       });
  435.   });
  436.  
  437.   it("greaterThanOrEqualTo queries", function(done) {
  438.     var makeBoxedNumber = function(i) {
  439.       return new BoxedNumber({ number: i });
  440.     };
  441.     Parse.Object.saveAll(
  442.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  443.       function() {
  444.         var query = new Parse.Query(BoxedNumber);
  445.         query.greaterThanOrEqualTo('number', 7);
  446.         query.find({
  447.           success: function(results) {
  448.             equal(results.length, 3);
  449.             done();
  450.           }
  451.         });
  452.       });
  453.   });
  454.  
  455.   it("lessThanOrEqualTo greaterThanOrEqualTo queries", function(done) {
  456.     var makeBoxedNumber = function(i) {
  457.       return new BoxedNumber({ number: i });
  458.     };
  459.     Parse.Object.saveAll(
  460.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  461.       function() {
  462.         var query = new Parse.Query(BoxedNumber);
  463.         query.lessThanOrEqualTo('number', 7);
  464.         query.greaterThanOrEqualTo('number', 7);
  465.         query.find({
  466.           success: function(results) {
  467.             equal(results.length, 1);
  468.             done();
  469.           }
  470.         });
  471.       });
  472.   });
  473.  
  474.   it("lessThan greaterThan queries", function(done) {
  475.     var makeBoxedNumber = function(i) {
  476.       return new BoxedNumber({ number: i });
  477.     };
  478.     Parse.Object.saveAll(
  479.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  480.       function() {
  481.         var query = new Parse.Query(BoxedNumber);
  482.         query.lessThan('number', 9);
  483.         query.greaterThan('number', 3);
  484.         query.find({
  485.           success: function(results) {
  486.             equal(results.length, 5);
  487.             done();
  488.           }
  489.         });
  490.       });
  491.   });
  492.  
  493.   it("notEqualTo queries", function(done) {
  494.     var makeBoxedNumber = function(i) {
  495.       return new BoxedNumber({ number: i });
  496.     };
  497.     Parse.Object.saveAll(
  498.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  499.       function() {
  500.         var query = new Parse.Query(BoxedNumber);
  501.         query.notEqualTo('number', 5);
  502.         query.find({
  503.           success: function(results) {
  504.             equal(results.length, 9);
  505.             done();
  506.           }
  507.         });
  508.       });
  509.   });
  510.  
  511.   it("containedIn queries", function(done) {
  512.     var makeBoxedNumber = function(i) {
  513.       return new BoxedNumber({ number: i });
  514.     };
  515.     Parse.Object.saveAll(
  516.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  517.       function() {
  518.         var query = new Parse.Query(BoxedNumber);
  519.         query.containedIn('number', [3,5,7,9,11]);
  520.         query.find({
  521.           success: function(results) {
  522.             equal(results.length, 4);
  523.             done();
  524.           }
  525.         });
  526.       });
  527.   });
  528.  
  529.   it("notContainedIn queries", function(done) {
  530.     var makeBoxedNumber = function(i) {
  531.       return new BoxedNumber({ number: i });
  532.     };
  533.     Parse.Object.saveAll(
  534.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  535.       function() {
  536.         var query = new Parse.Query(BoxedNumber);
  537.         query.notContainedIn('number', [3,5,7,9,11]);
  538.         query.find({
  539.           success: function(results) {
  540.             equal(results.length, 6);
  541.             done();
  542.           }
  543.         });
  544.       });
  545.   });
  546.  
  547.  
  548.   it("objectId containedIn queries", function(done) {
  549.     var makeBoxedNumber = function(i) {
  550.       return new BoxedNumber({ number: i });
  551.     };
  552.     Parse.Object.saveAll(
  553.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  554.       function(list) {
  555.         var query = new Parse.Query(BoxedNumber);
  556.         query.containedIn('objectId',
  557.           [list[2].id, list[3].id, list[0].id,
  558.             "NONSENSE"]);
  559.         query.ascending('number');
  560.         query.find({
  561.           success: function(results) {
  562.             if (results.length != 3) {
  563.               fail('expected 3 results');
  564.             } else {
  565.               equal(results[0].get('number'), 0);
  566.               equal(results[1].get('number'), 2);
  567.               equal(results[2].get('number'), 3);
  568.             }
  569.             done();
  570.           }
  571.         });
  572.       });
  573.   });
  574.  
  575.   it("objectId equalTo queries", function(done) {
  576.     var makeBoxedNumber = function(i) {
  577.       return new BoxedNumber({ number: i });
  578.     };
  579.     Parse.Object.saveAll(
  580.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  581.       function(list) {
  582.         var query = new Parse.Query(BoxedNumber);
  583.         query.equalTo('objectId', list[4].id);
  584.         query.find({
  585.           success: function(results) {
  586.             if (results.length != 1) {
  587.               fail('expected 1 result')
  588.               done();
  589.             } else {
  590.               equal(results[0].get('number'), 4);
  591.             }
  592.             done();
  593.           }
  594.         });
  595.       });
  596.   });
  597.  
  598.   it("find no elements", function(done) {
  599.     var makeBoxedNumber = function(i) {
  600.       return new BoxedNumber({ number: i });
  601.     };
  602.     Parse.Object.saveAll(
  603.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  604.       function() {
  605.         var query = new Parse.Query(BoxedNumber);
  606.         query.equalTo('number', 17);
  607.         query.find(expectSuccess({
  608.           success: function(results) {
  609.             equal(results.length, 0);
  610.             done();
  611.           }
  612.         }));
  613.       });
  614.   });
  615.  
  616.   it("find with error", function(done) {
  617.     var query = new Parse.Query(BoxedNumber);
  618.     query.equalTo('$foo', 'bar');
  619.     query.find(expectError(Parse.Error.INVALID_KEY_NAME, done));
  620.   });
  621.  
  622.   it("get", function(done) {
  623.     Parse.Object.saveAll([new TestObject({foo: 'bar'})], function(items) {
  624.       ok(items[0]);
  625.       var objectId = items[0].id;
  626.       var query = new Parse.Query(TestObject);
  627.       query.get(objectId, {
  628.         success: function(result) {
  629.           ok(result);
  630.           equal(result.id, objectId);
  631.           equal(result.get('foo'), 'bar');
  632.           ok(result.createdAt instanceof Date);
  633.           ok(result.updatedAt instanceof Date);
  634.           done();
  635.         }
  636.       });
  637.     });
  638.   });
  639.  
  640.   it("get undefined", function(done) {
  641.     Parse.Object.saveAll([new TestObject({foo: 'bar'})], function(items) {
  642.       ok(items[0]);
  643.       var query = new Parse.Query(TestObject);
  644.       query.get(undefined, {
  645.         success: fail,
  646.         error: done,
  647.       });
  648.     });
  649.   });
  650.  
  651.   it("get error", function(done) {
  652.     Parse.Object.saveAll([new TestObject({foo: 'bar'})], function(items) {
  653.       ok(items[0]);
  654.       var query = new Parse.Query(TestObject);
  655.       query.get("InvalidObjectID", {
  656.         success: function() {
  657.           ok(false, "The get should have failed.");
  658.           done();
  659.         },
  660.         error: function(object, error) {
  661.           equal(error.code, Parse.Error.OBJECT_NOT_FOUND);
  662.           done();
  663.         }
  664.       });
  665.     });
  666.   });
  667.  
  668.   it("first", function(done) {
  669.     Parse.Object.saveAll([new TestObject({foo: 'bar'})], function() {
  670.       var query = new Parse.Query(TestObject);
  671.       query.equalTo('foo', 'bar');
  672.       query.first({
  673.         success: function(result) {
  674.           equal(result.get('foo'), 'bar');
  675.           done();
  676.         }
  677.       });
  678.     });
  679.   });
  680.  
  681.   it("first no result", function(done) {
  682.     Parse.Object.saveAll([new TestObject({foo: 'bar'})], function() {
  683.       var query = new Parse.Query(TestObject);
  684.       query.equalTo('foo', 'baz');
  685.       query.first({
  686.         success: function(result) {
  687.           equal(result, undefined);
  688.           done();
  689.         }
  690.       });
  691.     });
  692.   });
  693.  
  694.   it("first with two results", function(done) {
  695.     Parse.Object.saveAll([new TestObject({foo: 'bar'}),
  696.       new TestObject({foo: 'bar'})], function() {
  697.       var query = new Parse.Query(TestObject);
  698.       query.equalTo('foo', 'bar');
  699.       query.first({
  700.         success: function(result) {
  701.           equal(result.get('foo'), 'bar');
  702.           done();
  703.         }
  704.       });
  705.     });
  706.   });
  707.  
  708.   it("first with error", function(done) {
  709.     var query = new Parse.Query(BoxedNumber);
  710.     query.equalTo('$foo', 'bar');
  711.     query.first(expectError(Parse.Error.INVALID_KEY_NAME, done));
  712.   });
  713.  
  714.   var Container = Parse.Object.extend({
  715.     className: "Container"
  716.   });
  717.  
  718.   it("notEqualTo object", function(done) {
  719.     var item1 = new TestObject();
  720.     var item2 = new TestObject();
  721.     var container1 = new Container({item: item1});
  722.     var container2 = new Container({item: item2});
  723.     Parse.Object.saveAll([item1, item2, container1, container2], function() {
  724.       var query = new Parse.Query(Container);
  725.       query.notEqualTo('item', item1);
  726.       query.find({
  727.         success: function(results) {
  728.           equal(results.length, 1);
  729.           done();
  730.         }
  731.       });
  732.     });
  733.   });
  734.  
  735.   it("skip", function(done) {
  736.     Parse.Object.saveAll([new TestObject(), new TestObject()], function() {
  737.       var query = new Parse.Query(TestObject);
  738.       query.skip(1);
  739.       query.find({
  740.         success: function(results) {
  741.           equal(results.length, 1);
  742.           query.skip(3);
  743.           query.find({
  744.             success: function(results) {
  745.               equal(results.length, 0);
  746.               done();
  747.             }
  748.           });
  749.         }
  750.       });
  751.     });
  752.   });
  753.  
  754.   it("skip doesn't affect count", function(done) {
  755.     Parse.Object.saveAll([new TestObject(), new TestObject()], function() {
  756.       var query = new Parse.Query(TestObject);
  757.       query.count({
  758.         success: function(count) {
  759.           equal(count, 2);
  760.           query.skip(1);
  761.           query.count({
  762.             success: function(count) {
  763.               equal(count, 2);
  764.               query.skip(3);
  765.               query.count({
  766.                 success: function(count) {
  767.                   equal(count, 2);
  768.                   done();
  769.                 }
  770.               });
  771.             }
  772.           });
  773.         }
  774.       });
  775.     });
  776.   });
  777.  
  778.   it("count", function(done) {
  779.     var makeBoxedNumber = function(i) {
  780.       return new BoxedNumber({ number: i });
  781.     };
  782.     Parse.Object.saveAll(
  783.       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(makeBoxedNumber),
  784.       function() {
  785.         var query = new Parse.Query(BoxedNumber);
  786.         query.greaterThan("number", 1);
  787.         query.count({
  788.           success: function(count) {
  789.             equal(count, 8);
  790.             done();
  791.           }
  792.         });
  793.       });
  794.   });
  795.  
  796.   it("order by ascending number", function(done) {
  797.     var makeBoxedNumber = function(i) {
  798.       return new BoxedNumber({ number: i });
  799.     };
  800.     Parse.Object.saveAll([3, 1, 2].map(makeBoxedNumber), function() {
  801.       var query = new Parse.Query(BoxedNumber);
  802.       query.ascending("number");
  803.       query.find(expectSuccess({
  804.         success: function(results) {
  805.           equal(results.length, 3);
  806.           equal(results[0].get("number"), 1);
  807.           equal(results[1].get("number"), 2);
  808.           equal(results[2].get("number"), 3);
  809.           done();
  810.         }
  811.       }));
  812.     });
  813.   });
  814.  
  815.   it("order by descending number", function(done) {
  816.     var makeBoxedNumber = function(i) {
  817.       return new BoxedNumber({ number: i });
  818.     };
  819.     Parse.Object.saveAll([3, 1, 2].map(makeBoxedNumber)).then(function() {
  820.       var query = new Parse.Query(BoxedNumber);
  821.       query.descending("number");
  822.       query.find(expectSuccess({
  823.         success: function(results) {
  824.           equal(results.length, 3);
  825.           equal(results[0].get("number"), 3);
  826.           equal(results[1].get("number"), 2);
  827.           equal(results[2].get("number"), 1);
  828.           done();
  829.         }
  830.       }));
  831.     });
  832.   });
  833.  
  834.   it("order by ascending number then descending string", function(done) {
  835.     var strings = ["a", "b", "c", "d"];
  836.     var makeBoxedNumber = function(num, i) {
  837.       return new BoxedNumber({ number: num, string: strings[i] });
  838.     };
  839.     Parse.Object.saveAll(
  840.       [3, 1, 3, 2].map(makeBoxedNumber)).then(
  841.       function() {
  842.         var query = new Parse.Query(BoxedNumber);
  843.         query.ascending("number").addDescending("string");
  844.         query.find(expectSuccess({
  845.           success: function(results) {
  846.             equal(results.length, 4);
  847.             equal(results[0].get("number"), 1);
  848.             equal(results[0].get("string"), "b");
  849.             equal(results[1].get("number"), 2);
  850.             equal(results[1].get("string"), "d");
  851.             equal(results[2].get("number"), 3);
  852.             equal(results[2].get("string"), "c");
  853.             equal(results[3].get("number"), 3);
  854.             equal(results[3].get("string"), "a");
  855.             done();
  856.           }
  857.         }));
  858.       });
  859.   });
  860.  
  861.   it("order by descending number then ascending string", function(done) {
  862.     var strings = ["a", "b", "c", "d"];
  863.     var makeBoxedNumber = function(num, i) {
  864.       return new BoxedNumber({ number: num, string: strings[i] });
  865.     };
  866.  
  867.     const objects = [3, 1, 3, 2].map(makeBoxedNumber);
  868.     Parse.Object.saveAll(objects)
  869.     .then(() => {
  870.       var query = new Parse.Query(BoxedNumber);
  871.       query.descending("number").addAscending("string");
  872.       return query.find();
  873.     }).then((results) => {
  874.       equal(results.length, 4);
  875.       equal(results[0].get("number"), 3);
  876.       equal(results[0].get("string"), "a");
  877.       equal(results[1].get("number"), 3);
  878.       equal(results[1].get("string"), "c");
  879.       equal(results[2].get("number"), 2);
  880.       equal(results[2].get("string"), "d");
  881.       equal(results[3].get("number"), 1);
  882.       equal(results[3].get("string"), "b");
  883.       done();
  884.     }, (err) => {
  885.       jfail(err);
  886.       done();
  887.     });
  888.   });
  889.  
  890.   it("order by descending number and string", function(done) {
  891.     var strings = ["a", "b", "c", "d"];
  892.     var makeBoxedNumber = function(num, i) {
  893.       return new BoxedNumber({ number: num, string: strings[i] });
  894.     };
  895.     Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then(
  896.                          function() {
  897.                            var query = new Parse.Query(BoxedNumber);
  898.                            query.descending("number,string");
  899.                            query.find(expectSuccess({
  900.                              success: function(results) {
  901.                                equal(results.length, 4);
  902.                                equal(results[0].get("number"), 3);
  903.                                equal(results[0].get("string"), "c");
  904.                                equal(results[1].get("number"), 3);
  905.                                equal(results[1].get("string"), "a");
  906.                                equal(results[2].get("number"), 2);
  907.                                equal(results[2].get("string"), "d");
  908.                                equal(results[3].get("number"), 1);
  909.                                equal(results[3].get("string"), "b");
  910.                                done();
  911.                              }
  912.                            }));
  913.                          });
  914.   });
  915.  
  916.   it("order by descending number and string, with space", function(done) {
  917.     var strings = ["a", "b", "c", "d"];
  918.     var makeBoxedNumber = function(num, i) {
  919.       return new BoxedNumber({ number: num, string: strings[i] });
  920.     };
  921.     Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then(
  922.                          function() {
  923.                            var query = new Parse.Query(BoxedNumber);
  924.                            query.descending("number, string");
  925.                            query.find(expectSuccess({
  926.                              success: function(results) {
  927.                                equal(results.length, 4);
  928.                                equal(results[0].get("number"), 3);
  929.                                equal(results[0].get("string"), "c");
  930.                                equal(results[1].get("number"), 3);
  931.                                equal(results[1].get("string"), "a");
  932.                                equal(results[2].get("number"), 2);
  933.                                equal(results[2].get("string"), "d");
  934.                                equal(results[3].get("number"), 1);
  935.                                equal(results[3].get("string"), "b");
  936.                                done();
  937.                              }
  938.                            }));
  939.                          }, (err) => {
  940.       jfail(err);
  941.       done();
  942.     });
  943.   });
  944.  
  945.   it("order by descending number and string, with array arg", function(done) {
  946.     var strings = ["a", "b", "c", "d"];
  947.     var makeBoxedNumber = function(num, i) {
  948.       return new BoxedNumber({ number: num, string: strings[i] });
  949.     };
  950.     Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then(
  951.                          function() {
  952.                            var query = new Parse.Query(BoxedNumber);
  953.                            query.descending(["number", "string"]);
  954.                            query.find(expectSuccess({
  955.                              success: function(results) {
  956.                                equal(results.length, 4);
  957.                                equal(results[0].get("number"), 3);
  958.                                equal(results[0].get("string"), "c");
  959.                                equal(results[1].get("number"), 3);
  960.                                equal(results[1].get("string"), "a");
  961.                                equal(results[2].get("number"), 2);
  962.                                equal(results[2].get("string"), "d");
  963.                                equal(results[3].get("number"), 1);
  964.                                equal(results[3].get("string"), "b");
  965.                                done();
  966.                              }
  967.                            }));
  968.                          });
  969.   });
  970.  
  971.   it("order by descending number and string, with multiple args", function(done) {
  972.     var strings = ["a", "b", "c", "d"];
  973.     var makeBoxedNumber = function(num, i) {
  974.       return new BoxedNumber({ number: num, string: strings[i] });
  975.     };
  976.     Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then(
  977.                          function() {
  978.                            var query = new Parse.Query(BoxedNumber);
  979.                            query.descending("number", "string");
  980.                            query.find(expectSuccess({
  981.                              success: function(results) {
  982.                                equal(results.length, 4);
  983.                                equal(results[0].get("number"), 3);
  984.                                equal(results[0].get("string"), "c");
  985.                                equal(results[1].get("number"), 3);
  986.                                equal(results[1].get("string"), "a");
  987.                                equal(results[2].get("number"), 2);
  988.                                equal(results[2].get("string"), "d");
  989.                                equal(results[3].get("number"), 1);
  990.                                equal(results[3].get("string"), "b");
  991.                                done();
  992.                              }
  993.                            }));
  994.                          });
  995.   });
  996.  
  997.   it("can't order by password", function(done) {
  998.     var makeBoxedNumber = function(i) {
  999.       return new BoxedNumber({ number: i });
  1000.     };
  1001.     Parse.Object.saveAll([3, 1, 2].map(makeBoxedNumber), function() {
  1002.       var query = new Parse.Query(BoxedNumber);
  1003.       query.ascending("_password");
  1004.       query.find(expectError(Parse.Error.INVALID_KEY_NAME, done));
  1005.     });
  1006.   });
  1007.  
  1008.   it("order by _created_at", function(done) {
  1009.     var makeBoxedNumber = function(i) {
  1010.       return new BoxedNumber({ number: i });
  1011.     };
  1012.     var numbers = [3, 1, 2].map(makeBoxedNumber);
  1013.     numbers[0].save().then(() => {
  1014.       return numbers[1].save();
  1015.     }).then(() => {
  1016.       return numbers[2].save();
  1017.     }).then(function() {
  1018.       var query = new Parse.Query(BoxedNumber);
  1019.       query.ascending("_created_at");
  1020.       query.find({
  1021.         success: function(results) {
  1022.           equal(results.length, 3);
  1023.           equal(results[0].get("number"), 3);
  1024.           equal(results[1].get("number"), 1);
  1025.           equal(results[2].get("number"), 2);
  1026.           done();
  1027.         },
  1028.         error: function(e) {
  1029.           jfail(e);
  1030.           done();
  1031.         },
  1032.       });
  1033.     });
  1034.   });
  1035.  
  1036.   it("order by createdAt", function(done) {
  1037.     var makeBoxedNumber = function(i) {
  1038.       return new BoxedNumber({ number: i });
  1039.     };
  1040.     var numbers = [3, 1, 2].map(makeBoxedNumber);
  1041.     numbers[0].save().then(() => {
  1042.       return numbers[1].save();
  1043.     }).then(() => {
  1044.       return numbers[2].save();
  1045.     }).then(function() {
  1046.       var query = new Parse.Query(BoxedNumber);
  1047.       query.descending("createdAt");
  1048.       query.find({
  1049.         success: function(results) {
  1050.           equal(results.length, 3);
  1051.           equal(results[0].get("number"), 2);
  1052.           equal(results[1].get("number"), 1);
  1053.           equal(results[2].get("number"), 3);
  1054.           done();
  1055.         }
  1056.       });
  1057.     });
  1058.   });
  1059.  
  1060.   it("order by _updated_at", function(done) {
  1061.     var makeBoxedNumber = function(i) {
  1062.       return new BoxedNumber({ number: i });
  1063.     };
  1064.     var numbers = [3, 1, 2].map(makeBoxedNumber);
  1065.     numbers[0].save().then(() => {
  1066.       return numbers[1].save();
  1067.     }).then(() => {
  1068.       return numbers[2].save();
  1069.     }).then(function() {
  1070.       numbers[1].set("number", 4);
  1071.       numbers[1].save(null, {
  1072.         success: function() {
  1073.           var query = new Parse.Query(BoxedNumber);
  1074.           query.ascending("_updated_at");
  1075.           query.find({
  1076.             success: function(results) {
  1077.               equal(results.length, 3);
  1078.               equal(results[0].get("number"), 3);
  1079.               equal(results[1].get("number"), 2);
  1080.               equal(results[2].get("number"), 4);
  1081.               done();
  1082.             }
  1083.           });
  1084.         }
  1085.       });
  1086.     });
  1087.   });
  1088.  
  1089.   it("order by updatedAt", function(done) {
  1090.     var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); };
  1091.     var numbers = [3, 1, 2].map(makeBoxedNumber);
  1092.     numbers[0].save().then(() => {
  1093.       return numbers[1].save();
  1094.     }).then(() => {
  1095.       return numbers[2].save();
  1096.     }).then(function() {
  1097.       numbers[1].set("number", 4);
  1098.       numbers[1].save(null, {
  1099.         success: function() {
  1100.           var query = new Parse.Query(BoxedNumber);
  1101.           query.descending("_updated_at");
  1102.           query.find({
  1103.             success: function(results) {
  1104.               equal(results.length, 3);
  1105.               equal(results[0].get("number"), 4);
  1106.               equal(results[1].get("number"), 2);
  1107.               equal(results[2].get("number"), 3);
  1108.               done();
  1109.             }
  1110.           });
  1111.         }
  1112.       });
  1113.     });
  1114.   });
  1115.  
  1116.   // Returns a promise
  1117.   function makeTimeObject(start, i) {
  1118.     var time = new Date();
  1119.     time.setSeconds(start.getSeconds() + i);
  1120.     var item = new TestObject({name: "item" + i, time: time});
  1121.     return item.save();
  1122.   }
  1123.  
  1124.   // Returns a promise for all the time objects
  1125.   function makeThreeTimeObjects() {
  1126.     var start = new Date();
  1127.     var one, two, three;
  1128.     return makeTimeObject(start, 1).then((o1) => {
  1129.       one = o1;
  1130.       return makeTimeObject(start, 2);
  1131.     }).then((o2) => {
  1132.       two = o2;
  1133.       return makeTimeObject(start, 3);
  1134.     }).then((o3) => {
  1135.       three = o3;
  1136.       return [one, two, three];
  1137.     });
  1138.   }
  1139.  
  1140.   it("time equality", function(done) {
  1141.     makeThreeTimeObjects().then(function(list) {
  1142.       var query = new Parse.Query(TestObject);
  1143.       query.equalTo("time", list[1].get("time"));
  1144.       query.find({
  1145.         success: function(results) {
  1146.           equal(results.length, 1);
  1147.           equal(results[0].get("name"), "item2");
  1148.           done();
  1149.         }
  1150.       });
  1151.     });
  1152.   });
  1153.  
  1154.   it("time lessThan", function(done) {
  1155.     makeThreeTimeObjects().then(function(list) {
  1156.       var query = new Parse.Query(TestObject);
  1157.       query.lessThan("time", list[2].get("time"));
  1158.       query.find({
  1159.         success: function(results) {
  1160.           equal(results.length, 2);
  1161.           done();
  1162.         }
  1163.       });
  1164.     });
  1165.   });
  1166.  
  1167.   // This test requires Date objects to be consistently stored as a Date.
  1168.   it("time createdAt", function(done) {
  1169.     makeThreeTimeObjects().then(function(list) {
  1170.       var query = new Parse.Query(TestObject);
  1171.       query.greaterThanOrEqualTo("createdAt", list[0].createdAt);
  1172.       query.find({
  1173.         success: function(results) {
  1174.           equal(results.length, 3);
  1175.           done();
  1176.         }
  1177.       });
  1178.     });
  1179.   });
  1180.  
  1181.   it("matches string", function(done) {
  1182.     var thing1 = new TestObject();
  1183.     thing1.set("myString", "football");
  1184.     var thing2 = new TestObject();
  1185.     thing2.set("myString", "soccer");
  1186.     Parse.Object.saveAll([thing1, thing2], function() {
  1187.       var query = new Parse.Query(TestObject);
  1188.       query.matches("myString", "^fo*\\wb[^o]l+$");
  1189.       query.find({
  1190.         success: function(results) {
  1191.           equal(results.length, 1);
  1192.           done();
  1193.         }
  1194.       });
  1195.     });
  1196.   });
  1197.  
  1198.   it("matches regex", function(done) {
  1199.     var thing1 = new TestObject();
  1200.     thing1.set("myString", "football");
  1201.     var thing2 = new TestObject();
  1202.     thing2.set("myString", "soccer");
  1203.     Parse.Object.saveAll([thing1, thing2], function() {
  1204.       var query = new Parse.Query(TestObject);
  1205.       query.matches("myString", /^fo*\wb[^o]l+$/);
  1206.       query.find({
  1207.         success: function(results) {
  1208.           equal(results.length, 1);
  1209.           done();
  1210.         }
  1211.       });
  1212.     });
  1213.   });
  1214.  
  1215.   it("case insensitive regex success", function(done) {
  1216.     var thing = new TestObject();
  1217.     thing.set("myString", "football");
  1218.     Parse.Object.saveAll([thing], function() {
  1219.       var query = new Parse.Query(TestObject);
  1220.       query.matches("myString", "FootBall", "i");
  1221.       query.find({
  1222.         success: function() {
  1223.           done();
  1224.         }
  1225.       });
  1226.     });
  1227.   });
  1228.  
  1229.   it("regexes with invalid options fail", function(done) {
  1230.     var query = new Parse.Query(TestObject);
  1231.     query.matches("myString", "FootBall", "some invalid option");
  1232.     query.find(expectError(Parse.Error.INVALID_QUERY, done));
  1233.   });
  1234.  
  1235.   it("Use a regex that requires all modifiers", function(done) {
  1236.     var thing = new TestObject();
  1237.     thing.set("myString", "PArSe\nCom");
  1238.     Parse.Object.saveAll([thing], function() {
  1239.       var query = new Parse.Query(TestObject);
  1240.       query.matches(
  1241.         "myString",
  1242.         "parse # First fragment. We'll write this in one case but match " +
  1243.           "insensitively\n.com  # Second fragment. This can be separated by any " +
  1244.           "character, including newline",
  1245.         "mixs");
  1246.       query.find({
  1247.         success: function(results) {
  1248.           equal(results.length, 1);
  1249.           done();
  1250.         },
  1251.         error: function(err) {
  1252.           jfail(err);
  1253.           done();
  1254.         }
  1255.       });
  1256.     });
  1257.   });
  1258.  
  1259.   it("Regular expression constructor includes modifiers inline", function(done) {
  1260.     var thing = new TestObject();
  1261.     thing.set("myString", "\n\nbuffer\n\nparse.COM");
  1262.     Parse.Object.saveAll([thing], function() {
  1263.       var query = new Parse.Query(TestObject);
  1264.       query.matches("myString", /parse\.com/mi);
  1265.       query.find({
  1266.         success: function(results) {
  1267.           equal(results.length, 1);
  1268.           done();
  1269.         }
  1270.       });
  1271.     });
  1272.   });
  1273.  
  1274.   var someAscii = "\\E' !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTU" +
  1275.     "VWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'";
  1276.  
  1277.   it("contains", function(done) {
  1278.     Parse.Object.saveAll([new TestObject({myString: "zax" + someAscii + "qub"}),
  1279.       new TestObject({myString: "start" + someAscii}),
  1280.       new TestObject({myString: someAscii + "end"}),
  1281.       new TestObject({myString: someAscii})], function() {
  1282.       var query = new Parse.Query(TestObject);
  1283.       query.contains("myString", someAscii);
  1284.       query.find({
  1285.         success: function(results) {
  1286.           equal(results.length, 4);
  1287.           done();
  1288.         }
  1289.       });
  1290.     });
  1291.   });
  1292.  
  1293.   it("startsWith", function(done) {
  1294.     Parse.Object.saveAll([new TestObject({myString: "zax" + someAscii + "qub"}),
  1295.       new TestObject({myString: "start" + someAscii}),
  1296.       new TestObject({myString: someAscii + "end"}),
  1297.       new TestObject({myString: someAscii})], function() {
  1298.       var query = new Parse.Query(TestObject);
  1299.       query.startsWith("myString", someAscii);
  1300.       query.find({
  1301.         success: function(results) {
  1302.           equal(results.length, 2);
  1303.           done();
  1304.         }
  1305.       });
  1306.     });
  1307.   });
  1308.  
  1309.   it("endsWith", function(done) {
  1310.     Parse.Object.saveAll([new TestObject({myString: "zax" + someAscii + "qub"}),
  1311.       new TestObject({myString: "start" + someAscii}),
  1312.       new TestObject({myString: someAscii + "end"}),
  1313.       new TestObject({myString: someAscii})], function() {
  1314.       var query = new Parse.Query(TestObject);
  1315.       query.endsWith("myString", someAscii);
  1316.       query.find({
  1317.         success: function(results) {
  1318.           equal(results.length, 2);
  1319.           done();
  1320.         }
  1321.       });
  1322.     });
  1323.   });
  1324.  
  1325.   it("exists", function(done) {
  1326.     var objects = [];
  1327.     for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) {
  1328.       var item = new TestObject();
  1329.       if (i % 2 === 0) {
  1330.         item.set('x', i + 1);
  1331.       } else {
  1332.         item.set('y', i + 1);
  1333.       }
  1334.       objects.push(item);
  1335.     }
  1336.     Parse.Object.saveAll(objects, function() {
  1337.       var query = new Parse.Query(TestObject);
  1338.       query.exists("x");
  1339.       query.find({
  1340.         success: function(results) {
  1341.           equal(results.length, 5);
  1342.           for (var result of results) {
  1343.             ok(result.get("x"));
  1344.           }
  1345.           done();
  1346.         }
  1347.       });
  1348.     });
  1349.   });
  1350.  
  1351.   it("doesNotExist", function(done) {
  1352.     var objects = [];
  1353.     for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) {
  1354.       var item = new TestObject();
  1355.       if (i % 2 === 0) {
  1356.         item.set('x', i + 1);
  1357.       } else {
  1358.         item.set('y', i + 1);
  1359.       }
  1360.       objects.push(item);
  1361.     }
  1362.     Parse.Object.saveAll(objects, function() {
  1363.       var query = new Parse.Query(TestObject);
  1364.       query.doesNotExist("x");
  1365.       query.find({
  1366.         success: function(results) {
  1367.           equal(results.length, 4);
  1368.           for (var result of results) {
  1369.             ok(result.get("y"));
  1370.           }
  1371.           done();
  1372.         }
  1373.       });
  1374.     });
  1375.   });
  1376.  
  1377.   it("exists relation", function(done) {
  1378.     var objects = [];
  1379.     for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) {
  1380.       var container = new Container();
  1381.       if (i % 2 === 0) {
  1382.         var item = new TestObject();
  1383.         item.set('x', i);
  1384.         container.set('x', item);
  1385.         objects.push(item);
  1386.       } else {
  1387.         container.set('y', i);
  1388.       }
  1389.       objects.push(container);
  1390.     }
  1391.     Parse.Object.saveAll(objects).then(function() {
  1392.       var query = new Parse.Query(Container);
  1393.       query.exists("x");
  1394.       query.find({
  1395.         success: function(results) {
  1396.           equal(results.length, 5);
  1397.           for (var result of results) {
  1398.             ok(result.get("x"));
  1399.           }
  1400.           done();
  1401.         }
  1402.       });
  1403.     });
  1404.   });
  1405.  
  1406.   it("doesNotExist relation", function(done) {
  1407.     var objects = [];
  1408.     for (var i of [0, 1, 2, 3, 4, 5, 6, 7]) {
  1409.       var container = new Container();
  1410.       if (i % 2 === 0) {
  1411.         var item = new TestObject();
  1412.         item.set('x', i);
  1413.         container.set('x', item);
  1414.         objects.push(item);
  1415.       } else {
  1416.         container.set('y', i);
  1417.       }
  1418.       objects.push(container);
  1419.     }
  1420.     Parse.Object.saveAll(objects, function() {
  1421.       var query = new Parse.Query(Container);
  1422.       query.doesNotExist("x");
  1423.       query.find({
  1424.         success: function(results) {
  1425.           equal(results.length, 4);
  1426.           for (var result of results) {
  1427.             ok(result.get("y"));
  1428.           }
  1429.           done();
  1430.         }
  1431.       });
  1432.     });
  1433.   });
  1434.  
  1435.   it("don't include by default", function(done) {
  1436.     var child = new TestObject();
  1437.     var parent = new Container();
  1438.     child.set("foo", "bar");
  1439.     parent.set("child", child);
  1440.     Parse.Object.saveAll([child, parent], function() {
  1441.       child._clearServerData();
  1442.       var query = new Parse.Query(Container);
  1443.       query.find({
  1444.         success: function(results) {
  1445.           equal(results.length, 1);
  1446.           var parentAgain = results[0];
  1447.           var goodURL = Parse.serverURL;
  1448.           Parse.serverURL = "YAAAAAAAAARRRRRGGGGGGGGG";
  1449.           var childAgain = parentAgain.get("child");
  1450.           ok(childAgain);
  1451.           equal(childAgain.get("foo"), undefined);
  1452.           Parse.serverURL = goodURL;
  1453.           done();
  1454.         }
  1455.       });
  1456.     });
  1457.   });
  1458.  
  1459.   it("include relation", function(done) {
  1460.     var child = new TestObject();
  1461.     var parent = new Container();
  1462.     child.set("foo", "bar");
  1463.     parent.set("child", child);
  1464.     Parse.Object.saveAll([child, parent], function() {
  1465.       var query = new Parse.Query(Container);
  1466.       query.include("child");
  1467.       query.find({
  1468.         success: function(results) {
  1469.           equal(results.length, 1);
  1470.           var parentAgain = results[0];
  1471.           var goodURL = Parse.serverURL;
  1472.           Parse.serverURL = "YAAAAAAAAARRRRRGGGGGGGGG";
  1473.           var childAgain = parentAgain.get("child");
  1474.           ok(childAgain);
  1475.           equal(childAgain.get("foo"), "bar");
  1476.           Parse.serverURL = goodURL;
  1477.           done();
  1478.         }
  1479.       });
  1480.     });
  1481.   });
  1482.  
  1483.   it("include relation array", function(done) {
  1484.     var child = new TestObject();
  1485.     var parent = new Container();
  1486.     child.set("foo", "bar");
  1487.     parent.set("child", child);
  1488.     Parse.Object.saveAll([child, parent], function() {
  1489.       var query = new Parse.Query(Container);
  1490.       query.include(["child"]);
  1491.       query.find({
  1492.         success: function(results) {
  1493.           equal(results.length, 1);
  1494.           var parentAgain = results[0];
  1495.           var goodURL = Parse.serverURL;
  1496.           Parse.serverURL = "YAAAAAAAAARRRRRGGGGGGGGG";
  1497.           var childAgain = parentAgain.get("child");
  1498.           ok(childAgain);
  1499.           equal(childAgain.get("foo"), "bar");
  1500.           Parse.serverURL = goodURL;
  1501.           done();
  1502.         }
  1503.       });
  1504.     });
  1505.   });
  1506.  
  1507.   it("nested include", function(done) {
  1508.     var Child = Parse.Object.extend("Child");
  1509.     var Parent = Parse.Object.extend("Parent");
  1510.     var Grandparent = Parse.Object.extend("Grandparent");
  1511.     var objects = [];
  1512.     for (var i = 0; i < 5; ++i) {
  1513.       var grandparent = new Grandparent({
  1514.         z:i,
  1515.         parent: new Parent({
  1516.           y:i,
  1517.           child: new Child({
  1518.             x:i
  1519.           })
  1520.         })
  1521.       });
  1522.       objects.push(grandparent);
  1523.     }
  1524.  
  1525.     Parse.Object.saveAll(objects, function() {
  1526.       var query = new Parse.Query(Grandparent);
  1527.       query.include(["parent.child"]);
  1528.       query.find({
  1529.         success: function(results) {
  1530.           equal(results.length, 5);
  1531.           for (var object of results) {
  1532.             equal(object.get("z"), object.get("parent").get("y"));
  1533.             equal(object.get("z"), object.get("parent").get("child").get("x"));
  1534.           }
  1535.           done();
  1536.         }
  1537.       });
  1538.     });
  1539.   });
  1540.  
  1541.   it("include doesn't make dirty wrong", function(done) {
  1542.     var Parent = Parse.Object.extend("ParentObject");
  1543.     var Child = Parse.Object.extend("ChildObject");
  1544.     var parent = new Parent();
  1545.     var child = new Child();
  1546.     child.set("foo", "bar");
  1547.     parent.set("child", child);
  1548.  
  1549.     Parse.Object.saveAll([child, parent], function() {
  1550.       var query = new Parse.Query(Parent);
  1551.       query.include("child");
  1552.       query.find({
  1553.         success: function(results) {
  1554.           equal(results.length, 1);
  1555.           var parentAgain = results[0];
  1556.           var childAgain = parentAgain.get("child");
  1557.           equal(childAgain.id, child.id);
  1558.           equal(parentAgain.id, parent.id);
  1559.           equal(childAgain.get("foo"), "bar");
  1560.           equal(false, parentAgain.dirty());
  1561.           equal(false, childAgain.dirty());
  1562.           done();
  1563.         }
  1564.       });
  1565.     });
  1566.   });
  1567.  
  1568.   it('properly includes array', (done) => {
  1569.     const objects = [];
  1570.     let total = 0;
  1571.     while(objects.length != 5) {
  1572.       const object = new Parse.Object('AnObject');
  1573.       object.set('key', objects.length);
  1574.       total += objects.length;
  1575.       objects.push(object);
  1576.     }
  1577.     Parse.Object.saveAll(objects).then(() => {
  1578.       const object = new Parse.Object("AContainer");
  1579.       object.set('objects', objects);
  1580.       return object.save();
  1581.     }).then(() => {
  1582.       const query = new Parse.Query('AContainer');
  1583.       query.include('objects');
  1584.       return query.find()
  1585.     }).then((results) => {
  1586.       expect(results.length).toBe(1);
  1587.       const res = results[0];
  1588.       const objects = res.get('objects');
  1589.       expect(objects.length).toBe(5);
  1590.       objects.forEach((object) => {
  1591.         total -= object.get('key');
  1592.       });
  1593.       expect(total).toBe(0);
  1594.       done()
  1595.     }, () => {
  1596.       fail('should not fail');
  1597.       done();
  1598.     })
  1599.   });
  1600.  
  1601.   it('properly includes array of mixed objects', (done) => {
  1602.     const objects = [];
  1603.     let total = 0;
  1604.     while(objects.length != 5) {
  1605.       const object = new Parse.Object('AnObject');
  1606.       object.set('key', objects.length);
  1607.       total += objects.length;
  1608.       objects.push(object);
  1609.     }
  1610.     while(objects.length != 10) {
  1611.       const object = new Parse.Object('AnotherObject');
  1612.       object.set('key', objects.length);
  1613.       total += objects.length;
  1614.       objects.push(object);
  1615.     }
  1616.     Parse.Object.saveAll(objects).then(() => {
  1617.       const object = new Parse.Object("AContainer");
  1618.       object.set('objects', objects);
  1619.       return object.save();
  1620.     }).then(() => {
  1621.       const query = new Parse.Query('AContainer');
  1622.       query.include('objects');
  1623.       return query.find()
  1624.     }).then((results) => {
  1625.       expect(results.length).toBe(1);
  1626.       const res = results[0];
  1627.       const objects = res.get('objects');
  1628.       expect(objects.length).toBe(10);
  1629.       objects.forEach((object) => {
  1630.         total -= object.get('key');
  1631.       });
  1632.       expect(total).toBe(0);
  1633.       done()
  1634.     }, (e) => {
  1635.       fail('should not fail');
  1636.       fail(JSON.stringify(e));
  1637.       done();
  1638.     })
  1639.   });
  1640.  
  1641.   it('properly nested array of mixed objects with bad ids', (done) => {
  1642.     const objects = [];
  1643.     let total = 0;
  1644.     while(objects.length != 5) {
  1645.       const object = new Parse.Object('AnObject');
  1646.       object.set('key', objects.length);
  1647.       objects.push(object);
  1648.     }
  1649.     while(objects.length != 10) {
  1650.       const object = new Parse.Object('AnotherObject');
  1651.       object.set('key', objects.length);
  1652.       objects.push(object);
  1653.     }
  1654.     Parse.Object.saveAll(objects).then(() => {
  1655.       const object = new Parse.Object("AContainer");
  1656.       for (var i = 0; i < objects.length; i++) {
  1657.         if (i % 2 == 0) {
  1658.           objects[i].id = 'randomThing'
  1659.         } else {
  1660.           total += objects[i].get('key');
  1661.         }
  1662.       }
  1663.       object.set('objects', objects);
  1664.       return object.save();
  1665.     }).then(() => {
  1666.       const query = new Parse.Query('AContainer');
  1667.       query.include('objects');
  1668.       return query.find()
  1669.     }).then((results) => {
  1670.       expect(results.length).toBe(1);
  1671.       const res = results[0];
  1672.       const objects = res.get('objects');
  1673.       expect(objects.length).toBe(5);
  1674.       objects.forEach((object) => {
  1675.         total -= object.get('key');
  1676.       });
  1677.       expect(total).toBe(0);
  1678.       done()
  1679.     }, (err) => {
  1680.       jfail(err);
  1681.       fail('should not fail');
  1682.       done();
  1683.     })
  1684.   });
  1685.  
  1686.   it('properly fetches nested pointers', (done) =>  {
  1687.     const color = new Parse.Object('Color');
  1688.     color.set('hex','#133733');
  1689.     const circle = new Parse.Object('Circle');
  1690.     circle.set('radius', 1337);
  1691.  
  1692.     Parse.Object.saveAll([color, circle]).then(() => {
  1693.       circle.set('color', color);
  1694.       const badCircle = new Parse.Object('Circle');
  1695.       badCircle.id = 'badId';
  1696.       const complexFigure = new Parse.Object('ComplexFigure');
  1697.       complexFigure.set('consistsOf', [circle, badCircle]);
  1698.       return complexFigure.save();
  1699.     }).then(() => {
  1700.       const q = new Parse.Query('ComplexFigure');
  1701.       q.include('consistsOf.color');
  1702.       return q.find()
  1703.     }).then((results) => {
  1704.       expect(results.length).toBe(1);
  1705.       const figure = results[0];
  1706.       expect(figure.get('consistsOf').length).toBe(1);
  1707.       expect(figure.get('consistsOf')[0].get('color').get('hex')).toBe('#133733');
  1708.       done();
  1709.     }, () => {
  1710.       fail('should not fail');
  1711.       done();
  1712.     })
  1713.  
  1714.   });
  1715.  
  1716.   it("result object creation uses current extension", function(done) {
  1717.     var ParentObject = Parse.Object.extend({ className: "ParentObject" });
  1718.     // Add a foo() method to ChildObject.
  1719.     var ChildObject = Parse.Object.extend("ChildObject", {
  1720.       foo: function() {
  1721.         return "foo";
  1722.       }
  1723.     });
  1724.  
  1725.     var parent = new ParentObject();
  1726.     var child = new ChildObject();
  1727.     parent.set("child", child);
  1728.     Parse.Object.saveAll([child, parent], function() {
  1729.       // Add a bar() method to ChildObject.
  1730.       ChildObject = Parse.Object.extend("ChildObject", {
  1731.         bar: function() {
  1732.           return "bar";
  1733.         }
  1734.       });
  1735.  
  1736.       var query = new Parse.Query(ParentObject);
  1737.       query.include("child");
  1738.       query.find({
  1739.         success: function(results) {
  1740.           equal(results.length, 1);
  1741.           var parentAgain = results[0];
  1742.           var childAgain = parentAgain.get("child");
  1743.           equal(childAgain.foo(), "foo");
  1744.           equal(childAgain.bar(), "bar");
  1745.           done();
  1746.         }
  1747.       });
  1748.     });
  1749.   });
  1750.  
  1751.   it("matches query", function(done) {
  1752.     var ParentObject = Parse.Object.extend("ParentObject");
  1753.     var ChildObject = Parse.Object.extend("ChildObject");
  1754.     var objects = [];
  1755.     for (var i = 0; i < 10; ++i) {
  1756.       objects.push(
  1757.         new ParentObject({
  1758.           child: new ChildObject({x: i}),
  1759.           x: 10 + i
  1760.         }));
  1761.     }
  1762.     Parse.Object.saveAll(objects, function() {
  1763.       var subQuery = new Parse.Query(ChildObject);
  1764.       subQuery.greaterThan("x", 5);
  1765.       var query = new Parse.Query(ParentObject);
  1766.       query.matchesQuery("child", subQuery);
  1767.       query.find({
  1768.         success: function(results) {
  1769.           equal(results.length, 4);
  1770.           for (var object of results) {
  1771.             ok(object.get("x") > 15);
  1772.           }
  1773.           var query = new Parse.Query(ParentObject);
  1774.           query.doesNotMatchQuery("child", subQuery);
  1775.           query.find({
  1776.             success: function (results) {
  1777.               equal(results.length, 6);
  1778.               for (var object of results) {
  1779.                 ok(object.get("x") >= 10);
  1780.                 ok(object.get("x") <= 15);
  1781.                 done();
  1782.               }
  1783.             }
  1784.           });
  1785.         }
  1786.       });
  1787.     });
  1788.   });
  1789.  
  1790.   it("select query", function(done) {
  1791.     var RestaurantObject = Parse.Object.extend("Restaurant");
  1792.     var PersonObject = Parse.Object.extend("Person");
  1793.     var objects = [
  1794.       new RestaurantObject({ ratings: 5, location: "Djibouti" }),
  1795.       new RestaurantObject({ ratings: 3, location: "Ouagadougou" }),
  1796.       new PersonObject({ name: "Bob", hometown: "Djibouti" }),
  1797.       new PersonObject({ name: "Tom", hometown: "Ouagadougou" }),
  1798.       new PersonObject({ name: "Billy", hometown: "Detroit" })
  1799.     ];
  1800.  
  1801.     Parse.Object.saveAll(objects, function() {
  1802.       var query = new Parse.Query(RestaurantObject);
  1803.       query.greaterThan("ratings", 4);
  1804.       var mainQuery = new Parse.Query(PersonObject);
  1805.       mainQuery.matchesKeyInQuery("hometown", "location", query);
  1806.       mainQuery.find(expectSuccess({
  1807.         success: function(results) {
  1808.           equal(results.length, 1);
  1809.           equal(results[0].get('name'), 'Bob');
  1810.           done();
  1811.         }
  1812.       }));
  1813.     });
  1814.   });
  1815.  
  1816.   it('$select inside $or', (done) => {
  1817.     var Restaurant = Parse.Object.extend('Restaurant');
  1818.     var Person = Parse.Object.extend('Person');
  1819.     var objects = [
  1820.       new Restaurant({ ratings: 5, location: "Djibouti" }),
  1821.       new Restaurant({ ratings: 3, location: "Ouagadougou" }),
  1822.       new Person({ name: "Bob", hometown: "Djibouti" }),
  1823.       new Person({ name: "Tom", hometown: "Ouagadougou" }),
  1824.       new Person({ name: "Billy", hometown: "Detroit" })
  1825.     ];
  1826.  
  1827.     Parse.Object.saveAll(objects).then(() => {
  1828.       var subquery = new Parse.Query(Restaurant);
  1829.       subquery.greaterThan('ratings', 4);
  1830.       var query1 = new Parse.Query(Person);
  1831.       query1.matchesKeyInQuery('hometown', 'location', subquery);
  1832.       var query2 = new Parse.Query(Person);
  1833.       query2.equalTo('name', 'Tom');
  1834.       var query = Parse.Query.or(query1, query2);
  1835.       return query.find();
  1836.     }).then((results) => {
  1837.       expect(results.length).toEqual(2);
  1838.       done();
  1839.     }, (error) => {
  1840.       jfail(error);
  1841.       done();
  1842.     });
  1843.   });
  1844.  
  1845.   it("dontSelect query", function(done) {
  1846.     var RestaurantObject = Parse.Object.extend("Restaurant");
  1847.     var PersonObject = Parse.Object.extend("Person");
  1848.     var objects = [
  1849.       new RestaurantObject({ ratings: 5, location: "Djibouti" }),
  1850.       new RestaurantObject({ ratings: 3, location: "Ouagadougou" }),
  1851.       new PersonObject({ name: "Bob", hometown: "Djibouti" }),
  1852.       new PersonObject({ name: "Tom", hometown: "Ouagadougou" }),
  1853.       new PersonObject({ name: "Billy", hometown: "Djibouti" })
  1854.     ];
  1855.  
  1856.     Parse.Object.saveAll(objects, function() {
  1857.       var query = new Parse.Query(RestaurantObject);
  1858.       query.greaterThan("ratings", 4);
  1859.       var mainQuery = new Parse.Query(PersonObject);
  1860.       mainQuery.doesNotMatchKeyInQuery("hometown", "location", query);
  1861.       mainQuery.find(expectSuccess({
  1862.         success: function(results) {
  1863.           equal(results.length, 1);
  1864.           equal(results[0].get('name'), 'Tom');
  1865.           done();
  1866.         }
  1867.       }));
  1868.     });
  1869.   });
  1870.  
  1871.   it("dontSelect query without conditions", function(done) {
  1872.     const RestaurantObject = Parse.Object.extend("Restaurant");
  1873.     const PersonObject = Parse.Object.extend("Person");
  1874.     const objects = [
  1875.       new RestaurantObject({ location: "Djibouti" }),
  1876.       new RestaurantObject({ location: "Ouagadougou" }),
  1877.       new PersonObject({ name: "Bob", hometown: "Djibouti" }),
  1878.       new PersonObject({ name: "Tom", hometown: "Yoloblahblahblah" }),
  1879.       new PersonObject({ name: "Billy", hometown: "Ouagadougou" })
  1880.     ];
  1881.  
  1882.     Parse.Object.saveAll(objects, function() {
  1883.       const query = new Parse.Query(RestaurantObject);
  1884.       const mainQuery = new Parse.Query(PersonObject);
  1885.       mainQuery.doesNotMatchKeyInQuery("hometown", "location", query);
  1886.       mainQuery.find().then(results => {
  1887.         equal(results.length, 1);
  1888.         equal(results[0].get('name'), 'Tom');
  1889.         done();
  1890.       });
  1891.     });
  1892.   });
  1893.  
  1894.   it("equalTo on same column as $dontSelect should not break $dontSelect functionality (#3678)", function(done) {
  1895.     var AuthorObject = Parse.Object.extend("Author");
  1896.     var BlockedObject = Parse.Object.extend("Blocked");
  1897.     var PostObject = Parse.Object.extend("Post");
  1898.  
  1899.     var postAuthor = null;
  1900.     var requestUser = null;
  1901.  
  1902.     return new AuthorObject({ name: "Julius"}).save().then((user) => {
  1903.       postAuthor = user;
  1904.       return new AuthorObject({ name: "Bob"}).save();
  1905.     }).then((user) => {
  1906.       requestUser = user;
  1907.       var objects = [
  1908.         new PostObject({ author: postAuthor, title: "Lorem ipsum" }),
  1909.         new PostObject({ author: requestUser, title: "Kafka" }),
  1910.         new PostObject({ author: requestUser, title: "Brown fox" }),
  1911.         new BlockedObject({ blockedBy: postAuthor, blockedUser: requestUser})
  1912.       ];
  1913.       return Parse.Object.saveAll(objects);
  1914.     }).then(() => {
  1915.       var banListQuery = new Parse.Query(BlockedObject);
  1916.       banListQuery.equalTo("blockedUser", requestUser);
  1917.  
  1918.       return new Parse.Query(PostObject)
  1919.         .equalTo("author", postAuthor)
  1920.         .doesNotMatchKeyInQuery("author", "blockedBy", banListQuery)
  1921.         .find()
  1922.         .then((r) => {
  1923.           expect(r.length).toEqual(0);
  1924.           done();
  1925.         }, done.fail);
  1926.     })
  1927.   });
  1928.  
  1929.   it("object with length", function(done) {
  1930.     var TestObject = Parse.Object.extend("TestObject");
  1931.     var obj = new TestObject();
  1932.     obj.set("length", 5);
  1933.     equal(obj.get("length"), 5);
  1934.     obj.save(null, {
  1935.       success: function() {
  1936.         var query = new Parse.Query(TestObject);
  1937.         query.find({
  1938.           success: function(results) {
  1939.             equal(results.length, 1);
  1940.             equal(results[0].get("length"), 5);
  1941.             done();
  1942.           },
  1943.           error: function(error) {
  1944.             ok(false, error.message);
  1945.             done();
  1946.           }
  1947.         });
  1948.       },
  1949.       error: function(error) {
  1950.         ok(false, error.message);
  1951.         done();
  1952.       }
  1953.     });
  1954.   });
  1955.  
  1956.   it("include user", function(done) {
  1957.     Parse.User.signUp("bob", "password", { age: 21 }, {
  1958.       success: function(user) {
  1959.         var TestObject = Parse.Object.extend("TestObject");
  1960.         var obj = new TestObject();
  1961.         obj.save({
  1962.           owner: user
  1963.         }, {
  1964.           success: function(obj) {
  1965.             var query = new Parse.Query(TestObject);
  1966.             query.include("owner");
  1967.             query.get(obj.id, {
  1968.               success: function(objAgain) {
  1969.                 equal(objAgain.id, obj.id);
  1970.                 ok(objAgain.get("owner") instanceof Parse.User);
  1971.                 equal(objAgain.get("owner").get("age"), 21);
  1972.                 done();
  1973.               },
  1974.               error: function(objAgain, error) {
  1975.                 ok(false, error.message);
  1976.                 done();
  1977.               }
  1978.             });
  1979.           },
  1980.           error: function(obj, error) {
  1981.             ok(false, error.message);
  1982.             done();
  1983.           }
  1984.         });
  1985.       },
  1986.       error: function(user, error) {
  1987.         ok(false, error.message);
  1988.         done();
  1989.       }
  1990.     });
  1991.   });
  1992.  
  1993.   it("or queries", function(done) {
  1994.     var objects = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) {
  1995.       var object = new Parse.Object('BoxedNumber');
  1996.       object.set('x', x);
  1997.       return object;
  1998.     });
  1999.     Parse.Object.saveAll(objects, expectSuccess({
  2000.       success: function() {
  2001.         var query1 = new Parse.Query('BoxedNumber');
  2002.         query1.lessThan('x', 2);
  2003.         var query2 = new Parse.Query('BoxedNumber');
  2004.         query2.greaterThan('x', 5);
  2005.         var orQuery = Parse.Query.or(query1, query2);
  2006.         orQuery.find(expectSuccess({
  2007.           success: function(results) {
  2008.             equal(results.length, 6);
  2009.             for (var number of results) {
  2010.               ok(number.get('x') < 2 || number.get('x') > 5);
  2011.             }
  2012.             done();
  2013.           }
  2014.         }));
  2015.       }
  2016.     }));
  2017.   });
  2018.  
  2019.   // This relies on matchesQuery aka the $inQuery operator
  2020.   it("or complex queries", function(done) {
  2021.     var objects = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) {
  2022.       var child = new Parse.Object('Child');
  2023.       child.set('x', x);
  2024.       var parent = new Parse.Object('Parent');
  2025.       parent.set('child', child);
  2026.       parent.set('y', x);
  2027.       return parent;
  2028.     });
  2029.  
  2030.     Parse.Object.saveAll(objects, expectSuccess({
  2031.       success: function() {
  2032.         var subQuery = new Parse.Query('Child');
  2033.         subQuery.equalTo('x', 4);
  2034.         var query1 = new Parse.Query('Parent');
  2035.         query1.matchesQuery('child', subQuery);
  2036.         var query2 = new Parse.Query('Parent');
  2037.         query2.lessThan('y', 2);
  2038.         var orQuery = Parse.Query.or(query1, query2);
  2039.         orQuery.find(expectSuccess({
  2040.           success: function(results) {
  2041.             equal(results.length, 3);
  2042.             done();
  2043.           }
  2044.         }));
  2045.       }
  2046.     }));
  2047.   });
  2048.  
  2049.   it("async methods", function(done) {
  2050.     var saves = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) {
  2051.       var obj = new Parse.Object("TestObject");
  2052.       obj.set("x", x + 1);
  2053.       return obj.save();
  2054.     });
  2055.  
  2056.     Parse.Promise.when(saves).then(function() {
  2057.       var query = new Parse.Query("TestObject");
  2058.       query.ascending("x");
  2059.       return query.first();
  2060.  
  2061.     }).then(function(obj) {
  2062.       equal(obj.get("x"), 1);
  2063.       var query = new Parse.Query("TestObject");
  2064.       query.descending("x");
  2065.       return query.find();
  2066.  
  2067.     }).then(function(results) {
  2068.       equal(results.length, 10);
  2069.       var query = new Parse.Query("TestObject");
  2070.       return query.get(results[0].id);
  2071.  
  2072.     }).then(function(obj1) {
  2073.       equal(obj1.get("x"), 10);
  2074.       var query = new Parse.Query("TestObject");
  2075.       return query.count();
  2076.  
  2077.     }).then(function(count) {
  2078.       equal(count, 10);
  2079.  
  2080.     }).then(function() {
  2081.       done();
  2082.  
  2083.     });
  2084.   });
  2085.  
  2086.   it("query.each", function(done) {
  2087.     var TOTAL = 50;
  2088.     var COUNT = 25;
  2089.  
  2090.     var items = range(TOTAL).map(function(x) {
  2091.       var obj = new TestObject();
  2092.       obj.set("x", x);
  2093.       return obj;
  2094.     });
  2095.  
  2096.     Parse.Object.saveAll(items).then(function() {
  2097.       var query = new Parse.Query(TestObject);
  2098.       query.lessThan("x", COUNT);
  2099.  
  2100.       var seen = [];
  2101.       query.each(function(obj) {
  2102.         seen[obj.get("x")] = (seen[obj.get("x")] || 0) + 1;
  2103.  
  2104.       }, {
  2105.         batchSize: 10,
  2106.         success: function() {
  2107.           equal(seen.length, COUNT);
  2108.           for (var i = 0; i < COUNT; i++) {
  2109.             equal(seen[i], 1, "Should have seen object number " + i);
  2110.           }
  2111.           done();
  2112.         },
  2113.         error: function(error) {
  2114.           ok(false, error);
  2115.           done();
  2116.         }
  2117.       });
  2118.     });
  2119.   });
  2120.  
  2121.   it("query.each async", function(done) {
  2122.     var TOTAL = 50;
  2123.     var COUNT = 25;
  2124.  
  2125.     expect(COUNT + 1);
  2126.  
  2127.     var items = range(TOTAL).map(function(x) {
  2128.       var obj = new TestObject();
  2129.       obj.set("x", x);
  2130.       return obj;
  2131.     });
  2132.  
  2133.     var seen = [];
  2134.  
  2135.     Parse.Object.saveAll(items).then(function() {
  2136.       var query = new Parse.Query(TestObject);
  2137.       query.lessThan("x", COUNT);
  2138.       return query.each(function(obj) {
  2139.         var promise = new Parse.Promise();
  2140.         process.nextTick(function() {
  2141.           seen[obj.get("x")] = (seen[obj.get("x")] || 0) + 1;
  2142.           promise.resolve();
  2143.         });
  2144.         return promise;
  2145.       }, {
  2146.         batchSize: 10
  2147.       });
  2148.  
  2149.     }).then(function() {
  2150.       equal(seen.length, COUNT);
  2151.       for (var i = 0; i < COUNT; i++) {
  2152.         equal(seen[i], 1, "Should have seen object number " + i);
  2153.       }
  2154.       done();
  2155.     });
  2156.   });
  2157.  
  2158.   it("query.each fails with order", function(done) {
  2159.     var TOTAL = 50;
  2160.     var COUNT = 25;
  2161.  
  2162.     var items = range(TOTAL).map(function(x) {
  2163.       var obj = new TestObject();
  2164.       obj.set("x", x);
  2165.       return obj;
  2166.     });
  2167.  
  2168.     var seen = [];
  2169.  
  2170.     Parse.Object.saveAll(items).then(function() {
  2171.       var query = new Parse.Query(TestObject);
  2172.       query.lessThan("x", COUNT);
  2173.       query.ascending("x");
  2174.       return query.each(function(obj) {
  2175.         seen[obj.get("x")] = (seen[obj.get("x")] || 0) + 1;
  2176.       });
  2177.  
  2178.     }).then(function() {
  2179.       ok(false, "This should have failed.");
  2180.       done();
  2181.     }, function() {
  2182.       done();
  2183.     });
  2184.   });
  2185.  
  2186.   it("query.each fails with skip", function(done) {
  2187.     var TOTAL = 50;
  2188.     var COUNT = 25;
  2189.  
  2190.     var items = range(TOTAL).map(function(x) {
  2191.       var obj = new TestObject();
  2192.       obj.set("x", x);
  2193.       return obj;
  2194.     });
  2195.  
  2196.     var seen = [];
  2197.  
  2198.     Parse.Object.saveAll(items).then(function() {
  2199.       var query = new Parse.Query(TestObject);
  2200.       query.lessThan("x", COUNT);
  2201.       query.skip(5);
  2202.       return query.each(function(obj) {
  2203.         seen[obj.get("x")] = (seen[obj.get("x")] || 0) + 1;
  2204.       });
  2205.  
  2206.     }).then(function() {
  2207.       ok(false, "This should have failed.");
  2208.       done();
  2209.     }, function() {
  2210.       done();
  2211.     });
  2212.   });
  2213.  
  2214.   it("query.each fails with limit", function(done) {
  2215.     var TOTAL = 50;
  2216.     var COUNT = 25;
  2217.  
  2218.     expect(0);
  2219.  
  2220.     var items = range(TOTAL).map(function(x) {
  2221.       var obj = new TestObject();
  2222.       obj.set("x", x);
  2223.       return obj;
  2224.     });
  2225.  
  2226.     var seen = [];
  2227.  
  2228.     Parse.Object.saveAll(items).then(function() {
  2229.       var query = new Parse.Query(TestObject);
  2230.       query.lessThan("x", COUNT);
  2231.       query.limit(5);
  2232.       return query.each(function(obj) {
  2233.         seen[obj.get("x")] = (seen[obj.get("x")] || 0) + 1;
  2234.       });
  2235.  
  2236.     }).then(function() {
  2237.       ok(false, "This should have failed.");
  2238.       done();
  2239.     }, function() {
  2240.       done();
  2241.     });
  2242.   });
  2243.  
  2244.   it("select keys query", function(done) {
  2245.     var obj = new TestObject({ foo: 'baz', bar: 1 });
  2246.  
  2247.     obj.save().then(function () {
  2248.       obj._clearServerData();
  2249.       var query = new Parse.Query(TestObject);
  2250.       query.select('foo');
  2251.       return query.first();
  2252.     }).then(function(result) {
  2253.       ok(result.id, "expected object id to be set");
  2254.       ok(result.createdAt, "expected object createdAt to be set");
  2255.       ok(result.updatedAt, "expected object updatedAt to be set");
  2256.       ok(!result.dirty(), "expected result not to be dirty");
  2257.       strictEqual(result.get('foo'), 'baz');
  2258.       strictEqual(result.get('bar'), undefined,
  2259.                   "expected 'bar' field to be unset");
  2260.       return result.fetch();
  2261.     }).then(function(result) {
  2262.       strictEqual(result.get('foo'), 'baz');
  2263.       strictEqual(result.get('bar'), 1);
  2264.     }).then(function() {
  2265.       obj._clearServerData();
  2266.       var query = new Parse.Query(TestObject);
  2267.       query.select([]);
  2268.       return query.first();
  2269.     }).then(function(result) {
  2270.       ok(result.id, "expected object id to be set");
  2271.       ok(!result.dirty(), "expected result not to be dirty");
  2272.       strictEqual(result.get('foo'), undefined,
  2273.                   "expected 'foo' field to be unset");
  2274.       strictEqual(result.get('bar'), undefined,
  2275.                   "expected 'bar' field to be unset");
  2276.     }).then(function() {
  2277.       obj._clearServerData();
  2278.       var query = new Parse.Query(TestObject);
  2279.       query.select(['foo','bar']);
  2280.       return query.first();
  2281.     }).then(function(result) {
  2282.       ok(result.id, "expected object id to be set");
  2283.       ok(!result.dirty(), "expected result not to be dirty");
  2284.       strictEqual(result.get('foo'), 'baz');
  2285.       strictEqual(result.get('bar'), 1);
  2286.     }).then(function() {
  2287.       obj._clearServerData();
  2288.       var query = new Parse.Query(TestObject);
  2289.       query.select('foo', 'bar');
  2290.       return query.first();
  2291.     }).then(function(result) {
  2292.       ok(result.id, "expected object id to be set");
  2293.       ok(!result.dirty(), "expected result not to be dirty");
  2294.       strictEqual(result.get('foo'), 'baz');
  2295.       strictEqual(result.get('bar'), 1);
  2296.     }).then(function() {
  2297.       done();
  2298.     }, function (err) {
  2299.       ok(false, "other error: " + JSON.stringify(err));
  2300.       done();
  2301.     });
  2302.   });
  2303.  
  2304.   it('select keys with each query', function(done) {
  2305.     var obj = new TestObject({ foo: 'baz', bar: 1 });
  2306.  
  2307.     obj.save().then(function() {
  2308.       obj._clearServerData();
  2309.       var query = new Parse.Query(TestObject);
  2310.       query.select('foo');
  2311.       query.each(function(result) {
  2312.         ok(result.id, 'expected object id to be set');
  2313.         ok(result.createdAt, 'expected object createdAt to be set');
  2314.         ok(result.updatedAt, 'expected object updatedAt to be set');
  2315.         ok(!result.dirty(), 'expected result not to be dirty');
  2316.         strictEqual(result.get('foo'), 'baz');
  2317.         strictEqual(result.get('bar'), undefined,
  2318.                     'expected "bar" field to be unset');
  2319.       }).then(function() {
  2320.         done();
  2321.       }, function(err) {