Browse Source

Added CommonTableExpression::recursive() and removed Query::withRecursive()

Corey Taylor 5 years ago
parent
commit
3fce2fd84d

+ 30 - 1
src/Database/Expression/CommonTableExpression.php

@@ -55,6 +55,13 @@ class CommonTableExpression implements ExpressionInterface
     protected $materialized = null;
 
     /**
+     * Whether the CTE is recursive.
+     *
+     * @var bool
+     */
+    protected $recursive = false;
+
+    /**
      * Constructor.
      *
      * @param string $name The CTE name.
@@ -96,7 +103,7 @@ class CommonTableExpression implements ExpressionInterface
             $query = $query();
             if (!($query instanceof ExpressionInterface)) {
                 throw new RuntimeException(
-                    'You must return an `ExpressionInterface` from closure passed to `query()`.'
+                    'You must return an `ExpressionInterface` from a Closure passed to `query()`.'
                 );
             }
         }
@@ -149,6 +156,28 @@ class CommonTableExpression implements ExpressionInterface
     }
 
     /**
+     * Gets whether this CTE is recursive.
+     *
+     * @return bool
+     */
+    public function isRecursive(): bool
+    {
+        return $this->recursive;
+    }
+
+    /**
+     * Sets this CTE as recursive.
+     *
+     * @return $this
+     */
+    public function recursive()
+    {
+        $this->recursive = true;
+
+        return $this;
+    }
+
+    /**
      * @inheritDoc
      */
     public function sql(ValueBinder $generator): string

+ 3 - 16
src/Database/Query.php

@@ -414,11 +414,10 @@ class Query implements ExpressionInterface, IteratorAggregate
      * ```
      *
      * @param \Closure|\Cake\Database\Expression\CommonTableExpression $cte The CTE to add.
-     * @param bool $recursive Whether the CTE is recursive.
      * @param bool $overwrite Whether to reset the list of CTEs.
      * @return $this
      */
-    public function with($cte, bool $recursive = false, bool $overwrite = false)
+    public function with($cte, bool $overwrite = false)
     {
         if ($overwrite) {
             $this->_parts['with'] = [];
@@ -428,30 +427,18 @@ class Query implements ExpressionInterface, IteratorAggregate
             $cte = $cte(new CommonTableExpression(), $this);
             if (!($cte instanceof CommonTableExpression)) {
                 throw new RuntimeException(
-                    'You must return a `CommonTableExpression` from closure passed to `with()`.'
+                    'You must return a `CommonTableExpression` from a Closure passed to `with()`.'
                 );
             }
         }
 
-        $this->_parts['with'][] = ['cte' => $cte, 'recursive' => $recursive];
+        $this->_parts['with'][] = $cte;
         $this->_dirty();
 
         return $this;
     }
 
     /**
-     * Adds a new recursive common table expression (CTE) to the query.
-     *
-     * @param \Closure|\Cake\Database\Expression\CommonTableExpression $cte The CTE to add.
-     * @param bool $overwrite Whether to reset the list of CTEs.
-     * @return $this
-     */
-    public function withRecursive($cte, bool $overwrite = false)
-    {
-        return $this->with($cte, true, $overwrite);
-    }
-
-    /**
      * Adds new fields to be returned by a `SELECT` statement when this query is
      * executed. Fields can be passed as an array of strings, array of expression
      * objects, a single expression or a single string.

+ 2 - 2
src/Database/QueryCompiler.php

@@ -172,8 +172,8 @@ class QueryCompiler
         $recursive = false;
         $expressions = [];
         foreach ($parts as $cte) {
-            $recursive = $recursive || $cte['recursive'];
-            $expressions[] = $cte['cte']->sql($generator);
+            $recursive = $recursive || $cte->isRecursive();
+            $expressions[] = $cte->sql($generator);
         }
 
         $recursive = $recursive ? 'RECURSIVE ' : '';

+ 1 - 1
src/Database/SqlserverCompiler.php

@@ -67,7 +67,7 @@ class SqlserverCompiler extends QueryCompiler
     {
         $expressions = [];
         foreach ($parts as $cte) {
-            $expressions[] = $cte['cte']->sql($generator);
+            $expressions[] = $cte->sql($generator);
         }
 
         return sprintf('WITH %s ', implode(', ', $expressions));

+ 4 - 3
tests/TestCase/Database/CommonTableExpressionQueryTests.php

@@ -117,7 +117,7 @@ class CommonTableExpressionQueryTests extends TestCase
         );
 
         $query
-            ->with(new CommonTableExpression('cte2', $this->connection->newQuery()), false, true)
+            ->with(new CommonTableExpression('cte2', $this->connection->newQuery()), true)
             ->from('cte2', true);
         $this->assertEqualsSql(
             'WITH cte2 AS () SELECT col FROM cte2',
@@ -133,7 +133,7 @@ class CommonTableExpressionQueryTests extends TestCase
     public function testWithRecursiveCte()
     {
         $query = $this->connection->newQuery()
-            ->withRecursive(function (CommonTableExpression $cte, Query $query) {
+            ->with(function (CommonTableExpression $cte, Query $query) {
                 $anchorQuery = $query->getConnection()
                     ->newQuery()
                     ->select(1);
@@ -151,7 +151,8 @@ class CommonTableExpressionQueryTests extends TestCase
                 return $cte
                     ->name('cte')
                     ->field(['col'])
-                    ->query($cteQuery);
+                    ->query($cteQuery)
+                    ->recursive();
             })
             ->select('col')
             ->from('cte');

+ 12 - 0
tests/TestCase/Database/Expression/CommonTableExpressionTest.php

@@ -86,6 +86,18 @@ class CommonTableExpressionTest extends TestCase
     }
 
     /**
+     * Tests setting CTE as recursive.
+     *
+     * @return void
+     */
+    public function testRecursive()
+    {
+        $cte = (new CommonTableExpression('test', $this->connection->newQuery()))
+            ->recursive();
+        $this->assertTrue($cte->isRecursive());
+    }
+
+    /**
      * Tests setting query using closures.
      *
      * @return void