Browse Source

Add tuple comparison integration tests.

ndm2 4 years ago
parent
commit
b261961550

+ 195 - 0
tests/TestCase/Database/QueryTests/TupleComparisonQueryTest.php

@@ -17,10 +17,13 @@ declare(strict_types=1);
 
 namespace Cake\Test\TestCase\Database\QueryTests;
 
+use Cake\Database\Driver\Mysql;
+use Cake\Database\Driver\Postgres;
 use Cake\Database\Driver\Sqlite;
 use Cake\Database\Driver\Sqlserver;
 use Cake\Database\Expression\TupleComparison;
 use Cake\TestSuite\TestCase;
+use PDOException;
 use RuntimeException;
 
 /**
@@ -77,4 +80,196 @@ class TupleComparisonQueryTest extends TestCase
             ->disableHydration()
             ->toArray();
     }
+
+    public function testInWithMultiResultSubquery(): void
+    {
+        $articles = $this->getTableLocator()->get('Articles');
+
+        $query = $articles
+            ->find()
+            ->select(['Articles.id', 'Articles.author_id'])
+            ->where([
+                new TupleComparison(
+                    ['Articles.id', 'Articles.author_id'],
+                    $articles
+                        ->subquery()
+                        ->select(['ArticlesAlias.id', 'ArticlesAlias.author_id'])
+                        ->from(['ArticlesAlias' => $articles->getTable()])
+                        ->where(['ArticlesAlias.author_id' => 1]),
+                    [],
+                    'IN'
+                ),
+            ])
+            ->orderAsc('Articles.id')
+            ->disableHydration();
+
+        $expected = [
+            [
+                'id' => 1,
+                'author_id' => 1,
+            ],
+            [
+                'id' => 3,
+                'author_id' => 1,
+            ],
+        ];
+        $this->assertSame($expected, $query->toArray());
+    }
+
+    public function testInWithSingleResultSubquery(): void
+    {
+        $articles = $this->getTableLocator()->get('Articles');
+
+        $query = $articles
+            ->find()
+            ->select(['Articles.id', 'Articles.author_id'])
+            ->where([
+                new TupleComparison(
+                    ['Articles.id', 'Articles.author_id'],
+                    $articles
+                        ->subquery()
+                        ->select(['ArticlesAlias.id', 'ArticlesAlias.author_id'])
+                        ->from(['ArticlesAlias' => $articles->getTable()])
+                        ->where(['ArticlesAlias.id' => 1]),
+                    [],
+                    'IN'
+                ),
+            ])
+            ->disableHydration();
+
+        $expected = [
+            [
+                'id' => 1,
+                'author_id' => 1,
+            ],
+        ];
+        $this->assertSame($expected, $query->toArray());
+    }
+
+    public function testInWithMultiArrayValues(): void
+    {
+        $articles = $this->getTableLocator()->get('Articles');
+
+        $query = $articles
+            ->find()
+            ->select(['Articles.id', 'Articles.author_id'])
+            ->where([
+                new TupleComparison(
+                    ['Articles.id', 'Articles.author_id'],
+                    [[1, 1], [3, 1]],
+                    ['integer', 'integer'],
+                    'IN'
+                ),
+            ])
+            ->orderAsc('Articles.id')
+            ->disableHydration();
+
+        $expected = [
+            [
+                'id' => 1,
+                'author_id' => 1,
+            ],
+            [
+                'id' => 3,
+                'author_id' => 1,
+            ],
+        ];
+        $this->assertSame($expected, $query->toArray());
+    }
+
+    public function testEqualWithMultiResultSubquery(): void
+    {
+        $articles = $this->getTableLocator()->get('Articles');
+
+        $driver = $articles->getConnection()->getDriver();
+        if (
+            $driver instanceof Mysql ||
+            $driver instanceof Postgres
+        ) {
+            $this->expectException(PDOException::class);
+            $this->expectExceptionMessageMatches('/cardinality violation/i');
+        } else {
+            // Due to the way tuple comparisons are being translated, the DBMS will
+            // not run into a cardinality violation scenario.
+            $this->markTestSkipped(
+                'Sqlite and Sqlserver currently do not fail with subqueries returning incompatible results.'
+            );
+        }
+
+        $articles
+            ->find()
+            ->select(['Articles.id', 'Articles.author_id'])
+            ->where([
+                new TupleComparison(
+                    ['Articles.id', 'Articles.author_id'],
+                    $articles
+                        ->subquery()
+                        ->select(['ArticlesAlias.id', 'ArticlesAlias.author_id'])
+                        ->from(['ArticlesAlias' => $articles->getTable()])
+                        ->where(['ArticlesAlias.author_id' => 1]),
+                    [],
+                    '='
+                ),
+            ])
+            ->orderAsc('Articles.id')
+            ->disableHydration()
+            ->toArray();
+    }
+
+    public function testEqualWithSingleResultSubquery(): void
+    {
+        $articles = $this->getTableLocator()->get('Articles');
+
+        $query = $articles
+            ->find()
+            ->select(['Articles.id', 'Articles.author_id'])
+            ->where([
+                new TupleComparison(
+                    ['Articles.id', 'Articles.author_id'],
+                    $articles
+                        ->subquery()
+                        ->select(['ArticlesAlias.id', 'ArticlesAlias.author_id'])
+                        ->from(['ArticlesAlias' => $articles->getTable()])
+                        ->where(['ArticlesAlias.id' => 1]),
+                    [],
+                    '='
+                ),
+            ])
+            ->disableHydration();
+
+        $expected = [
+            [
+                'id' => 1,
+                'author_id' => 1,
+            ],
+        ];
+        $this->assertSame($expected, $query->toArray());
+    }
+
+    public function testEqualWithSingleArrayValue(): void
+    {
+        $articles = $this->getTableLocator()->get('Articles');
+
+        $query = $articles
+            ->find()
+            ->select(['Articles.id', 'Articles.author_id'])
+            ->where([
+                new TupleComparison(
+                    ['Articles.id', 'Articles.author_id'],
+                    [1, 1],
+                    ['integer', 'integer'],
+                    '='
+                ),
+            ])
+            ->orderAsc('Articles.id')
+            ->disableHydration();
+
+        $expected = [
+            [
+                'id' => 1,
+                'author_id' => 1,
+            ],
+        ];
+        $this->assertSame($expected, $query->toArray());
+    }
 }

+ 0 - 46
tests/TestCase/ORM/QueryRegressionTest.php

@@ -19,7 +19,6 @@ namespace Cake\Test\TestCase\ORM;
 use Cake\Database\Driver\Sqlserver;
 use Cake\Database\Expression\ComparisonExpression;
 use Cake\Database\Expression\QueryExpression;
-use Cake\Database\Expression\TupleComparison;
 use Cake\Datasource\EntityInterface;
 use Cake\Event\EventInterface;
 use Cake\I18n\FrozenTime;
@@ -1751,49 +1750,4 @@ class QueryRegressionTest extends TestCase
         $result = $query->first()->get('value');
         $this->assertSame('mariano appended', $result);
     }
-
-    /**
-     * Tests that tuple comparisons can use multiple fields and subqueries
-     * for an `IN` lookup of multiple results.
-     *
-     * This test is specifically relevant in the context of Sqlite and
-     * Sqlserver, for which the tuple comparison will be transformed when
-     * composite keys are used.
-     *
-     * @see \Cake\Database\Driver\TupleComparisonTranslatorTrait::_transformTupleComparison()
-     */
-    public function testTupleComparisonWithCompositeKeysAndSubqueries(): void
-    {
-        $articles = $this->getTableLocator()->get('Articles');
-
-        $query = $articles
-            ->find()
-            ->select(['id', 'author_id'])
-            ->where(
-                new TupleComparison(
-                    ['Articles.id', 'Articles.author_id'],
-                    $articles
-                        ->subquery()
-                        ->select(['ArticlesAlias.id', 'ArticlesAlias.author_id'])
-                        ->from(['ArticlesAlias' => $articles->getTable()])
-                        ->where(['ArticlesAlias.author_id' => 1]),
-                    [],
-                    'IN'
-                )
-            )
-            ->orderAsc('id')
-            ->disableHydration();
-
-        $expected = [
-            [
-                'id' => 1,
-                'author_id' => 1,
-            ],
-            [
-                'id' => 3,
-                'author_id' => 1,
-            ],
-        ];
-        $this->assertSame($expected, $query->toArray());
-    }
 }