From b5fd237cfe4314ff20291aa0a3b4807180ed2301 Mon Sep 17 00:00:00 2001 From: Stephan de Souza Date: Fri, 15 Jan 2021 10:16:51 -0300 Subject: [PATCH 1/4] Fixes `has` with numeric keys. --- .../Mongodb/Helpers/QueriesRelationships.php | 4 +++- tests/RelationsTest.php | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php b/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php index 151ead62d..8efa3cd24 100644 --- a/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php +++ b/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php @@ -145,7 +145,9 @@ protected function getConstrainedRelatedIds($relations, $operator, $count) }); // All related ids. - return array_keys($relationCount); + return array_map(static function ($id) { + return (string) $id; + }, array_keys($relationCount)); } /** diff --git a/tests/RelationsTest.php b/tests/RelationsTest.php index 86065aac3..dc592c5a6 100644 --- a/tests/RelationsTest.php +++ b/tests/RelationsTest.php @@ -436,6 +436,16 @@ public function testHasManyHas(): void $this->assertCount(1, $authors); } + public function testHasNumeric(): void + { + $author1 = User::create(['_id' => '1', 'name' => 'George R. R. Martin']); + $author1->books()->create(['_id' => '1', 'title' => 'A Game of Thrones', 'rating' => 5]); + $author1->books()->create(['_id' => '2', 'title' => 'A Clash of Kings', 'rating' => 5]); + + $authors = User::has('books', '>', 1)->get(); + $this->assertCount(1, $authors); + } + public function testHasOneHas(): void { $user1 = User::create(['name' => 'John Doe']); From 0918c68536ef01cc53466e9e815bd82bb11ff521 Mon Sep 17 00:00:00 2001 From: Stephan de Souza Date: Fri, 15 Jan 2021 15:57:45 -0300 Subject: [PATCH 2/4] Fixes `has` with numeric keys on hybrid relations. --- .../Mongodb/Helpers/QueriesRelationships.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php b/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php index 8efa3cd24..5de2e5f7e 100644 --- a/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php +++ b/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php @@ -122,7 +122,11 @@ protected function getHasCompareKey(Relation $relation) */ protected function getConstrainedRelatedIds($relations, $operator, $count) { - $relationCount = array_count_values(array_map(function ($id) { + $intHash = 'INT_RELATION_'; + $relationCount = array_count_values(array_map(function ($id) use ($intHash) { + if (!is_string($id) && is_int($id)) { + return $intHash . $id; + } return (string) $id; // Convert Back ObjectIds to Strings }, is_array($relations) ? $relations : $relations->flatten()->toArray())); // Remove unwanted related objects based on the operator and count. @@ -145,7 +149,10 @@ protected function getConstrainedRelatedIds($relations, $operator, $count) }); // All related ids. - return array_map(static function ($id) { + return array_map(static function ($id) use ($intHash) { + if (strpos($id, $intHash, 0) === 0) { + return (int) str_replace($intHash, '', $id); + } return (string) $id; }, array_keys($relationCount)); } From c2bbc5c0238652f6e53adde1a21f4dcbfe9ad786 Mon Sep 17 00:00:00 2001 From: Stephan de Souza Date: Tue, 11 May 2021 08:25:12 -0300 Subject: [PATCH 3/4] Optimizing int related id handling - Fixes StyleCI --- .../Mongodb/Helpers/QueriesRelationships.php | 26 +++++++++++++------ tests/RelationsTest.php | 8 ++++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php b/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php index 5de2e5f7e..acddb0dd4 100644 --- a/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php +++ b/src/Jenssegers/Mongodb/Helpers/QueriesRelationships.php @@ -71,7 +71,7 @@ protected function isAcrossConnections(Relation $relation) } /** - * Compare across databases + * Compare across databases. * @param Relation $relation * @param string $operator * @param int $count @@ -91,7 +91,7 @@ public function addHybridHas(Relation $relation, $operator = '>=', $count = 1, $ $not = in_array($operator, ['<', '<=', '!=']); // If we are comparing to 0, we need an additional $not flip. if ($count == 0) { - $not = !$not; + $not = ! $not; } $relations = $hasQuery->pluck($this->getHasCompareKey($relation)); @@ -123,10 +123,14 @@ protected function getHasCompareKey(Relation $relation) protected function getConstrainedRelatedIds($relations, $operator, $count) { $intHash = 'INT_RELATION_'; - $relationCount = array_count_values(array_map(function ($id) use ($intHash) { - if (!is_string($id) && is_int($id)) { - return $intHash . $id; + $hasNumericIndex = false; + $relationCount = array_count_values(array_map(function ($id) use ($intHash, &$hasNumericIndex) { + if (! is_string($id) && is_int($id)) { + $hasNumericIndex = true; + + return $intHash.$id; } + return (string) $id; // Convert Back ObjectIds to Strings }, is_array($relations) ? $relations : $relations->flatten()->toArray())); // Remove unwanted related objects based on the operator and count. @@ -149,16 +153,22 @@ protected function getConstrainedRelatedIds($relations, $operator, $count) }); // All related ids. + if (! $hasNumericIndex) { + return array_keys($relationCount); + } + + // Has any numeric index? return array_map(static function ($id) use ($intHash) { if (strpos($id, $intHash, 0) === 0) { return (int) str_replace($intHash, '', $id); } + return (string) $id; }, array_keys($relationCount)); } /** - * Returns key we are constraining this parent model's query with + * Returns key we are constraining this parent model's query with. * @param Relation $relation * @return string * @throws Exception @@ -173,10 +183,10 @@ protected function getRelatedConstraintKey(Relation $relation) return $relation->getForeignKeyName(); } - if ($relation instanceof BelongsToMany && !$this->isAcrossConnections($relation)) { + if ($relation instanceof BelongsToMany && ! $this->isAcrossConnections($relation)) { return $this->model->getKeyName(); } - throw new Exception(class_basename($relation) . ' is not supported for hybrid query constraints.'); + throw new Exception(class_basename($relation).' is not supported for hybrid query constraints.'); } } diff --git a/tests/RelationsTest.php b/tests/RelationsTest.php index dc592c5a6..1ab49377b 100644 --- a/tests/RelationsTest.php +++ b/tests/RelationsTest.php @@ -1,4 +1,5 @@ '1', 'name' => 'George R. R. Martin']); - $author1->books()->create(['_id' => '1', 'title' => 'A Game of Thrones', 'rating' => 5]); + $author1 = User::create(['name' => 'George R. R. Martin']); + $author1->books()->create(['title' => 'A Game of Thrones', 'rating' => 5]); $author1->books()->create(['_id' => '2', 'title' => 'A Clash of Kings', 'rating' => 5]); + $author2 = User::create(['name' => 'John Doe']); + $author2->books()->create(['title' => 'My book', 'rating' => 2]); + $authors = User::has('books', '>', 1)->get(); $this->assertCount(1, $authors); } From 428eacd08aa5f788bb0b8f01dd6f61b6d9c0f97b Mon Sep 17 00:00:00 2001 From: Stephan de Souza Date: Wed, 12 May 2021 15:48:55 -0300 Subject: [PATCH 4/4] Fixing tests --- tests/RelationsTest.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/RelationsTest.php b/tests/RelationsTest.php index 1ab49377b..5046ef4bc 100644 --- a/tests/RelationsTest.php +++ b/tests/RelationsTest.php @@ -439,15 +439,22 @@ public function testHasManyHas(): void public function testHasNumeric(): void { - $author1 = User::create(['name' => 'George R. R. Martin']); + $author1 = User::create(['_id' => 1, 'name' => 'George R. R. Martin']); $author1->books()->create(['title' => 'A Game of Thrones', 'rating' => 5]); - $author1->books()->create(['_id' => '2', 'title' => 'A Clash of Kings', 'rating' => 5]); + $author1->books()->create(['title' => 'A Clash of Kings', 'rating' => 5]); - $author2 = User::create(['name' => 'John Doe']); + // Mixing with int passed as string + $author2 = User::create(['_id' => '2', 'name' => 'John Doe']); $author2->books()->create(['title' => 'My book', 'rating' => 2]); $authors = User::has('books', '>', 1)->get(); $this->assertCount(1, $authors); + + $authors = User::has('books')->get(); + $this->assertCount(2, $authors); + + $authors = User::has('books', '>', 2)->get(); + $this->assertCount(0, $authors); } public function testHasOneHas(): void