diff --git a/src/Parse/ParseQuery.php b/src/Parse/ParseQuery.php index be7826b8..a212390d 100644 --- a/src/Parse/ParseQuery.php +++ b/src/Parse/ParseQuery.php @@ -140,7 +140,11 @@ public function get($objectId, $useMasterKey = false) */ public function equalTo($key, $value) { - $this->addCondition($key, '$eq', $value); + if (isset($this->where[$key]) && $this->isConditionMap($this->where[$key])) { + $this->addCondition($key, '$eq', $value); + } else { + $this->where[$key] = ParseClient::_encode($value, true); + } return $this; } @@ -156,12 +160,36 @@ public function equalTo($key, $value) */ private function addCondition($key, $condition, $value) { - if (!isset($this->where[$key])) { + if (!array_key_exists($key, $this->where)) { $this->where[$key] = []; + } elseif (!$this->isConditionMap($this->where[$key])) { + $this->where[$key] = ['$eq' => $this->where[$key]]; } $this->where[$key][$condition] = ParseClient::_encode($value, true); } + /** + * Checks whether a where entry is an operator map rather than a direct equality value. + * + * @param mixed $value Where entry value. + * + * @return bool + */ + private function isConditionMap($value) + { + if (!is_array($value)) { + return false; + } + + foreach ($value as $operatorKey => $_) { + if (!is_string($operatorKey) || strpos($operatorKey, '$') !== 0) { + return false; + } + } + + return !empty($value); + } + /** * Sets the conditions of this parse query from an array * diff --git a/tests/Parse/ParseQueryTest.php b/tests/Parse/ParseQueryTest.php index ae251ab1..fb891232 100644 --- a/tests/Parse/ParseQueryTest.php +++ b/tests/Parse/ParseQueryTest.php @@ -2663,9 +2663,7 @@ public function testGetAndSetConditions() $this->assertEquals([ 'where' => [ - 'key' => [ - '$eq' => 'value', - ], + 'key' => 'value', 'key2' => [ '$ne' => 'value2', ], @@ -2726,9 +2724,7 @@ public function testCountDoesNotOverrideConditions() $this->assertSame([ 'where' => [ - 'country' => [ - '$eq' => 'US' - ] + 'country' => 'US' ], 'limit' => 1, ], $query->_getOptions()); @@ -2811,4 +2807,66 @@ public function testEqualToWithSameKeyDoesNotOverrideOtherConditions() ], ], $query->_getOptions()); } + + /** + * @group query-equalTo-conditions + */ + public function testEqualToAfterDirectEqualityDoesNotOverrideOtherConditions() + { + $query = new ParseQuery('TestObject'); + $query->equalTo('status', 'active'); + $query->notEqualTo('status', 'archived'); + + $this->assertSame([ + 'where' => [ + 'status' => [ + '$eq' => 'active', + '$ne' => 'archived', + ] + ], + ], $query->_getOptions()); + } + + /** + * @group query-equalTo-conditions + */ + public function testEqualToNullBeforeConditionPreservesNullEquality() + { + $query = new ParseQuery('TestObject'); + $query->equalTo('status', null); + $query->notEqualTo('status', 'archived'); + + $this->assertSame([ + 'where' => [ + 'status' => [ + '$eq' => null, + '$ne' => 'archived', + ] + ], + ], $query->_getOptions()); + } + + /** + * @group query-equalTo-conditions + */ + public function testEqualToPointerSerializesAsDirectWhereValue() + { + $user = new ParseObject('_User'); + $user->_mergeAfterFetch([ + 'objectId' => 'someUserId', + ]); + + $query = new ParseQuery('_Role'); + $query->equalTo('users', $user); + + $this->assertSame([ + 'where' => [ + 'users' => [ + '__type' => 'Pointer', + 'className' => '_User', + 'objectId' => 'someUserId', + ], + ], + ], $query->_getOptions()); + } }