diff --git a/src/Parse/ParseQuery.php b/src/Parse/ParseQuery.php index c024aaf6..5e294b0f 100755 --- a/src/Parse/ParseQuery.php +++ b/src/Parse/ParseQuery.php @@ -1040,6 +1040,62 @@ public function doesNotMatchKeyInQuery($key, $queryKey, $query) * @return ParseQuery The query that is the OR of the passed in queries. */ public static function orQueries($queryObjects) + { + $className = self::_matchClassName($queryObjects); + $query = new self($className); + $query->_or($queryObjects); + + return $query; + } + + /** + * Constructs a ParseQuery object that is the NOR of the passed in queries objects. + * All queries must have same class name. + * + * @param array $queryObjects Array of ParseQuery objects to NOR. + * + * @throws \Exception If all queries don't have same class. + * + * @return ParseQuery The query that is the NOR of the passed in queries. + */ + public static function norQueries($queryObjects) + { + $className = self::_matchClassName($queryObjects); + $query = new self($className); + $query->_nor($queryObjects); + + return $query; + } + + /** + * Constructs a ParseQuery object that is the AND of the passed in queries objects. + * All queries must have same class name. + * + * @param array $queryObjects Array of ParseQuery objects to AND. + * + * @throws \Exception If all queries don't have same class. + * + * @return ParseQuery The query that is the AND of the passed in queries. + */ + public static function andQueries($queryObjects) + { + $className = self::_matchClassName($queryObjects); + $query = new self($className); + $query->_and($queryObjects); + + return $query; + } + + /** + * All queries must have same class name. + * + * @param array $queryObjects Array of ParseQuery objects. + * + * @throws \Exception If all queries don't have same class. + * + * @return string class name. + */ + private static function _matchClassname($queryObjects) { $className = null; $length = count($queryObjects); @@ -1051,10 +1107,7 @@ public static function orQueries($queryObjects) throw new Exception('All queries must be for the same class', 103); } } - $query = new self($className); - $query->_or($queryObjects); - - return $query; + return $className; } /** @@ -1066,10 +1119,47 @@ public static function orQueries($queryObjects) */ private function _or($queries) { - $this->where['$or'] = []; + return $this->_mergeQueries('$or', $queries); + } + + /** + * Add constraint that at none of the passed in queries matches. + * + * @param array $queries The list of queries to NOR. + * + * @return ParseQuery Returns the query, so you can chain this call. + */ + private function _nor($queries) + { + return $this->_mergeQueries('$nor', $queries); + } + + /** + * Add constraint that at all of the passed in queries matches. + * + * @param array $queries The list of queries to OR. + * + * @return ParseQuery Returns the query, so you can chain this call. + */ + private function _and($queries) + { + return $this->_mergeQueries('$and', $queries); + } + + /** + * Combines queries for NOR, AND, OR queries. + * + * @param string $key The condition $and, $or, $nor. + * @param array $queries The list of queries to combine. + * + * @return ParseQuery Returns the query, so you can chain this call. + */ + private function _mergeQueries($key, $queries) + { + $this->where[$key] = []; $length = count($queries); for ($i = 0; $i < $length; $i++) { - $this->where['$or'][] = $queries[$i]->where; + $this->where[$key][] = $queries[$i]->where; } return $this; diff --git a/tests/Parse/ParseQueryTest.php b/tests/Parse/ParseQueryTest.php index d773bb9c..0793c6b5 100644 --- a/tests/Parse/ParseQueryTest.php +++ b/tests/Parse/ParseQueryTest.php @@ -1053,6 +1053,54 @@ public function testOrQueries() } } + public function testNorQueries() + { + $this->provideTestObjects(10); + $subQuery1 = new ParseQuery('TestObject'); + $subQuery1->lessThan('foo', 'bar3'); + $subQuery2 = new ParseQuery('TestObject'); + $subQuery2->greaterThan('foo', 'bar5'); + + $mainQuery = ParseQuery::norQueries([$subQuery1, $subQuery2]); + $results = $mainQuery->find(); + $length = count($results); + $this->assertEquals( + 3, + $length, + 'Did not return correct number of objects.' + ); + for ($i = 0; $i < $length; ++$i) { + $this->assertTrue( + $results[$i]->get('foo') >= 'bar3' || + $results[$i]->get('foo') <= 'bar5', + 'Did not return the correct object.' + ); + } + } + + public function testAndQueries() + { + Helper::clearClass('ChildObject'); + Helper::clearClass('ParentObject'); + $this->provideTestObjectsForQuery(10); + $subQuery = new ParseQuery('ChildObject'); + $subQuery->equalTo('x', 4); + $q1 = new ParseQuery('ParentObject'); + $q1->matchesQuery('child', $subQuery); + $q2 = new ParseQuery('ParentObject'); + $q2->equalTo('x', 14); + + $mainQuery = ParseQuery::andQueries([$q1, $q2]); + $results = $mainQuery->find(); + $length = count($results); + $this->assertEquals( + 1, + $length, + 'Did not return correct number of objects.' + ); + $this->assertTrue($results[0]->get('x') == 14); + } + public function testComplexQueries() { Helper::clearClass('Child'); @@ -2249,6 +2297,30 @@ public function testOrQueriesVaryingClasses() ]); } + public function testNorQueriesVaryingClasses() + { + $this->setExpectedException( + '\Exception', + 'All queries must be for the same class' + ); + ParseQuery::norQueries([ + new ParseQuery('Class1'), + new ParseQuery('Class2') + ]); + } + + public function testAndQueriesVaryingClasses() + { + $this->setExpectedException( + '\Exception', + 'All queries must be for the same class' + ); + ParseQuery::andQueries([ + new ParseQuery('Class1'), + new ParseQuery('Class2') + ]); + } + /** * @group query-set-conditions */ @@ -2338,7 +2410,7 @@ public function testUnknownCondition() '\Parse\ParseException', 'Unknown condition to set' ); - + $query = new ParseQuery('TestObject'); $query->_setConditions([ 'unrecognized' => 1