Browse Source

Add ORM date functions

Ladislav Gallay 10 years ago
parent
commit
9d2dc4df4c

+ 12 - 0
src/Database/Dialect/PostgresDialectTrait.php

@@ -129,6 +129,18 @@ trait PostgresDialectTrait
             case 'NOW':
                 $expression->name('LOCALTIMESTAMP')->add([' 0 ' => 'literal']);
                 break;
+            case 'DATE_ADD':
+                $expression
+                    ->name('')
+                    ->type(' + INTERVAL')
+                    ->iterateParts(function ($p, $key) {
+                        if ($key === 1) {
+                            $interval = sprintf("'%s'", key($p));
+                            $p = [$interval => 'literal'];
+                        }
+                        return $p;
+                    });
+                break;
         }
     }
 

+ 39 - 0
src/Database/Dialect/SqliteDialectTrait.php

@@ -53,6 +53,21 @@ trait SqliteDialectTrait
     protected $_schemaDialect;
 
     /**
+     * Mapping of date parts.
+     *
+     * @var array
+     */
+    protected $_dateParts = [
+        'day' => 'd',
+        'hour' => 'H',
+        'month' => 'm',
+        'minute' => 'M',
+        'second' => 'S',
+        'week' => 'W',
+        'year' => 'Y'
+    ];
+
+    /**
      * Returns a dictionary of expressions to be transformed when compiling a Query
      * to SQL. Array keys are method names to be called in this class
      *
@@ -99,6 +114,30 @@ trait SqliteDialectTrait
             case 'CURRENT_TIME':
                 $expression->name('TIME')->add(["'now'" => 'literal']);
                 break;
+            case 'EXTRACT':
+                $expression
+                    ->name('STRFTIME')
+                    ->type(' ,')
+                    ->iterateParts(function ($p, $key) {
+                        if ($key === 0) {
+                            $value = rtrim(key($p), 's');
+                            if (isset($this->_dateParts[$value])) {
+                                $p = '%' . $this->_dateParts[$value];
+                            }
+                        }
+                        return $p;
+                    });
+                break;
+            case 'DATE_ADD':
+                $expression
+                    ->name('DATE')
+                    ->type(',')
+                    ->iterateParts(function ($p, $key) {
+                        if ($key === 1) {
+                            $p = key($p);
+                        }
+                        return $p;
+                    });
         }
     }
 

+ 26 - 0
src/Database/Dialect/SqlserverDialectTrait.php

@@ -236,6 +236,32 @@ trait SqlserverDialectTrait
             case 'NOW':
                 $expression->name('GETUTCDATE');
                 break;
+            case 'EXTRACT':
+                $expression->name('DATEPART')->type(' ,');
+                break;
+            case 'DATE_ADD':
+                $params = [];
+                $visitor = function ($p, $key) (&$params) {
+                    if ($key === 0) {
+                        $params[2] = $value;
+                    } else {
+                        $valueUnit = explode(' ', key($p));
+                        $params[0] = $valueUnit[1];
+                        $params[1] = $valueUnit[0];
+                    }
+                    return $p;
+                });
+                $manipulator = function ($p, $key) ($params) {
+                    return $params[$key];
+                };
+
+                $expression
+                    ->name('DATEADD')
+                    ->type(',')
+                    ->iterateParts($visitor)
+                    ->iterateParts($manipulator)
+                    ->add($params[2]);
+                break;
         }
     }
 

+ 45 - 0
src/Database/FunctionsBuilder.php

@@ -155,6 +155,51 @@ class FunctionsBuilder
     }
 
     /**
+     * Returns the specified date part from the SQL expression.
+     *
+     * @param string $part Part of the date to return.
+     * @param string $expression Expression to obtain the date part from.
+     * @param array $types list of types to bind to the arguments
+     * @return FunctionExpression
+     */
+    public function datePart($part, $expression, $types = [])
+    {
+        return $this->extract($part, $expression);
+    }
+
+    /**
+     * Returns the specified date part from the SQL expression.
+     *
+     * @param string $part Part of the date to return.
+     * @param string $expression Expression to obtain the date part from.
+     * @param array $types list of types to bind to the arguments
+     * @return FunctionExpression
+     */
+    public function extract($part, $expression, $types = [])
+    {
+        $expression = $this->_literalArgumentFunction('EXTRACT', $expression, $types);
+        $expression->type(' FROM')->add([$part => 'literal'], [], true);
+        return $expression;
+    }
+
+    /**
+     * Add the time unit to the date expression
+     *
+     * @param string $expression Expression to obtain the date part from.
+     * @param string $value Value to be added. Use negative to substract.
+     * @param string $unit Unit of the value e.g. hour or day.
+     * @param array $types list of types to bind to the arguments
+     * @return FunctionExpression
+     */
+    public function dateAdd($expression, $value, $unit, $types = [])
+    {
+        $interval = $value . ' ' . $unit;
+        $expression = $this->_literalArgumentFunction('DATE_ADD', $expression, $types);
+        $expression->type(', INTERVAL')->add([$interval => 'literal']);
+        return $expression;
+    }
+
+    /**
      * Returns a FunctionExpression representing a call that will return the current
      * date and time. By default it returns both date and time, but you can also
      * make it generate only the date or only the time.

+ 28 - 0
tests/TestCase/Database/FunctionsBuilderTest.php

@@ -151,4 +151,32 @@ class FunctionsBuilderTest extends TestCase
         $this->assertInstanceOf('Cake\Database\Expression\FunctionExpression', $function);
         $this->assertEquals("CURRENT_TIME()", $function->sql(new ValueBinder));
     }
+
+    /**
+     * Tests generating a EXTRACT() function
+     *
+     * @return void
+     */
+    public function testExtract()
+    {
+        $function = $this->functions->extract('day', 'created');
+        $this->assertInstanceOf('Cake\Database\Expression\FunctionExpression', $function);
+        $this->assertEquals("EXTRACT(day FROM created)", $function->sql(new ValueBinder));
+
+        $function = $this->functions->datePart('year', 'modified');
+        $this->assertInstanceOf('Cake\Database\Expression\FunctionExpression', $function);
+        $this->assertEquals("EXTRACT(year FROM modified)", $function->sql(new ValueBinder));
+    }
+
+    /**
+     * Tests generating a DATE_ADD() function
+     *
+     * @return void
+     */
+    public function testExtract()
+    {
+        $function = $this->functions->dateAdd('created', -3, 'day');
+        $this->assertInstanceOf('Cake\Database\Expression\FunctionExpression', $function);
+        $this->assertEquals("DATE_ADD(created, INTERVAL -3 day)", $function->sql(new ValueBinder));
+    }
 }