diff --git a/doc/book/sql-ddl.md b/doc/book/sql-ddl.md index 8dd4467ab2..d187cb90da 100644 --- a/doc/book/sql-ddl.md +++ b/doc/book/sql-ddl.md @@ -115,13 +115,13 @@ use Zend\Db\Sql\Sql; $sql = new Sql($adapter); $adapter->query( - $sql->getSqlStringForSqlObject($ddl), + $sql->buildSqlString($ddl), $adapter::QUERY_MODE_EXECUTE ); ``` By passing the `$ddl` object through the `$sql` instance's -`getSqlStringForSqlObject()` method, we ensure that any platform specific +`buildSqlString()` method, we ensure that any platform specific specializations/modifications are utilized to create a platform specific SQL statement. diff --git a/doc/book/sql.md b/doc/book/sql.md index 9b6392b252..91796f62cc 100644 --- a/doc/book/sql.md +++ b/doc/book/sql.md @@ -43,7 +43,7 @@ $select = $sql->select(); $select->from('foo'); $select->where(['id' => 2]); -$statement = $sql->prepareStatementForSqlObject($select); +$statement = $sql->prepareSqlStatement($select); $results = $statement->execute(); ``` @@ -78,19 +78,16 @@ $select->where(['id' => 2]); // $select already has from('foo') applied Each of these objects implements the following two interfaces: ```php -interface PreparableSqlInterface +interface SelectableInterface { - public function prepareStatement(Adapter $adapter, StatementInterface $statement) : void; } -interface SqlInterface +interface PreparableSqlInterface { - public function getSqlString(PlatformInterface $adapterPlatform = null) : string; } ``` -Use these functions to produce either (a) a prepared statement, or (b) a string -to execute. +Use these interfaces for create user defined sql objects. ## Select @@ -113,22 +110,33 @@ Once you have a valid `Select` object, the following API can be used to further specify various select statement parts: ```php -class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface +class Select extends AbstractSql implements PreparableSqlInterface, SelectableInterface { - const JOIN_INNER = 'inner'; - const JOIN_OUTER = 'outer'; - const JOIN_LEFT = 'left'; - const JOIN_RIGHT = 'right'; + const QUANTIFIER_DISTINCT = 'DISTINCT'; + const QUANTIFIER_ALL = 'ALL'; const SQL_STAR = '*'; const ORDER_ASCENDING = 'ASC'; const ORDER_DESCENDING = 'DESC'; + public $table // @param TableSource $table + public $quantifier; // @param string|Expression $quantifier DISTINCT|ALL + public $columns; // @param array $columns + public $joins; // @param $joins public $where; // @param Where $where - - public function __construct(string|array|TableIdentifier $table = null); - public function from(string|array|TableIdentifier $table) : self; - public function columns(array $columns, bool $prefixColumnsWithTable = true) : self; - public function join(string|array $name, string $on, string|array $columns = self::SQL_STAR, string $type = self::JOIN_INNER) : self; + public $order; // @param string|array $order + public $group; // @param $group + public $having; // @param Having $having + public $limit; // @param int $limit + public $offset; // @param int $offset + public $combine; // @param $combine + public $prefixColumnsWithTable; // @param $prefixColumnsWithTable + + public function __construct(null|string|array|TableIdentifier|TableSource $table = null); + public function from(string|array|TableIdentifier|TableSource $table) : self; + public function quantifier(string|ExpressionInterface $quantifier) :self; + public function columns(array $columns) : self; + public function setPrefixColumnsWithTable(bool $flag) :self; + public function join(string|array|TableIdentifier|TableSource $name, string $on, string|array $columns = self::SQL_STAR, string $type = Joins::JOIN_INNER) : self; public function where(Where|callable|string|array|PredicateInterface $predicate, string $combination = Predicate\PredicateSet::OP_AND) : self; public function group(string|array $group); public function having(Having|callable|string|array $predicate, string $combination = Predicate\PredicateSet::OP_AND) : self; @@ -148,9 +156,17 @@ $select->from('foo'); // (produces SELECT "t".* FROM "table" AS "t") $select->from(['t' => 'table']); +// As an array to specify an alias and schema +// (produces SELECT "t".* FROM "schema"."table" AS "t") +$select->from(['t' => ['schema', 'table']]); + // Using a Sql\TableIdentifier: -// (same output as above) +// (produces SELECT "t".* FROM "table" AS "t") $select->from(new TableIdentifier(['t' => 'table'])); + +// Using a Sql\TableSource: +// (produces SELECT "t".* FROM "table" AS "t") +$select->from(new TableSource('table', 't')); ``` ### columns() @@ -286,15 +302,20 @@ $select->offset(10); // similarly takes an integer/numeric The Insert API: ```php -class Insert implements SqlInterface, PreparableSqlInterface +class Insert extends AbstractSql implements PreparableSqlInterface { const VALUES_MERGE = 'merge'; const VALUES_SET = 'set'; - public function __construct(string|TableIdentifier $table = null); - public function into(string|TableIdentifier $table) : self; + public $table // @param TableSource $table + public $columns // @param array $columns + public $values // @param array|SelectableInterface $values + + public function __construct(null|string|array|TableIdentifier|TableSource $table = null); + public function into(string|array|TableIdentifier|TableSource $table) : self; public function columns(array $columns) : self; - public function values(array $values, string $flag = self::VALUES_SET) : self; + public function values(array|SelectableInterface $values, string $flag = self::VALUES_SET) : self; + public function select(SelectableInterface $select) : self; } ``` @@ -323,17 +344,27 @@ $insert->values([ $insert->values(['col_2' => 'value2'], $insert::VALUES_MERGE); ``` +```php +// To use `Select` for values: +$insert->values(new Select('foo'); +// or +$insert->select(new Select('foo'); +``` + ## Update ```php -class Update +class Update extends AbstractSql implements PreparableSqlInterface { const VALUES_MERGE = 'merge'; const VALUES_SET = 'set'; + public $table // @param TableSource $table + public $set // @param PriorityList $set public $where; // @param Where $where - public function __construct(string|TableIdentifier $table = null); - public function table(string|TableIdentifier $table) : self; + + public function __construct(null|string|array|TableIdentifier|TableSource $table = null); + public function table(string|array|TableIdentifier|TableSource $table) : self; public function set(array $values, string $flag = self::VALUES_SET) : self; public function where(Where|callable|string|array|PredicateInterface $predicate, string $combination = Predicate\PredicateSet::OP_AND) : self; } @@ -352,12 +383,13 @@ See the [section on Where and Having](#where-and-having). ## Delete ```php -class Delete +class Delete extends AbstractSql implements PreparableSqlInterface { + public $table // @param TableSource $table public $where; // @param Where $where - public function __construct(string|TableIdentifier $table = null); - public function from(string|TableIdentifier $table); + public function __construct(null|string|array|TableIdentifier|TableSource $table = null); + public function from(string|array|TableIdentifier|TableSource $table); public function where(Where|callable|string|array|PredicateInterface $predicate, string $combination = Predicate\PredicateSet::OP_AND) : self; } ``` diff --git a/src/Adapter/Adapter.php b/src/Adapter/Adapter.php index 99de917cc9..4216a00550 100644 --- a/src/Adapter/Adapter.php +++ b/src/Adapter/Adapter.php @@ -11,10 +11,6 @@ use Zend\Db\ResultSet; -/** - * @property Driver\DriverInterface $driver - * @property Platform\PlatformInterface $platform - */ class Adapter implements AdapterInterface, Profiler\ProfilerAwareInterface { /** @@ -56,9 +52,9 @@ class Adapter implements AdapterInterface, Profiler\ProfilerAwareInterface protected $queryResultSetPrototype = null; /** - * @var Driver\StatementInterface + * @var SqlBuilderInterface */ - protected $lastPreparedStatement = null; + protected $sqlBuilder; /** * @param Driver\DriverInterface|array $driver @@ -74,6 +70,9 @@ public function __construct($driver, Platform\PlatformInterface $platform = null if (is_array($driver)) { $parameters = $driver; + if (isset($parameters['sql_builder'])) { + $this->setSqlBuilder($parameters['sql_builder']); + } if ($profiler === null && isset($parameters['profiler'])) { $profiler = $this->createProfiler($parameters); } @@ -155,6 +154,24 @@ public function getCurrentSchema() return $this->driver->getConnection()->getCurrentSchema(); } + /** + * @return SqlBuilderInterface + */ + public function getSqlBuilder() + { + return $this->sqlBuilder; + } + + /** + * @param SqlBuilderInterface $sqlBuilder + * @return self + */ + public function setSqlBuilder(SqlBuilderInterface $sqlBuilder) + { + $this->sqlBuilder = $sqlBuilder; + return $this; + } + /** * query() is a convenience function * @@ -176,17 +193,31 @@ public function query($sql, $parametersOrQueryMode = self::QUERY_MODE_PREPARE, R throw new Exception\InvalidArgumentException('Parameter 2 to this method must be a flag, an array, or ParameterContainer'); } + $sqlIsString = is_string($sql) || (is_object($sql) && method_exists($sql, '__toString')); + if ($mode == self::QUERY_MODE_PREPARE) { - $this->lastPreparedStatement = null; - $this->lastPreparedStatement = $this->driver->createStatement($sql); - $this->lastPreparedStatement->prepare(); - if (is_array($parameters) || $parameters instanceof ParameterContainer) { - $this->lastPreparedStatement->setParameterContainer((is_array($parameters)) ? new ParameterContainer($parameters) : $parameters); - $result = $this->lastPreparedStatement->execute(); + if ($sqlIsString) { + $preparedStatement = $this->driver->createStatement($sql); } else { - return $this->lastPreparedStatement; + if (!$this->sqlBuilder) { + throw new Exception\RuntimeException('sqlBuilder must be set for non string sql'); + } + $preparedStatement = $this->sqlBuilder->prepareSqlStatement($sql, $this); + } + $preparedStatement->prepare(); + if ($parameters !== null) { + $preparedStatement->setParameterContainer((is_array($parameters)) ? new ParameterContainer($parameters) : $parameters); + $result = $preparedStatement->execute(); + } else { + return $preparedStatement; } } else { + if (!$sqlIsString) { + if (!$this->sqlBuilder) { + throw new Exception\RuntimeException('sqlBuilder must be set for non string sql'); + } + $sql = $this->sqlBuilder->buildSqlString($sql, $this); + } $result = $this->driver->getConnection()->execute($sql); } @@ -233,23 +264,6 @@ public function getHelpers(/* $functions */) } } - /** - * @param $name - * @throws Exception\InvalidArgumentException - * @return Driver\DriverInterface|Platform\PlatformInterface - */ - public function __get($name) - { - switch (strtolower($name)) { - case 'driver': - return $this->driver; - case 'platform': - return $this->platform; - default: - throw new Exception\InvalidArgumentException('Invalid magic property on adapter'); - } - } - /** * @param array $parameters * @return Driver\DriverInterface @@ -369,26 +383,4 @@ protected function createProfiler($parameters) } return $profiler; } - - /** - * @param array $parameters - * @return Driver\DriverInterface - * @throws \InvalidArgumentException - * @throws Exception\InvalidArgumentException - * @deprecated - */ - protected function createDriverFromParameters(array $parameters) - { - return $this->createDriver($parameters); - } - - /** - * @param Driver\DriverInterface $driver - * @return Platform\PlatformInterface - * @deprecated - */ - protected function createPlatformFromDriver(Driver\DriverInterface $driver) - { - return $this->createPlatform($driver); - } } diff --git a/src/Adapter/AdapterAbstractServiceFactory.php b/src/Adapter/AdapterAbstractServiceFactory.php index 470e48198d..cb47eec0b4 100644 --- a/src/Adapter/AdapterAbstractServiceFactory.php +++ b/src/Adapter/AdapterAbstractServiceFactory.php @@ -70,6 +70,9 @@ public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator public function __invoke(ContainerInterface $container, $requestedName, array $options = null) { $config = $this->getConfig($container); + if (isset($config[$requestedName]['sql_builder'])) { + $config[$requestedName]['sql_builder'] = $container->get($config[$requestedName]['sql_builder']); + } return new Adapter($config[$requestedName]); } diff --git a/src/Adapter/AdapterInterface.php b/src/Adapter/AdapterInterface.php index 692ac56e5f..1d94e3e7c8 100644 --- a/src/Adapter/AdapterInterface.php +++ b/src/Adapter/AdapterInterface.php @@ -9,11 +9,6 @@ namespace Zend\Db\Adapter; -/** - * - * @property Driver\DriverInterface $driver - * @property Platform\PlatformInterface $platform - */ interface AdapterInterface { /** diff --git a/src/Adapter/AdapterServiceFactory.php b/src/Adapter/AdapterServiceFactory.php index 95869f15e9..4f1b447c4d 100644 --- a/src/Adapter/AdapterServiceFactory.php +++ b/src/Adapter/AdapterServiceFactory.php @@ -24,6 +24,9 @@ class AdapterServiceFactory implements FactoryInterface public function __invoke(ContainerInterface $container, $requestedName, array $options = null) { $config = $container->get('config'); + if (isset($config['db']['sql_builder'])) { + $config['db']['sql_builder'] = $container->get($config['db']['sql_builder']); + } return new Adapter($config['db']); } diff --git a/src/Adapter/SqlBuilderInterface.php b/src/Adapter/SqlBuilderInterface.php new file mode 100644 index 0000000000..5313bc4aa0 --- /dev/null +++ b/src/Adapter/SqlBuilderInterface.php @@ -0,0 +1,27 @@ + [ Adapter\AdapterInterface::class => Adapter\AdapterServiceFactory::class, + Adapter\SqlBuilderInterface::class => Sql\Builder\BuilderServiceFactory::class, ], 'aliases' => [ Adapter\Adapter::class => Adapter\AdapterInterface::class, diff --git a/src/RowGateway/AbstractRowGateway.php b/src/RowGateway/AbstractRowGateway.php index c4284a8b5b..74b7181ad6 100644 --- a/src/RowGateway/AbstractRowGateway.php +++ b/src/RowGateway/AbstractRowGateway.php @@ -22,7 +22,7 @@ abstract class AbstractRowGateway implements ArrayAccess, Countable, RowGatewayI protected $isInitialized = false; /** - * @var string|TableIdentifier + * @var TableIdentifier */ protected $table = null; @@ -67,7 +67,7 @@ public function initialize() $this->featureSet->setRowGateway($this); $this->featureSet->apply('preInitialize', []); - if (!is_string($this->table) && !$this->table instanceof TableIdentifier) { + if (!$this->table instanceof TableIdentifier) { throw new Exception\RuntimeException('This row object does not have a valid table set.'); } @@ -142,7 +142,7 @@ public function save() } } - $statement = $this->sql->prepareStatementForSqlObject($this->sql->update()->set($data)->where($where)); + $statement = $this->sql->prepareSqlStatement($this->sql->update()->set($data)->where($where)); $result = $statement->execute(); $rowsAffected = $result->getAffectedRows(); unset($statement, $result); // cleanup @@ -160,7 +160,7 @@ public function save() $insert = $this->sql->insert(); $insert->values($this->data); - $statement = $this->sql->prepareStatementForSqlObject($insert); + $statement = $this->sql->prepareSqlStatement($insert); $result = $statement->execute(); if (($primaryKeyValue = $result->getGeneratedValue()) && count($this->primaryKeyColumn) == 1) { @@ -180,7 +180,7 @@ public function save() } // refresh data - $statement = $this->sql->prepareStatementForSqlObject($this->sql->select()->where($where)); + $statement = $this->sql->prepareSqlStatement($this->sql->select()->where($where)); $result = $statement->execute(); $rowData = $result->current(); unset($statement, $result); // cleanup @@ -209,7 +209,7 @@ public function delete() // @todo determine if we need to do a select to ensure 1 row will be affected - $statement = $this->sql->prepareStatementForSqlObject($this->sql->delete()->where($where)); + $statement = $this->sql->prepareSqlStatement($this->sql->delete()->where($where)); $result = $statement->execute(); $affectedRows = $result->getAffectedRows(); diff --git a/src/RowGateway/RowGateway.php b/src/RowGateway/RowGateway.php index 8ce5db176e..34407ec993 100644 --- a/src/RowGateway/RowGateway.php +++ b/src/RowGateway/RowGateway.php @@ -11,6 +11,7 @@ use Zend\Db\Adapter\Adapter; use Zend\Db\Sql\Sql; +use Zend\Db\Sql\TableIdentifier; class RowGateway extends AbstractRowGateway { @@ -28,7 +29,7 @@ public function __construct($primaryKeyColumn, $table, $adapterOrSql = null) $this->primaryKeyColumn = empty($primaryKeyColumn) ? null : (array) $primaryKeyColumn; // set table - $this->table = $table; + $this->table = new TableIdentifier($table); // set Sql object if ($adapterOrSql instanceof Sql) { @@ -39,7 +40,7 @@ public function __construct($primaryKeyColumn, $table, $adapterOrSql = null) throw new Exception\InvalidArgumentException('A valid Sql object was not provided.'); } - if ($this->sql->getTable() !== $this->table) { + if ($this->sql->getTable() != $this->table) { throw new Exception\InvalidArgumentException('The Sql object provided does not have a table that matches this row object'); } diff --git a/src/Sql/AbstractExpression.php b/src/Sql/AbstractExpression.php deleted file mode 100644 index 3fbee7c1c6..0000000000 --- a/src/Sql/AbstractExpression.php +++ /dev/null @@ -1,93 +0,0 @@ -buildNormalizedArgument($argument, self::TYPE_VALUE); - } - - if (is_scalar($argument) || $argument === null) { - return $this->buildNormalizedArgument($argument, $defaultType); - } - - if (is_array($argument)) { - $value = current($argument); - - if ($value instanceof ExpressionInterface || $value instanceof SqlInterface) { - return $this->buildNormalizedArgument($value, self::TYPE_VALUE); - } - - $key = key($argument); - - if (is_integer($key) && ! in_array($value, $this->allowedTypes)) { - return $this->buildNormalizedArgument($value, $defaultType); - } - - return $this->buildNormalizedArgument($key, $value); - } - - throw new Exception\InvalidArgumentException(sprintf( - '$argument should be %s or %s or %s or %s or %s, "%s" given', - 'null', - 'scalar', - 'array', - 'Zend\Db\Sql\ExpressionInterface', - 'Zend\Db\Sql\SqlInterface', - is_object($argument) ? get_class($argument) : gettype($argument) - )); - } - - /** - * @param mixed $argument - * @param string $argumentType - * - * @return array - * - * @throws Exception\InvalidArgumentException - */ - private function buildNormalizedArgument($argument, $argumentType) - { - if (! in_array($argumentType, $this->allowedTypes)) { - throw new Exception\InvalidArgumentException(sprintf( - 'Argument type should be in array(%s)', - implode(',', $this->allowedTypes) - )); - } - - return [ - $argument, - $argumentType, - ]; - } -} diff --git a/src/Sql/AbstractPreparableSql.php b/src/Sql/AbstractPreparableSql.php deleted file mode 100644 index 6d95f90d84..0000000000 --- a/src/Sql/AbstractPreparableSql.php +++ /dev/null @@ -1,39 +0,0 @@ -getParameterContainer(); - - if (! $parameterContainer instanceof ParameterContainer) { - $parameterContainer = new ParameterContainer(); - - $statementContainer->setParameterContainer($parameterContainer); - } - - $statementContainer->setSql( - $this->buildSqlString($adapter->getPlatform(), $adapter->getDriver(), $parameterContainer) - ); - - return $statementContainer; - } -} diff --git a/src/Sql/AbstractSql.php b/src/Sql/AbstractSql.php index f7d1d42e82..06e4cbd211 100644 --- a/src/Sql/AbstractSql.php +++ b/src/Sql/AbstractSql.php @@ -9,448 +9,102 @@ namespace Zend\Db\Sql; -use Zend\Db\Adapter\Driver\DriverInterface; -use Zend\Db\Adapter\ParameterContainer; -use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Sql\Platform\PlatformDecoratorInterface; -use Zend\Db\Adapter\Platform\Sql92 as DefaultAdapterPlatform; +use Zend\Db\Adapter\AdapterInterface; -abstract class AbstractSql implements SqlInterface +abstract class AbstractSql { - /** - * Specifications for Sql String generation - * - * @var string[]|array[] - */ - protected $specifications = []; + /** @var AdapterInterface */ + protected $adapter = null; - /** - * @var string - */ - protected $processInfo = ['paramPrefix' => '', 'subselectCount' => 0]; + /** @var TableIdentifier */ + protected $table = null; - /** - * @var array - */ - protected $instanceParameterIndex = []; + /** @var Builder\Builder */ + protected $builder = null; /** - * {@inheritDoc} + * @param null|AdapterInterface $adapter + * @param null|string|array|TableIdentifier $table + * @param null|Builder\Builder $builder */ - public function getSqlString(PlatformInterface $adapterPlatform = null) + public function __construct(AdapterInterface $adapter = null, $table = null, Builder\Builder $builder = null) { - $adapterPlatform = ($adapterPlatform) ?: new DefaultAdapterPlatform; - return $this->buildSqlString($adapterPlatform); - } - - /** - * @param PlatformInterface $platform - * @param null|DriverInterface $driver - * @param null|ParameterContainer $parameterContainer - * @return string - */ - protected function buildSqlString( - PlatformInterface $platform, - DriverInterface $driver = null, - ParameterContainer $parameterContainer = null - ) { - $this->localizeVariables(); - - $sqls = []; - $parameters = []; - - foreach ($this->specifications as $name => $specification) { - $parameters[$name] = $this->{'process' . $name}( - $platform, - $driver, - $parameterContainer, - $sqls, - $parameters - ); - - if ($specification && is_array($parameters[$name])) { - $sqls[$name] = $this->createSqlFromSpecificationAndParameters($specification, $parameters[$name]); - - continue; - } - - if (is_string($parameters[$name])) { - $sqls[$name] = $parameters[$name]; - } + $this->adapter = $adapter; + if ($table) { + $this->setTable($table); } - - return rtrim(implode(' ', $sqls), "\n ,"); + $this->builder = $builder ?: new Builder\Builder($adapter); } /** - * Render table with alias in from/join parts - * - * @todo move TableIdentifier concatination here - * @param string $table - * @param string $alias - * @return string + * @return null|\Zend\Db\Adapter\AdapterInterface */ - protected function renderTable($table, $alias = null) + public function getAdapter() { - return $table . ($alias ? ' AS ' . $alias : ''); + return $this->adapter; } /** - * @staticvar int $runtimeExpressionPrefix - * @param ExpressionInterface $expression - * @param PlatformInterface $platform - * @param null|DriverInterface $driver - * @param null|ParameterContainer $parameterContainer - * @param null|string $namedParameterPrefix - * @return string - * @throws Exception\RuntimeException + * @return bool */ - protected function processExpression( - ExpressionInterface $expression, - PlatformInterface $platform, - DriverInterface $driver = null, - ParameterContainer $parameterContainer = null, - $namedParameterPrefix = null - ) { - $namedParameterPrefix = ! $namedParameterPrefix - ? $namedParameterPrefix - : $this->processInfo['paramPrefix'] . $namedParameterPrefix; - // static counter for the number of times this method was invoked across the PHP runtime - static $runtimeExpressionPrefix = 0; - - if ($parameterContainer && ((!is_string($namedParameterPrefix) || $namedParameterPrefix == ''))) { - $namedParameterPrefix = sprintf('expr%04dParam', ++$runtimeExpressionPrefix); - } else { - $namedParameterPrefix = preg_replace('/\s/', '__', $namedParameterPrefix); - } - - $sql = ''; - - // initialize variables - $parts = $expression->getExpressionData(); - - if (! isset($this->instanceParameterIndex[$namedParameterPrefix])) { - $this->instanceParameterIndex[$namedParameterPrefix] = 1; - } - - $expressionParamIndex = &$this->instanceParameterIndex[$namedParameterPrefix]; - - foreach ($parts as $part) { - // #7407: use $expression->getExpression() to get the unescaped - // version of the expression - if (is_string($part) && $expression instanceof Expression) { - $sql .= $expression->getExpression(); - continue; - } - - // If it is a string, simply tack it onto the return sql - // "specification" string - if (is_string($part)) { - $sql .= $part; - continue; - } - - if (! is_array($part)) { - throw new Exception\RuntimeException( - 'Elements returned from getExpressionData() array must be a string or array.' - ); - } - - // Process values and types (the middle and last position of the - // expression data) - $values = $part[1]; - $types = isset($part[2]) ? $part[2] : []; - foreach ($values as $vIndex => $value) { - if (!isset($types[$vIndex])) { - continue; - } - $type = $types[$vIndex]; - if ($value instanceof Select) { - // process sub-select - $values[$vIndex] = '(' - . $this->processSubSelect($value, $platform, $driver, $parameterContainer) - . ')'; - } elseif ($value instanceof ExpressionInterface) { - // recursive call to satisfy nested expressions - $values[$vIndex] = $this->processExpression( - $value, - $platform, - $driver, - $parameterContainer, - $namedParameterPrefix . $vIndex . 'subpart' - ); - } elseif ($type == ExpressionInterface::TYPE_IDENTIFIER) { - $values[$vIndex] = $platform->quoteIdentifierInFragment($value); - } elseif ($type == ExpressionInterface::TYPE_VALUE) { - // if prepareType is set, it means that this particular value must be - // passed back to the statement in a way it can be used as a placeholder value - if ($parameterContainer) { - $name = $namedParameterPrefix . $expressionParamIndex++; - $parameterContainer->offsetSet($name, $value); - $values[$vIndex] = $driver->formatParameterName($name); - continue; - } - - // if not a preparable statement, simply quote the value and move on - $values[$vIndex] = $platform->quoteValue($value); - } elseif ($type == ExpressionInterface::TYPE_LITERAL) { - $values[$vIndex] = $value; - } - } - - // After looping the values, interpolate them into the sql string - // (they might be placeholder names, or values) - $sql .= vsprintf($part[0], $values); - } - - return $sql; + public function hasTable() + { + return ($this->table !== null); } /** - * @param string|array $specifications - * @param array $parameters - * - * @return string - * - * @throws Exception\RuntimeException + * @param null|string|array|TableIdentifier $table + * @return self + * @throws Exception\InvalidArgumentException */ - protected function createSqlFromSpecificationAndParameters($specifications, $parameters) + public function setTable($table) { - if (is_string($specifications)) { - return vsprintf($specifications, $parameters); - } - - $parametersCount = count($parameters); - - foreach ($specifications as $specificationString => $paramSpecs) { - if ($parametersCount == count($paramSpecs)) { - break; - } - - unset($specificationString, $paramSpecs); + if (!$table) { + throw new Exception\InvalidArgumentException('Table must be a string, array or instance of TableIdentifier.'); } - - if (!isset($specificationString)) { - throw new Exception\RuntimeException( - 'A number of parameters was found that is not supported by this specification' - ); - } - - $topParameters = []; - foreach ($parameters as $position => $paramsForPosition) { - if (isset($paramSpecs[$position]['combinedby'])) { - $multiParamValues = []; - foreach ($paramsForPosition as $multiParamsForPosition) { - $ppCount = count($multiParamsForPosition); - if (!isset($paramSpecs[$position][$ppCount])) { - throw new Exception\RuntimeException(sprintf( - 'A number of parameters (%d) was found that is not supported by this specification', - $ppCount - )); - } - $multiParamValues[] = vsprintf($paramSpecs[$position][$ppCount], $multiParamsForPosition); - } - $topParameters[] = implode($paramSpecs[$position]['combinedby'], $multiParamValues); - } elseif ($paramSpecs[$position] !== null) { - $ppCount = count($paramsForPosition); - if (!isset($paramSpecs[$position][$ppCount])) { - throw new Exception\RuntimeException(sprintf( - 'A number of parameters (%d) was found that is not supported by this specification', - $ppCount - )); - } - $topParameters[] = vsprintf($paramSpecs[$position][$ppCount], $paramsForPosition); - } else { - $topParameters[] = $paramsForPosition; - } - } - return vsprintf($specificationString, $topParameters); + $this->table = TableIdentifier::factory($table); + return $this; } /** - * @param Select $subselect - * @param PlatformInterface $platform - * @param null|DriverInterface $driver - * @param null|ParameterContainer $parameterContainer - * @return string + * @return TableIdentifier */ - protected function processSubSelect( - Select $subselect, - PlatformInterface $platform, - DriverInterface $driver = null, - ParameterContainer $parameterContainer = null - ) { - if ($this instanceof PlatformDecoratorInterface) { - $decorator = clone $this; - $decorator->setSubject($subselect); - } else { - $decorator = $subselect; - } - - if ($parameterContainer) { - // Track subselect prefix and count for parameters - $processInfoContext = ($decorator instanceof PlatformDecoratorInterface) ? $subselect : $decorator; - $this->processInfo['subselectCount']++; - $processInfoContext->processInfo['subselectCount'] = $this->processInfo['subselectCount']; - $processInfoContext->processInfo['paramPrefix'] = 'subselect' - . $processInfoContext->processInfo['subselectCount']; - - $sql = $decorator->buildSqlString($platform, $driver, $parameterContainer); - - // copy count - $this->processInfo['subselectCount'] = $decorator->processInfo['subselectCount']; - return $sql; - } - - return $decorator->buildSqlString($platform, $driver, $parameterContainer); + public function getTable() + { + return $this->table; } /** - * @param Join[] $joins - * @param PlatformInterface $platform - * @param null|DriverInterface $driver - * @param null|ParameterContainer $parameterContainer - * @return null|string[] Null if no joins present, array of JOIN statements - * otherwise - * @throws Exception\InvalidArgumentException for invalid JOIN table names. + * @return Builder\Builder */ - protected function processJoin( - Join $joins, - PlatformInterface $platform, - DriverInterface $driver = null, - ParameterContainer $parameterContainer = null - ) { - if (! $joins->count()) { - return; - } - - // process joins - $joinSpecArgArray = []; - foreach ($joins->getJoins() as $j => $join) { - $joinName = null; - $joinAs = null; - - // table name - if (is_array($join['name'])) { - $joinName = current($join['name']); - $joinAs = $platform->quoteIdentifier(key($join['name'])); - } else { - $joinName = $join['name']; - } - - if ($joinName instanceof Expression) { - $joinName = $joinName->getExpression(); - } elseif ($joinName instanceof TableIdentifier) { - $joinName = $joinName->getTableAndSchema(); - $joinName = ($joinName[1] ? $platform->quoteIdentifier($joinName[1]) . $platform->getIdentifierSeparator() : '') . $platform->quoteIdentifier($joinName[0]); - } elseif ($joinName instanceof Select) { - $joinName = '(' . $this->processSubSelect($joinName, $platform, $driver, $parameterContainer) . ')'; - } elseif (is_string($joinName) || (is_object($joinName) && is_callable([$joinName, '__toString']))) { - $joinName = $platform->quoteIdentifier($joinName); - } else { - throw new Exception\InvalidArgumentException(sprintf('Join name expected to be Expression|TableIdentifier|Select|string, "%s" given', gettype($joinName))); - } - - $joinSpecArgArray[$j] = [ - strtoupper($join['type']), - $this->renderTable($joinName, $joinAs), - ]; - - // on expression - // note: for Expression objects, pass them to processExpression with a prefix specific to each join (used for named parameters) - $joinSpecArgArray[$j][] = ($join['on'] instanceof ExpressionInterface) - ? $this->processExpression($join['on'], $platform, $driver, $parameterContainer, 'join' . ($j+1) . 'part') - : $platform->quoteIdentifierInFragment($join['on'], ['=', 'AND', 'OR', '(', ')', 'BETWEEN', '<', '>']); // on - } - - return [$joinSpecArgArray]; + public function getBuilder() + { + return $this->builder; } - /** - * @param null|array|ExpressionInterface|Select $column - * @param PlatformInterface $platform - * @param null|DriverInterface $driver - * @param null|string $namedParameterPrefix - * @param null|ParameterContainer $parameterContainer - * @return string - */ - protected function resolveColumnValue( - $column, - PlatformInterface $platform, - DriverInterface $driver = null, - ParameterContainer $parameterContainer = null, - $namedParameterPrefix = null - ) { - $namedParameterPrefix = ! $namedParameterPrefix - ? $namedParameterPrefix - : $this->processInfo['paramPrefix'] . $namedParameterPrefix; - $isIdentifier = false; - $fromTable = ''; - if (is_array($column)) { - if (isset($column['isIdentifier'])) { - $isIdentifier = (bool) $column['isIdentifier']; - } - if (isset($column['fromTable']) && $column['fromTable'] !== null) { - $fromTable = $column['fromTable']; - } - $column = $column['column']; - } - - if ($column instanceof ExpressionInterface) { - return $this->processExpression($column, $platform, $driver, $parameterContainer, $namedParameterPrefix); - } - if ($column instanceof Select) { - return '(' . $this->processSubSelect($column, $platform, $driver, $parameterContainer) . ')'; - } - if ($column === null) { - return 'NULL'; + protected function validateTable($table = null) + { + if ($this->table !== null && $table !== null) { + throw new Exception\InvalidArgumentException(sprintf( + 'This Sql object is intended to work with only the table "%s" provided at construction time.', + $this->table->getTable() + )); } - return $isIdentifier - ? $fromTable . $platform->quoteIdentifierInFragment($column) - : $platform->quoteValue($column); } /** - * @param string|TableIdentifier|Select $table - * @param PlatformInterface $platform - * @param DriverInterface $driver - * @param ParameterContainer $parameterContainer + * @param SqlObjectInterface $sqlObject + * @param null|AdapterInterface $adapter + * * @return string + * + * @throws Exception\InvalidArgumentException */ - protected function resolveTable( - $table, - PlatformInterface $platform, - DriverInterface $driver = null, - ParameterContainer $parameterContainer = null - ) { - $schema = null; - if ($table instanceof TableIdentifier) { - list($table, $schema) = $table->getTableAndSchema(); - } - - if ($table instanceof Select) { - $table = '(' . $this->processSubselect($table, $platform, $driver, $parameterContainer) . ')'; - } elseif ($table) { - $table = $platform->quoteIdentifier($table); - } - - if ($schema && $table) { - $table = $platform->quoteIdentifier($schema) . $platform->getIdentifierSeparator() . $table; - } - return $table; - } - - /** - * Copy variables from the subject into the local properties - */ - protected function localizeVariables() + public function buildSqlString(SqlObjectInterface $sqlObject, AdapterInterface $adapter = null) { - if (! $this instanceof PlatformDecoratorInterface) { - return; - } - - foreach (get_object_vars($this->subject) as $name => $value) { - $this->{$name} = $value; - } + return $this->builder->buildSqlString( + $sqlObject, + $adapter ?: $this->adapter + ); } } diff --git a/src/Sql/AbstractSqlObject.php b/src/Sql/AbstractSqlObject.php new file mode 100644 index 0000000000..69c0742e53 --- /dev/null +++ b/src/Sql/AbstractSqlObject.php @@ -0,0 +1,30 @@ +__getProperties = array_flip($this->__getProperties); + } + + public function __get($name) + { + if (!array_key_exists($name, $this->__getProperties)) { + throw new Exception\InvalidArgumentException( + 'Not a valid property "'. $name . '" for this object' + ); + } + return $this->{$name}; + } +} diff --git a/src/Sql/Builder/AbstractBuilder.php b/src/Sql/Builder/AbstractBuilder.php new file mode 100644 index 0000000000..b2289ea37f --- /dev/null +++ b/src/Sql/Builder/AbstractBuilder.php @@ -0,0 +1,83 @@ +getAlias(); + $identifier = $identifier->getSource(); + } + if ($identifier instanceof TableIdentifier) { + $name = $identifier->getTable(); + $schema = $identifier->getSchema(); + } else { + $name = $identifier; + } + + if ($alias) { + $alias = $context->getPlatform()->quoteIdentifier($alias); + $columnAlias = $alias; + } + + if (is_string($name)) { + $name = $schema + ? $context->getPlatform()->quoteIdentifierInFragment($schema . '.' . $name) + : $context->getPlatform()->quoteIdentifier($name); + if (!$columnAlias) { + $columnAlias = $name; + } + } + + return [ + 'name' => $name, + 'alias' => $alias, + 'columnAlias' => $columnAlias, + ]; + } + + /** + * + * @param mixed $argument + * @param string $class + * @param string $method + * @return null + * @throws \Zend\Db\Sql\Exception\InvalidArgumentException + */ + protected function validateSqlObject($argument, $class, $method) + { + if ($argument instanceof $class) { + return; + } + throw new \Zend\Db\Sql\Exception\InvalidArgumentException(sprintf( + 'Argument 1 passed to %s must be an instance of %s, instance of %s given', + $method . '()', + $class, + is_object($argument) ? get_class($argument) : gettype($argument) + )); + } +} diff --git a/src/Sql/Builder/AbstractSqlBuilder.php b/src/Sql/Builder/AbstractSqlBuilder.php new file mode 100644 index 0000000000..afeeabd494 --- /dev/null +++ b/src/Sql/Builder/AbstractSqlBuilder.php @@ -0,0 +1,94 @@ +platformBuilder = $platformBuilder; + } + + abstract public function build($sqlObject, Context $context); + + /** + * @param string|array $column + * @param mixed $value + * @param Context $context + * @return array + */ + protected function resolveColumnValue($column, $value, Context $context) + { + if (is_scalar($value) || $value === null) { + if ($context->getParameterContainer() && $column !== null) { + $context->getParameterContainer()->offsetSet($column, $value); + $value = $context->getDriver()->formatParameterName($column); + } elseif ($value === null) { + $value = 'NULL'; + } else { + $value = $context->getPlatform()->quoteValue($value); + } + } + + return [ + $context->getPlatform()->quoteIdentifier($column), + $value + ]; + } + + /** + * @param SqlObjectInterface $sqlObject + * @param Context $context + * @return array|null + */ + protected function build_Joins(SqlObjectInterface $sqlObject, Context $context) + { + if (!$sqlObject->joins || !$sqlObject->joins->count()) { + return; + } + + // build_ joins + $joinSpecArgArray = []; + foreach ($sqlObject->joins as $j => $join) { + $jTable = $this->nornalizeTable($join['name'], $context); + unset($jTable['columnAlias']); + if (!$jTable['alias']) { + unset($jTable['alias']); + } + if (!$jTable['name']) { + $jTable = null; + } + $joinSpecArgArray[$j] = [ + strtoupper($join['type']), + $jTable, + ]; + $joinSpecArgArray[$j][] = ($join['on'] instanceof ExpressionInterface) + ? $join['on'] + : $context->getPlatform()->quoteIdentifierInFragment($join['on'], ['=', 'AND', 'OR', '(', ')', 'BETWEEN', '<', '>']); // on + } + return [ + 'spec' => $this->joinsSpecification, + 'params' => $joinSpecArgArray + ]; + } +} diff --git a/src/Sql/Builder/Builder.php b/src/Sql/Builder/Builder.php new file mode 100644 index 0000000000..9de2b18353 --- /dev/null +++ b/src/Sql/Builder/Builder.php @@ -0,0 +1,481 @@ + [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\CombineBuilder', + ], + 'Zend\Db\Sql\Delete' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\DeleteBuilder', + ], + 'Zend\Db\Sql\Insert' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\InsertBuilder', + ], + 'Zend\Db\Sql\Select' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\SelectBuilder', + 'mysql' => 'Zend\Db\Sql\Builder\MySql\SelectBuilder', + 'ibmdb2' => 'Zend\Db\Sql\Builder\IbmDb2\SelectBuilder', + 'oracle' => 'Zend\Db\Sql\Builder\Oracle\SelectBuilder', + 'sqlserver' => 'Zend\Db\Sql\Builder\SqlServer\SelectBuilder', + ], + 'Zend\Db\Sql\Update' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\UpdateBuilder', + ], + + 'Zend\Db\Sql\Ddl\AlterTable' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Ddl\AlterTableBuilder', + ], + 'Zend\Db\Sql\Ddl\CreateTable' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Ddl\CreateTableBuilder', + 'sqlserver' => 'Zend\Db\Sql\Builder\SqlServer\Ddl\CreateTableBuilder', + ], + 'Zend\Db\Sql\Ddl\DropTable' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Ddl\DropTableBuilder', + 'sqlserver' => 'Zend\Db\Sql\Builder\SqlServer\Ddl\DropTableBuilder', + ], + + 'Zend\Db\Sql\Predicate\NotBetween' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Predicate\NotBetweenBuilder', + ], + 'Zend\Db\Sql\Predicate\Between' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Predicate\BetweenBuilder', + ], + 'Zend\Db\Sql\Predicate\NotIn' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Predicate\NotInBuilder', + ], + 'Zend\Db\Sql\Predicate\In' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Predicate\InBuilder', + ], + 'Zend\Db\Sql\Predicate\IsNotNull' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Predicate\IsNotNullBuilder', + ], + 'Zend\Db\Sql\Predicate\IsNull' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Predicate\IsNullBuilder', + ], + 'Zend\Db\Sql\Predicate\NotLike' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Predicate\NotLikeBuilder', + ], + 'Zend\Db\Sql\Predicate\Like' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Predicate\LikeBuilder', + ], + 'Zend\Db\Sql\Predicate\Operator' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Predicate\OperatorBuilder', + ], + 'Zend\Db\Sql\Predicate\PredicateSet' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Predicate\PredicateSetBuilder', + ], + 'Zend\Db\Sql\Predicate\Predicate' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Predicate\PredicateBuilder', + ], + 'Zend\Db\Sql\Ddl\Column\Column' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Ddl\Column\ColumnBuilder', + 'mysql' => 'Zend\Db\Sql\Builder\Mysql\Ddl\Column\ColumnBuilder', + ], + 'Zend\Db\Sql\Ddl\Index\Index' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Ddl\Index\IndexBuilder', + ], + 'Zend\Db\Sql\Ddl\Constraint\UniqueKey' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Ddl\Constraint\UniqueKeyBuilder', + ], + 'Zend\Db\Sql\Ddl\Constraint\PrimaryKey' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Ddl\Constraint\PrimaryKeyBuilder', + ], + 'Zend\Db\Sql\Ddl\Constraint\ForeignKey' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Ddl\Constraint\ForeignKeyBuilder', + ], + 'Zend\Db\Sql\Ddl\Constraint\Check' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Ddl\Constraint\CheckBuilder', + ], + 'Zend\Db\Sql\Ddl\Constraint\AbstractConstraint' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\Ddl\Constraint\AbstractBuilder', + ], + 'Zend\Db\Sql\Literal' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\LiteralBuilder', + ], + 'Zend\Db\Sql\Expression' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\ExpressionBuilder', + ], + ]; + + /** + * @param Adapter\AdapterInterface $adapter + */ + public function __construct(Adapter\AdapterInterface $adapter = null) + { + $this->defaultAdapter = $adapter; + } + + /** + * @return Adapter\AdapterInterface + */ + public function setDefaultAdapter($adapter) + { + $this->defaultAdapter = $adapter; + return $this; + } + + /** + * @return Adapter\AdapterInterface + */ + public function getDefaultAdapter() + { + return $this->defaultAdapter; + } + + /** + * @param array $builders + * @return self + */ + public function setPlatformBuilders(array $builders) + { + foreach ($builders as $platform => $classes) { + foreach ($classes as $objectClass => $builderClass) { + $this->setPlatformBuilder($platform, $objectClass, $builderClass); + } + } + return $this; + } + /** + * @param string|Context|PlatformInterface|Adapter\AdapterInterface $platform + * @param string $objectClass + * @param string $builderClass + * @return self + */ + public function setPlatformBuilder($platform, $objectClass, $builderClass) + { + $platform = $this->resolvePlatformName($platform); + if ($builderClass instanceof AbstractSqlBuilder) { + $builder = get_class($builderClass); + $this->buildersInstances[$builder] = $builderClass; + } elseif (is_string($builderClass)) { + $builder = $builderClass; + } else { + throw new Exception\InvalidArgumentException(sprintf( + '$builderClass should be %s or %s instance', + 'string', + 'Zend\Db\Sql\Builder\AbstractSqlBuilder' + )); + } + $this->inheritableBuilders[$objectClass][$platform] = $builder; + return $this; + } + + /** + * @param SqlObjectInterface $sqlObject + * @param string|Context|PlatformInterface|Adapter\AdapterInterface $platform + * @return AbstractSqlBuilder + * @throws Exception\RuntimeException + */ + public function getPlatformBuilder($sqlObject, $platform = 'sql92') + { + $platform = $this->resolvePlatformName($platform); + + $mapName = $platform . '-' . get_class($sqlObject); + if (array_key_exists($mapName, $this->concreteBuilders)) { + $builder = $this->concreteBuilders[$mapName]; + if ($builder === false) { + throw new Exception\RuntimeException(sprintf( + 'Builder for "%s" not found', + get_class($sqlObject) + )); + } + if (!isset($this->buildersInstances[$builder])) { + $this->buildersInstances[$builder] = new $builder($this); + } + return $this->buildersInstances[$builder]; + } + + foreach ($this->inheritableBuilders as $type => $builders) { + if (!$sqlObject instanceof $type) { + continue; + } + if (!isset($builders[$platform])) { + break; + } + $builder = $builders[$platform]; + if (!isset($this->concreteBuilders[$mapName])) { + $this->concreteBuilders[$mapName] = $builder; + } + if (!isset($this->buildersInstances[$builder])) { + $this->buildersInstances[$builder] = new $builder($this); + } + return $this->buildersInstances[$builder]; + } + + if ($platform == 'sql92') { + throw new Exception\RuntimeException(sprintf( + 'Builder for "%s" not found', + get_class($sqlObject) + )); + } + return $this->getPlatformBuilder($sqlObject); + } + + /** + * @param SqlObjectInterface|ExpressionInterface $object + * @param null|Adapter\AdapterInterface $adapter + * @return string + */ + public function buildSqlString($object, Adapter\AdapterInterface $adapter = null) + { + $adapter = $adapter ?: $this->defaultAdapter; + return $this->build($object, new Context($adapter)); + } + + /** + * @param SqlObjectInterface|ExpressionInterface $object + * @param null|Adapter\AdapterInterface $adapter + * @return \Zend\Db\Adapter\Driver\StatementInterface + */ + public function prepareSqlStatement($object, Adapter\AdapterInterface $adapter = null) + { + $adapter = $adapter ?: $this->defaultAdapter; + $statement = $adapter->getDriver()->createStatement(); + if (!$statement->getParameterContainer()) { + $statement->setParameterContainer(new Adapter\ParameterContainer); + } + $statement->setSql( + $this->build($object, new Context($adapter, $statement->getParameterContainer())) + ); + + return $statement; + } + + /** + * @param string|Context|PlatformInterface|Adapter\AdapterInterface $platform + * @return string + */ + protected function resolvePlatformName($platform) + { + if ($platform instanceof Context) { + $platform = $platform->getPlatform()->getName(); + } elseif ($platform instanceof PlatformInterface) { + $platform = $platform->getName(); + } elseif ($platform instanceof Adapter\AdapterInterface) { + $platform = $platform->getPlatform()->getName(); + } + return str_replace(' ', '', strtolower($platform)); + } + + /** + * @param SqlObjectInterface|ExpressionInterface $sqlObject + * @param Context $context + * @return string + * @throws \Zend\Db\Sql\Exception\InvalidArgumentException + */ + protected function build($sqlObject, Context $context) + { + if (is_array($sqlObject)) { + return $this->createSqlFromSpecificationAndParameters($sqlObject['spec'], $sqlObject['params'], $context); + } + + if (!$sqlObject instanceof SqlObjectInterface && !$sqlObject instanceof ExpressionInterface) { + throw new \Zend\Db\Sql\Exception\InvalidArgumentException(sprintf( + 'Argument $sqlObject passed to %s must be an instance of %s, instance of %s given', + __METHOD__ . '()', + 'Zend\Db\Sql\SqlObjectInterface or Zend\Db\Sql\ExpressionInterface', + is_object($sqlObject) ? get_class($sqlObject) : gettype($sqlObject) + )); + } + + $specAndParams = $this + ->getPlatformBuilder($sqlObject, $context->getAdapter()) + ->build($sqlObject, $context); + + if ($specAndParams === false) { + return; + } + + if (isset($specAndParams[$this->implodeGlueKey])) { + $implodeGlue = $specAndParams[$this->implodeGlueKey]; + unset($specAndParams[$this->implodeGlueKey]); + } else { + $implodeGlue = $sqlObject instanceof SqlObjectInterface ? ' ' : ''; + } + + $sqls = []; + foreach ($specAndParams as $spec) { + if (!$spec) { + continue; + } + if (is_scalar($spec)) { + $sqls[] = $spec; + continue; + } + if (is_array($spec)) { + $sqls[] = $this->createSqlFromSpecificationAndParameters($spec['spec'], $spec['params'], $context); + continue; + } + $sqls[] = $this->buildSpecificationParameter($spec, $context); + } + + return rtrim(implode($implodeGlue, $sqls), "\n ,"); + } + + /* + * $spec = array( + 'format' => ' string format : http://php.net/manual/en/function.sprintf.php', + 'byArgNumber' => array( + 'parameter index' => 'spec for parameter', + ' ... ' => ' ... ', + 'parameter index' => 'spec for parameter', + ), + 'byCount' => array( + -1 => 'spec if count not found or !is_array($args)', + 'count($args)' => 'spec', + ' ... ' => ' .. ', + 'count($args)' => 'spec', + ), + 'implode' => 'is isset - do implode array', + ); + */ + private function createSqlFromSpecificationAndParameters($specification, $args, Context $context = null) + { + if (is_string($specification)) { + $args = $this->buildSpecificationParameter($args, $context); + if ($args === null) { + return; + } + return vsprintf( + $specification, + $args + ); + } + + foreach ($specification as $specName => $spec) { + if ($specName == 'forEach') { + foreach ($args as $pName => &$param) { + $param = $this->createSqlFromSpecificationAndParameters($spec, $args[$pName], $context); + } + } elseif ($specName == 'byArgNumber') { + $i = 0; + foreach ($args as $pName => &$param) { + if (isset($spec[++$i])) { + $param = $this->createSqlFromSpecificationAndParameters($spec[$i], $args[$pName], $context); + } + } + } elseif ($specName == 'byCount') { + $pCount = is_array($args) ? count($args) : -1; + if (isset($spec[$pCount])) { + $spec = $spec[$pCount]; + } elseif (isset($spec[-1])) { + $spec = $spec[-1]; + } else { + throw new \Exception('A number of parameters (' . $pCount . ') was found that is not supported by this specification'); + } + $args = $this->createSqlFromSpecificationAndParameters($spec, $args, $context); + } elseif ($specName == 'implode') { + if (is_array($spec)) { + $prefix = isset($spec['prefix']) ? $spec['prefix'] : ''; + $suffix = isset($spec['suffix']) ? $spec['suffix'] : ''; + $glue = isset($spec['glue']) ? $spec['glue'] : ''; + $args = + $prefix + . implode($glue, $this->buildSpecificationParameter($args, $context)) + . $suffix; + } else { + $args = implode($spec, $this->buildSpecificationParameter($args, $context)); + } + } elseif ($specName == 'format') { + $args = vsprintf( + $spec, + $this->buildSpecificationParameter($args, $context) + ); + } + } + return $args; + } + + private function buildSpecificationParameter($parameter, Context $context = null) + { + if (is_array($parameter)) { + foreach ($parameter as &$ppp) { + $ppp = $this->buildSpecificationParameter($ppp, $context); + } + return $parameter; + } + + $isQuoted = false; + if ($parameter instanceof ExpressionParameter) { + $value = $parameter->getValue(); + $type = $parameter->getType(); + $paramName = $parameter->getName(); + $isQuoted = $parameter->getOption('isQuoted'); + } else { + $value = $parameter; + $type = ExpressionInterface::TYPE_LITERAL; + } + + if ($value instanceof TableIdentifier || $value instanceof TableSource) { + $parameter = $this->nornalizeTable($value, $context)['name']; + } elseif ($value instanceof SelectableInterface) { + $parameter = $this->buildSubSelect($value, $context); + } elseif ($value instanceof ExpressionInterface) { + $parameter = $this->build($value, $context); + } elseif ($type == ExpressionInterface::TYPE_IDENTIFIER) { + $parameter = $context->getPlatform()->quoteIdentifierInFragment($value); + } elseif ($type == ExpressionInterface::TYPE_VALUE) { + if ($context->getParameterContainer()) { + $name = isset($paramName) + ? $paramName + : $context->getNestedAlias('expr'); + if (is_array($name)) { + $context->getParameterContainer()->offsetSet($name[0], $value); + $context->getParameterContainer()->offsetSetReference($name[1], $name[0]); + } else { + $context->getParameterContainer()->offsetSet($name, $value); + } + $parameter = $context->getDriver()->formatParameterName($name); + } else { + $parameter = $isQuoted + ? $value + : $context->getPlatform()->quoteValue($value); + } + } elseif ($type == ExpressionInterface::TYPE_LITERAL) { + $parameter = $value; + } + + return $parameter; + } + + private function buildSubSelect(SelectableInterface $subselect, Context $context) + { + $context->startPrefix('subselect'); + + $result = '(' . $this->build($subselect, $context) . ')'; + + $context->endPrefix(); + + return $result; + } +} diff --git a/src/Sql/Builder/BuilderServiceFactory.php b/src/Sql/Builder/BuilderServiceFactory.php new file mode 100644 index 0000000000..6e6c042221 --- /dev/null +++ b/src/Sql/Builder/BuilderServiceFactory.php @@ -0,0 +1,48 @@ +has('config')) { + return $builder; + } + $config = $container->get('config'); + if (!isset($config['sql_builder'])) { + return $builder; + } + + $config = $config['sql_builder']; + + if (isset($config['default_adapter'])) { + $adapter = $container->get($config['default_adapter']); + $builder->setDefaultAdapter($adapter); + } + + if (isset($config['builders'])) { + $builder->setPlatformBuilders($config['builders']); + } + + return $builder; + } + + public function createService(ServiceLocatorInterface $serviceLocator) + { + return $this($serviceLocator, 'SqlBuilder'); + } +} diff --git a/src/Sql/Builder/Context.php b/src/Sql/Builder/Context.php new file mode 100644 index 0000000000..5680e7e55e --- /dev/null +++ b/src/Sql/Builder/Context.php @@ -0,0 +1,95 @@ + '', + 'suffixIndex' => 0, + ]]; + + public function __construct(Adapter\Adapter $adapter, Adapter\ParameterContainer $parameterContainer = null) + { + $this->adapter = $adapter; + $this->platform = $adapter->getPlatform(); + $this->driver = $adapter->getDriver(); + $this->parameterContainer = $parameterContainer; + } + + /** + * @return Adapter\Adapter + */ + public function getAdapter() + { + return $this->adapter; + } + + /** + * @return Adapter\Platform\PlatformInterface + */ + public function getPlatform() + { + return $this->platform; + } + + /** + * @return Adapter\Driver\DriverInterface + */ + public function getDriver() + { + return $this->driver; + } + + /** + * @return Adapter\ParameterContainer + */ + public function getParameterContainer() + { + return $this->parameterContainer; + } + + /** + * @param string $name + */ + public function startPrefix($name) + { + if (!isset($this->prefixCounter[$name])) { + $this->prefixCounter[$name] = 0; + } + $this->prefixCurrent[] = [ + 'prefix' => $name . ++$this->prefixCounter[$name], + 'suffixIndex' => 0, + ]; + } + + public function endPrefix() + { + array_pop($this->prefixCurrent); + } + + /** + * @param string $suffix + * @return string + */ + public function getNestedAlias($suffix) + { + $curr = &$this->prefixCurrent[count($this->prefixCurrent) - 1]; + return $curr['prefix'] . $suffix . ++$curr['suffixIndex']; + } +} diff --git a/src/Sql/Builder/IbmDb2/SelectBuilder.php b/src/Sql/Builder/IbmDb2/SelectBuilder.php new file mode 100644 index 0000000000..89f7ecc2f1 --- /dev/null +++ b/src/Sql/Builder/IbmDb2/SelectBuilder.php @@ -0,0 +1,34 @@ + [ + 1 => '%1$s', 2 => '%1$s %2$s' + ], + ]; + $this->selectColumnsTableSpecification['byArgNumber'][2] = $asSpec; + $this->selectFullSpecification['byArgNumber'][3] = $asSpec; + } +} diff --git a/src/Sql/Builder/Mysql/Ddl/Column/ColumnBuilder.php b/src/Sql/Builder/Mysql/Ddl/Column/ColumnBuilder.php new file mode 100644 index 0000000000..51a15f213e --- /dev/null +++ b/src/Sql/Builder/Mysql/Ddl/Column/ColumnBuilder.php @@ -0,0 +1,56 @@ +specifications = [ + 'name' => $this->specifications['name'], + 'type' => $this->specifications['type'], + 'typeData' => [ + 'spec' => [ + 'implode' => ' ', + ], + 'subProperties' => [ + 'unsigned' => [ + 'valueMap' => [true => 'UNSIGNED', false => null], + ], + 'zerofill' => [ + 'valueMap' => [true => 'ZEROFILL', false => null], + ], + ], + ], + 'charset' => 'CHARACTER SET %s', + 'nullable' => $this->specifications['nullable'], + 'identity' => [ + 'valueMap' => [true => 'AUTO_INCREMENT', false => null], + ], + 'constraints' => $this->specifications['constraints'], + 'default' => $this->specifications['default'], + 'comment' => [ + 'spec' => 'COMMENT %s', + 'propertyType' => ExpressionInterface::TYPE_VALUE, + ], + 'columnformat' => 'COLUMN_FORMAT %s', + 'storage' => 'STORAGE %s', + 'on_update' => 'ON UPDATE %s', + ]; + } +} diff --git a/src/Sql/Builder/Mysql/SelectBuilder.php b/src/Sql/Builder/Mysql/SelectBuilder.php new file mode 100644 index 0000000000..9938dee686 --- /dev/null +++ b/src/Sql/Builder/Mysql/SelectBuilder.php @@ -0,0 +1,75 @@ +limit; + if ($limit === null && $sqlObject->offset !== null) { + $limitParam = '18446744073709551615'; + } elseif ($limit === null) { + return; + } else { + $limitParam = new ExpressionParameter($limit); + $limitParam + ->setType(ExpressionInterface::TYPE_VALUE) + ->setName('limit') + ->setOptions([ + 'errata' => Adapter\ParameterContainer::TYPE_INTEGER, + 'isQuoted' => true, + ]); + } + + return [ + 'spec' => $this->limitSpecification, + 'params' => [ + $limitParam, + ], + ]; + } + + /** + * @param Select $sqlObject + * @param Context $context + * @return null|array + */ + protected function build_Offset(Select $sqlObject, Context $context) + { + $offset = $sqlObject->offset; + if ($offset === null) { + return; + } + $offset = new ExpressionParameter($offset, ExpressionInterface::TYPE_VALUE, 'offset'); + $offset->setOptions([ + 'errata' => Adapter\ParameterContainer::TYPE_INTEGER, + 'isQuoted' => true, + ]); + return [ + 'spec' => $this->offsetSpecification, + 'params' => [ + $offset, + ], + ]; + } +} diff --git a/src/Sql/Builder/Oracle/SelectBuilder.php b/src/Sql/Builder/Oracle/SelectBuilder.php new file mode 100644 index 0000000000..f27b4abf9c --- /dev/null +++ b/src/Sql/Builder/Oracle/SelectBuilder.php @@ -0,0 +1,35 @@ + [ + 1 => '%1$s', 2 => '%1$s %2$s' + ], + ]; + $this->selectColumnsTableSpecification['byArgNumber'][2] = $asSpec; + $this->selectFullSpecification['byArgNumber'][3] = $asSpec; + $this->joinsSpecification['forEach']['byArgNumber'][2] = $asSpec; + } +} diff --git a/src/Sql/Builder/SelectLimitOffsetTrait.php b/src/Sql/Builder/SelectLimitOffsetTrait.php new file mode 100644 index 0000000000..b8767299fb --- /dev/null +++ b/src/Sql/Builder/SelectLimitOffsetTrait.php @@ -0,0 +1,62 @@ +validateSqlObject($sqlObject, 'Zend\Db\Sql\Select', __METHOD__); + if ($sqlObject->limit === null && $sqlObject->offset === null) { + return parent::build($sqlObject, $context); + } + + $sqlObject = clone $sqlObject; + $wrapObject = new Select(); + $newSelect = new Select([ + 'LIMIT_OFFSET_WRAP_2' => $wrapObject + ->columns([ + Select::SQL_STAR, + 'LIMIT_OFFSET_ROWNUM' => new Expression('ROW_NUMBER() OVER ()'), + ]) + ->setPrefixColumnsWithTable(false) + ->from([ + 'LIMIT_OFFSET_WRAP_1' => $sqlObject + ]) + ]); + $newSelect->columns([Select::SQL_STAR])->setPrefixColumnsWithTable(false); + + if ($sqlObject->offset !== null) { + $offset = new ExpressionParameter((int) $sqlObject->offset, Expression::TYPE_VALUE, 'offset'); + $newSelect->where->greaterThan('LIMIT_OFFSET_ROWNUM', $offset); + } + + if ($sqlObject->limit !== null) { + $limit = new ExpressionParameter((int) $sqlObject->limit, Expression::TYPE_VALUE, 'limit'); + if ($sqlObject->offset !== null) { + $offset->setName(['offset', 'offsetForSum']); + $limit = new Operator($limit, '+', $offset); + } + $newSelect->where->lessThanOrEqualTo('LIMIT_OFFSET_ROWNUM', $limit); + } + unset($sqlObject->limit, $sqlObject->offset); + return parent::build($newSelect, $context); + } +} diff --git a/src/Sql/Builder/SqlServer/Ddl/CreateTableBuilder.php b/src/Sql/Builder/SqlServer/Ddl/CreateTableBuilder.php new file mode 100644 index 0000000000..3654383b29 --- /dev/null +++ b/src/Sql/Builder/SqlServer/Ddl/CreateTableBuilder.php @@ -0,0 +1,34 @@ +isTemporary ? '#' : '') . ltrim($sqlObject->table->getTable(), '#'); + return [ + 'spec' => $this->tableSpecification, + 'params' => [ + '', + $context->getPlatform()->quoteIdentifier($table), + ], + ]; + } +} diff --git a/src/Sql/Builder/SqlServer/Ddl/DropTableBuilder.php b/src/Sql/Builder/SqlServer/Ddl/DropTableBuilder.php new file mode 100644 index 0000000000..d959f2f3af --- /dev/null +++ b/src/Sql/Builder/SqlServer/Ddl/DropTableBuilder.php @@ -0,0 +1,48 @@ +ifExists) { + $tableString = + $sqlObject->table->getSchema() + ? $sqlObject->table->getSchema() . $context->getPlatform()->getIdentifierSeparator() + : '' + . $sqlObject->table->getTable(); + + return [ + 'spec' => $this->ifExistsSpecification, + 'params' => [ + $tableString, + $sqlObject->table, + ], + ]; + } else { + return [ + 'spec' => $this->tableSpecification, + 'params' => $sqlObject->table, + ]; + } + } +} diff --git a/src/Sql/Builder/SqlServer/SelectBuilder.php b/src/Sql/Builder/SqlServer/SelectBuilder.php new file mode 100644 index 0000000000..be362dccaa --- /dev/null +++ b/src/Sql/Builder/SqlServer/SelectBuilder.php @@ -0,0 +1,18 @@ +validateSqlObject($sqlObject, 'Zend\Db\Sql\Combine', __METHOD__); + $res = []; + foreach ($sqlObject->combine as $i => $combine) { + $type = $i == 0 + ? '' + : strtoupper($combine['type'] . ($combine['modifier'] ? ' ' . $combine['modifier'] : '')) . " "; + $res[] = [ + 'spec' => '%1$s%2$s', + 'params' => [ + $type, + $combine['select'] + ], + ]; + } + return $res; + } +} diff --git a/src/Sql/Builder/sql92/Ddl/AlterTableBuilder.php b/src/Sql/Builder/sql92/Ddl/AlterTableBuilder.php new file mode 100644 index 0000000000..5bc8bbf8d6 --- /dev/null +++ b/src/Sql/Builder/sql92/Ddl/AlterTableBuilder.php @@ -0,0 +1,152 @@ + "ADD COLUMN %1\$s,\n", + 'implode' => " ", + ]; + protected $changeColumnsSpecification = [ + 'forEach' => "CHANGE COLUMN %1\$s %2\$s,\n", + 'implode' => "", + ]; + protected $dropColumnsSpecification = [ + 'forEach' => "DROP COLUMN %1\$s,\n", + 'implode' => "", + ]; + protected $addConstraintsSpecification = [ + 'forEach' => "ADD %1\$s,\n", + 'implode' => "", + ]; + protected $dropConstraintsSpecification = [ + 'forEach' => "DROP CONSTRAINT %1\$s,\n", + 'implode' => "", + ]; + + /** + * @param AlterTable $sqlObject + * @param Context $context + * @return array + */ + public function build($sqlObject, Context $context) + { + $this->validateSqlObject($sqlObject, 'Zend\Db\Sql\Ddl\AlterTable', __METHOD__); + return [ + $this->build_Table($sqlObject, $context), + $this->build_AddColumns($sqlObject, $context), + $this->build_ChangeColumns($sqlObject, $context), + $this->build_DropColumns($sqlObject, $context), + $this->build_AddConstraints($sqlObject, $context), + $this->build_DropConstraints($sqlObject, $context), + ]; + } + + /** + * @param AlterTable $sqlObject + * @param Context $context + * @return array + */ + protected function build_Table(AlterTable $sqlObject, Context $context) + { + return [ + 'spec' => $this->tableSpecification, + 'params' => [ + $sqlObject->table, + ], + ]; + } + + /** + * @param AlterTable $sqlObject + * @param Context $context + * @return array + */ + protected function build_AddColumns(AlterTable $sqlObject, Context $context) + { + return [ + 'spec' => $this->addColumnsSpecification, + 'params' => $sqlObject->addColumns, + ]; + } + + /** + * @param AlterTable $sqlObject + * @param Context $context + * @return array + */ + protected function build_ChangeColumns(AlterTable $sqlObject, Context $context) + { + $sqls = []; + foreach ($sqlObject->changeColumns as $name => $column) { + $sqls[] = [ + $context->getPlatform()->quoteIdentifier($name), + $column + ]; + } + return [ + 'spec' => $this->changeColumnsSpecification, + 'params' => $sqls, + ]; + } + + /** + * @param AlterTable $sqlObject + * @param Context $context + * @return array + */ + protected function build_DropColumns(AlterTable $sqlObject, Context $context) + { + $columns = []; + foreach ($sqlObject->dropColumns as $column) { + $columns[] = $context->getPlatform()->quoteIdentifier($column); + } + return [ + 'spec' => $this->dropColumnsSpecification, + 'params' => $columns, + ]; + } + + /** + * @param AlterTable $sqlObject + * @param Context $context + * @return array + */ + protected function build_AddConstraints(AlterTable $sqlObject, Context $context) + { + return [ + 'spec' => $this->addConstraintsSpecification, + 'params' => $sqlObject->addConstraints, + ]; + } + + /** + * @param AlterTable $sqlObject + * @param Context $context + * @return array + */ + protected function build_DropConstraints(AlterTable $sqlObject, Context $context) + { + $sqls = []; + foreach ($sqlObject->dropConstraints as $constraint) { + $sqls[] = $context->getPlatform()->quoteIdentifier($constraint); + } + return [ + 'spec' => $this->dropConstraintsSpecification, + 'params' => $sqls, + ]; + } +} diff --git a/src/Sql/Builder/sql92/Ddl/Column/ColumnBuilder.php b/src/Sql/Builder/sql92/Ddl/Column/ColumnBuilder.php new file mode 100644 index 0000000000..afceae4f89 --- /dev/null +++ b/src/Sql/Builder/sql92/Ddl/Column/ColumnBuilder.php @@ -0,0 +1,128 @@ + [ + 'spec' => '%s', + 'propertyType' => ExpressionInterface::TYPE_IDENTIFIER, + ], + 'type' => [ + 'spec' => [ + 'byCount' => [ + 1 => '%1$s', + 2 => '%1$s(%2$s)', + 3 => '%1$s(%2$s,%3$s)' + ], + ], + 'subProperties' => [ + 'type' => null, + 'length' => null, + 'decimal' => null, + ], + ], + 'nullable' => [ + 'valueMap' => [false => 'NOT NULL', true => null], + ], + 'constraints' => [ + 'spec' => [ + 'implode' => ' ', + ], + ], + 'default' => [ + 'spec' => 'DEFAULT %s', + 'propertyType' => ExpressionInterface::TYPE_VALUE, + ], + ]; + + /** + * @param \Zend\Db\Sql\Ddl\Column\Column $column + * @param Context $context + * @return array + */ + public function build($column, Context $context) + { + $this->validateSqlObject($column, 'Zend\Db\Sql\Ddl\Column\Column', __METHOD__); + $data = $this->buildColumnSpec($context, $this->specifications, $column); + $data[$this->implodeGlueKey] = ' '; + return $data; + } + + /** + * @param Context $context + * @param array $description + * @param \Zend\Db\Sql\Ddl\Column\Column $column + * @param array $options + * @return array + */ + protected function buildColumnSpec(Context $context, $description, $column, $options = null) + { + if ($options === null) { + $options = []; + foreach ($column->getOptions() as $k=>$v) { + $options[strtolower(str_replace(['-', '_', ' '], '', $k))] = $v; + } + } + foreach ($description as $key => $spec) { + $value = null; + $spec = is_string($spec) ? ['spec' => $spec] : $spec; + if (isset($spec['subProperties'])) { + $value = $this->buildColumnSpec($context, $spec['subProperties'], $column, $options); + } else { + $methodGet = 'get' . ucfirst($key); + $methodIs = 'is' . ucfirst($key); + if (method_exists($column, $methodGet)) { + $value = $column->$methodGet(); + } elseif (method_exists($column, $methodIs)) { + $value = $column->$methodIs(); + } elseif (array_key_exists($key, $options)) { + $value = $options[$key]; + } + } + if ($value === null || $value === '') { + unset($description[$key]); + continue; + } + if (isset($spec['valueMap'])) { + $valueMapKey = is_bool($value) + ? (int)$value + : $value; + $value = array_key_exists($valueMapKey, $spec['valueMap']) + ? $spec['valueMap'][$valueMapKey] + : null; + } + + if ($value == null || $value === '') { + unset($description[$key]); + continue; + } + if (isset($spec['propertyType'])) { + switch ($spec['propertyType']) { + case ExpressionInterface::TYPE_IDENTIFIER : + $value = $context->getPlatform()->quoteIdentifier($value); + break; + case ExpressionInterface::TYPE_VALUE : + $value = $context->getPlatform()->quoteValue($value); + break; + } + } + $description[$key] = isset($spec['spec']) + ? ['spec' => $spec['spec'], 'params' => $value] + : $value; + } + return $description; + } +} diff --git a/src/Sql/Builder/sql92/Ddl/Constraint/AbstractBuilder.php b/src/Sql/Builder/sql92/Ddl/Constraint/AbstractBuilder.php new file mode 100644 index 0000000000..b697b5cf6d --- /dev/null +++ b/src/Sql/Builder/sql92/Ddl/Constraint/AbstractBuilder.php @@ -0,0 +1,67 @@ +validateSqlObject($constraint, 'Zend\Db\Sql\Ddl\Constraint\ConstraintInterface', __METHOD__); + $parameters = []; + $spec = ''; + + if ($constraint->getName()) { + $spec .= $this->namedSpecification; + $parameters[] = new ExpressionParameter($constraint->getName(), ExpressionInterface::TYPE_IDENTIFIER); + } + + $spec .= $this->specification; + + if ($constraint->getColumns()) { + foreach ($constraint->getColumns() as $column) { + $parameters[] = new ExpressionParameter($column, ExpressionInterface::TYPE_IDENTIFIER); + } + $spec .= sprintf( + $this->columnSpecification, + rtrim(str_repeat('%s, ', count($constraint->getColumns())), ', ') + ); + } + + return [[ + 'spec' => $spec, + 'params' => $parameters, + ]]; + } +} diff --git a/src/Sql/Builder/sql92/Ddl/Constraint/CheckBuilder.php b/src/Sql/Builder/sql92/Ddl/Constraint/CheckBuilder.php new file mode 100644 index 0000000000..5b4161047e --- /dev/null +++ b/src/Sql/Builder/sql92/Ddl/Constraint/CheckBuilder.php @@ -0,0 +1,46 @@ +validateSqlObject($check, 'Zend\Db\Sql\Ddl\Constraint\Check', __METHOD__); + $values = []; + $spec = ''; + + if ($check->getName()) { + $spec .= $this->namedSpecification; + $values[] = new ExpressionParameter($check->getName(), ExpressionInterface::TYPE_IDENTIFIER); + } + + $values[] = new ExpressionParameter($check->getExpression(), ExpressionInterface::TYPE_LITERAL); + + return [[ + 'spec' => $spec . $this->specification, + 'params' => $values, + ]]; + } +} diff --git a/src/Sql/Builder/sql92/Ddl/Constraint/ForeignKeyBuilder.php b/src/Sql/Builder/sql92/Ddl/Constraint/ForeignKeyBuilder.php new file mode 100644 index 0000000000..e2917bd6d5 --- /dev/null +++ b/src/Sql/Builder/sql92/Ddl/Constraint/ForeignKeyBuilder.php @@ -0,0 +1,58 @@ +validateSqlObject($constraint, 'Zend\Db\Sql\Ddl\Constraint\ForeignKey', __METHOD__); + $data = parent::build($constraint, $context); + $parameters = &$data[0]['params']; + $parameters[] = new ExpressionParameter($constraint->getReferenceTable(), ExpressionInterface::TYPE_IDENTIFIER); + + $spec = ''; + foreach ($constraint->getReferenceColumn() as $refColumn) { + $parameters[] = new ExpressionParameter($refColumn, ExpressionInterface::TYPE_IDENTIFIER); + $spec .= '%s, '; + } + if ($spec) { + $spec = '(' . rtrim($spec, ', ') . ') '; + } + + $data[0]['spec'] .= $this->referenceSpecification[0] . $spec . $this->referenceSpecification[1]; + $parameters[] = new ExpressionParameter($constraint->getOnDeleteRule(), ExpressionInterface::TYPE_LITERAL); + $parameters[] = new ExpressionParameter($constraint->getOnUpdateRule(), ExpressionInterface::TYPE_LITERAL); + + return $data; + } +} diff --git a/src/Sql/Platform/Sqlite/Sqlite.php b/src/Sql/Builder/sql92/Ddl/Constraint/PrimaryKeyBuilder.php similarity index 51% rename from src/Sql/Platform/Sqlite/Sqlite.php rename to src/Sql/Builder/sql92/Ddl/Constraint/PrimaryKeyBuilder.php index 00712dded1..4f290f83c5 100644 --- a/src/Sql/Platform/Sqlite/Sqlite.php +++ b/src/Sql/Builder/sql92/Ddl/Constraint/PrimaryKeyBuilder.php @@ -7,19 +7,12 @@ * @license http://framework.zend.com/license/new-bsd New BSD License */ -namespace Zend\Db\Sql\Platform\Sqlite; +namespace Zend\Db\Sql\Builder\sql92\Ddl\Constraint; -use Zend\Db\Sql\Platform\AbstractPlatform; - -class Sqlite extends AbstractPlatform +class PrimaryKeyBuilder extends AbstractBuilder { /** - * Constructor - * - * Registers the type decorator. + * @var string */ - public function __construct() - { - $this->setTypeDecorator('Zend\Db\Sql\Select', new SelectDecorator()); - } + protected $specification = 'PRIMARY KEY'; } diff --git a/src/Sql/Builder/sql92/Ddl/Constraint/UniqueKeyBuilder.php b/src/Sql/Builder/sql92/Ddl/Constraint/UniqueKeyBuilder.php new file mode 100644 index 0000000000..bbbcb53cb2 --- /dev/null +++ b/src/Sql/Builder/sql92/Ddl/Constraint/UniqueKeyBuilder.php @@ -0,0 +1,18 @@ + [ + 'prefix' => "\n ", + 'glue' => ",\n ", + ], + ]; + protected $combinedBySpecification = ",\n "; + protected $constraintsSpecification = [ + 'implode' => ",\n ", + ]; + protected $statementEndSpecification = "\n)"; + + /** + * @param CreateTable $sqlObject + * @param Context $context + * @return array + */ + public function build($sqlObject, Context $context) + { + $this->validateSqlObject($sqlObject, 'Zend\Db\Sql\Ddl\CreateTable', __METHOD__); + return [ + $this->build_Table($sqlObject, $context), + $this->build_Columns($sqlObject, $context), + $this->build_Combinedby($sqlObject, $context), + $this->build_Constraints($sqlObject, $context), + $this->build_StatementEnd($sqlObject, $context), + ]; + } + + /** + * @param CreateTable $sqlObject + * @param Context $context + * @return array + */ + protected function build_Table(CreateTable $sqlObject, Context $context) + { + return [ + 'spec' => $this->tableSpecification, + 'params' => [ + $sqlObject->isTemporary ? 'TEMPORARY ' : '', + $sqlObject->table, + ], + ]; + } + + /** + * @param CreateTable $sqlObject + * @param Context $context + * @return array + */ + protected function build_Columns(CreateTable $sqlObject, Context $context) + { + if (! $sqlObject->columns) { + return; + } + return [ + 'spec' => $this->columnsSpecification, + 'params' => $sqlObject->columns, + ]; + } + + /** + * @param CreateTable $sqlObject + * @param Context $context + * @return string + */ + protected function build_Combinedby(CreateTable $sqlObject, Context $context) + { + if ($sqlObject->constraints && $sqlObject->columns) { + return $this->combinedBySpecification; + } + if ($sqlObject->constraints && !$sqlObject->columns) { + return "\n "; + } + } + + /** + * @param CreateTable $sqlObject + * @param Context $context + * @return null|array + */ + protected function build_Constraints(CreateTable $sqlObject, Context $context) + { + if (!$sqlObject->constraints) { + return; + } + + return [ + 'spec' => $this->constraintsSpecification, + 'params' => $sqlObject->constraints, + ]; + } + + /** + * @param CreateTable $sqlObject + * @param Context $context + * @return string + */ + protected function build_StatementEnd(CreateTable $sqlObject, Context $context) + { + return $this->statementEndSpecification; + } +} diff --git a/src/Sql/Builder/sql92/Ddl/DropTableBuilder.php b/src/Sql/Builder/sql92/Ddl/DropTableBuilder.php new file mode 100644 index 0000000000..df2759fe5e --- /dev/null +++ b/src/Sql/Builder/sql92/Ddl/DropTableBuilder.php @@ -0,0 +1,50 @@ +validateSqlObject($sqlObject, 'Zend\Db\Sql\Ddl\DropTable', __METHOD__); + return [ + $this->build_Table($sqlObject, $context), + ]; + } + + /** + * @param DropTable $sqlObject + * @param Context $context + * @return array + */ + protected function build_Table(DropTable $sqlObject, Context $context) + { + return [ + 'spec' => $this->tableSpecification, + 'params' => [ + $sqlObject->ifExists ? $this->ifExistsSpecification : '', + $sqlObject->table, + ], + ]; + } +} diff --git a/src/Sql/Builder/sql92/Ddl/Index/IndexBuilder.php b/src/Sql/Builder/sql92/Ddl/Index/IndexBuilder.php new file mode 100644 index 0000000000..2eeda9a6d1 --- /dev/null +++ b/src/Sql/Builder/sql92/Ddl/Index/IndexBuilder.php @@ -0,0 +1,47 @@ +validateSqlObject($index, 'Zend\Db\Sql\Ddl\Index\AbstractIndex', __METHOD__); + $properties = [ + new ExpressionParameter($index->getName() ?: '', ExpressionInterface::TYPE_IDENTIFIER) + ]; + + $spec = ''; + foreach ($index->getColumns() as $i => $column) { + $properties[] = new ExpressionParameter($column, ExpressionInterface::TYPE_IDENTIFIER); + $spec .= '%s' . (isset($index->getLengths()[$i]) ? '(' . $index->getLengths()[$i] . ')' : '') . ', '; + } + + return [[ + 'spec' => str_replace('...', rtrim($spec, ', '), $this->specification), + 'params' => $properties, + ]]; + } +} diff --git a/src/Sql/Builder/sql92/DeleteBuilder.php b/src/Sql/Builder/sql92/DeleteBuilder.php new file mode 100644 index 0000000000..c8a30d600c --- /dev/null +++ b/src/Sql/Builder/sql92/DeleteBuilder.php @@ -0,0 +1,63 @@ +validateSqlObject($sqlObject, 'Zend\Db\Sql\Delete', __METHOD__); + return [ + $this->build_Delete($sqlObject, $context), + $this->build_Where($sqlObject, $context), + ]; + } + + /** + * @param Delete $sqlObject + * @param Context $context + * @return array + */ + protected function build_Delete(Delete $sqlObject, Context $context) + { + return [ + 'spec' => $this->deleteSpecification, + 'params' => $sqlObject->table, + ]; + } + + /** + * @param Delete $sqlObject + * @param Context $context + * @return array + */ + protected function build_Where(Delete $sqlObject, Context $context) + { + if ($sqlObject->where->count() == 0) { + return; + } + return [ + 'spec' => $this->whereSpecification, + 'params' => $sqlObject->where + ]; + } +} diff --git a/src/Sql/Builder/sql92/ExpressionBuilder.php b/src/Sql/Builder/sql92/ExpressionBuilder.php new file mode 100644 index 0000000000..5265017683 --- /dev/null +++ b/src/Sql/Builder/sql92/ExpressionBuilder.php @@ -0,0 +1,44 @@ +validateSqlObject($expression, 'Zend\Db\Sql\Expression', __METHOD__); + $parameters = (is_scalar($expression->getParameters())) ? [$expression->getParameters()] : $expression->getParameters(); + $parametersCount = count($parameters); + $expression = str_replace('%', '%%', $expression->getExpression()); + + // assign locally, escaping % signs + $expression = str_replace(Expression::PLACEHOLDER, '%s', $expression, $count); + // test number of replacements without considering same variable begin used many times first, which is + // faster, if the test fails then resort to regex wich are slow and used rarely + if ($count !== $parametersCount && $parametersCount === preg_match_all('/\:[a-zA-Z0-9_]*/', $expression)) { + throw new Exception\RuntimeException('The number of replacements in the expression does not match the number of parameters'); + } + return [[ + 'spec' => $expression, + 'params' => $parameters, + ]]; + } +} diff --git a/src/Sql/Builder/sql92/InsertBuilder.php b/src/Sql/Builder/sql92/InsertBuilder.php new file mode 100644 index 0000000000..820be8b6e7 --- /dev/null +++ b/src/Sql/Builder/sql92/InsertBuilder.php @@ -0,0 +1,106 @@ + ', ', + 'format' => '(%s)', + ]; + protected $specificationValues = [ + 'implode' => ', ', + 'format' => 'VALUES (%s)', + ]; + protected $specificationValuesMultiple = [ + 'forEach' => [ + 'implode' => ', ', + 'format' => '(%s)', + ], + 'implode' => ', ', + 'format' => 'VALUES %s', + ]; + + /** + * @param Insert $sqlObject + * @param Context $context + * @return array + */ + public function build($sqlObject, Context $context) + { + $this->validateSqlObject($sqlObject, 'Zend\Db\Sql\Insert', __METHOD__); + return [ + $this->build_Table($sqlObject, $context), + $this->build_Columns($sqlObject, $context), + $this->build_Values($sqlObject, $context), + ]; + } + + protected function build_Table(Insert $sqlObject, Context $context) + { + return [ + 'spec' => $this->specificationTable, + 'params' => $sqlObject->table, + ]; + } + + protected function build_Columns(Insert $sqlObject, Context $context) + { + if (!$sqlObject->columns) { + return; + } + return [ + 'spec' => $this->specificationColumns, + 'params' => array_map([$context->getPlatform(), 'quoteIdentifier'], $sqlObject->columns), + ]; + } + + protected function build_Values(Insert $sqlObject, Context $context) + { + $values = $sqlObject->values; + + if ($values instanceof SelectableInterface) { + return $values; + } + + if (!is_array(reset($values))) { + $pValues = []; + if ($sqlObject->columns) { + foreach (array_combine($sqlObject->columns, $values) as $column=>$value) { + list(, $pValues[]) = $this->resolveColumnValue($column, $value, $context); + } + } else { + foreach ($values as $value) { + list(, $pValues[]) = $this->resolveColumnValue(null, $value, $context); + } + } + return [ + 'spec' => $this->specificationValues, + 'params' => $pValues, + ]; + } + + foreach ($values as &$valueRow) { + foreach ($valueRow as &$value) { + list(, $value) = $this->resolveColumnValue(null, $value, $context); + } + } + return [ + 'spec' => $this->specificationValuesMultiple, + 'params' => $values, + ]; + } +} diff --git a/src/Sql/Builder/sql92/LiteralBuilder.php b/src/Sql/Builder/sql92/LiteralBuilder.php new file mode 100644 index 0000000000..1bc954c526 --- /dev/null +++ b/src/Sql/Builder/sql92/LiteralBuilder.php @@ -0,0 +1,29 @@ +validateSqlObject($expression, 'Zend\Db\Sql\Literal', __METHOD__); + return [ + 'spec' => $expression->getLiteral() + ]; + } +} diff --git a/src/Sql/Builder/sql92/Predicate/BetweenBuilder.php b/src/Sql/Builder/sql92/Predicate/BetweenBuilder.php new file mode 100644 index 0000000000..8388672f1e --- /dev/null +++ b/src/Sql/Builder/sql92/Predicate/BetweenBuilder.php @@ -0,0 +1,36 @@ +validateSqlObject($expression, 'Zend\Db\Sql\Predicate\Between', __METHOD__); + return [[ + 'spec' => $this->specification, + 'params' => [ + $expression->getIdentifier(), + $expression->getMinValue(), + $expression->getMaxValue(), + ], + ]]; + } +} diff --git a/src/Sql/Builder/sql92/Predicate/InBuilder.php b/src/Sql/Builder/sql92/Predicate/InBuilder.php new file mode 100644 index 0000000000..324fe58490 --- /dev/null +++ b/src/Sql/Builder/sql92/Predicate/InBuilder.php @@ -0,0 +1,58 @@ +validateSqlObject($expression, 'Zend\Db\Sql\Predicate\In', __METHOD__); + $identifier = $expression->getIdentifier(); + $values = $expression->getValueSet(); + $replacements = []; + + if (is_array($identifier)) { + $identifierSpecFragment = '(' . implode(', ', array_fill(0, count($identifier), '%s')) . ')'; + $replacements = $identifier; + } else { + $identifierSpecFragment = '%s'; + $replacements[] = $identifier; + } + + if (is_array($values)) { + $replacements = array_merge($replacements, $values); + $specification = vsprintf( + $this->specification, + [$identifierSpecFragment, '(' . implode(', ', array_fill(0, count($values), '%s')) . ')'] + ); + } else { + $specification = vsprintf( + $this->specification, + [$identifierSpecFragment, '%s'] + ); + $replacements[] = $values; + } + + return [[ + 'spec' => $specification, + 'params' => $replacements, + ]]; + } +} diff --git a/src/Sql/Builder/sql92/Predicate/IsNotNullBuilder.php b/src/Sql/Builder/sql92/Predicate/IsNotNullBuilder.php new file mode 100644 index 0000000000..6eae0d9b8f --- /dev/null +++ b/src/Sql/Builder/sql92/Predicate/IsNotNullBuilder.php @@ -0,0 +1,15 @@ +validateSqlObject($expression, 'Zend\Db\Sql\Predicate\IsNull', __METHOD__); + return [[ + 'spec' => $this->specification, + 'params' => [$expression->getIdentifier()], + ]]; + } +} diff --git a/src/Sql/Builder/sql92/Predicate/LikeBuilder.php b/src/Sql/Builder/sql92/Predicate/LikeBuilder.php new file mode 100644 index 0000000000..56525715ae --- /dev/null +++ b/src/Sql/Builder/sql92/Predicate/LikeBuilder.php @@ -0,0 +1,38 @@ +validateSqlObject($expression, 'Zend\Db\Sql\Predicate\Like', __METHOD__); + return [[ + 'spec' => $this->specification, + 'params' => [ + $expression->getIdentifier(), + $expression->getLike(), + ], + ]]; + } +} diff --git a/src/Sql/Builder/sql92/Predicate/NotBetweenBuilder.php b/src/Sql/Builder/sql92/Predicate/NotBetweenBuilder.php new file mode 100644 index 0000000000..c390dd8e1f --- /dev/null +++ b/src/Sql/Builder/sql92/Predicate/NotBetweenBuilder.php @@ -0,0 +1,36 @@ +validateSqlObject($expression, 'Zend\Db\Sql\Predicate\NotBetween', __METHOD__); + return [[ + 'spec' => $this->specification, + 'params' => [ + $expression->getIdentifier(), + $expression->getMinValue(), + $expression->getMaxValue(), + ], + ]]; + } +} diff --git a/src/Sql/Builder/sql92/Predicate/NotInBuilder.php b/src/Sql/Builder/sql92/Predicate/NotInBuilder.php new file mode 100644 index 0000000000..cb431013b9 --- /dev/null +++ b/src/Sql/Builder/sql92/Predicate/NotInBuilder.php @@ -0,0 +1,15 @@ +validateSqlObject($expression, 'Zend\Db\Sql\Predicate\Operator', __METHOD__); + return [[ + 'spec' => '%s ' . $expression->getOperator() . ' %s', + 'params' => [ + $expression->getLeft(), + $expression->getRight(), + ], + ]]; + } +} diff --git a/src/Sql/Builder/sql92/Predicate/PredicateBuilder.php b/src/Sql/Builder/sql92/Predicate/PredicateBuilder.php new file mode 100644 index 0000000000..6ec9b0ed9a --- /dev/null +++ b/src/Sql/Builder/sql92/Predicate/PredicateBuilder.php @@ -0,0 +1,14 @@ +validateSqlObject($expression, 'Zend\Db\Sql\Predicate\PredicateSet', __METHOD__); + $predicates = $expression->getPredicates(); + $parts = []; + for ($i = 0, $count = count($predicates); $i < $count; $i++) { + /** @var $predicate PredicateInterface */ + $predicate = $predicates[$i][1]; + + if ($predicate instanceof PredicateSet) { + if ($predicate->count() == 0) { + continue; + } + $parts[] = '('; + } + + $parts = array_merge( + $parts, + $this->platformBuilder->getPlatformBuilder($predicate, $context)->build($predicate, $context) + ); + + if ($predicate instanceof PredicateSet) { + $parts[] = ')'; + } + + if (isset($predicates[$i+1])) { + $parts[] = sprintf(' %s ', $predicates[$i+1][0]); + } + } + return !$parts + ? false + : $parts; + } +} diff --git a/src/Sql/Builder/sql92/SelectBuilder.php b/src/Sql/Builder/sql92/SelectBuilder.php new file mode 100644 index 0000000000..6d513cdeea --- /dev/null +++ b/src/Sql/Builder/sql92/SelectBuilder.php @@ -0,0 +1,376 @@ + [ + 1 => [ + 'forEach' => [ + 'byCount' => [ + 1 => '%1$s', 2 => '%1$s AS %2$s' + ], + ], + 'implode' => ', ', + ], + ], + 'format' => 'SELECT %1$s', + ]; + protected $selectColumnsTableSpecification = [ + 'byArgNumber' => [ + 1 => [ + 'forEach' => [ + 'byCount' => [ + 1 => '%1$s', 2 => '%1$s AS %2$s' + ], + ], + 'implode' => ', ', + ], + 2 => [ + 'byCount' => [ + 1 => '%1$s', 2 => '%1$s AS %2$s' + ], + ], + ], + 'format' => 'SELECT %1$s FROM %2$s', + ]; + protected $selectFullSpecification = [ + 'byArgNumber' => [ + 2 => [ + 'forEach' => [ + 'byCount' => [ + 1 => '%1$s', 2 => '%1$s AS %2$s' + ], + ], + 'implode' => ', ', + ], + 3 => [ + 'byCount' => [ + 1 => '%1$s', 2 => '%1$s AS %2$s' + ], + ], + ], + 'format' => 'SELECT %1$s %2$s FROM %3$s', + ]; + protected $joinsSpecification = [ + 'forEach' => [ + 'byArgNumber' => [ + 2 => [ + 'byCount' => [ + 1 => '%1$s', 2 => '%1$s AS %2$s' + ], + ], + ], + 'format' => '%1$s JOIN %2$s ON %3$s', + ], + 'implode' => ' ', + ]; + protected $whereSpecification = 'WHERE %1$s'; + protected $groupSpecification = [ + 'implode' => ', ', + 'format' => 'GROUP BY %1$s', + ]; + protected $havingSpecification = 'HAVING %1$s'; + protected $orderSpecification = [ + 'forEach' => [ + 'byCount' => [ + 1 => '%1$s', 2 => '%1$s %2$s' + ], + ], + 'implode' => ', ', + 'format' => 'ORDER BY %1$s', + ]; + protected $limitSpecification = 'LIMIT %1$s'; + protected $offsetSpecification = 'OFFSET %1$s'; + + /** + * @param Select $sqlObject + * @param Context $context + * @return array|null + */ + public function build($sqlObject, Context $context) + { + $this->validateSqlObject($sqlObject, 'Zend\Db\Sql\Select', __METHOD__); + + if ($sqlObject->combine) { + return $this->build_Combine($sqlObject, $context); + } + + $sqls = []; + $sqls['select'] = $this->build_Select($sqlObject, $context, $sqls); + $sqls['joins'] = $this->build_Joins($sqlObject, $context, $sqls); + $sqls['where'] = $this->build_Where($sqlObject, $context, $sqls); + $sqls['group'] = $this->build_Group($sqlObject, $context, $sqls); + $sqls['having'] = $this->build_Having($sqlObject, $context, $sqls); + $sqls['order'] = $this->build_Order($sqlObject, $context, $sqls); + $sqls['limit'] = $this->build_Limit($sqlObject, $context, $sqls); + $sqls['offset'] = $this->build_Offset($sqlObject, $context, $sqls); + return $sqls; + } + + /** + * @param Select $sqlObject + * @param Context $context + * @return array + */ + protected function build_Select(Select $sqlObject, Context $context) + { + $table = $this->nornalizeTable($sqlObject->table, $context); + $fromTable = ($sqlObject->prefixColumnsWithTable && $table['columnAlias']) + ? $table['columnAlias'] . $context->getPlatform()->getIdentifierSeparator() + : ''; + unset($table['columnAlias']); + if (!$table['alias']) { + unset($table['alias']); + } + if (!$table['name']) { + $table = null; + } + + // build_ table columns + $columns = []; + foreach ($sqlObject->columns as $columnIndexOrAs => $column) { + $columns[] = $this->resolveSelectColumn($fromTable, $columnIndexOrAs, $column, $context); + } + + // build_ join columns + foreach ($sqlObject->joins as $join) { + $jTable = $this->nornalizeTable($join['name'], $context); + $joinName = $jTable['columnAlias'] + ? $jTable['columnAlias'] . $context->getPlatform()->getIdentifierSeparator() + : ''; + + foreach ($join['columns'] as $columnIndexOrAs => $column) { + $columns[] = $this->resolveSelectColumn($joinName, $columnIndexOrAs, $column, $context); + } + } + + if (!$table) { + return [ + 'spec' => $this->selectNoTableSpecification, + 'params' => [ + $columns + ], + ]; + } elseif ($sqlObject->quantifier) { + return [ + 'spec' => $this->selectFullSpecification, + 'params' => [ + $sqlObject->quantifier, + $columns, + $table, + ], + ]; + } else { + return [ + 'spec' => $this->selectColumnsTableSpecification, + 'params' => [ + $columns, + $table, + ], + ]; + } + } + + /** + * @param Select $sqlObject + * @param Context $context + * @return array|null + */ + protected function build_Where(Select $sqlObject, Context $context) + { + if ($sqlObject->where->count() == 0) { + return; + } + return [ + 'spec' => $this->whereSpecification, + 'params' => $sqlObject->where, + ]; + } + + /** + * @param Select $sqlObject + * @param Context $context + * @return array|null + */ + protected function build_Group(Select $sqlObject, Context $context) + { + if ($sqlObject->group === null) { + return; + } + // build_ table columns + $groups = []; + foreach ($sqlObject->group as $column) { + $groups[] = is_scalar($column) + ? $context->getPlatform()->quoteIdentifierInFragment($column) + : $column; + } + return [ + 'spec' => $this->groupSpecification, + 'params' => $groups, + ]; + } + + /** + * @param Select $sqlObject + * @param Context $context + * @return array|null + */ + protected function build_Having(Select $sqlObject, Context $context) + { + if ($sqlObject->having->count() == 0) { + return; + } + return [ + 'spec' => $this->havingSpecification, + 'params' => $sqlObject->having, + ]; + } + + /** + * @param Select $sqlObject + * @param Context $context + * @return array|null + */ + protected function build_Order(Select $sqlObject, Context $context) + { + if (!$sqlObject->order) { + return; + } + $orders = []; + foreach ($sqlObject->order as $k => $v) { + if ($v instanceof ExpressionInterface) { + $orders[] = [ + $v + ]; + continue; + } + if (is_int($k)) { + if (strpos($v, ' ') !== false) { + list($k, $v) = preg_split('# #', $v, 2); + } else { + $k = $v; + $v = Select::ORDER_ASCENDING; + } + } + if (strtoupper($v) == Select::ORDER_DESCENDING) { + $orders[] = [$context->getPlatform()->quoteIdentifierInFragment($k), Select::ORDER_DESCENDING]; + } else { + $orders[] = [$context->getPlatform()->quoteIdentifierInFragment($k), Select::ORDER_ASCENDING]; + } + } + return [ + 'spec' => $this->orderSpecification, + 'params' => $orders, + ]; + } + + /** + * @param Select $sqlObject + * @param Context $context + * @return array|null + */ + protected function build_Limit(Select $sqlObject, Context $context) + { + if ($sqlObject->limit === null) { + return; + } + + $limit = new ExpressionParameter($sqlObject->limit); + $limit->setType(ExpressionInterface::TYPE_VALUE); + $limit->setName('limit'); + $limit->setOption('errata', Adapter\ParameterContainer::TYPE_INTEGER); + + return [ + 'spec' => $this->limitSpecification, + 'params' => $limit, + ]; + } + + /** + * @param Select $sqlObject + * @param Context $context + * @return array|null + */ + protected function build_Offset(Select $sqlObject, Context $context) + { + if ($sqlObject->offset === null) { + return; + } + + $offset = new ExpressionParameter($sqlObject->offset, ExpressionInterface::TYPE_VALUE, 'offset'); + $offset->setOption('errata', Adapter\ParameterContainer::TYPE_INTEGER); + + return [ + 'spec' => $this->offsetSpecification, + 'params' => $offset + ]; + } + + /** + * @param Select $sqlObject + * @param Context $context + * @return array|null + */ + protected function build_Combine(Select $sqlObject, Context $context) + { + $combine = clone $sqlObject->combine; + $combineInternal = $combine->combine; + unset($combineInternal[0]['select']->combine); + return $this->platformBuilder->getPlatformBuilder($combine)->build($combine, $context); + } + + /** + * @param array $fromTable + * @param int|string $indexOrAlias + * @param null|string|ExpressionInterface|SelectableInterface $column + * @param Context $context + * @return array + */ + protected function resolveSelectColumn($fromTable, $indexOrAlias, $column, Context $context) + { + if ($column === Select::SQL_STAR) { + return [$fromTable . Select::SQL_STAR]; + } + + if (is_string($indexOrAlias)) { + $indexOrAlias = $context->getPlatform()->quoteIdentifier($indexOrAlias); + } elseif (is_string($column)) { + $indexOrAlias = $context->getPlatform()->quoteIdentifier($column); + } else { + $indexOrAlias = $context->getNestedAlias('column'); + } + + if ($column === null) { + $column = 'NULL'; + } elseif (!$column instanceof ExpressionInterface && !$column instanceof SelectableInterface) { + $column = $fromTable . $context->getPlatform()->quoteIdentifierInFragment($column); + } + + if ($indexOrAlias) { + return [ + $column, + $indexOrAlias, + ]; + } + + return [$column]; + } +} diff --git a/src/Sql/Builder/sql92/UpdateBuilder.php b/src/Sql/Builder/sql92/UpdateBuilder.php new file mode 100644 index 0000000000..d894c9209f --- /dev/null +++ b/src/Sql/Builder/sql92/UpdateBuilder.php @@ -0,0 +1,111 @@ + [ + [3 => '%1$s JOIN %2$s ON %3$s', 'combinedby' => ' '] + ] + ];*/ + protected $joinsSpecification = [ + 'forEach' => [ + 'byArgNumber' => [ + 2 => [ + 'byCount' => [ + 1 => '%1$s', 2 => '%1$s AS %2$s' + ], + ], + ], + 'format' => '%1$s JOIN %2$s ON %3$s', + ], + 'implode' => ' ', + ]; + protected $setSpecification = [ + 'byArgNumber' => [ + 1 => [ + 'forEach' => '%1$s = %2$s', + 'implode' => ', ', + ], + ], + 'format' => 'SET %1$s', + ]; + + /** + * @param Update $sqlObject + * @param Context $context + * @return array + */ + public function build($sqlObject, Context $context) + { + $this->validateSqlObject($sqlObject, 'Zend\Db\Sql\Update', __METHOD__); + return [ + $this->build_Update($sqlObject, $context), + $this->build_Joins($sqlObject, $context), + $this->build_Set($sqlObject, $context), + $this->build_Where($sqlObject, $context), + ]; + } + + /** + * @param Update $sqlObject + * @param Context $context + * @return array + */ + protected function build_Update(Update $sqlObject, Context $context) + { + return [ + 'spec' => $this->updateSpecification, + 'params' => $sqlObject->table, + ]; + } + + /** + * @param Update $sqlObject + * @param Context $context + * @return string + */ + protected function build_Set(Update $sqlObject, Context $context) + { + $setSql = []; + foreach ($sqlObject->set as $column => $value) { + $setSql[] = $this->resolveColumnValue($column, $value, $context); + } + return [ + 'spec' => $this->setSpecification, + 'params' => [ + $setSql + ], + ]; + } + + /** + * @param Update $sqlObject + * @param Context $context + * @return array|null + */ + protected function build_Where(Update $sqlObject, Context $context) + { + if ($sqlObject->where->count() == 0) { + return; + } + return [ + 'spec' => $this->whereSpecification, + 'params' => $sqlObject->where + ]; + } +} diff --git a/src/Sql/Combine.php b/src/Sql/Combine.php index 5d9f96f040..dd128c4b25 100644 --- a/src/Sql/Combine.php +++ b/src/Sql/Combine.php @@ -9,32 +9,28 @@ namespace Zend\Db\Sql; -use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\Driver\DriverInterface; -use Zend\Db\Adapter\ParameterContainer; - /** * Combine SQL statement - allows combining multiple select statements into one + * + * @property array $columns + * @property SelectableInterface[][] $combine */ -class Combine extends AbstractPreparableSql +class Combine extends AbstractSqlObject implements PreparableSqlObjectInterface, SelectableInterface { - const COLUMNS = 'columns'; - const COMBINE = 'combine'; const COMBINE_UNION = 'union'; const COMBINE_EXCEPT = 'except'; const COMBINE_INTERSECT = 'intersect'; - /** - * @var string[] - */ - protected $specifications = [ - self::COMBINE => '%1$s (%2$s) ', - ]; /** - * @var Select[][] + * @var SelectableInterface[][] */ - private $combine = []; + protected $combine = []; + + protected $__getProperties = [ + 'combine', + 'columns' + ]; /** * @param Select|array|null $select @@ -43,6 +39,7 @@ class Combine extends AbstractPreparableSql */ public function __construct($select = null, $type = self::COMBINE_UNION, $modifier = '') { + parent::__construct(); if ($select) { $this->combine($select, $type, $modifier); } @@ -51,7 +48,7 @@ public function __construct($select = null, $type = self::COMBINE_UNION, $modifi /** * Create combine clause * - * @param Select|array $select + * @param SelectableInterface|array $select * @param string $type * @param string $modifier * @@ -61,20 +58,26 @@ public function combine($select, $type = self::COMBINE_UNION, $modifier = '') { if (is_array($select)) { foreach ($select as $combine) { - if ($combine instanceof Select) { - $combine = [$combine]; + if ($combine instanceof SelectableInterface) { + $this->combine($combine, $type, $modifier); + } elseif (is_string(key($combine))) { + $this->combine( + $combine['select'], + isset($combine['type']) ? $combine['type'] : $type, + isset($combine['modifier']) ? $combine['modifier'] : $modifier + ); + } else { + $this->combine( + $combine[0], + isset($combine[1]) ? $combine[1] : $type, + isset($combine[2]) ? $combine[2] : $modifier + ); } - - $this->combine( - $combine[0], - isset($combine[1]) ? $combine[1] : $type, - isset($combine[2]) ? $combine[2] : $modifier - ); } return $this; } - if (! $select instanceof Select) { + if (! $select instanceof SelectableInterface) { throw new Exception\InvalidArgumentException(sprintf( '$select must be a array or instance of Select, "%s" given', is_object($select) ? get_class($select) : gettype($select) @@ -92,7 +95,7 @@ public function combine($select, $type = self::COMBINE_UNION, $modifier = '') /** * Create union clause * - * @param Select|array $select + * @param SelectableInterface|array $select * @param string $modifier * * @return self @@ -105,7 +108,7 @@ public function union($select, $modifier = '') /** * Create except clause * - * @param Select|array $select + * @param SelectableInterface|array $select * @param string $modifier * * @return self @@ -118,7 +121,7 @@ public function except($select, $modifier = '') /** * Create intersect clause * - * @param Select|array $select + * @param SelectableInterface|array $select * @param string $modifier * @return self */ @@ -127,36 +130,6 @@ public function intersect($select, $modifier = '') return $this->combine($select, self::COMBINE_INTERSECT, $modifier); } - /** - * Build sql string - * - * @param PlatformInterface $platform - * @param DriverInterface $driver - * @param ParameterContainer $parameterContainer - * - * @return string - */ - protected function buildSqlString(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if (!$this->combine) { - return; - } - - $sql = ''; - foreach ($this->combine as $i => $combine) { - $type = $i == 0 - ? '' - : strtoupper($combine['type'] . ($combine['modifier'] ? ' ' . $combine['modifier'] : '')); - $select = $this->processSubSelect($combine['select'], $platform, $driver, $parameterContainer); - $sql .= sprintf( - $this->specifications[self::COMBINE], - $type, - $select - ); - } - return trim($sql, ' '); - } - /** * @return $this */ @@ -170,12 +143,12 @@ public function alignColumns() foreach ($this->combine as $combine) { $allColumns = array_merge( $allColumns, - $combine['select']->getRawState(self::COLUMNS) + $combine['select']->columns ); } foreach ($this->combine as $combine) { - $combineColumns = $combine['select']->getRawState(self::COLUMNS); + $combineColumns = $combine['select']->columns; $aligned = []; foreach ($allColumns as $alias => $column) { $aligned[$alias] = isset($combineColumns[$alias]) @@ -187,21 +160,27 @@ public function alignColumns() return $this; } + public function __get($name) + { + if ($name == 'columns') { + return $this->combine + ? $this->combine[0]['select']->columns + : []; + } + return parent::__get($name); + } + /** - * Get raw state + * __clone * - * @param string $key + * Resets the where object each time the Select is cloned. * - * @return array + * @return void */ - public function getRawState($key = null) + public function __clone() { - $rawState = [ - self::COMBINE => $this->combine, - self::COLUMNS => $this->combine - ? $this->combine[0]['select']->getRawState(self::COLUMNS) - : [], - ]; - return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; + foreach ($this->combine as $k => $v) { + $this->combine[$k]['select'] = clone $v['select']; + } } } diff --git a/src/Sql/Ddl/AlterTable.php b/src/Sql/Ddl/AlterTable.php index 3daba72eb8..a07e28173a 100644 --- a/src/Sql/Ddl/AlterTable.php +++ b/src/Sql/Ddl/AlterTable.php @@ -9,18 +9,19 @@ namespace Zend\Db\Sql\Ddl; -use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Sql\AbstractSql; +use Zend\Db\Sql\AbstractSqlObject; +use Zend\Db\Sql\TableIdentifier; -class AlterTable extends AbstractSql implements SqlInterface +/** + * @property null|string|array|TableIdentifier $table + * @property array $addColumns + * @property array $dropColumns + * @property array $changeColumns + * @property array $addConstraints + * @property array $dropConstraints + */ +class AlterTable extends AbstractSqlObject { - const ADD_COLUMNS = 'addColumns'; - const ADD_CONSTRAINTS = 'addConstraints'; - const CHANGE_COLUMNS = 'changeColumns'; - const DROP_COLUMNS = 'dropColumns'; - const DROP_CONSTRAINTS = 'dropConstraints'; - const TABLE = 'table'; - /** * @var array */ @@ -46,59 +47,37 @@ class AlterTable extends AbstractSql implements SqlInterface */ protected $dropConstraints = []; - /** - * Specifications for Sql String generation - * @var array - */ - protected $specifications = [ - self::TABLE => "ALTER TABLE %1\$s\n", - self::ADD_COLUMNS => [ - "%1\$s" => [ - [1 => "ADD COLUMN %1\$s,\n", 'combinedby' => ""] - ] - ], - self::CHANGE_COLUMNS => [ - "%1\$s" => [ - [2 => "CHANGE COLUMN %1\$s %2\$s,\n", 'combinedby' => ""], - ] - ], - self::DROP_COLUMNS => [ - "%1\$s" => [ - [1 => "DROP COLUMN %1\$s,\n", 'combinedby' => ""], - ] - ], - self::ADD_CONSTRAINTS => [ - "%1\$s" => [ - [1 => "ADD %1\$s,\n", 'combinedby' => ""], - ] - ], - self::DROP_CONSTRAINTS => [ - "%1\$s" => [ - [1 => "DROP CONSTRAINT %1\$s,\n", 'combinedby' => ""], - ] - ] - ]; /** - * @var string + * @var TableIdentifier */ - protected $table = ''; + protected $table; + + protected $__getProperties = [ + 'table', + 'addColumns', + 'dropColumns', + 'changeColumns', + 'addConstraints', + 'dropConstraints', + ]; /** - * @param string $table + * @param string|array|TableIdentifier $table */ - public function __construct($table = '') + public function __construct($table = null) { - ($table) ? $this->setTable($table) : null; + parent::__construct(); + $this->setTable($table); } /** - * @param string $name + * @param string|array|TableIdentifier $name * @return self */ public function setTable($name) { - $this->table = $name; + $this->table = TableIdentifier::factory($name); return $this; } @@ -158,80 +137,4 @@ public function addConstraint(Constraint\ConstraintInterface $constraint) return $this; } - - /** - * @param string|null $key - * @return array - */ - public function getRawState($key = null) - { - $rawState = [ - self::TABLE => $this->table, - self::ADD_COLUMNS => $this->addColumns, - self::DROP_COLUMNS => $this->dropColumns, - self::CHANGE_COLUMNS => $this->changeColumns, - self::ADD_CONSTRAINTS => $this->addConstraints, - self::DROP_CONSTRAINTS => $this->dropConstraints, - ]; - - return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; - } - - protected function processTable(PlatformInterface $adapterPlatform = null) - { - return [$adapterPlatform->quoteIdentifier($this->table)]; - } - - protected function processAddColumns(PlatformInterface $adapterPlatform = null) - { - $sqls = []; - foreach ($this->addColumns as $column) { - $sqls[] = $this->processExpression($column, $adapterPlatform); - } - - return [$sqls]; - } - - protected function processChangeColumns(PlatformInterface $adapterPlatform = null) - { - $sqls = []; - foreach ($this->changeColumns as $name => $column) { - $sqls[] = [ - $adapterPlatform->quoteIdentifier($name), - $this->processExpression($column, $adapterPlatform) - ]; - } - - return [$sqls]; - } - - protected function processDropColumns(PlatformInterface $adapterPlatform = null) - { - $sqls = []; - foreach ($this->dropColumns as $column) { - $sqls[] = $adapterPlatform->quoteIdentifier($column); - } - - return [$sqls]; - } - - protected function processAddConstraints(PlatformInterface $adapterPlatform = null) - { - $sqls = []; - foreach ($this->addConstraints as $constraint) { - $sqls[] = $this->processExpression($constraint, $adapterPlatform); - } - - return [$sqls]; - } - - protected function processDropConstraints(PlatformInterface $adapterPlatform = null) - { - $sqls = []; - foreach ($this->dropConstraints as $constraint) { - $sqls[] = $adapterPlatform->quoteIdentifier($constraint); - } - - return [$sqls]; - } } diff --git a/src/Sql/Ddl/Column/AbstractLengthColumn.php b/src/Sql/Ddl/Column/AbstractLengthColumn.php index 397887acd4..7e5d5532e7 100644 --- a/src/Sql/Ddl/Column/AbstractLengthColumn.php +++ b/src/Sql/Ddl/Column/AbstractLengthColumn.php @@ -47,26 +47,4 @@ public function getLength() { return $this->length; } - - /** - * @return string - */ - protected function getLengthExpression() - { - return (string) $this->length; - } - - /** - * @return array - */ - public function getExpressionData() - { - $data = parent::getExpressionData(); - - if ($this->getLengthExpression()) { - $data[0][1][1] .= '(' . $this->getLengthExpression() . ')'; - } - - return $data; - } } diff --git a/src/Sql/Ddl/Column/AbstractPrecisionColumn.php b/src/Sql/Ddl/Column/AbstractPrecisionColumn.php index bf50c3f62c..7044695afb 100644 --- a/src/Sql/Ddl/Column/AbstractPrecisionColumn.php +++ b/src/Sql/Ddl/Column/AbstractPrecisionColumn.php @@ -65,16 +65,4 @@ public function getDecimal() { return $this->decimal; } - - /** - * {@inheritDoc} - */ - protected function getLengthExpression() - { - if ($this->decimal !== null) { - return $this->length . ',' . $this->decimal; - } - - return $this->length; - } } diff --git a/src/Sql/Ddl/Column/AbstractTimestampColumn.php b/src/Sql/Ddl/Column/AbstractTimestampColumn.php index 8bdda7e94f..e1b1a076a2 100644 --- a/src/Sql/Ddl/Column/AbstractTimestampColumn.php +++ b/src/Sql/Ddl/Column/AbstractTimestampColumn.php @@ -16,48 +16,4 @@ */ abstract class AbstractTimestampColumn extends Column { - /** - * @return array - */ - public function getExpressionData() - { - $spec = $this->specification; - - $params = []; - $params[] = $this->name; - $params[] = $this->type; - - $types = [self::TYPE_IDENTIFIER, self::TYPE_LITERAL]; - - if (!$this->isNullable) { - $spec .= ' NOT NULL'; - } - - if ($this->default !== null) { - $spec .= ' DEFAULT %s'; - $params[] = $this->default; - $types[] = self::TYPE_VALUE; - } - - $options = $this->getOptions(); - - if (isset($options['on_update'])) { - $spec .= ' %s'; - $params[] = 'ON UPDATE CURRENT_TIMESTAMP'; - $types[] = self::TYPE_LITERAL; - } - - $data = [[ - $spec, - $params, - $types, - ]]; - - foreach ($this->constraints as $constraint) { - $data[] = ' '; - $data = array_merge($data, $constraint->getExpressionData()); - } - - return $data; - } } diff --git a/src/Sql/Ddl/Column/Boolean.php b/src/Sql/Ddl/Column/Boolean.php index 6c650e948e..79b98c44d2 100644 --- a/src/Sql/Ddl/Column/Boolean.php +++ b/src/Sql/Ddl/Column/Boolean.php @@ -26,6 +26,6 @@ class Boolean extends Column */ public function setNullable($nullable) { - return parent::setNullable(false); + return parent::setNullable($nullable); } } diff --git a/src/Sql/Ddl/Column/Column.php b/src/Sql/Ddl/Column/Column.php index f204db96df..d7e60edd7d 100644 --- a/src/Sql/Ddl/Column/Column.php +++ b/src/Sql/Ddl/Column/Column.php @@ -38,11 +38,6 @@ class Column implements ColumnInterface */ protected $constraints = []; - /** - * @var string - */ - protected $specification = '%s %s'; - /** * @var string */ @@ -80,6 +75,11 @@ public function getName() return $this->name; } + public function getType() + { + return $this->type; + } + /** * @param bool $nullable * @return self @@ -157,40 +157,8 @@ public function addConstraint(ConstraintInterface $constraint) return $this; } - /** - * @return array - */ - public function getExpressionData() + public function getConstraints() { - $spec = $this->specification; - - $params = []; - $params[] = $this->name; - $params[] = $this->type; - - $types = [self::TYPE_IDENTIFIER, self::TYPE_LITERAL]; - - if (!$this->isNullable) { - $spec .= ' NOT NULL'; - } - - if ($this->default !== null) { - $spec .= ' DEFAULT %s'; - $params[] = $this->default; - $types[] = self::TYPE_VALUE; - } - - $data = [[ - $spec, - $params, - $types, - ]]; - - foreach ($this->constraints as $constraint) { - $data[] = ' '; - $data = array_merge($data, $constraint->getExpressionData()); - } - - return $data; + return $this->constraints; } } diff --git a/src/Sql/Ddl/Column/Float.php b/src/Sql/Ddl/Column/Float.php deleted file mode 100644 index a67f857568..0000000000 --- a/src/Sql/Ddl/Column/Float.php +++ /dev/null @@ -1,48 +0,0 @@ -getOptions(); - - if (isset($options['length'])) { - $data[0][1][1] .= '(' . $options['length'] . ')'; - } - - return $data; - } } diff --git a/src/Sql/Ddl/Constraint/AbstractConstraint.php b/src/Sql/Ddl/Constraint/AbstractConstraint.php index 88f3b07744..7ac0dee860 100644 --- a/src/Sql/Ddl/Constraint/AbstractConstraint.php +++ b/src/Sql/Ddl/Constraint/AbstractConstraint.php @@ -11,21 +11,6 @@ abstract class AbstractConstraint implements ConstraintInterface { - /** - * @var string - */ - protected $columnSpecification = ' (%s)'; - - /** - * @var string - */ - protected $namedSpecification = 'CONSTRAINT %s '; - - /** - * @var string - */ - protected $specification = ''; - /** * @var string */ @@ -95,36 +80,4 @@ public function getColumns() { return $this->columns; } - - /** - * {@inheritDoc} - */ - public function getExpressionData() - { - $colCount = count($this->columns); - $newSpecTypes = []; - $values = []; - $newSpec = ''; - - if ($this->name) { - $newSpec .= $this->namedSpecification; - $values[] = $this->name; - $newSpecTypes[] = self::TYPE_IDENTIFIER; - } - - $newSpec .= $this->specification; - - if ($colCount) { - $values = array_merge($values, $this->columns); - $newSpecParts = array_fill(0, $colCount, '%s'); - $newSpecTypes = array_merge($newSpecTypes, array_fill(0, $colCount, self::TYPE_IDENTIFIER)); - $newSpec .= sprintf($this->columnSpecification, implode(', ', $newSpecParts)); - } - - return [[ - $newSpec, - $values, - $newSpecTypes, - ]]; - } } diff --git a/src/Sql/Ddl/Constraint/Check.php b/src/Sql/Ddl/Constraint/Check.php index df3917b0e8..b09937c6f5 100644 --- a/src/Sql/Ddl/Constraint/Check.php +++ b/src/Sql/Ddl/Constraint/Check.php @@ -16,11 +16,6 @@ class Check extends AbstractConstraint */ protected $expression; - /** - * {@inheritDoc} - */ - protected $specification = 'CHECK (%s)'; - /** * @param string|\Zend\Db\Sql\ExpressionInterface $expression * @param null|string $name @@ -32,25 +27,20 @@ public function __construct($expression, $name) } /** - * {@inheritDoc} + * @param string|\Zend\Db\Sql\ExpressionInterface $expression + * @return \Zend\Db\Sql\Ddl\Constraint\Check */ - public function getExpressionData() + public function setExpression($expression) { - $newSpecTypes = [self::TYPE_LITERAL]; - $values = [$this->expression]; - $newSpec = ''; - - if ($this->name) { - $newSpec .= $this->namedSpecification; - - array_unshift($values, $this->name); - array_unshift($newSpecTypes, self::TYPE_IDENTIFIER); - } + $this->expression = $expression; + return $this; + } - return [[ - $newSpec . $this->specification, - $values, - $newSpecTypes, - ]]; + /** + * @return string|\Zend\Db\Sql\ExpressionInterface + */ + public function getExpression() + { + return $this->expression; } } diff --git a/src/Sql/Ddl/Constraint/ForeignKey.php b/src/Sql/Ddl/Constraint/ForeignKey.php index 8a2a44394d..0574f3cee0 100644 --- a/src/Sql/Ddl/Constraint/ForeignKey.php +++ b/src/Sql/Ddl/Constraint/ForeignKey.php @@ -31,19 +31,6 @@ class ForeignKey extends AbstractConstraint */ protected $referenceTable = ''; - /** - * {@inheritDoc} - */ - protected $columnSpecification = 'FOREIGN KEY (%s) '; - - /** - * @var string[] - */ - protected $referenceSpecification = [ - 'REFERENCES %s ', - 'ON DELETE %s ON UPDATE %s' - ]; - /** * @param null|string $name * @param null|string|array $columns @@ -142,37 +129,4 @@ public function getOnUpdateRule() { return $this->onUpdateRule; } - - /** - * @return array - */ - public function getExpressionData() - { - $data = parent::getExpressionData(); - $colCount = count($this->referenceColumn); - $newSpecTypes = [self::TYPE_IDENTIFIER]; - $values = [$this->referenceTable]; - - $data[0][0] .= $this->referenceSpecification[0]; - - if ($colCount) { - $values = array_merge($values, $this->referenceColumn); - $newSpecParts = array_fill(0, $colCount, '%s'); - $newSpecTypes = array_merge($newSpecTypes, array_fill(0, $colCount, self::TYPE_IDENTIFIER)); - - $data[0][0] .= sprintf('(%s) ', implode(', ', $newSpecParts)); - } - - $data[0][0] .= $this->referenceSpecification[1]; - - $values[] = $this->onDeleteRule; - $values[] = $this->onUpdateRule; - $newSpecTypes[] = self::TYPE_LITERAL; - $newSpecTypes[] = self::TYPE_LITERAL; - - $data[0][1] = array_merge($data[0][1], $values); - $data[0][2] = array_merge($data[0][2], $newSpecTypes); - - return $data; - } } diff --git a/src/Sql/Ddl/Constraint/PrimaryKey.php b/src/Sql/Ddl/Constraint/PrimaryKey.php index 9775bb018f..ead9e056da 100644 --- a/src/Sql/Ddl/Constraint/PrimaryKey.php +++ b/src/Sql/Ddl/Constraint/PrimaryKey.php @@ -11,8 +11,4 @@ class PrimaryKey extends AbstractConstraint { - /** - * @var string - */ - protected $specification = 'PRIMARY KEY'; } diff --git a/src/Sql/Ddl/Constraint/UniqueKey.php b/src/Sql/Ddl/Constraint/UniqueKey.php index b46dbd159b..777b4cac14 100644 --- a/src/Sql/Ddl/Constraint/UniqueKey.php +++ b/src/Sql/Ddl/Constraint/UniqueKey.php @@ -11,8 +11,4 @@ class UniqueKey extends AbstractConstraint { - /** - * @var string - */ - protected $specification = 'UNIQUE'; } diff --git a/src/Sql/Ddl/CreateTable.php b/src/Sql/Ddl/CreateTable.php index 12f94ab03b..bc394979fc 100644 --- a/src/Sql/Ddl/CreateTable.php +++ b/src/Sql/Ddl/CreateTable.php @@ -9,15 +9,17 @@ namespace Zend\Db\Sql\Ddl; -use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Sql\AbstractSql; +use Zend\Db\Sql\AbstractSqlObject; +use Zend\Db\Sql\TableIdentifier; -class CreateTable extends AbstractSql implements SqlInterface +/** + * @property TableIdentifier $table + * @property array $columns + * @property array $constraints + * @property bool $isTemporary + */ +class CreateTable extends AbstractSqlObject { - const COLUMNS = 'columns'; - const CONSTRAINTS = 'constraints'; - const TABLE = 'table'; - /** * @var Column\ColumnInterface[] */ @@ -33,37 +35,26 @@ class CreateTable extends AbstractSql implements SqlInterface */ protected $isTemporary = false; - /** - * {@inheritDoc} - */ - protected $specifications = [ - self::TABLE => 'CREATE %1$sTABLE %2$s (', - self::COLUMNS => [ - "\n %1\$s" => [ - [1 => '%1$s', 'combinedby' => ",\n "] - ] - ], - 'combinedBy' => ",", - self::CONSTRAINTS => [ - "\n %1\$s" => [ - [1 => '%1$s', 'combinedby' => ",\n "] - ] - ], - 'statementEnd' => '%1$s', + protected $__getProperties = [ + 'table', + 'columns', + 'constraints', + 'isTemporary', ]; /** - * @var string + * @var TableIdentifier */ - protected $table = ''; + protected $table; /** * @param string $table * @param bool $isTemporary */ - public function __construct($table = '', $isTemporary = false) + public function __construct($table = null, $isTemporary = false) { - $this->table = $table; + parent::__construct(); + $this->setTable($table); $this->setTemporary($isTemporary); } @@ -91,7 +82,7 @@ public function isTemporary() */ public function setTable($name) { - $this->table = $name; + $this->table = TableIdentifier::factory($name); return $this; } @@ -114,94 +105,4 @@ public function addConstraint(Constraint\ConstraintInterface $constraint) $this->constraints[] = $constraint; return $this; } - - /** - * @param string|null $key - * @return array - */ - public function getRawState($key = null) - { - $rawState = [ - self::COLUMNS => $this->columns, - self::CONSTRAINTS => $this->constraints, - self::TABLE => $this->table, - ]; - - return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; - } - - /** - * @param PlatformInterface $adapterPlatform - * - * @return string[] - */ - protected function processTable(PlatformInterface $adapterPlatform = null) - { - return [ - $this->isTemporary ? 'TEMPORARY ' : '', - $adapterPlatform->quoteIdentifier($this->table), - ]; - } - - /** - * @param PlatformInterface $adapterPlatform - * - * @return string[][]|null - */ - protected function processColumns(PlatformInterface $adapterPlatform = null) - { - if (! $this->columns) { - return; - } - - $sqls = []; - - foreach ($this->columns as $column) { - $sqls[] = $this->processExpression($column, $adapterPlatform); - } - - return [$sqls]; - } - - /** - * @param PlatformInterface $adapterPlatform - * - * @return array|string - */ - protected function processCombinedby(PlatformInterface $adapterPlatform = null) - { - if ($this->constraints && $this->columns) { - return $this->specifications['combinedBy']; - } - } - - /** - * @param PlatformInterface $adapterPlatform - * - * @return string[][]|null - */ - protected function processConstraints(PlatformInterface $adapterPlatform = null) - { - if (!$this->constraints) { - return; - } - - $sqls = []; - - foreach ($this->constraints as $constraint) { - $sqls[] = $this->processExpression($constraint, $adapterPlatform); - } - - return [$sqls]; - } - - /** - * @param PlatformInterface $adapterPlatform - * - * @return string[] - */ - protected function processStatementEnd(PlatformInterface $adapterPlatform = null) - { - return ["\n)"]; - } } diff --git a/src/Sql/Ddl/DropTable.php b/src/Sql/Ddl/DropTable.php index ecf5e5f5db..a008695185 100644 --- a/src/Sql/Ddl/DropTable.php +++ b/src/Sql/Ddl/DropTable.php @@ -9,35 +9,39 @@ namespace Zend\Db\Sql\Ddl; -use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Sql\AbstractSql; +use Zend\Db\Sql\AbstractSqlObject; +use Zend\Db\Sql\TableIdentifier; -class DropTable extends AbstractSql implements SqlInterface +/** + * @property TableIdentifier $table + * @property bool $ifExists + */ +class DropTable extends AbstractSqlObject { - const TABLE = 'table'; - /** - * @var array + * @var TableIdentifier */ - protected $specifications = [ - self::TABLE => 'DROP TABLE %1$s' - ]; + protected $table; - /** - * @var string - */ - protected $table = ''; + protected $ifExists = false; + + protected $__getProperties = [ + 'table', + 'ifExists', + ]; /** * @param string $table */ - public function __construct($table = '') + public function __construct($table = null) { - $this->table = $table; + parent::__construct(); + $this->table = TableIdentifier::factory($table); } - protected function processTable(PlatformInterface $adapterPlatform = null) + public function ifExists($ifExists = false) { - return [$adapterPlatform->quoteIdentifier($this->table)]; + $this->ifExists = (bool)$ifExists; + return $this; } } diff --git a/src/Sql/Ddl/Index/Index.php b/src/Sql/Ddl/Index/Index.php index a0239089a4..4148fe928b 100644 --- a/src/Sql/Ddl/Index/Index.php +++ b/src/Sql/Ddl/Index/Index.php @@ -11,11 +11,6 @@ class Index extends AbstractIndex { - /** - * @var string - */ - protected $specification = 'INDEX %s(...)'; - /** * @var array */ @@ -34,47 +29,14 @@ public function __construct($columns, $name = null, array $lengths = []) $this->lengths = $lengths; } - /** - * - * @return array of array|string should return an array in the format: - * - * array ( - * // a sprintf formatted string - * string $specification, - * - * // the values for the above sprintf formatted string - * array $values, - * - * // an array of equal length of the $values array, with either TYPE_IDENTIFIER or TYPE_VALUE for each value - * array $types, - * ) - * - */ - public function getExpressionData() + public function setLengths($lengths) { - $colCount = count($this->columns); - $values = []; - $values[] = $this->name ?: ''; - $newSpecTypes = [self::TYPE_IDENTIFIER]; - $newSpecParts = []; - - for ($i = 0; $i < $colCount; $i++) { - $specPart = '%s'; - - if (isset($this->lengths[$i])) { - $specPart .= "({$this->lengths[$i]})"; - } - - $newSpecParts[] = $specPart; - $newSpecTypes[] = self::TYPE_IDENTIFIER; - } - - $newSpec = str_replace('...', implode(', ', $newSpecParts), $this->specification); + $this->lengths = $lengths; + return $this; + } - return [[ - $newSpec, - array_merge($values, $this->columns), - $newSpecTypes, - ]]; + public function getLengths() + { + return $this->lengths; } } diff --git a/src/Sql/Ddl/Sql.php b/src/Sql/Ddl/Sql.php new file mode 100644 index 0000000000..d220289d17 --- /dev/null +++ b/src/Sql/Ddl/Sql.php @@ -0,0 +1,49 @@ +validateTable($table); + return new AlterTable($table ?: $this->table); + } + + /** + * @param null|string|array|BaseSql\TableIdentifier $table + * @return CreateTable + * @throws Exception\InvalidArgumentException + */ + public function createTable($table = null) + { + $this->validateTable($table); + return new CreateTable($table ?: $this->table); + } + + /** + * @param null|string|array|BaseSql\TableIdentifier $table + * @return DropTable + * @throws Exception\InvalidArgumentException + */ + public function dropTable($table = null) + { + $this->validateTable($table); + return new DropTable($table ?: $this->table); + } +} diff --git a/src/Sql/Ddl/SqlInterface.php b/src/Sql/Ddl/SqlObjectInterface.php similarity index 73% rename from src/Sql/Ddl/SqlInterface.php rename to src/Sql/Ddl/SqlObjectInterface.php index 0f8660f452..d6d41b2155 100644 --- a/src/Sql/Ddl/SqlInterface.php +++ b/src/Sql/Ddl/SqlObjectInterface.php @@ -9,8 +9,8 @@ namespace Zend\Db\Sql\Ddl; -use Zend\Db\Sql\SqlInterface as BaseSqlInterface; +use Zend\Db\Sql\SqlObjectInterface as BaseSqlObjectInterface; -interface SqlInterface extends BaseSqlInterface +interface SqlObjectInterface extends BaseSqlObjectInterface { } diff --git a/src/Sql/Delete.php b/src/Sql/Delete.php index 6c81efd48b..6da40c0eb0 100644 --- a/src/Sql/Delete.php +++ b/src/Sql/Delete.php @@ -9,92 +9,51 @@ namespace Zend\Db\Sql; -use Zend\Db\Adapter\ParameterContainer; -use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\Driver\DriverInterface; - /** - * + * @property TableSource $table * @property Where $where */ -class Delete extends AbstractPreparableSql +class Delete extends AbstractSqlObject implements PreparableSqlObjectInterface { - /**@#+ - * @const - */ - const SPECIFICATION_DELETE = 'delete'; - const SPECIFICATION_WHERE = 'where'; - /**@#-*/ - /** - * {@inheritDoc} - */ - protected $specifications = [ - self::SPECIFICATION_DELETE => 'DELETE FROM %1$s', - self::SPECIFICATION_WHERE => 'WHERE %1$s' - ]; - - /** - * @var string|TableIdentifier + * @var TableSource */ protected $table = ''; - /** - * @var bool - */ - protected $emptyWhereProtection = true; - - /** - * @var array - */ - protected $set = []; - /** * @var null|string|Where */ protected $where = null; + protected $__getProperties = [ + 'table', + 'where', + ]; + /** * Constructor * - * @param null|string|TableIdentifier $table + * @param null|string|array|TableIdentifier|TableSource $table */ public function __construct($table = null) { - if ($table) { - $this->from($table); - } + parent::__construct(); + $this->from($table); $this->where = new Where(); } /** * Create from statement * - * @param string|TableIdentifier $table + * @param string|array|TableIdentifier|TableSource $table * @return Delete */ public function from($table) { - $this->table = $table; + $this->table = TableSource::factory($table); return $this; } - /** - * @param null $key - * - * @return mixed - */ - public function getRawState($key = null) - { - $rawState = [ - 'emptyWhereProtection' => $this->emptyWhereProtection, - 'table' => $this->table, - 'set' => $this->set, - 'where' => $this->where - ]; - return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; - } - /** * Create where clause * @@ -113,54 +72,8 @@ public function where($predicate, $combination = Predicate\PredicateSet::OP_AND) return $this; } - /** - * @param PlatformInterface $platform - * @param DriverInterface|null $driver - * @param ParameterContainer|null $parameterContainer - * - * @return string - */ - protected function processDelete(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) + public function __clone() { - return sprintf( - $this->specifications[static::SPECIFICATION_DELETE], - $this->resolveTable($this->table, $platform, $driver, $parameterContainer) - ); - } - - /** - * @param PlatformInterface $platform - * @param DriverInterface|null $driver - * @param ParameterContainer|null $parameterContainer - * - * @return null|string - */ - protected function processWhere(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->where->count() == 0) { - return; - } - - return sprintf( - $this->specifications[static::SPECIFICATION_WHERE], - $this->processExpression($this->where, $platform, $driver, $parameterContainer, 'where') - ); - } - - /** - * Property overloading - * - * Overloads "where" only. - * - * @param string $name - * - * @return Where|null - */ - public function __get($name) - { - switch (strtolower($name)) { - case 'where': - return $this->where; - } + $this->table = clone $this->table; } } diff --git a/src/Sql/Expression.php b/src/Sql/Expression.php index 95692a6f5a..939d6a6f1a 100644 --- a/src/Sql/Expression.php +++ b/src/Sql/Expression.php @@ -9,13 +9,10 @@ namespace Zend\Db\Sql; -class Expression extends AbstractExpression -{ - /** - * @const - */ - const PLACEHOLDER = '?'; +use Zend\Stdlib\ArrayUtils; +class Expression implements ExpressionInterface +{ /** * @var string */ @@ -26,44 +23,22 @@ class Expression extends AbstractExpression */ protected $parameters = []; - /** - * @var array - */ - protected $types = []; - /** * @param string $expression - * @param string|array $parameters - * @param array $types @deprecated will be dropped in version 3.0.0 + * @param string|array $valueParameter */ - public function __construct($expression = '', $parameters = null, array $types = []) + public function __construct($expression = '', $valueParameter = null /*[, $valueParameter, ... ]*/) { if ($expression !== '') { $this->setExpression($expression); } - if ($types) { // should be deprecated and removed version 3.0.0 - if (is_array($parameters)) { - foreach ($parameters as $i=>$parameter) { - $parameters[$i] = [ - $parameter => isset($types[$i]) ? $types[$i] : self::TYPE_VALUE, - ]; - } - } elseif (is_scalar($parameters)) { - $parameters = [ - $parameters => $types[0], - ]; - } - } - - if ($parameters) { - $this->setParameters($parameters); - } + $this->setParameters(is_array($valueParameter) ? $valueParameter : array_slice(func_get_args(), 1)); } /** - * @param $expression - * @return Expression + * @param string $expression + * @return self * @throws Exception\InvalidArgumentException */ public function setExpression($expression) @@ -93,7 +68,18 @@ public function setParameters($parameters) if (!is_scalar($parameters) && !is_array($parameters)) { throw new Exception\InvalidArgumentException('Expression parameters must be a scalar or array.'); } - $this->parameters = $parameters; + $this->parameters = []; + + $parameters = (array)$parameters; + if (ArrayUtils::hasStringKeys($parameters)) { + foreach ($parameters as $value => $type) { + $this->parameters[] = new ExpressionParameter($value, $type); + } + } else { + foreach ($parameters as $parameter) { + $this->parameters[] = new ExpressionParameter($parameter, self::TYPE_VALUE); + } + } return $this; } @@ -104,59 +90,4 @@ public function getParameters() { return $this->parameters; } - - /** - * @deprecated - * @param array $types - * @return Expression - */ - public function setTypes(array $types) - { - $this->types = $types; - return $this; - } - - /** - * @deprecated - * @return array - */ - public function getTypes() - { - return $this->types; - } - - /** - * @return array - * @throws Exception\RuntimeException - */ - public function getExpressionData() - { - $parameters = (is_scalar($this->parameters)) ? [$this->parameters] : $this->parameters; - $parametersCount = count($parameters); - $expression = str_replace('%', '%%', $this->expression); - - if ($parametersCount == 0) { - return [ - str_ireplace(self::PLACEHOLDER, '', $expression) - ]; - } - - // assign locally, escaping % signs - $expression = str_replace(self::PLACEHOLDER, '%s', $expression, $count); - - // test number of replacements without considering same variable begin used many times first, which is - // faster, if the test fails then resort to regex wich are slow and used rarely - if ($count !== $parametersCount && $parametersCount === preg_match_all('/\:[a-zA-Z0-9_]*/', $expression)) { - throw new Exception\RuntimeException('The number of replacements in the expression does not match the number of parameters'); - } - - foreach ($parameters as $parameter) { - list($values[], $types[]) = $this->normalizeArgument($parameter, self::TYPE_VALUE); - } - return [[ - $expression, - $values, - $types - ]]; - } } diff --git a/src/Sql/ExpressionInterface.php b/src/Sql/ExpressionInterface.php index 282b408683..3f1f1f92a6 100644 --- a/src/Sql/ExpressionInterface.php +++ b/src/Sql/ExpressionInterface.php @@ -11,27 +11,10 @@ interface ExpressionInterface { + const PLACEHOLDER = '?'; + const TYPE_IDENTIFIER = 'identifier'; const TYPE_VALUE = 'value'; const TYPE_LITERAL = 'literal'; const TYPE_SELECT = 'select'; - - /** - * @abstract - * - * @return array of array|string should return an array in the format: - * - * array ( - * // a sprintf formatted string - * string $specification, - * - * // the values for the above sprintf formatted string - * array $values, - * - * // an array of equal length of the $values array, with either TYPE_IDENTIFIER or TYPE_VALUE for each value - * array $types, - * ) - * - */ - public function getExpressionData(); } diff --git a/src/Sql/ExpressionParameter.php b/src/Sql/ExpressionParameter.php new file mode 100644 index 0000000000..85457c9df6 --- /dev/null +++ b/src/Sql/ExpressionParameter.php @@ -0,0 +1,150 @@ +value = $value->value; + $this->type = $value->type; + $this->name = $value->name; + $this->options = $value->options; + return; + } + + if (is_array($type)) { + $this->options = $type; + $type = ExpressionInterface::TYPE_VALUE; + } + if (is_array($value)) { + if (is_string(key($value))) { + $type = current($value); + $value = key($value); + } elseif (count($value) == 1) { + $type = current($value); + $value = key($value); + } else { + $type = isset($value[1]) ? $value[1] : $type; + $value = $value[0]; + } + } + + if ($value instanceof ExpressionInterface || $value instanceof SqlObjectInterface) { + $type = ExpressionInterface::TYPE_SELECT; + } + + $this->value = $value; + $this->type = $type; + $this->name = $name; + } + + /** + * @param mixed $value + * @return self + */ + public function setValue($value) + { + $this->value = $value; + return $this; + } + + /** + * @return mixed + */ + public function getValue() + { + return $this->value; + } + + /** + * @param string $type + * @return self + */ + public function setType($type) + { + $this->type = $type; + return $this; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @param string $name + * @return self + */ + public function setName($name) + { + $this->name = $name; + return $this; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + * @param mixed $value + * @return self + */ + public function setOption($name, $value) + { + $this->options[$name] = $value; + return $this; + } + + /** + * @param array $options + * @return self + */ + public function setOptions(array $options) + { + foreach ($options as $name=>$value) { + $this->options[$name] = $value; + } + return $this; + } + + /** + * @param string $name + * @return null|mixed + */ + public function getOption($name) + { + return array_key_exists($name, $this->options) + ? $this->options[$name] + : null; + } +} diff --git a/src/Sql/Insert.php b/src/Sql/Insert.php index 891f59906b..ceb50b29c9 100644 --- a/src/Sql/Insert.php +++ b/src/Sql/Insert.php @@ -9,63 +9,49 @@ namespace Zend\Db\Sql; -use Zend\Db\Adapter\Driver\DriverInterface; -use Zend\Db\Adapter\ParameterContainer; -use Zend\Db\Adapter\Platform\PlatformInterface; - -class Insert extends AbstractPreparableSql +/** + * @property TableSource $table + * @property array $columns + * @property array|SelectableInterface $values + */ +class Insert extends AbstractSqlObject implements PreparableSqlObjectInterface { - /**#@+ - * Constants - * - * @const - */ - const SPECIFICATION_INSERT = 'insert'; - const SPECIFICATION_SELECT = 'select'; const VALUES_MERGE = 'merge'; const VALUES_SET = 'set'; - /**#@-*/ /** - * @var array Specification array - */ - protected $specifications = [ - self::SPECIFICATION_INSERT => 'INSERT INTO %1$s (%2$s) VALUES (%3$s)', - self::SPECIFICATION_SELECT => 'INSERT INTO %1$s %2$s %3$s', - ]; - - /** - * @var string|TableIdentifier + * @var TableSource */ protected $table = null; protected $columns = []; + protected $values = []; - /** - * @var array|Select - */ - protected $select = null; + protected $__getProperties = [ + 'table', + 'columns', + 'values', + ]; /** * Constructor * - * @param null|string|TableIdentifier $table + * @param null|string|array|TableIdentifier|TableSource $table */ public function __construct($table = null) { - if ($table) { - $this->into($table); - } + parent::__construct(); + $this->into($table); } /** * Create INTO clause * - * @param string|TableIdentifier $table - * @return Insert + * @param string|array|TableIdentifier|TableSource $table + * @return self */ public function into($table) { - $this->table = $table; + $this->table = TableSource::factory($table); return $this; } @@ -73,210 +59,90 @@ public function into($table) * Specify columns * * @param array $columns - * @return Insert + * @return self */ public function columns(array $columns) { - $this->columns = array_flip($columns); + $this->columns = $columns; return $this; } /** * Specify values to insert * - * @param array|Select $values + * @param array|SelectableInterface $values * @param string $flag one of VALUES_MERGE or VALUES_SET; defaults to VALUES_SET * @throws Exception\InvalidArgumentException - * @return Insert + * @return self */ public function values($values, $flag = self::VALUES_SET) { - if ($values instanceof Select) { + if ($values instanceof SelectableInterface) { if ($flag == self::VALUES_MERGE) { throw new Exception\InvalidArgumentException( - 'A Zend\Db\Sql\Select instance cannot be provided with the merge flag' + 'A Zend\Db\Sql\SelectableInterface instance cannot be provided with the merge flag' ); } - $this->select = $values; + $this->values = $values; return $this; } if (!is_array($values)) { throw new Exception\InvalidArgumentException( - 'values() expects an array of values or Zend\Db\Sql\Select instance' + 'values() expects an array of values or Zend\Db\Sql\SelectableInterface instance' ); } - - if ($this->select && $flag == self::VALUES_MERGE) { + if ($this->values instanceof SelectableInterface && $flag == self::VALUES_MERGE) { throw new Exception\InvalidArgumentException( - 'An array of values cannot be provided with the merge flag when a Zend\Db\Sql\Select instance already exists as the value source' + 'An array of values cannot be provided with the merge flag when a Zend\Db\Sql\SelectableInterface instance already exists as the value source' ); } + $columns = null; + if (!is_numeric(key($values))) { + $columns = array_keys($values); + $values = array_values($values); + } + if ($flag == self::VALUES_SET) { - $this->columns = $this->isAssocativeArray($values) - ? $values - : array_combine(array_keys($this->columns), array_values($values)); - } else { - foreach ($values as $column => $value) { - $this->columns[$column] = $value; + $this->values = $values; + if ($columns) { + $this->columns = $columns; } + return $this; } - return $this; - } - - - /** - * Simple test for an associative array - * - * @link http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential - * @param array $array - * @return bool - */ - private function isAssocativeArray(array $array) - { - return array_keys($array) !== range(0, count($array) - 1); - } - - /** - * Create INTO SELECT clause - * - * @param Select $select - * @return self - */ - public function select(Select $select) - { - return $this->values($select); - } - /** - * Get raw state - * - * @param string $key - * @return mixed - */ - public function getRawState($key = null) - { - $rawState = [ - 'table' => $this->table, - 'columns' => array_keys($this->columns), - 'values' => array_values($this->columns) - ]; - return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; - } - - protected function processInsert(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->select) { - return; - } - if (!$this->columns) { - throw new Exception\InvalidArgumentException('values or select should be present'); + if (!$columns) { + $this->values = array_merge($this->values, $values); + return $this; } - $columns = []; - $values = []; - - foreach ($this->columns as $column => $value) { - $columns[] = $platform->quoteIdentifier($column); - if (is_scalar($value) && $parameterContainer) { - $values[] = $driver->formatParameterName($column); - $parameterContainer->offsetSet($column, $value); + foreach ($columns as $i=>$column) { + if (($k = array_search($column, $this->columns)) !== false) { + $this->values[$k] = $values[$i]; + unset($values[$i], $columns[$i]); } else { - $values[] = $this->resolveColumnValue( - $value, - $platform, - $driver, - $parameterContainer - ); + $this->values[] = $values[$i]; + $this->columns[] = $column; } } - return sprintf( - $this->specifications[static::SPECIFICATION_INSERT], - $this->resolveTable($this->table, $platform, $driver, $parameterContainer), - implode(', ', $columns), - implode(', ', $values) - ); - } - - protected function processSelect(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if (!$this->select) { - return; - } - $selectSql = $this->processSubSelect($this->select, $platform, $driver, $parameterContainer); - - $columns = array_map([$platform, 'quoteIdentifier'], array_keys($this->columns)); - $columns = implode(', ', $columns); - - return sprintf( - $this->specifications[static::SPECIFICATION_SELECT], - $this->resolveTable($this->table, $platform, $driver, $parameterContainer), - $columns ? "($columns)" : "", - $selectSql - ); - } - /** - * Overloading: variable setting - * - * Proxies to values, using VALUES_MERGE strategy - * - * @param string $name - * @param mixed $value - * @return Insert - */ - public function __set($name, $value) - { - $this->columns[$name] = $value; return $this; } /** - * Overloading: variable unset - * - * Proxies to values and columns - * - * @param string $name - * @throws Exception\InvalidArgumentException - * @return void - */ - public function __unset($name) - { - if (!array_key_exists($name, $this->columns)) { - throw new Exception\InvalidArgumentException('The key ' . $name . ' was not found in this objects column list'); - } - - unset($this->columns[$name]); - } - - /** - * Overloading: variable isset - * - * Proxies to columns; does a column of that name exist? + * Create INTO SELECT clause * - * @param string $name - * @return bool + * @param SelectableInterface $select + * @return self */ - public function __isset($name) + public function select(SelectableInterface $select) { - return array_key_exists($name, $this->columns); + return $this->values($select); } - /** - * Overloading: variable retrieval - * - * Retrieves value by column name - * - * @param string $name - * @throws Exception\InvalidArgumentException - * @return mixed - */ - public function __get($name) + public function __clone() { - if (!array_key_exists($name, $this->columns)) { - throw new Exception\InvalidArgumentException('The key ' . $name . ' was not found in this objects column list'); - } - return $this->columns[$name]; + $this->table = clone $this->table; } } diff --git a/src/Sql/Join.php b/src/Sql/Joins.php similarity index 87% rename from src/Sql/Join.php rename to src/Sql/Joins.php index 770e35a4c1..141729e9e7 100644 --- a/src/Sql/Join.php +++ b/src/Sql/Joins.php @@ -22,7 +22,7 @@ * - type: the type of JOIN being performed; see the `JOIN_*` constants; * defaults to `JOIN_INNER` */ -class Join implements Iterator, Countable +class Joins implements Iterator, Countable { const JOIN_INNER = 'inner'; const JOIN_OUTER = 'outer'; @@ -118,25 +118,17 @@ public function getJoins() * @return self Implements a fluent interface. * @throws Exception\InvalidArgumentException for invalid $name values. */ - public function join($name, $on, $columns = [Select::SQL_STAR], $type = Join::JOIN_INNER) + public function join($name, $on, $columns = [Select::SQL_STAR], $type = Joins::JOIN_INNER) { - if (is_array($name) && (! is_string(key($name)) || count($name) !== 1)) { - throw new Exception\InvalidArgumentException( - sprintf("join() expects '%s' as a single element associative array", array_shift($name)) - ); - } - - if (! is_array($columns)) { + if (!is_array($columns)) { $columns = [$columns]; } - $this->joins[] = [ - 'name' => $name, + 'name' => TableSource::factory($name), 'on' => $on, 'columns' => $columns, - 'type' => $type ? $type : Join::JOIN_INNER + 'type' => $type ? $type : Joins::JOIN_INNER ]; - return $this; } diff --git a/src/Sql/Literal.php b/src/Sql/Literal.php index d8f8ee5eac..903de07258 100644 --- a/src/Sql/Literal.php +++ b/src/Sql/Literal.php @@ -41,16 +41,4 @@ public function getLiteral() { return $this->literal; } - - /** - * @return array - */ - public function getExpressionData() - { - return [[ - str_replace('%', '%%', $this->literal), - [], - [] - ]]; - } } diff --git a/src/Sql/Platform/AbstractPlatform.php b/src/Sql/Platform/AbstractPlatform.php deleted file mode 100644 index 55411d7d33..0000000000 --- a/src/Sql/Platform/AbstractPlatform.php +++ /dev/null @@ -1,106 +0,0 @@ -subject = $subject; - - return $this; - } - - /** - * @param string $type - * @param PlatformDecoratorInterface $decorator - * - * @return void - */ - public function setTypeDecorator($type, PlatformDecoratorInterface $decorator) - { - $this->decorators[$type] = $decorator; - } - - /** - * @param PreparableSqlInterface|SqlInterface $subject - * @return PlatformDecoratorInterface|PreparableSqlInterface|SqlInterface - */ - public function getTypeDecorator($subject) - { - foreach ($this->decorators as $type => $decorator) { - if ($subject instanceof $type) { - $decorator->setSubject($subject); - - return $decorator; - } - } - - return $subject; - } - - /** - * @return array|PlatformDecoratorInterface[] - */ - public function getDecorators() - { - return $this->decorators; - } - - /** - * {@inheritDoc} - * - * @throws Exception\RuntimeException - */ - public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) - { - if (! $this->subject instanceof PreparableSqlInterface) { - throw new Exception\RuntimeException('The subject does not appear to implement Zend\Db\Sql\PreparableSqlInterface, thus calling prepareStatement() has no effect'); - } - - $this->getTypeDecorator($this->subject)->prepareStatement($adapter, $statementContainer); - - return $statementContainer; - } - - /** - * {@inheritDoc} - * - * @throws Exception\RuntimeException - */ - public function getSqlString(PlatformInterface $adapterPlatform = null) - { - if (! $this->subject instanceof SqlInterface) { - throw new Exception\RuntimeException('The subject does not appear to implement Zend\Db\Sql\SqlInterface, thus calling prepareStatement() has no effect'); - } - - return $this->getTypeDecorator($this->subject)->getSqlString($adapterPlatform); - } -} diff --git a/src/Sql/Platform/IbmDb2/IbmDb2.php b/src/Sql/Platform/IbmDb2/IbmDb2.php deleted file mode 100644 index 35ddc2c768..0000000000 --- a/src/Sql/Platform/IbmDb2/IbmDb2.php +++ /dev/null @@ -1,23 +0,0 @@ -setTypeDecorator('Zend\Db\Sql\Select', ($selectDecorator) ?: new SelectDecorator()); - } -} diff --git a/src/Sql/Platform/IbmDb2/SelectDecorator.php b/src/Sql/Platform/IbmDb2/SelectDecorator.php deleted file mode 100644 index 28602b20e4..0000000000 --- a/src/Sql/Platform/IbmDb2/SelectDecorator.php +++ /dev/null @@ -1,164 +0,0 @@ -isSelectContainDistinct; - } - - /** - * @param boolean $isSelectContainDistinct - */ - public function setIsSelectContainDistinct($isSelectContainDistinct) - { - $this->isSelectContainDistinct = $isSelectContainDistinct; - } - - /** - * @param Select $select - */ - public function setSubject($select) - { - $this->subject = $select; - } - - /** - * @see Select::renderTable - */ - protected function renderTable($table, $alias = null) - { - return $table . ' ' . $alias; - } - - protected function localizeVariables() - { - parent::localizeVariables(); - // set specifications - unset($this->specifications[self::LIMIT]); - unset($this->specifications[self::OFFSET]); - - $this->specifications['LIMITOFFSET'] = null; - } - - /** - * @param PlatformInterface $platform - * @param DriverInterface $driver - * @param ParameterContainer $parameterContainer - * @param array $sqls - * @param array $parameters - */ - protected function processLimitOffset(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null, &$sqls, &$parameters) - { - if ($this->limit === null && $this->offset === null) { - return; - } - - $selectParameters = $parameters[self::SELECT]; - - $starSuffix = $platform->getIdentifierSeparator() . self::SQL_STAR; - foreach ($selectParameters[0] as $i => $columnParameters) { - if ($columnParameters[0] == self::SQL_STAR - || (isset($columnParameters[1]) && $columnParameters[1] == self::SQL_STAR) - || strpos($columnParameters[0], $starSuffix) - ) { - $selectParameters[0] = [[self::SQL_STAR]]; - break; - } - - if (isset($columnParameters[1])) { - array_shift($columnParameters); - $selectParameters[0][$i] = $columnParameters; - } - } - - // first, produce column list without compound names (using the AS portion only) - array_unshift($sqls, $this->createSqlFromSpecificationAndParameters( - ['SELECT %1$s FROM (' => current($this->specifications[self::SELECT])], - $selectParameters - )); - - if (preg_match('/DISTINCT/i', $sqls[0])) { - $this->setIsSelectContainDistinct(true); - } - - if ($parameterContainer) { - // create bottom part of query, with offset and limit using row_number - $limitParamName = $driver->formatParameterName('limit'); - $offsetParamName = $driver->formatParameterName('offset'); - - array_push($sqls, sprintf( - ") AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN %s AND %s", - $offsetParamName, - $limitParamName - )); - - if ((int) $this->offset > 0) { - $parameterContainer->offsetSet('offset', (int) $this->offset + 1); - } else { - $parameterContainer->offsetSet('offset', (int) $this->offset); - } - - $parameterContainer->offsetSet('limit', (int) $this->limit + (int) $this->offset); - } else { - if ((int) $this->offset > 0) { - $offset = (int) $this->offset + 1; - } else { - $offset = (int) $this->offset; - } - - array_push($sqls, sprintf( - ") AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN %d AND %d", - $offset, - (int) $this->limit + (int) $this->offset - )); - } - - if (isset($sqls[self::ORDER])) { - $orderBy = $sqls[self::ORDER]; - unset($sqls[self::ORDER]); - } else { - $orderBy = ''; - } - - // add a column for row_number() using the order specification //dense_rank() - if ($this->getIsSelectContainDistinct()) { - $parameters[self::SELECT][0][] = ['DENSE_RANK() OVER (' . $orderBy . ')', 'ZEND_DB_ROWNUM']; - } else { - $parameters[self::SELECT][0][] = ['ROW_NUMBER() OVER (' . $orderBy . ')', 'ZEND_DB_ROWNUM']; - } - - $sqls[self::SELECT] = $this->createSqlFromSpecificationAndParameters( - $this->specifications[self::SELECT], - $parameters[self::SELECT] - ); - } -} diff --git a/src/Sql/Platform/Mysql/Ddl/AlterTableDecorator.php b/src/Sql/Platform/Mysql/Ddl/AlterTableDecorator.php deleted file mode 100644 index 538f0b35f4..0000000000 --- a/src/Sql/Platform/Mysql/Ddl/AlterTableDecorator.php +++ /dev/null @@ -1,247 +0,0 @@ - 0, - 'zerofill' => 1, - 'identity' => 2, - 'serial' => 2, - 'autoincrement' => 2, - 'comment' => 3, - 'columnformat' => 4, - 'format' => 4, - 'storage' => 5, - ]; - - /** - * @param AlterTable $subject - * @return \Zend\Db\Sql\Platform\PlatformDecoratorInterface - */ - public function setSubject($subject) - { - $this->subject = $subject; - - return $this; - } - - /** - * @param string $sql - * @return array - */ - protected function getSqlInsertOffsets($sql) - { - $sqlLength = strlen($sql); - $insertStart = []; - - foreach (['NOT NULL', 'NULL', 'DEFAULT', 'UNIQUE', 'PRIMARY', 'REFERENCES'] as $needle) { - $insertPos = strpos($sql, ' ' . $needle); - - if ($insertPos !== false) { - switch ($needle) { - case 'REFERENCES': - $insertStart[2] = !isset($insertStart[2]) ? $insertPos : $insertStart[2]; - // no break - case 'PRIMARY': - case 'UNIQUE': - $insertStart[1] = !isset($insertStart[1]) ? $insertPos : $insertStart[1]; - // no break - default: - $insertStart[0] = !isset($insertStart[0]) ? $insertPos : $insertStart[0]; - } - } - } - - foreach (range(0, 3) as $i) { - $insertStart[$i] = isset($insertStart[$i]) ? $insertStart[$i] : $sqlLength; - } - - return $insertStart; - } - - /** - * @param PlatformInterface $adapterPlatform - * @return array - */ - protected function processAddColumns(PlatformInterface $adapterPlatform = null) - { - $sqls = []; - - foreach ($this->addColumns as $i => $column) { - $sql = $this->processExpression($column, $adapterPlatform); - $insertStart = $this->getSqlInsertOffsets($sql); - $columnOptions = $column->getOptions(); - - uksort($columnOptions, [$this, 'compareColumnOptions']); - - foreach ($columnOptions as $coName => $coValue) { - $insert = ''; - - if (! $coValue) { - continue; - } - - switch ($this->normalizeColumnOption($coName)) { - case 'unsigned': - $insert = ' UNSIGNED'; - $j = 0; - break; - case 'zerofill': - $insert = ' ZEROFILL'; - $j = 0; - break; - case 'identity': - case 'serial': - case 'autoincrement': - $insert = ' AUTO_INCREMENT'; - $j = 1; - break; - case 'comment': - $insert = ' COMMENT ' . $adapterPlatform->quoteValue($coValue); - $j = 2; - break; - case 'columnformat': - case 'format': - $insert = ' COLUMN_FORMAT ' . strtoupper($coValue); - $j = 2; - break; - case 'storage': - $insert = ' STORAGE ' . strtoupper($coValue); - $j = 2; - break; - } - - if ($insert) { - $j = isset($j) ? $j : 0; - $sql = substr_replace($sql, $insert, $insertStart[$j], 0); - $insertStartCount = count($insertStart); - for (; $j < $insertStartCount; ++$j) { - $insertStart[$j] += strlen($insert); - } - } - } - $sqls[$i] = $sql; - } - return [$sqls]; - } - - /** - * @param PlatformInterface $adapterPlatform - * @return array - */ - protected function processChangeColumns(PlatformInterface $adapterPlatform = null) - { - $sqls = []; - foreach ($this->changeColumns as $name => $column) { - $sql = $this->processExpression($column, $adapterPlatform); - $insertStart = $this->getSqlInsertOffsets($sql); - $columnOptions = $column->getOptions(); - - uksort($columnOptions, [$this, 'compareColumnOptions']); - - foreach ($columnOptions as $coName => $coValue) { - $insert = ''; - - if (! $coValue) { - continue; - } - - switch ($this->normalizeColumnOption($coName)) { - case 'unsigned': - $insert = ' UNSIGNED'; - $j = 0; - break; - case 'zerofill': - $insert = ' ZEROFILL'; - $j = 0; - break; - case 'identity': - case 'serial': - case 'autoincrement': - $insert = ' AUTO_INCREMENT'; - $j = 1; - break; - case 'comment': - $insert = ' COMMENT ' . $adapterPlatform->quoteValue($coValue); - $j = 2; - break; - case 'columnformat': - case 'format': - $insert = ' COLUMN_FORMAT ' . strtoupper($coValue); - $j = 2; - break; - case 'storage': - $insert = ' STORAGE ' . strtoupper($coValue); - $j = 2; - break; - } - - if ($insert) { - $j = isset($j) ? $j : 0; - $sql = substr_replace($sql, $insert, $insertStart[$j], 0); - $insertStartCount = count($insertStart); - for (; $j < $insertStartCount; ++$j) { - $insertStart[$j] += strlen($insert); - } - } - } - $sqls[] = [ - $adapterPlatform->quoteIdentifier($name), - $sql - ]; - } - - return [$sqls]; - } - - /** - * @param string $name - * - * @return string - */ - private function normalizeColumnOption($name) - { - return strtolower(str_replace(['-', '_', ' '], '', $name)); - } - - /** - * - * @param string $columnA - * @param string $columnB - * - * @return int - */ - private function compareColumnOptions($columnA, $columnB) - { - $columnA = $this->normalizeColumnOption($columnA); - $columnA = isset($this->columnOptionSortOrder[$columnA]) - ? $this->columnOptionSortOrder[$columnA] : count($this->columnOptionSortOrder); - - $columnB = $this->normalizeColumnOption($columnB); - $columnB = isset($this->columnOptionSortOrder[$columnB]) - ? $this->columnOptionSortOrder[$columnB] : count($this->columnOptionSortOrder); - - return $columnA - $columnB; - } -} diff --git a/src/Sql/Platform/Mysql/Ddl/CreateTableDecorator.php b/src/Sql/Platform/Mysql/Ddl/CreateTableDecorator.php deleted file mode 100644 index b8f7df5f58..0000000000 --- a/src/Sql/Platform/Mysql/Ddl/CreateTableDecorator.php +++ /dev/null @@ -1,184 +0,0 @@ - 0, - 'zerofill' => 1, - 'identity' => 2, - 'serial' => 2, - 'autoincrement' => 2, - 'comment' => 3, - 'columnformat' => 4, - 'format' => 4, - 'storage' => 5, - ]; - - /** - * @param CreateTable $subject - * - * @return self - */ - public function setSubject($subject) - { - $this->subject = $subject; - - return $this; - } - - /** - * @param string $sql - * @return array - */ - protected function getSqlInsertOffsets($sql) - { - $sqlLength = strlen($sql); - $insertStart = []; - - foreach (['NOT NULL', 'NULL', 'DEFAULT', 'UNIQUE', 'PRIMARY', 'REFERENCES'] as $needle) { - $insertPos = strpos($sql, ' ' . $needle); - - if ($insertPos !== false) { - switch ($needle) { - case 'REFERENCES': - $insertStart[2] = !isset($insertStart[2]) ? $insertPos : $insertStart[2]; - // no break - case 'PRIMARY': - case 'UNIQUE': - $insertStart[1] = !isset($insertStart[1]) ? $insertPos : $insertStart[1]; - // no break - default: - $insertStart[0] = !isset($insertStart[0]) ? $insertPos : $insertStart[0]; - } - } - } - - foreach (range(0, 3) as $i) { - $insertStart[$i] = isset($insertStart[$i]) ? $insertStart[$i] : $sqlLength; - } - - return $insertStart; - } - - /** - * {@inheritDoc} - */ - protected function processColumns(PlatformInterface $platform = null) - { - if (! $this->columns) { - return; - } - - $sqls = []; - - foreach ($this->columns as $i => $column) { - $sql = $this->processExpression($column, $platform); - $insertStart = $this->getSqlInsertOffsets($sql); - $columnOptions = $column->getOptions(); - - uksort($columnOptions, [$this, 'compareColumnOptions']); - - foreach ($columnOptions as $coName => $coValue) { - $insert = ''; - - if (! $coValue) { - continue; - } - - switch ($this->normalizeColumnOption($coName)) { - case 'unsigned': - $insert = ' UNSIGNED'; - $j = 0; - break; - case 'zerofill': - $insert = ' ZEROFILL'; - $j = 0; - break; - case 'identity': - case 'serial': - case 'autoincrement': - $insert = ' AUTO_INCREMENT'; - $j = 1; - break; - case 'comment': - $insert = ' COMMENT ' . $platform->quoteValue($coValue); - $j = 2; - break; - case 'columnformat': - case 'format': - $insert = ' COLUMN_FORMAT ' . strtoupper($coValue); - $j = 2; - break; - case 'storage': - $insert = ' STORAGE ' . strtoupper($coValue); - $j = 2; - break; - } - - if ($insert) { - $j = isset($j) ? $j : 0; - $sql = substr_replace($sql, $insert, $insertStart[$j], 0); - $insertStartCount = count($insertStart); - for (; $j < $insertStartCount; ++$j) { - $insertStart[$j] += strlen($insert); - } - } - } - - $sqls[$i] = $sql; - } - - return [$sqls]; - } - - /** - * @param string $name - * - * @return string - */ - private function normalizeColumnOption($name) - { - return strtolower(str_replace(['-', '_', ' '], '', $name)); - } - - /** - * - * @param string $columnA - * @param string $columnB - * - * @return int - */ - private function compareColumnOptions($columnA, $columnB) - { - $columnA = $this->normalizeColumnOption($columnA); - $columnA = isset($this->columnOptionSortOrder[$columnA]) - ? $this->columnOptionSortOrder[$columnA] : count($this->columnOptionSortOrder); - - $columnB = $this->normalizeColumnOption($columnB); - $columnB = isset($this->columnOptionSortOrder[$columnB]) - ? $this->columnOptionSortOrder[$columnB] : count($this->columnOptionSortOrder); - - return $columnA - $columnB; - } -} diff --git a/src/Sql/Platform/Mysql/Mysql.php b/src/Sql/Platform/Mysql/Mysql.php deleted file mode 100644 index 3e1611b87f..0000000000 --- a/src/Sql/Platform/Mysql/Mysql.php +++ /dev/null @@ -1,22 +0,0 @@ -setTypeDecorator('Zend\Db\Sql\Select', new SelectDecorator()); - $this->setTypeDecorator('Zend\Db\Sql\Ddl\CreateTable', new Ddl\CreateTableDecorator()); - $this->setTypeDecorator('Zend\Db\Sql\Ddl\AlterTable', new Ddl\AlterTableDecorator()); - } -} diff --git a/src/Sql/Platform/Mysql/SelectDecorator.php b/src/Sql/Platform/Mysql/SelectDecorator.php deleted file mode 100644 index 37f5b6cead..0000000000 --- a/src/Sql/Platform/Mysql/SelectDecorator.php +++ /dev/null @@ -1,69 +0,0 @@ -subject = $select; - } - - protected function localizeVariables() - { - parent::localizeVariables(); - if ($this->limit === null && $this->offset !== null) { - $this->specifications[self::LIMIT] = 'LIMIT 18446744073709551615'; - } - } - - protected function processLimit(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->limit === null && $this->offset !== null) { - return ['']; - } - if ($this->limit === null) { - return; - } - if ($parameterContainer) { - $parameterContainer->offsetSet('limit', $this->limit, ParameterContainer::TYPE_INTEGER); - return [$driver->formatParameterName('limit')]; - } - - return [$this->limit]; - } - - protected function processOffset(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->offset === null) { - return; - } - if ($parameterContainer) { - $parameterContainer->offsetSet('offset', $this->offset, ParameterContainer::TYPE_INTEGER); - return [$driver->formatParameterName('offset')]; - } - - return [$this->offset]; - } -} diff --git a/src/Sql/Platform/Oracle/Oracle.php b/src/Sql/Platform/Oracle/Oracle.php deleted file mode 100644 index bf1dc31df5..0000000000 --- a/src/Sql/Platform/Oracle/Oracle.php +++ /dev/null @@ -1,20 +0,0 @@ -setTypeDecorator('Zend\Db\Sql\Select', ($selectDecorator) ?: new SelectDecorator()); - } -} diff --git a/src/Sql/Platform/Oracle/SelectDecorator.php b/src/Sql/Platform/Oracle/SelectDecorator.php deleted file mode 100644 index 9961b4dcf9..0000000000 --- a/src/Sql/Platform/Oracle/SelectDecorator.php +++ /dev/null @@ -1,155 +0,0 @@ -subject = $select; - } - - /** - * @see \Zend\Db\Sql\Select::renderTable - */ - protected function renderTable($table, $alias = null) - { - return $table . ($alias ? ' ' . $alias : ''); - } - - protected function localizeVariables() - { - parent::localizeVariables(); - unset($this->specifications[self::LIMIT]); - unset($this->specifications[self::OFFSET]); - - $this->specifications['LIMITOFFSET'] = null; - } - - /** - * @param PlatformInterface $platform - * @param DriverInterface $driver - * @param ParameterContainer $parameterContainer - * @param array $sqls - * @param array $parameters - * @return null - */ - protected function processLimitOffset( - PlatformInterface $platform, - DriverInterface $driver = null, - ParameterContainer $parameterContainer = null, - &$sqls = [], - &$parameters = [] - ) { - if ($this->limit === null && $this->offset === null) { - return; - } - - $selectParameters = $parameters[self::SELECT]; - $starSuffix = $platform->getIdentifierSeparator() . self::SQL_STAR; - - foreach ($selectParameters[0] as $i => $columnParameters) { - if ($columnParameters[0] == self::SQL_STAR - || (isset($columnParameters[1]) && $columnParameters[1] == self::SQL_STAR) - || strpos($columnParameters[0], $starSuffix) - ) { - $selectParameters[0] = [[self::SQL_STAR]]; - break; - } - - if (isset($columnParameters[1])) { - array_shift($columnParameters); - $selectParameters[0][$i] = $columnParameters; - } - } - - if ($this->offset === null) { - $this->offset = 0; - } - - // first, produce column list without compound names (using the AS portion only) - array_unshift($sqls, $this->createSqlFromSpecificationAndParameters([ - 'SELECT %1$s FROM (SELECT b.%1$s, rownum b_rownum FROM (' => current($this->specifications[self::SELECT]), - ], $selectParameters)); - - if ($parameterContainer) { - $number = $this->processInfo['subselectCount'] ? $this->processInfo['subselectCount'] : ''; - - if ($this->limit === null) { - array_push( - $sqls, - ') b ) WHERE b_rownum > (:offset' . $number . ')' - ); - $parameterContainer->offsetSet( - 'offset' . $number, - $this->offset, - $parameterContainer::TYPE_INTEGER - ); - } else { - // create bottom part of query, with offset and limit using row_number - array_push( - $sqls, - ') b WHERE rownum <= (:offset' - . $number - . '+:limit' - . $number - . ')) WHERE b_rownum >= (:offset' - . $number - . ' + 1)' - ); - $parameterContainer->offsetSet( - 'offset' . $number, - $this->offset, - $parameterContainer::TYPE_INTEGER - ); - $parameterContainer->offsetSet( - 'limit' . $number, - $this->limit, - $parameterContainer::TYPE_INTEGER - ); - } - $this->processInfo['subselectCount']++; - } else { - if ($this->limit === null) { - array_push($sqls, ') b ) WHERE b_rownum > (' . (int) $this->offset . ')'); - } else { - array_push( - $sqls, - ') b WHERE rownum <= (' - . (int) $this->offset - . '+' - . (int) $this->limit - . ')) WHERE b_rownum >= (' - . (int) $this->offset - . ' + 1)' - ); - } - } - - $sqls[self::SELECT] = $this->createSqlFromSpecificationAndParameters( - $this->specifications[self::SELECT], - $parameters[self::SELECT] - ); - } -} diff --git a/src/Sql/Platform/Platform.php b/src/Sql/Platform/Platform.php deleted file mode 100644 index ad375d5d71..0000000000 --- a/src/Sql/Platform/Platform.php +++ /dev/null @@ -1,167 +0,0 @@ -defaultPlatform = $adapter->getPlatform(); - - $mySqlPlatform = new Mysql\Mysql(); - $sqlServerPlatform = new SqlServer\SqlServer(); - $oraclePlatform = new Oracle\Oracle(); - $ibmDb2Platform = new IbmDb2\IbmDb2(); - $sqlitePlatform = new Sqlite\Sqlite(); - - $this->decorators['mysql'] = $mySqlPlatform->getDecorators(); - $this->decorators['sqlserver'] = $sqlServerPlatform->getDecorators(); - $this->decorators['oracle'] = $oraclePlatform->getDecorators(); - $this->decorators['ibmdb2'] = $ibmDb2Platform->getDecorators(); - $this->decorators['sqlite'] = $sqlitePlatform->getDecorators(); - } - - /** - * @param string $type - * @param PlatformDecoratorInterface $decorator - * @param AdapterInterface|PlatformInterface $adapterOrPlatform - */ - public function setTypeDecorator($type, PlatformDecoratorInterface $decorator, $adapterOrPlatform = null) - { - $platformName = $this->resolvePlatformName($adapterOrPlatform); - $this->decorators[$platformName][$type] = $decorator; - } - - /** - * @param PreparableSqlInterface|SqlInterface $subject - * @param AdapterInterface|PlatformInterface|null $adapterOrPlatform - * @return PlatformDecoratorInterface|PreparableSqlInterface|SqlInterface - */ - public function getTypeDecorator($subject, $adapterOrPlatform = null) - { - $platformName = $this->resolvePlatformName($adapterOrPlatform); - - if (isset($this->decorators[$platformName])) { - foreach ($this->decorators[$platformName] as $type => $decorator) { - if ($subject instanceof $type && is_a($decorator, $type, true)) { - $decorator->setSubject($subject); - return $decorator; - } - } - } - - return $subject; - } - - /** - * @return array|PlatformDecoratorInterface[] - */ - public function getDecorators() - { - $platformName = $this->resolvePlatformName($this->getDefaultPlatform()); - return $this->decorators[$platformName]; - } - - /** - * {@inheritDoc} - * - * @throws Exception\RuntimeException - */ - public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) - { - if (! $this->subject instanceof PreparableSqlInterface) { - throw new Exception\RuntimeException('The subject does not appear to implement Zend\Db\Sql\PreparableSqlInterface, thus calling prepareStatement() has no effect'); - } - - $this->getTypeDecorator($this->subject, $adapter)->prepareStatement($adapter, $statementContainer); - - return $statementContainer; - } - - /** - * {@inheritDoc} - * - * @throws Exception\RuntimeException - */ - public function getSqlString(PlatformInterface $adapterPlatform = null) - { - if (! $this->subject instanceof SqlInterface) { - throw new Exception\RuntimeException('The subject does not appear to implement Zend\Db\Sql\SqlInterface, thus calling prepareStatement() has no effect'); - } - - $adapterPlatform = $this->resolvePlatform($adapterPlatform); - - return $this->getTypeDecorator($this->subject, $adapterPlatform)->getSqlString($adapterPlatform); - } - - protected function resolvePlatformName($adapterOrPlatform) - { - $platformName = $this->resolvePlatform($adapterOrPlatform)->getName(); - return str_replace([' ', '_'], '', strtolower($platformName)); - } - /** - * @param null|PlatformInterface|AdapterInterface $adapterOrPlatform - * - * @return PlatformInterface - * - * @throws Exception\InvalidArgumentException - */ - protected function resolvePlatform($adapterOrPlatform) - { - if (! $adapterOrPlatform) { - return $this->getDefaultPlatform(); - } - - if ($adapterOrPlatform instanceof AdapterInterface) { - return $adapterOrPlatform->getPlatform(); - } - - if ($adapterOrPlatform instanceof PlatformInterface) { - return $adapterOrPlatform; - } - - throw new Exception\InvalidArgumentException(sprintf( - '$adapterOrPlatform should be null, %s, or %s', - 'Zend\Db\Adapter\AdapterInterface', - 'Zend\Db\Adapter\Platform\PlatformInterface' - )); - } - - /** - * @return PlatformInterface - * - * @throws Exception\RuntimeException - */ - protected function getDefaultPlatform() - { - if (! $this->defaultPlatform) { - throw new Exception\RuntimeException('$this->defaultPlatform was not set'); - } - - return $this->defaultPlatform; - } -} diff --git a/src/Sql/Platform/SqlServer/Ddl/CreateTableDecorator.php b/src/Sql/Platform/SqlServer/Ddl/CreateTableDecorator.php deleted file mode 100644 index 9a72b2c7d6..0000000000 --- a/src/Sql/Platform/SqlServer/Ddl/CreateTableDecorator.php +++ /dev/null @@ -1,45 +0,0 @@ -subject = $subject; - return $this; - } - - /** - * @param PlatformInterface $adapterPlatform - * @return array - */ - protected function processTable(PlatformInterface $adapterPlatform = null) - { - $table = ($this->isTemporary ? '#' : '') . ltrim($this->table, '#'); - return [ - '', - $adapterPlatform->quoteIdentifier($table), - ]; - } -} diff --git a/src/Sql/Platform/SqlServer/SelectDecorator.php b/src/Sql/Platform/SqlServer/SelectDecorator.php deleted file mode 100644 index aef0540f0c..0000000000 --- a/src/Sql/Platform/SqlServer/SelectDecorator.php +++ /dev/null @@ -1,117 +0,0 @@ -subject = $select; - } - - protected function localizeVariables() - { - parent::localizeVariables(); - // set specifications - unset($this->specifications[self::LIMIT]); - unset($this->specifications[self::OFFSET]); - - $this->specifications['LIMITOFFSET'] = null; - } - - /** - * @param PlatformInterface $platform - * @param DriverInterface $driver - * @param ParameterContainer $parameterContainer - * @param $sqls - * @param $parameters - * @return null - */ - protected function processLimitOffset(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null, &$sqls, &$parameters) - { - if ($this->limit === null && $this->offset === null) { - return; - } - - $selectParameters = $parameters[self::SELECT]; - - /** if this is a DISTINCT query then real SELECT part goes to second element in array **/ - $parameterIndex = 0; - if ($selectParameters[0] === 'DISTINCT') { - unset($selectParameters[0]); - $selectParameters = array_values($selectParameters); - $parameterIndex = 1; - } - - $starSuffix = $platform->getIdentifierSeparator() . self::SQL_STAR; - foreach ($selectParameters[0] as $i => $columnParameters) { - if ($columnParameters[0] == self::SQL_STAR || (isset($columnParameters[1]) && $columnParameters[1] == self::SQL_STAR) || strpos($columnParameters[0], $starSuffix)) { - $selectParameters[0] = [[self::SQL_STAR]]; - break; - } - if (isset($columnParameters[1])) { - array_shift($columnParameters); - $selectParameters[0][$i] = $columnParameters; - } - } - - // first, produce column list without compound names (using the AS portion only) - array_unshift($sqls, $this->createSqlFromSpecificationAndParameters( - ['SELECT %1$s FROM (' => current($this->specifications[self::SELECT])], - $selectParameters - )); - - if ($parameterContainer) { - // create bottom part of query, with offset and limit using row_number - $limitParamName = $driver->formatParameterName('limit'); - $offsetParamName = $driver->formatParameterName('offset'); - $offsetForSumParamName = $driver->formatParameterName('offsetForSum'); - array_push($sqls, ') AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN ' - . $offsetParamName . '+1 AND ' . $limitParamName . '+' . $offsetForSumParamName); - $parameterContainer->offsetSet('offset', $this->offset); - $parameterContainer->offsetSet('limit', $this->limit); - $parameterContainer->offsetSetReference('offsetForSum', 'offset'); - } else { - array_push($sqls, ') AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN ' - . (int) $this->offset . '+1 AND ' - . (int) $this->limit . '+' . (int) $this->offset - ); - } - - if (isset($sqls[self::ORDER])) { - $orderBy = $sqls[self::ORDER]; - unset($sqls[self::ORDER]); - } else { - $orderBy = 'ORDER BY (SELECT 1)'; - } - - // add a column for row_number() using the order specification - $parameters[self::SELECT][$parameterIndex][] = ['ROW_NUMBER() OVER (' . $orderBy . ')', '[__ZEND_ROW_NUMBER]']; - - $sqls[self::SELECT] = $this->createSqlFromSpecificationAndParameters( - $this->specifications[self::SELECT], - $parameters[self::SELECT] - ); - } -} diff --git a/src/Sql/Platform/SqlServer/SqlServer.php b/src/Sql/Platform/SqlServer/SqlServer.php deleted file mode 100644 index 0dc383d0be..0000000000 --- a/src/Sql/Platform/SqlServer/SqlServer.php +++ /dev/null @@ -1,21 +0,0 @@ -setTypeDecorator('Zend\Db\Sql\Select', ($selectDecorator) ?: new SelectDecorator()); - $this->setTypeDecorator('Zend\Db\Sql\Ddl\CreateTable', new Ddl\CreateTableDecorator()); - } -} diff --git a/src/Sql/Platform/Sqlite/SelectDecorator.php b/src/Sql/Platform/Sqlite/SelectDecorator.php deleted file mode 100644 index e875dc740f..0000000000 --- a/src/Sql/Platform/Sqlite/SelectDecorator.php +++ /dev/null @@ -1,62 +0,0 @@ -subject = $select; - - return $this; - } - - /** - * {@inheritDoc} - */ - protected function localizeVariables() - { - parent::localizeVariables(); - $this->specifications[self::COMBINE] = '%1$s %2$s'; - } - - /** - * {@inheritDoc} - */ - protected function processStatementStart(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - return ''; - } - - /** - * {@inheritDoc} - */ - protected function processStatementEnd(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - return ''; - } -} diff --git a/src/Sql/Predicate/Between.php b/src/Sql/Predicate/Between.php index 99f2573872..61fa8b83f9 100644 --- a/src/Sql/Predicate/Between.php +++ b/src/Sql/Predicate/Between.php @@ -9,11 +9,10 @@ namespace Zend\Db\Sql\Predicate; -use Zend\Db\Sql\AbstractExpression; +use Zend\Db\Sql\ExpressionParameter; -class Between extends AbstractExpression implements PredicateInterface +class Between implements PredicateInterface { - protected $specification = '%1$s BETWEEN %2$s AND %3$s'; protected $identifier = null; protected $minValue = null; protected $maxValue = null; @@ -44,9 +43,9 @@ public function __construct($identifier = null, $minValue = null, $maxValue = nu * @param string $identifier * @return Between */ - public function setIdentifier($identifier) + public function setIdentifier($identifier, $type = self::TYPE_IDENTIFIER) { - $this->identifier = $identifier; + $this->identifier = new ExpressionParameter($identifier, $type); return $this; } @@ -66,9 +65,9 @@ public function getIdentifier() * @param int|float|string $minValue * @return Between */ - public function setMinValue($minValue) + public function setMinValue($minValue, $type = self::TYPE_VALUE) { - $this->minValue = $minValue; + $this->minValue = new ExpressionParameter($minValue, $type); return $this; } @@ -88,9 +87,9 @@ public function getMinValue() * @param int|float|string $maxValue * @return Between */ - public function setMaxValue($maxValue) + public function setMaxValue($maxValue, $type = self::TYPE_VALUE) { - $this->maxValue = $maxValue; + $this->maxValue = new ExpressionParameter($maxValue, $type); return $this; } @@ -103,45 +102,4 @@ public function getMaxValue() { return $this->maxValue; } - - /** - * Set specification string to use in forming SQL predicate - * - * @param string $specification - * @return Between - */ - public function setSpecification($specification) - { - $this->specification = $specification; - return $this; - } - - /** - * Get specification string to use in forming SQL predicate - * - * @return string - */ - public function getSpecification() - { - return $this->specification; - } - - /** - * Return "where" parts - * - * @return array - */ - public function getExpressionData() - { - list($values[], $types[]) = $this->normalizeArgument($this->identifier, self::TYPE_IDENTIFIER); - list($values[], $types[]) = $this->normalizeArgument($this->minValue, self::TYPE_VALUE); - list($values[], $types[]) = $this->normalizeArgument($this->maxValue, self::TYPE_VALUE); - return [ - [ - $this->getSpecification(), - $values, - $types, - ], - ]; - } } diff --git a/src/Sql/Predicate/Expression.php b/src/Sql/Predicate/Expression.php index e9b5363f24..602329afd1 100644 --- a/src/Sql/Predicate/Expression.php +++ b/src/Sql/Predicate/Expression.php @@ -11,20 +11,6 @@ use Zend\Db\Sql\Expression as BaseExpression; -class Expression extends BaseExpression implements PredicateInterface +final class Expression extends BaseExpression implements PredicateInterface { - /** - * Constructor - * - * @param string $expression - * @param int|float|bool|string|array $valueParameter - */ - public function __construct($expression = null, $valueParameter = null /*[, $valueParameter, ... ]*/) - { - if ($expression) { - $this->setExpression($expression); - } - - $this->setParameters(is_array($valueParameter) ? $valueParameter : array_slice(func_get_args(), 1)); - } } diff --git a/src/Sql/Predicate/In.php b/src/Sql/Predicate/In.php index 46ba61b62c..e0bdb0e227 100644 --- a/src/Sql/Predicate/In.php +++ b/src/Sql/Predicate/In.php @@ -11,17 +11,14 @@ use Zend\Db\Sql\Exception; use Zend\Db\Sql\Select; -use Zend\Db\Sql\AbstractExpression; +use Zend\Db\Sql\SelectableInterface; +use Zend\Db\Sql\ExpressionParameter; -class In extends AbstractExpression implements PredicateInterface +class In implements PredicateInterface { protected $identifier; protected $valueSet; - protected $specification = '%s IN %s'; - - protected $valueSpecSpecification = '%%s IN (%s)'; - /** * Constructor * @@ -44,9 +41,16 @@ public function __construct($identifier = null, $valueSet = null) * @param string|array $identifier * @return In */ - public function setIdentifier($identifier) + public function setIdentifier($identifier, $type = self::TYPE_IDENTIFIER) { - $this->identifier = $identifier; + if (is_array($identifier)) { + $this->identifier = []; + foreach ($identifier as $ident) { + $this->identifier[] = new ExpressionParameter($ident, $type); + } + } else { + $this->identifier = new ExpressionParameter($identifier, $type); + } return $this; } @@ -64,19 +68,24 @@ public function getIdentifier() /** * Set set of values for IN comparison * - * @param array|Select $valueSet + * @param array|SelectableInterface $valueSet * @throws Exception\InvalidArgumentException * @return In */ public function setValueSet($valueSet) { - if (!is_array($valueSet) && !$valueSet instanceof Select) { + if ($valueSet instanceof SelectableInterface) { + $this->valueSet = new ExpressionParameter($valueSet); + } elseif (is_array($valueSet)) { + $this->valueSet = []; + foreach ($valueSet as $value) { + $this->valueSet[] = new ExpressionParameter($value, self::TYPE_VALUE); + } + } else { throw new Exception\InvalidArgumentException( - '$valueSet must be either an array or a Zend\Db\Sql\Select object, ' . gettype($valueSet) . ' given' + '$valueSet must be either an array or a Zend\Db\Sql\SelectableInterface object, ' . gettype($valueSet) . ' given' ); } - $this->valueSet = $valueSet; - return $this; } @@ -89,49 +98,4 @@ public function getValueSet() { return $this->valueSet; } - - /** - * Return array of parts for where statement - * - * @return array - */ - public function getExpressionData() - { - $identifier = $this->getIdentifier(); - $values = $this->getValueSet(); - $replacements = []; - - if (is_array($identifier)) { - $identifierSpecFragment = '(' . implode(', ', array_fill(0, count($identifier), '%s')) . ')'; - $types = array_fill(0, count($identifier), self::TYPE_IDENTIFIER); - $replacements = $identifier; - } else { - $identifierSpecFragment = '%s'; - $replacements[] = $identifier; - $types = [self::TYPE_IDENTIFIER]; - } - - if ($values instanceof Select) { - $specification = vsprintf( - $this->specification, - [$identifierSpecFragment, '%s'] - ); - $replacements[] = $values; - $types[] = self::TYPE_VALUE; - } else { - foreach ($values as $argument) { - list($replacements[], $types[]) = $this->normalizeArgument($argument, self::TYPE_VALUE); - } - $specification = vsprintf( - $this->specification, - [$identifierSpecFragment, '(' . implode(', ', array_fill(0, count($values), '%s')) . ')'] - ); - } - - return [[ - $specification, - $replacements, - $types, - ]]; - } } diff --git a/src/Sql/Predicate/IsNotNull.php b/src/Sql/Predicate/IsNotNull.php index e42c9aa5b5..518cf520d3 100644 --- a/src/Sql/Predicate/IsNotNull.php +++ b/src/Sql/Predicate/IsNotNull.php @@ -11,5 +11,4 @@ class IsNotNull extends IsNull { - protected $specification = '%1$s IS NOT NULL'; } diff --git a/src/Sql/Predicate/IsNull.php b/src/Sql/Predicate/IsNull.php index cb9c64c55e..77e9377206 100644 --- a/src/Sql/Predicate/IsNull.php +++ b/src/Sql/Predicate/IsNull.php @@ -9,15 +9,10 @@ namespace Zend\Db\Sql\Predicate; -use Zend\Db\Sql\AbstractExpression; +use Zend\Db\Sql\ExpressionParameter; -class IsNull extends AbstractExpression implements PredicateInterface +class IsNull implements PredicateInterface { - /** - * @var string - */ - protected $specification = '%1$s IS NULL'; - /** * @var */ @@ -41,9 +36,9 @@ public function __construct($identifier = null) * @param string $identifier * @return IsNull */ - public function setIdentifier($identifier) + public function setIdentifier($identifier, $type = self::TYPE_IDENTIFIER) { - $this->identifier = $identifier; + $this->identifier = new ExpressionParameter($identifier, $type); return $this; } @@ -56,41 +51,4 @@ public function getIdentifier() { return $this->identifier; } - - /** - * Set specification string to use in forming SQL predicate - * - * @param string $specification - * @return IsNull - */ - public function setSpecification($specification) - { - $this->specification = $specification; - return $this; - } - - /** - * Get specification string to use in forming SQL predicate - * - * @return string - */ - public function getSpecification() - { - return $this->specification; - } - - /** - * Get parts for where statement - * - * @return array - */ - public function getExpressionData() - { - $identifier = $this->normalizeArgument($this->identifier, self::TYPE_IDENTIFIER); - return [[ - $this->getSpecification(), - [$identifier[0]], - [$identifier[1]], - ]]; - } } diff --git a/src/Sql/Predicate/Like.php b/src/Sql/Predicate/Like.php index 457b6596a1..be0599b319 100644 --- a/src/Sql/Predicate/Like.php +++ b/src/Sql/Predicate/Like.php @@ -9,15 +9,10 @@ namespace Zend\Db\Sql\Predicate; -use Zend\Db\Sql\AbstractExpression; +use Zend\Db\Sql\ExpressionParameter; -class Like extends AbstractExpression implements PredicateInterface +class Like implements PredicateInterface { - /** - * @var string - */ - protected $specification = '%1$s LIKE %2$s'; - /** * @var string */ @@ -46,9 +41,9 @@ public function __construct($identifier = null, $like = null) * @param string $identifier * @return self */ - public function setIdentifier($identifier) + public function setIdentifier($identifier, $type = self::TYPE_IDENTIFIER) { - $this->identifier = $identifier; + $this->identifier = new ExpressionParameter($identifier, $type); return $this; } @@ -64,9 +59,9 @@ public function getIdentifier() * @param string $like * @return self */ - public function setLike($like) + public function setLike($like, $type = self::TYPE_VALUE) { - $this->like = $like; + $this->like = new ExpressionParameter($like, $type); return $this; } @@ -77,38 +72,4 @@ public function getLike() { return $this->like; } - - /** - * @param string $specification - * @return self - */ - public function setSpecification($specification) - { - $this->specification = $specification; - return $this; - } - - /** - * @return string - */ - public function getSpecification() - { - return $this->specification; - } - - /** - * @return array - */ - public function getExpressionData() - { - list($values[], $types[]) = $this->normalizeArgument($this->identifier, self::TYPE_IDENTIFIER); - list($values[], $types[]) = $this->normalizeArgument($this->like, self::TYPE_VALUE); - return [ - [ - $this->specification, - $values, - $types, - ] - ]; - } } diff --git a/src/Sql/Predicate/Literal.php b/src/Sql/Predicate/Literal.php index d4b509fc93..58b7beca42 100644 --- a/src/Sql/Predicate/Literal.php +++ b/src/Sql/Predicate/Literal.php @@ -11,6 +11,6 @@ use Zend\Db\Sql\Literal as BaseLiteral; -class Literal extends BaseLiteral implements PredicateInterface +final class Literal extends BaseLiteral implements PredicateInterface { } diff --git a/src/Sql/Predicate/NotBetween.php b/src/Sql/Predicate/NotBetween.php index a448a77e69..30fa1c3beb 100644 --- a/src/Sql/Predicate/NotBetween.php +++ b/src/Sql/Predicate/NotBetween.php @@ -11,5 +11,4 @@ class NotBetween extends Between { - protected $specification = '%1$s NOT BETWEEN %2$s AND %3$s'; } diff --git a/src/Sql/Predicate/NotIn.php b/src/Sql/Predicate/NotIn.php index f1ce87c235..ac0b0a4f01 100644 --- a/src/Sql/Predicate/NotIn.php +++ b/src/Sql/Predicate/NotIn.php @@ -11,5 +11,4 @@ class NotIn extends In { - protected $specification = '%s NOT IN %s'; } diff --git a/src/Sql/Predicate/NotLike.php b/src/Sql/Predicate/NotLike.php index 18d627c551..f82c3045d0 100644 --- a/src/Sql/Predicate/NotLike.php +++ b/src/Sql/Predicate/NotLike.php @@ -11,5 +11,4 @@ class NotLike extends Like { - protected $specification = '%1$s NOT LIKE %2$s'; } diff --git a/src/Sql/Predicate/Operator.php b/src/Sql/Predicate/Operator.php index 5b51c4d61a..eedf3249d3 100644 --- a/src/Sql/Predicate/Operator.php +++ b/src/Sql/Predicate/Operator.php @@ -9,10 +9,9 @@ namespace Zend\Db\Sql\Predicate; -use Zend\Db\Sql\Exception; -use Zend\Db\Sql\AbstractExpression; +use Zend\Db\Sql\ExpressionParameter; -class Operator extends AbstractExpression implements PredicateInterface +class Operator implements PredicateInterface { const OPERATOR_EQUAL_TO = '='; const OP_EQ = '='; @@ -32,14 +31,6 @@ class Operator extends AbstractExpression implements PredicateInterface const OPERATOR_GREATER_THAN_OR_EQUAL_TO = '>='; const OP_GTE = '>='; - /** - * {@inheritDoc} - */ - protected $allowedTypes = [ - self::TYPE_IDENTIFIER, - self::TYPE_VALUE, - ]; - /** * @var int|float|bool|string */ @@ -50,16 +41,6 @@ class Operator extends AbstractExpression implements PredicateInterface */ protected $right; - /** - * @var string - */ - protected $leftType = self::TYPE_IDENTIFIER; - - /** - * @var string - */ - protected $rightType = self::TYPE_VALUE; - /** * @var string */ @@ -71,15 +52,11 @@ class Operator extends AbstractExpression implements PredicateInterface * @param int|float|bool|string $left * @param string $operator * @param int|float|bool|string $right - * @param string $leftType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_IDENTIFIER {@see allowedTypes} - * @param string $rightType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_VALUE {@see allowedTypes} */ public function __construct( $left = null, $operator = self::OPERATOR_EQUAL_TO, - $right = null, - $leftType = self::TYPE_IDENTIFIER, - $rightType = self::TYPE_VALUE + $right = null ) { if ($left !== null) { $this->setLeft($left); @@ -92,14 +69,6 @@ public function __construct( if ($right !== null) { $this->setRight($right); } - - if ($leftType !== self::TYPE_IDENTIFIER) { - $this->setLeftType($leftType); - } - - if ($rightType !== self::TYPE_VALUE) { - $this->setRightType($rightType); - } } /** @@ -109,15 +78,9 @@ public function __construct( * * @return Operator */ - public function setLeft($left) + public function setLeft($left, $type = self::TYPE_IDENTIFIER) { - $this->left = $left; - - if (is_array($left)) { - $left = $this->normalizeArgument($left, $this->leftType); - $this->leftType = $left[1]; - } - + $this->left = new ExpressionParameter($left, $type); return $this; } @@ -131,41 +94,6 @@ public function getLeft() return $this->left; } - /** - * Set parameter type for left side of operator - * - * @param string $type TYPE_IDENTIFIER or TYPE_VALUE {@see allowedTypes} - * - * @return Operator - * - * @throws Exception\InvalidArgumentException - */ - public function setLeftType($type) - { - if (!in_array($type, $this->allowedTypes)) { - throw new Exception\InvalidArgumentException(sprintf( - 'Invalid type "%s" provided; must be of type "%s" or "%s"', - $type, - __CLASS__ . '::TYPE_IDENTIFIER', - __CLASS__ . '::TYPE_VALUE' - )); - } - - $this->leftType = $type; - - return $this; - } - - /** - * Get parameter type on left side of operator - * - * @return string - */ - public function getLeftType() - { - return $this->leftType; - } - /** * Set operator string * @@ -196,15 +124,9 @@ public function getOperator() * * @return Operator */ - public function setRight($right) + public function setRight($right, $type = self::TYPE_VALUE) { - $this->right = $right; - - if (is_array($right)) { - $right = $this->normalizeArgument($right, $this->rightType); - $this->rightType = $right[1]; - } - + $this->right = new ExpressionParameter($right, $type); return $this; } @@ -217,54 +139,4 @@ public function getRight() { return $this->right; } - - /** - * Set parameter type for right side of operator - * - * @param string $type TYPE_IDENTIFIER or TYPE_VALUE {@see allowedTypes} - * @throws Exception\InvalidArgumentException - * @return Operator - */ - public function setRightType($type) - { - if (!in_array($type, $this->allowedTypes)) { - throw new Exception\InvalidArgumentException(sprintf( - 'Invalid type "%s" provided; must be of type "%s" or "%s"', - $type, - __CLASS__ . '::TYPE_IDENTIFIER', - __CLASS__ . '::TYPE_VALUE' - )); - } - - $this->rightType = $type; - - return $this; - } - - /** - * Get parameter type on right side of operator - * - * @return string - */ - public function getRightType() - { - return $this->rightType; - } - - /** - * Get predicate parts for where statement - * - * @return array - */ - public function getExpressionData() - { - list($values[], $types[]) = $this->normalizeArgument($this->left, $this->leftType); - list($values[], $types[]) = $this->normalizeArgument($this->right, $this->rightType); - - return [[ - '%s ' . $this->operator . ' %s', - $values, - $types - ]]; - } } diff --git a/src/Sql/Predicate/Predicate.php b/src/Sql/Predicate/Predicate.php index c6f4c3a0d4..4fef03ff77 100644 --- a/src/Sql/Predicate/Predicate.php +++ b/src/Sql/Predicate/Predicate.php @@ -72,14 +72,12 @@ public function unnest() * * @param int|float|bool|string $left * @param int|float|bool|string $right - * @param string $leftType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_IDENTIFIER {@see allowedTypes} - * @param string $rightType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_VALUE {@see allowedTypes} * @return Predicate */ - public function equalTo($left, $right, $leftType = self::TYPE_IDENTIFIER, $rightType = self::TYPE_VALUE) + public function equalTo($left, $right) { $this->addPredicate( - new Operator($left, Operator::OPERATOR_EQUAL_TO, $right, $leftType, $rightType), + new Operator($left, Operator::OPERATOR_EQUAL_TO, $right), ($this->nextPredicateCombineOperator) ?: $this->defaultCombination ); $this->nextPredicateCombineOperator = null; @@ -94,14 +92,12 @@ public function equalTo($left, $right, $leftType = self::TYPE_IDENTIFIER, $right * * @param int|float|bool|string $left * @param int|float|bool|string $right - * @param string $leftType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_IDENTIFIER {@see allowedTypes} - * @param string $rightType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_VALUE {@see allowedTypes} * @return Predicate */ - public function notEqualTo($left, $right, $leftType = self::TYPE_IDENTIFIER, $rightType = self::TYPE_VALUE) + public function notEqualTo($left, $right) { $this->addPredicate( - new Operator($left, Operator::OPERATOR_NOT_EQUAL_TO, $right, $leftType, $rightType), + new Operator($left, Operator::OPERATOR_NOT_EQUAL_TO, $right), ($this->nextPredicateCombineOperator) ?: $this->defaultCombination ); $this->nextPredicateCombineOperator = null; @@ -116,14 +112,12 @@ public function notEqualTo($left, $right, $leftType = self::TYPE_IDENTIFIER, $ri * * @param int|float|bool|string $left * @param int|float|bool|string $right - * @param string $leftType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_IDENTIFIER {@see allowedTypes} - * @param string $rightType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_VALUE {@see allowedTypes} * @return Predicate */ - public function lessThan($left, $right, $leftType = self::TYPE_IDENTIFIER, $rightType = self::TYPE_VALUE) + public function lessThan($left, $right) { $this->addPredicate( - new Operator($left, Operator::OPERATOR_LESS_THAN, $right, $leftType, $rightType), + new Operator($left, Operator::OPERATOR_LESS_THAN, $right), ($this->nextPredicateCombineOperator) ?: $this->defaultCombination ); $this->nextPredicateCombineOperator = null; @@ -138,14 +132,12 @@ public function lessThan($left, $right, $leftType = self::TYPE_IDENTIFIER, $righ * * @param int|float|bool|string $left * @param int|float|bool|string $right - * @param string $leftType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_IDENTIFIER {@see allowedTypes} - * @param string $rightType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_VALUE {@see allowedTypes} * @return Predicate */ - public function greaterThan($left, $right, $leftType = self::TYPE_IDENTIFIER, $rightType = self::TYPE_VALUE) + public function greaterThan($left, $right) { $this->addPredicate( - new Operator($left, Operator::OPERATOR_GREATER_THAN, $right, $leftType, $rightType), + new Operator($left, Operator::OPERATOR_GREATER_THAN, $right), ($this->nextPredicateCombineOperator) ?: $this->defaultCombination ); $this->nextPredicateCombineOperator = null; @@ -160,14 +152,12 @@ public function greaterThan($left, $right, $leftType = self::TYPE_IDENTIFIER, $r * * @param int|float|bool|string $left * @param int|float|bool|string $right - * @param string $leftType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_IDENTIFIER {@see allowedTypes} - * @param string $rightType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_VALUE {@see allowedTypes} * @return Predicate */ - public function lessThanOrEqualTo($left, $right, $leftType = self::TYPE_IDENTIFIER, $rightType = self::TYPE_VALUE) + public function lessThanOrEqualTo($left, $right) { $this->addPredicate( - new Operator($left, Operator::OPERATOR_LESS_THAN_OR_EQUAL_TO, $right, $leftType, $rightType), + new Operator($left, Operator::OPERATOR_LESS_THAN_OR_EQUAL_TO, $right), ($this->nextPredicateCombineOperator) ?: $this->defaultCombination ); $this->nextPredicateCombineOperator = null; @@ -182,14 +172,12 @@ public function lessThanOrEqualTo($left, $right, $leftType = self::TYPE_IDENTIFI * * @param int|float|bool|string $left * @param int|float|bool|string $right - * @param string $leftType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_IDENTIFIER {@see allowedTypes} - * @param string $rightType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_VALUE {@see allowedTypes} * @return Predicate */ - public function greaterThanOrEqualTo($left, $right, $leftType = self::TYPE_IDENTIFIER, $rightType = self::TYPE_VALUE) + public function greaterThanOrEqualTo($left, $right) { $this->addPredicate( - new Operator($left, Operator::OPERATOR_GREATER_THAN_OR_EQUAL_TO, $right, $leftType, $rightType), + new Operator($left, Operator::OPERATOR_GREATER_THAN_OR_EQUAL_TO, $right), ($this->nextPredicateCombineOperator) ?: $this->defaultCombination ); $this->nextPredicateCombineOperator = null; diff --git a/src/Sql/Predicate/PredicateSet.php b/src/Sql/Predicate/PredicateSet.php index 36f1909fe3..57826b78fe 100644 --- a/src/Sql/Predicate/PredicateSet.php +++ b/src/Sql/Predicate/PredicateSet.php @@ -158,35 +158,6 @@ public function andPredicate(PredicateInterface $predicate) return $this; } - /** - * Get predicate parts for where statement - * - * @return array - */ - public function getExpressionData() - { - $parts = []; - for ($i = 0, $count = count($this->predicates); $i < $count; $i++) { - /** @var $predicate PredicateInterface */ - $predicate = $this->predicates[$i][1]; - - if ($predicate instanceof PredicateSet) { - $parts[] = '('; - } - - $parts = array_merge($parts, $predicate->getExpressionData()); - - if ($predicate instanceof PredicateSet) { - $parts[] = ')'; - } - - if (isset($this->predicates[$i+1])) { - $parts[] = sprintf(' %s ', $this->predicates[$i+1][0]); - } - } - return $parts; - } - /** * Get count of attached predicates * diff --git a/src/Sql/PreparableSqlInterface.php b/src/Sql/PreparableSqlInterface.php deleted file mode 100644 index f937e07b7b..0000000000 --- a/src/Sql/PreparableSqlInterface.php +++ /dev/null @@ -1,24 +0,0 @@ - '%1$s', - self::SELECT => [ - 'SELECT %1$s FROM %2$s' => [ - [1 => '%1$s', 2 => '%1$s AS %2$s', 'combinedby' => ', '], - null - ], - 'SELECT %1$s %2$s FROM %3$s' => [ - null, - [1 => '%1$s', 2 => '%1$s AS %2$s', 'combinedby' => ', '], - null - ], - 'SELECT %1$s' => [ - [1 => '%1$s', 2 => '%1$s AS %2$s', 'combinedby' => ', '], - ], - ], - self::JOINS => [ - '%1$s' => [ - [3 => '%1$s JOIN %2$s ON %3$s', 'combinedby' => ' '] - ] - ], - self::WHERE => 'WHERE %1$s', - self::GROUP => [ - 'GROUP BY %1$s' => [ - [1 => '%1$s', 'combinedby' => ', '] - ] - ], - self::HAVING => 'HAVING %1$s', - self::ORDER => [ - 'ORDER BY %1$s' => [ - [1 => '%1$s', 2 => '%1$s %2$s', 'combinedby' => ', '] - ] - ], - self::LIMIT => 'LIMIT %1$s', - self::OFFSET => 'OFFSET %1$s', - 'statementEnd' => '%1$s', - self::COMBINE => '%1$s ( %2$s )', - ]; - - /** - * @var bool - */ - protected $tableReadOnly = false; /** * @var bool @@ -115,7 +38,7 @@ class Select extends AbstractPreparableSql protected $prefixColumnsWithTable = true; /** - * @var string|array|TableIdentifier + * @var TableSource */ protected $table = null; @@ -130,7 +53,7 @@ class Select extends AbstractPreparableSql protected $columns = [self::SQL_STAR]; /** - * @var null|Join + * @var null|Joins */ protected $joins = null; @@ -164,56 +87,56 @@ class Select extends AbstractPreparableSql */ protected $offset = null; + protected $__getProperties = [ + 'table', + 'quantifier', + 'columns', + 'joins', + 'where', + 'order', + 'group', + 'having', + 'limit', + 'offset', + 'combine', + 'prefixColumnsWithTable', + ]; + /** - * @var array + * @var Combine */ - protected $combine = []; + protected $combine; /** * Constructor * - * @param null|string|array|TableIdentifier $table + * @param null|string|array|TableIdentifier|TableSource $table */ public function __construct($table = null) { - if ($table) { - $this->from($table); - $this->tableReadOnly = true; - } - + parent::__construct(); + $this->from($table); $this->where = new Where; - $this->joins = new Join; + $this->joins = new Joins; $this->having = new Having; } /** * Create from clause * - * @param string|array|TableIdentifier $table - * @throws Exception\InvalidArgumentException - * @return Select + * @param string|array|TableIdentifier|TableSource $table + * @return self */ public function from($table) { - if ($this->tableReadOnly) { - throw new Exception\InvalidArgumentException('Since this object was created with a table and/or schema in the constructor, it is read only.'); - } - - if (!is_string($table) && !is_array($table) && !$table instanceof TableIdentifier) { - throw new Exception\InvalidArgumentException('$table must be a string, array, or an instance of TableIdentifier'); - } - - if (is_array($table) && (!is_string(key($table)) || count($table) !== 1)) { - throw new Exception\InvalidArgumentException('from() expects $table as an array is a single element associative array'); - } - - $this->table = $table; + $this->table = TableSource::factory($table); return $this; } /** - * @param string|Expression $quantifier DISTINCT|ALL - * @return Select + * @param string|ExpressionInterface $quantifier DISTINCT|ALL + * @return self + * @throws Exception\InvalidArgumentException */ public function quantifier($quantifier) { @@ -241,27 +164,24 @@ public function quantifier($quantifier) * value can be string or Expression objects * * @param array $columns - * @param bool $prefixColumnsWithTable - * @return Select + * @return self */ - public function columns(array $columns, $prefixColumnsWithTable = true) + public function columns(array $columns) { $this->columns = $columns; - $this->prefixColumnsWithTable = (bool) $prefixColumnsWithTable; return $this; } /** * Create join clause * - * @param string|array $name - * @param string $on - * @param string|array $columns + * @param string|array|TableIdentifier|TableSource $name + * @param string $on + * @param string|array $columns * @param string $type one of the JOIN_* constants - * @throws Exception\InvalidArgumentException - * @return Select + * @return self */ - public function join($name, $on, $columns = self::SQL_STAR, $type = self::JOIN_INNER) + public function join($name, $on, $columns = self::SQL_STAR, $type = Joins::JOIN_INNER) { $this->joins->join($name, $on, $columns, $type); @@ -274,7 +194,7 @@ public function join($name, $on, $columns = self::SQL_STAR, $type = self::JOIN_I * @param Where|\Closure|string|array|Predicate\PredicateInterface $predicate * @param string $combination One of the OP_* constants from Predicate\PredicateSet * @throws Exception\InvalidArgumentException - * @return Select + * @return self */ public function where($predicate, $combination = Predicate\PredicateSet::OP_AND) { @@ -286,6 +206,10 @@ public function where($predicate, $combination = Predicate\PredicateSet::OP_AND) return $this; } + /** + * @param string|array $group + * @return self + */ public function group($group) { if (is_array($group)) { @@ -301,9 +225,9 @@ public function group($group) /** * Create having clause * - * @param Where|\Closure|string|array $predicate + * @param Having|\Closure|string|array $predicate * @param string $combination One of the OP_* constants from Predicate\PredicateSet - * @return Select + * @return self */ public function having($predicate, $combination = Predicate\PredicateSet::OP_AND) { @@ -317,7 +241,7 @@ public function having($predicate, $combination = Predicate\PredicateSet::OP_AND /** * @param string|array $order - * @return Select + * @return self */ public function order($order) { @@ -342,7 +266,8 @@ public function order($order) /** * @param int $limit - * @return Select + * @return self + * @throws Exception\InvalidArgumentException */ public function limit($limit) { @@ -360,7 +285,8 @@ public function limit($limit) /** * @param int $offset - * @return Select + * @return self + * @throws Exception\InvalidArgumentException */ public function offset($offset) { @@ -377,350 +303,76 @@ public function offset($offset) } /** - * @param Select $select + * @param SelectableInterface $select * @param string $type * @param string $modifier - * @return Select + * @return self * @throws Exception\InvalidArgumentException */ - public function combine(Select $select, $type = self::COMBINE_UNION, $modifier = '') + public function combine(SelectableInterface $select, $type = Combine::COMBINE_UNION, $modifier = '') { - if ($this->combine !== []) { - throw new Exception\InvalidArgumentException('This Select object is already combined and cannot be combined with multiple Selects objects'); + if (!$this->combine) { + $this->combine = new Combine($this); } - $this->combine = [ - 'select' => $select, - 'type' => $type, - 'modifier' => $modifier - ]; + $this->combine->combine($select, $type, $modifier); return $this; } /** - * @param string $part - * @return Select - * @throws Exception\InvalidArgumentException + * @param bool $flag + * @return self */ - public function reset($part) + public function setPrefixColumnsWithTable($flag) { - switch ($part) { - case self::TABLE: - if ($this->tableReadOnly) { - throw new Exception\InvalidArgumentException( - 'Since this object was created with a table and/or schema in the constructor, it is read only.' - ); - } - $this->table = null; + $this->prefixColumnsWithTable = (bool)$flag; + return $this; + } + + public function __unset($name) + { + switch ($name) { + case 'table': + $this->table = TableSource::factory(null); break; - case self::QUANTIFIER: + case 'quantifier': $this->quantifier = null; break; - case self::COLUMNS: - $this->columns = []; + case 'columns': + $this->columns = [self::SQL_STAR]; break; - case self::JOINS: - $this->joins = new Join; + case 'joins': + $this->joins = new Joins; break; - case self::WHERE: + case 'where': $this->where = new Where; break; - case self::GROUP: + case 'group': $this->group = null; break; - case self::HAVING: + case 'having': $this->having = new Having; break; - case self::LIMIT: + case 'limit': $this->limit = null; break; - case self::OFFSET: + case 'offset': $this->offset = null; break; - case self::ORDER: + case 'order': $this->order = []; break; - case self::COMBINE: - $this->combine = []; + case 'prefixColumnsWithTable' : + $this->prefixColumnsWithTable = true; break; - } - return $this; - } - - public function setSpecification($index, $specification) - { - if (!method_exists($this, 'process' . $index)) { - throw new Exception\InvalidArgumentException('Not a valid specification name.'); - } - $this->specifications[$index] = $specification; - return $this; - } - - public function getRawState($key = null) - { - $rawState = [ - self::TABLE => $this->table, - self::QUANTIFIER => $this->quantifier, - self::COLUMNS => $this->columns, - self::JOINS => $this->joins, - self::WHERE => $this->where, - self::ORDER => $this->order, - self::GROUP => $this->group, - self::HAVING => $this->having, - self::LIMIT => $this->limit, - self::OFFSET => $this->offset, - self::COMBINE => $this->combine - ]; - return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; - } - - /** - * Returns whether the table is read only or not. - * - * @return bool - */ - public function isTableReadOnly() - { - return $this->tableReadOnly; - } - - protected function processStatementStart(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->combine !== []) { - return ['(']; - } - } - - protected function processStatementEnd(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->combine !== []) { - return [')']; - } - } - - /** - * Process the select part - * - * @param PlatformInterface $platform - * @param DriverInterface $driver - * @param ParameterContainer $parameterContainer - * @return null|array - */ - protected function processSelect(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - $expr = 1; - - list($table, $fromTable) = $this->resolveTable($this->table, $platform, $driver, $parameterContainer); - // process table columns - $columns = []; - foreach ($this->columns as $columnIndexOrAs => $column) { - if ($column === self::SQL_STAR) { - $columns[] = [$fromTable . self::SQL_STAR]; - continue; - } - - $columnName = $this->resolveColumnValue( - [ - 'column' => $column, - 'fromTable' => $fromTable, - 'isIdentifier' => true, - ], - $platform, - $driver, - $parameterContainer, - (is_string($columnIndexOrAs) ? $columnIndexOrAs : 'column') - ); - // process As portion - if (is_string($columnIndexOrAs)) { - $columnAs = $platform->quoteIdentifier($columnIndexOrAs); - } elseif (stripos($columnName, ' as ') === false) { - $columnAs = (is_string($column)) ? $platform->quoteIdentifier($column) : 'Expression' . $expr++; - } - $columns[] = (isset($columnAs)) ? [$columnName, $columnAs] : [$columnName]; - } - - // process join columns - foreach ($this->joins->getJoins() as $join) { - $joinName = (is_array($join['name'])) ? key($join['name']) : $join['name']; - $joinName = parent::resolveTable($joinName, $platform, $driver, $parameterContainer); - - foreach ($join['columns'] as $jKey => $jColumn) { - $jColumns = []; - $jFromTable = is_scalar($jColumn) - ? $joinName . $platform->getIdentifierSeparator() - : ''; - $jColumns[] = $this->resolveColumnValue( - [ - 'column' => $jColumn, - 'fromTable' => $jFromTable, - 'isIdentifier' => true, - ], - $platform, - $driver, - $parameterContainer, - (is_string($jKey) ? $jKey : 'column') + case 'combine': + $this->combine = null; + break; + default : + throw new Exception\InvalidArgumentException( + 'Not a valid property "' . $name . '" for this object' ); - if (is_string($jKey)) { - $jColumns[] = $platform->quoteIdentifier($jKey); - } elseif ($jColumn !== self::SQL_STAR) { - $jColumns[] = $platform->quoteIdentifier($jColumn); - } - $columns[] = $jColumns; - } - } - - if ($this->quantifier) { - $quantifier = ($this->quantifier instanceof ExpressionInterface) - ? $this->processExpression($this->quantifier, $platform, $driver, $parameterContainer, 'quantifier') - : $this->quantifier; - } - - if (!isset($table)) { - return [$columns]; - } elseif (isset($quantifier)) { - return [$quantifier, $columns, $table]; - } else { - return [$columns, $table]; - } - } - - protected function processJoins(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - return $this->processJoin($this->joins, $platform, $driver, $parameterContainer); - } - - protected function processWhere(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->where->count() == 0) { - return; - } - return [ - $this->processExpression($this->where, $platform, $driver, $parameterContainer, 'where') - ]; - } - - protected function processGroup(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->group === null) { - return; - } - // process table columns - $groups = []; - foreach ($this->group as $column) { - $groups[] = $this->resolveColumnValue( - [ - 'column' => $column, - 'isIdentifier' => true, - ], - $platform, - $driver, - $parameterContainer, - 'group' - ); - } - return [$groups]; - } - - protected function processHaving(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->having->count() == 0) { - return; - } - return [ - $this->processExpression($this->having, $platform, $driver, $parameterContainer, 'having') - ]; - } - - protected function processOrder(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if (empty($this->order)) { - return; - } - $orders = []; - foreach ($this->order as $k => $v) { - if ($v instanceof ExpressionInterface) { - $orders[] = [ - $this->processExpression($v, $platform, $driver, $parameterContainer) - ]; - continue; - } - if (is_int($k)) { - if (strpos($v, ' ') !== false) { - list($k, $v) = preg_split('# #', $v, 2); - } else { - $k = $v; - $v = self::ORDER_ASCENDING; - } - } - if (strtoupper($v) == self::ORDER_DESCENDING) { - $orders[] = [$platform->quoteIdentifierInFragment($k), self::ORDER_DESCENDING]; - } else { - $orders[] = [$platform->quoteIdentifierInFragment($k), self::ORDER_ASCENDING]; - } - } - return [$orders]; - } - - protected function processLimit(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->limit === null) { - return; - } - if ($parameterContainer) { - $parameterContainer->offsetSet('limit', $this->limit, ParameterContainer::TYPE_INTEGER); - return [$driver->formatParameterName('limit')]; - } - return [$platform->quoteValue($this->limit)]; - } - - protected function processOffset(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->offset === null) { - return; - } - if ($parameterContainer) { - $parameterContainer->offsetSet('offset', $this->offset, ParameterContainer::TYPE_INTEGER); - return [$driver->formatParameterName('offset')]; - } - - return [$platform->quoteValue($this->offset)]; - } - - protected function processCombine(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->combine == []) { - return; - } - - $type = $this->combine['type']; - if ($this->combine['modifier']) { - $type .= ' ' . $this->combine['modifier']; - } - - return [ - strtoupper($type), - $this->processSubSelect($this->combine['select'], $platform, $driver, $parameterContainer), - ]; - } - - /** - * Variable overloading - * - * @param string $name - * @throws Exception\InvalidArgumentException - * @return mixed - */ - public function __get($name) - { - switch (strtolower($name)) { - case 'where': - return $this->where; - case 'having': - return $this->having; - case 'joins': - return $this->joins; - default: - throw new Exception\InvalidArgumentException('Not a valid magic property for this object'); } + return $this; } /** @@ -732,45 +384,23 @@ public function __get($name) */ public function __clone() { + if ($this->table) { + $this->table = clone $this->table; + } $this->where = clone $this->where; $this->joins = clone $this->joins; $this->having = clone $this->having; - } - /** - * @param string|TableIdentifier|Select $table - * @param PlatformInterface $platform - * @param DriverInterface $driver - * @param ParameterContainer $parameterContainer - * @return string - */ - protected function resolveTable($table, PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - $alias = null; - - if (is_array($table)) { - $alias = key($table); - $table = current($table); - } - - $table = parent::resolveTable($table, $platform, $driver, $parameterContainer); - - if ($alias) { - $fromTable = $platform->quoteIdentifier($alias); - $table = $this->renderTable($table, $fromTable); - } else { - $fromTable = $table; - } - - if ($this->prefixColumnsWithTable && $fromTable) { - $fromTable .= $platform->getIdentifierSeparator(); - } else { - $fromTable = ''; + if ($this->combine) { + $combine = $this->combine->combine; + $this->combine = new Combine(); + foreach ($combine as $i => $value) { + $this->combine->combine( + $i == 0 ? $this : clone $value['select'], + $value['type'], + $value['modifier'] + ); + } } - - return [ - $table, - $fromTable - ]; } } diff --git a/src/Sql/SqlInterface.php b/src/Sql/SelectableInterface.php similarity index 53% rename from src/Sql/SqlInterface.php rename to src/Sql/SelectableInterface.php index 551a458c98..dee352ba24 100644 --- a/src/Sql/SqlInterface.php +++ b/src/Sql/SelectableInterface.php @@ -9,16 +9,6 @@ namespace Zend\Db\Sql; -use Zend\Db\Adapter\Platform\PlatformInterface; - -interface SqlInterface +interface SelectableInterface extends SqlObjectInterface { - /** - * Get SQL string for statement - * - * @param null|PlatformInterface $adapterPlatform - * - * @return string - */ - public function getSqlString(PlatformInterface $adapterPlatform = null); } diff --git a/src/Sql/Sql.php b/src/Sql/Sql.php index 053dfe72b7..395a72f1a3 100644 --- a/src/Sql/Sql.php +++ b/src/Sql/Sql.php @@ -11,154 +11,80 @@ use Zend\Db\Adapter\AdapterInterface; use Zend\Db\Adapter\Driver\StatementInterface; -use Zend\Db\Adapter\Platform\PlatformInterface; -class Sql +class Sql extends AbstractSql { - /** @var AdapterInterface */ - protected $adapter = null; - - /** @var string|array|TableIdentifier */ - protected $table = null; - - /** @var Platform\Platform */ - protected $sqlPlatform = null; - /** - * @param AdapterInterface $adapter - * @param null|string|array|TableIdentifier $table - * @param null|Platform\AbstractPlatform $sqlPlatform @deprecated since version 3.0 + * @var Ddl\Sql */ - public function __construct(AdapterInterface $adapter, $table = null, Platform\AbstractPlatform $sqlPlatform = null) - { - $this->adapter = $adapter; - if ($table) { - $this->setTable($table); - } - $this->sqlPlatform = $sqlPlatform ?: new Platform\Platform($adapter); - } + protected $ddl; /** - * @return null|\Zend\Db\Adapter\AdapterInterface + * @param null|string|array|TableIdentifier $table + * @return Select + * @throws Exception\InvalidArgumentException */ - public function getAdapter() - { - return $this->adapter; - } - - public function hasTable() - { - return ($this->table !== null); - } - - public function setTable($table) - { - if (is_string($table) || is_array($table) || $table instanceof TableIdentifier) { - $this->table = $table; - } else { - throw new Exception\InvalidArgumentException('Table must be a string, array or instance of TableIdentifier.'); - } - return $this; - } - - public function getTable() - { - return $this->table; - } - - public function getSqlPlatform() - { - return $this->sqlPlatform; - } - public function select($table = null) { - if ($this->table !== null && $table !== null) { - throw new Exception\InvalidArgumentException(sprintf( - 'This Sql object is intended to work with only the table "%s" provided at construction time.', - $this->table - )); - } + $this->validateTable($table); return new Select(($table) ?: $this->table); } + /** + * @param null|string|array|TableIdentifier $table + * @return Insert + * @throws Exception\InvalidArgumentException + */ public function insert($table = null) { - if ($this->table !== null && $table !== null) { - throw new Exception\InvalidArgumentException(sprintf( - 'This Sql object is intended to work with only the table "%s" provided at construction time.', - $this->table - )); - } + $this->validateTable($table); return new Insert(($table) ?: $this->table); } + /** + * @param null|string|array|TableIdentifier $table + * @return Update + * @throws Exception\InvalidArgumentException + */ public function update($table = null) { - if ($this->table !== null && $table !== null) { - throw new Exception\InvalidArgumentException(sprintf( - 'This Sql object is intended to work with only the table "%s" provided at construction time.', - $this->table - )); - } + $this->validateTable($table); return new Update(($table) ?: $this->table); } - public function delete($table = null) - { - if ($this->table !== null && $table !== null) { - throw new Exception\InvalidArgumentException(sprintf( - 'This Sql object is intended to work with only the table "%s" provided at construction time.', - $this->table - )); - } - return new Delete(($table) ?: $this->table); - } - /** - * @param PreparableSqlInterface $sqlObject - * @param StatementInterface $statement - * @param AdapterInterface $adapter - * - * @return StatementInterface + * @param null|string|array|TableIdentifier $table + * @return Delete + * @throws Exception\InvalidArgumentException */ - public function prepareStatementForSqlObject(PreparableSqlInterface $sqlObject, StatementInterface $statement = null, AdapterInterface $adapter = null) + public function delete($table = null) { - $adapter = $adapter ?: $this->adapter; - $statement = $statement ?: $adapter->getDriver()->createStatement(); - - return $this->sqlPlatform->setSubject($sqlObject)->prepareStatement($adapter, $statement); + $this->validateTable($table); + return new Delete(($table) ?: $this->table); } /** - * Get sql string using platform or sql object - * - * @param SqlInterface $sqlObject - * @param PlatformInterface|null $platform - * - * @return string - * - * @deprecated Deprecated in 2.4. Use buildSqlString() instead + * @return Ddl\Sql */ - public function getSqlStringForSqlObject(SqlInterface $sqlObject, PlatformInterface $platform = null) + public function getDdl() { - $platform = ($platform) ?: $this->adapter->getPlatform(); - return $this->sqlPlatform->setSubject($sqlObject)->getSqlString($platform); + if (!$this->ddl) { + $this->ddl = new Ddl\Sql($this->adapter, $this->table, $this->builder); + } + return $this->ddl; } /** - * @param SqlInterface $sqlObject - * @param AdapterInterface $adapter + * @param PreparableSqlObjectInterface $sqlObject + * @param null|AdapterInterface $adapter * - * @return string - * - * @throws Exception\InvalidArgumentException + * @return StatementInterface */ - public function buildSqlString(SqlInterface $sqlObject, AdapterInterface $adapter = null) + public function prepareSqlStatement(PreparableSqlObjectInterface $sqlObject, AdapterInterface $adapter = null) { - return $this - ->sqlPlatform - ->setSubject($sqlObject) - ->getSqlString($adapter ? $adapter->getPlatform() : $this->adapter->getPlatform()); + return $this->builder->prepareSqlStatement( + $sqlObject, + $adapter ?: $this->adapter + ); } } diff --git a/src/Sql/SqlObjectInterface.php b/src/Sql/SqlObjectInterface.php new file mode 100644 index 0000000000..63f6ac3cd5 --- /dev/null +++ b/src/Sql/SqlObjectInterface.php @@ -0,0 +1,14 @@ +table = $table; - } - /** * @return string */ @@ -88,16 +92,6 @@ public function hasSchema() return ($this->schema !== null); } - /** - * @param $schema - * - * @deprecated please use the constructor and build a new {@see TableIdentifier} instead - */ - public function setSchema($schema) - { - $this->schema = $schema; - } - /** * @return null|string */ diff --git a/src/Sql/TableSource.php b/src/Sql/TableSource.php new file mode 100644 index 0000000000..5f957ded36 --- /dev/null +++ b/src/Sql/TableSource.php @@ -0,0 +1,92 @@ +setSource($source); + $this->alias = $alias; + } + + /** + * @param string $alias + * @return self + */ + public function setAlias($alias) + { + $this->alias = $alias; + return $this; + } + + /** + * @return string + */ + public function getAlias() + { + return $this->alias; + } + + /** + * @param string|array|TableIdentifier|SelectableInterface|ExpressionInterface $source + * @return self + */ + public function setSource($source) + { + if (is_string($source) || is_array($source)) { + $source = new TableIdentifier($source); + } elseif ($source !== null && !$source instanceof TableIdentifier && !$source instanceof ExpressionInterface && !$source instanceof SelectableInterface) { + throw new Exception\InvalidArgumentException('invalid $source parameter'); + } + + $this->source = $source; + return $this; + } + + /** + * @return TableIdentifier|SelectableInterface|ExpressionInterface + */ + public function getSource() + { + return $this->source; + } +} diff --git a/src/Sql/Update.php b/src/Sql/Update.php index d88156b32e..6e984f4e02 100644 --- a/src/Sql/Update.php +++ b/src/Sql/Update.php @@ -9,50 +9,23 @@ namespace Zend\Db\Sql; -use Zend\Db\Adapter\ParameterContainer; -use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Stdlib\PriorityList; /** - * + * @property TableSource $table + * @property PriorityList $set * @property Where $where */ -class Update extends AbstractPreparableSql +class Update extends AbstractSqlObject implements PreparableSqlObjectInterface { - /**@#++ - * @const - */ - const SPECIFICATION_UPDATE = 'update'; - const SPECIFICATION_SET = 'set'; - const SPECIFICATION_WHERE = 'where'; - const SPECIFICATION_JOIN = 'joins'; - const VALUES_MERGE = 'merge'; const VALUES_SET = 'set'; - /**@#-**/ - - protected $specifications = [ - self::SPECIFICATION_UPDATE => 'UPDATE %1$s', - self::SPECIFICATION_JOIN => [ - '%1$s' => [ - [3 => '%1$s JOIN %2$s ON %3$s', 'combinedby' => ' '] - ] - ], - self::SPECIFICATION_SET => 'SET %1$s', - self::SPECIFICATION_WHERE => 'WHERE %1$s', - ]; /** - * @var string|TableIdentifier + * @var TableSource */ protected $table = ''; - /** - * @var bool - */ - protected $emptyWhereProtection = true; - /** * @var PriorityList */ @@ -63,23 +36,29 @@ class Update extends AbstractPreparableSql */ protected $where = null; + protected $__getProperties = [ + 'table', + 'set', + 'where', + 'joins', + ]; + /** - * @var null|Join + * @var null|Joins */ protected $joins = null; /** * Constructor * - * @param null|string|TableIdentifier $table + * @param null|string|array|TableIdentifier|TableSource $table */ public function __construct($table = null) { - if ($table) { - $this->table($table); - } + parent::__construct(); + $this->table($table); $this->where = new Where(); - $this->joins = new Join(); + $this->joins = new Joins(); $this->set = new PriorityList(); $this->set->isLIFO(false); } @@ -87,12 +66,12 @@ public function __construct($table = null) /** * Specify table for statement * - * @param string|TableIdentifier $table - * @return Update + * @param string|array|TableIdentifier|TableSource $table + * @return self */ public function table($table) { - $this->table = $table; + $this->table = TableSource::factory($table); return $this; } @@ -102,11 +81,11 @@ public function table($table) * @param array $values Associative array of key values * @param string $flag One of the VALUES_* constants * @throws Exception\InvalidArgumentException - * @return Update + * @return self */ public function set(array $values, $flag = self::VALUES_SET) { - if ($values === null) { + if ($values == null) { throw new Exception\InvalidArgumentException('set() expects an array of values'); } @@ -129,7 +108,7 @@ public function set(array $values, $flag = self::VALUES_SET) * @param Where|\Closure|string|array $predicate * @param string $combination One of the OP_* constants from Predicate\PredicateSet * @throws Exception\InvalidArgumentException - * @return Update + * @return self */ public function where($predicate, $combination = Predicate\PredicateSet::OP_AND) { @@ -150,87 +129,13 @@ public function where($predicate, $combination = Predicate\PredicateSet::OP_AND) * @throws Exception\InvalidArgumentException * @return Update */ - public function join($name, $on, $type = Join::JOIN_INNER) + public function join($name, $on, $type = Joins::JOIN_INNER) { $this->joins->join($name, $on, [], $type); return $this; } - public function getRawState($key = null) - { - $rawState = [ - 'emptyWhereProtection' => $this->emptyWhereProtection, - 'table' => $this->table, - 'set' => $this->set->toArray(), - 'where' => $this->where, - 'joins' => $this->joins - ]; - return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; - } - - protected function processUpdate(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - return sprintf( - $this->specifications[static::SPECIFICATION_UPDATE], - $this->resolveTable($this->table, $platform, $driver, $parameterContainer) - ); - } - - protected function processSet(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - $setSql = []; - foreach ($this->set as $column => $value) { - $prefix = $platform->quoteIdentifier($column) . ' = '; - if (is_scalar($value) && $parameterContainer) { - $setSql[] = $prefix . $driver->formatParameterName($column); - $parameterContainer->offsetSet($column, $value); - } else { - $setSql[] = $prefix . $this->resolveColumnValue( - $value, - $platform, - $driver, - $parameterContainer - ); - } - } - - return sprintf( - $this->specifications[static::SPECIFICATION_SET], - implode(', ', $setSql) - ); - } - - protected function processWhere(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if ($this->where->count() == 0) { - return; - } - return sprintf( - $this->specifications[static::SPECIFICATION_WHERE], - $this->processExpression($this->where, $platform, $driver, $parameterContainer, 'where') - ); - } - - protected function processJoins(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - return $this->processJoin($this->joins, $platform, $driver, $parameterContainer); - } - - /** - * Variable overloading - * - * Proxies to "where" only - * - * @param string $name - * @return mixed - */ - public function __get($name) - { - if (strtolower($name) == 'where') { - return $this->where; - } - } /** * __clone @@ -241,6 +146,8 @@ public function __get($name) */ public function __clone() { + $this->table = clone $this->table; + $this->joins = clone $this->joins; $this->where = clone $this->where; $this->set = clone $this->set; } diff --git a/src/TableGateway/AbstractTableGateway.php b/src/TableGateway/AbstractTableGateway.php index a27d50756f..6e84c2570c 100644 --- a/src/TableGateway/AbstractTableGateway.php +++ b/src/TableGateway/AbstractTableGateway.php @@ -14,10 +14,10 @@ use Zend\Db\ResultSet\ResultSetInterface; use Zend\Db\Sql\Delete; use Zend\Db\Sql\Insert; -use Zend\Db\Sql\Join; +use Zend\Db\Sql\Joins; use Zend\Db\Sql\Select; use Zend\Db\Sql\Sql; -use Zend\Db\Sql\TableIdentifier; +use Zend\Db\Sql\TableSource; use Zend\Db\Sql\Update; use Zend\Db\Sql\Where; use Zend\Db\TableGateway\Feature\EventFeatureEventsInterface; @@ -41,7 +41,7 @@ abstract class AbstractTableGateway implements TableGatewayInterface protected $adapter = null; /** - * @var string|array|TableIdentifier + * @var TableSource */ protected $table = null; @@ -102,7 +102,7 @@ public function initialize() throw new Exception\RuntimeException('This table does not have an Adapter setup'); } - if (!is_string($this->table) && !$this->table instanceof TableIdentifier && !is_array($this->table)) { + if (!$this->table instanceof TableSource) { throw new Exception\RuntimeException('This table object does not have a valid table set.'); } @@ -122,7 +122,7 @@ public function initialize() /** * Get table name * - * @return string + * @return TableSource */ public function getTable() { @@ -216,17 +216,13 @@ public function selectWith(Select $select) */ protected function executeSelect(Select $select) { - $selectState = $select->getRawState(); - if ($selectState['table'] != $this->table - && (is_array($selectState['table']) - && end($selectState['table']) != $this->table) - ) { + if ($select->table->getSource() != $this->table->getSource()) { throw new Exception\RuntimeException( 'The table name of the provided Select object must match that of the table' ); } - if ($selectState['columns'] == [Select::SQL_STAR] + if ($select->columns == [Select::SQL_STAR] && $this->columns !== []) { $select->columns($this->columns); } @@ -235,7 +231,7 @@ protected function executeSelect(Select $select) $this->featureSet->apply(EventFeatureEventsInterface::EVENT_PRE_SELECT, [$select]); // prepare and execute - $statement = $this->sql->prepareStatementForSqlObject($select); + $statement = $this->sql->prepareSqlStatement($select); $result = $statement->execute(); // build result set @@ -285,8 +281,7 @@ public function insertWith(Insert $insert) */ protected function executeInsert(Insert $insert) { - $insertState = $insert->getRawState(); - if ($insertState['table'] != $this->table) { + if ($insert->table->getSource() != $this->table->getSource()) { throw new Exception\RuntimeException( 'The table name of the provided Insert object must match that of the table' ); @@ -298,13 +293,13 @@ protected function executeInsert(Insert $insert) // Most RDBMS solutions do not allow using table aliases in INSERTs // See https://github.com/zendframework/zf2/issues/7311 $unaliasedTable = false; - if (is_array($insertState['table'])) { - $tableData = array_values($insertState['table']); - $unaliasedTable = array_shift($tableData); - $insert->into($unaliasedTable); + if (is_array($insert->table)) { + $unaliasedTable = $insert->table; + $tableData = array_values($insert->table); + $insert->into(array_shift($tableData)); } - $statement = $this->sql->prepareStatementForSqlObject($insert); + $statement = $this->sql->prepareSqlStatement($insert); $result = $statement->execute(); $this->lastInsertValue = $this->adapter->getDriver()->getConnection()->getLastGeneratedValue(); @@ -313,7 +308,7 @@ protected function executeInsert(Insert $insert) // Reset original table information in Insert instance, if necessary if ($unaliasedTable) { - $insert->into($insertState['table']); + $insert->into($unaliasedTable); } return $result->getAffectedRows(); @@ -341,7 +336,7 @@ public function update($set, $where = null, array $joins = null) if ($joins) { foreach ($joins as $join) { - $type = isset($join['type']) ? $join['type'] : Join::JOIN_INNER; + $type = isset($join['type']) ? $join['type'] : Joins::JOIN_INNER; $update->join($join['name'], $join['on'], $type); } } @@ -370,8 +365,7 @@ public function updateWith(Update $update) */ protected function executeUpdate(Update $update) { - $updateState = $update->getRawState(); - if ($updateState['table'] != $this->table) { + if ($update->table->getSource() != $this->table->getSource()) { throw new Exception\RuntimeException( 'The table name of the provided Update object must match that of the table' ); @@ -381,13 +375,13 @@ protected function executeUpdate(Update $update) $this->featureSet->apply(EventFeatureEventsInterface::EVENT_PRE_UPDATE, [$update]); $unaliasedTable = false; - if (is_array($updateState['table'])) { - $tableData = array_values($updateState['table']); - $unaliasedTable = array_shift($tableData); - $update->table($unaliasedTable); + if (is_array($update->table)) { + $unaliasedTable = $update->table; + $tableData = array_values($update->table); + $update->table(array_shift($tableData)); } - $statement = $this->sql->prepareStatementForSqlObject($update); + $statement = $this->sql->prepareSqlStatement($update); $result = $statement->execute(); // apply postUpdate features @@ -395,7 +389,7 @@ protected function executeUpdate(Update $update) // Reset original table information in Update instance, if necessary if ($unaliasedTable) { - $update->table($updateState['table']); + $update->table($unaliasedTable); } return $result->getAffectedRows(); @@ -440,8 +434,7 @@ public function deleteWith(Delete $delete) */ protected function executeDelete(Delete $delete) { - $deleteState = $delete->getRawState(); - if ($deleteState['table'] != $this->table) { + if ($delete->table->getSource() != $this->table->getSource()) { throw new Exception\RuntimeException( 'The table name of the provided Delete object must match that of the table' ); @@ -450,7 +443,7 @@ protected function executeDelete(Delete $delete) // pre delete update $this->featureSet->apply(EventFeatureEventsInterface::EVENT_PRE_DELETE, [$delete]); - $statement = $this->sql->prepareStatementForSqlObject($delete); + $statement = $this->sql->prepareSqlStatement($delete); $result = $statement->execute(); // apply postDelete features @@ -531,15 +524,8 @@ public function __clone() { $this->resultSetPrototype = (isset($this->resultSetPrototype)) ? clone $this->resultSetPrototype : null; $this->sql = clone $this->sql; - if (is_object($this->table)) { + if ($this->table) { $this->table = clone $this->table; - } elseif (is_array($this->table) - && count($this->table) == 1 - && is_object(reset($this->table)) - ) { - foreach ($this->table as $alias => &$tableObject) { - $tableObject = clone $tableObject; - } } } } diff --git a/src/TableGateway/Feature/MasterSlaveFeature.php b/src/TableGateway/Feature/MasterSlaveFeature.php index 07d36f954d..ab04f74f29 100644 --- a/src/TableGateway/Feature/MasterSlaveFeature.php +++ b/src/TableGateway/Feature/MasterSlaveFeature.php @@ -66,7 +66,7 @@ public function postInitialize() $this->slaveSql = new Sql( $this->slaveAdapter, $this->tableGateway->sql->getTable(), - $this->tableGateway->sql->getSqlPlatform() + $this->tableGateway->sql->getBuilder() ); } } diff --git a/src/TableGateway/Feature/SequenceFeature.php b/src/TableGateway/Feature/SequenceFeature.php index 3c72fd3b6f..11633346b0 100644 --- a/src/TableGateway/Feature/SequenceFeature.php +++ b/src/TableGateway/Feature/SequenceFeature.php @@ -47,8 +47,8 @@ public function __construct($primaryKeyField, $sequenceName) */ public function preInsert(Insert $insert) { - $columns = $insert->getRawState('columns'); - $values = $insert->getRawState('values'); + $columns = $insert->columns; + $values = $insert->values; $key = array_search($this->primaryKeyField, $columns); if ($key !== false) { $this->sequenceValue = $values[$key]; diff --git a/src/TableGateway/TableGateway.php b/src/TableGateway/TableGateway.php index e2622baea9..da020aeea4 100644 --- a/src/TableGateway/TableGateway.php +++ b/src/TableGateway/TableGateway.php @@ -13,14 +13,14 @@ use Zend\Db\ResultSet\ResultSet; use Zend\Db\ResultSet\ResultSetInterface; use Zend\Db\Sql\Sql; -use Zend\Db\Sql\TableIdentifier; +use Zend\Db\Sql\TableSource; class TableGateway extends AbstractTableGateway { /** * Constructor * - * @param string|TableIdentifier|array $table + * @param string|array|TableIdentifier|TableSource $table * @param AdapterInterface $adapter * @param Feature\AbstractFeature|Feature\FeatureSet|Feature\AbstractFeature[]|null $features * @param ResultSetInterface|null $resultSetPrototype @@ -31,10 +31,10 @@ class TableGateway extends AbstractTableGateway public function __construct($table, AdapterInterface $adapter, $features = null, ResultSetInterface $resultSetPrototype = null, Sql $sql = null) { // table - if (!(is_string($table) || $table instanceof TableIdentifier || is_array($table))) { + if (!$table) { throw new Exception\InvalidArgumentException('Table name must be a string or an instance of Zend\Db\Sql\TableIdentifier'); } - $this->table = $table; + $this->table = TableSource::factory($table); // adapter $this->adapter = $adapter; @@ -61,10 +61,10 @@ public function __construct($table, AdapterInterface $adapter, $features = null, $this->resultSetPrototype = ($resultSetPrototype) ?: new ResultSet; // Sql object (factory for select, insert, update, delete) - $this->sql = ($sql) ?: new Sql($this->adapter, $this->table); + $this->sql = ($sql) ?: new Sql($this->adapter, $this->table->getSource()); - // check sql object bound to same table - if ($this->sql->getTable() != $this->table) { + // check sql object bound to same table(); + if ($this->sql->getTable() != $this->table->getSource()) { throw new Exception\InvalidArgumentException('The table inside the provided Sql object must match the table of this TableGateway'); } diff --git a/test/Adapter/AdapterAbstractServiceFactoryTest.php b/test/Adapter/AdapterAbstractServiceFactoryTest.php index de177ccd18..a94fa48b8e 100644 --- a/test/Adapter/AdapterAbstractServiceFactoryTest.php +++ b/test/Adapter/AdapterAbstractServiceFactoryTest.php @@ -88,4 +88,29 @@ public function testInvalidService($service) { $actual = $this->serviceManager->get($service); } + + public function testInjectSqlBuilder() + { + $mockBuilder = $this->getMock('Zend\Db\Adapter\SqlBuilderInterface'); + $this->serviceManager->setAllowOverride(true); + $this->serviceManager->setService('sqlBuilderAlias', $mockBuilder); + $this->serviceManager->setService('config', [ + 'db' => [ + 'adapters' => [ + 'Zend\Db\Adapter\Writer' => [ + 'driver' => 'mysqli', + 'sql_builder' => 'sqlBuilderAlias', + ], + 'Zend\Db\Adapter\Reader' => [ + 'driver' => 'mysqli', + 'sql_builder' => 'sqlBuilderAlias', + ], + ], + ], + ]); + + $adapter = $this->serviceManager->get('Zend\Db\Adapter\Writer'); + $this->assertInstanceOf('Zend\Db\Adapter\Adapter', $adapter); + $this->assertSame($mockBuilder, $adapter->getSqlBuilder()); + } } diff --git a/test/Adapter/AdapterServiceFactoryTest.php b/test/Adapter/AdapterServiceFactoryTest.php index 9b980d9e14..9c093f5733 100644 --- a/test/Adapter/AdapterServiceFactoryTest.php +++ b/test/Adapter/AdapterServiceFactoryTest.php @@ -54,4 +54,21 @@ public function testV3FactoryReturnsAdapter() $adapter = $this->factory->__invoke($this->services->reveal(), Adapter::class); $this->assertInstanceOf(Adapter::class, $adapter); } + + public function testInjectSqlBuilder() + { + $mockBuilder = $this->getMock('Zend\Db\Adapter\SqlBuilderInterface'); + $this->services->get('sqlBuilderAlias')->willReturn($mockBuilder); + $this->services->get('config')->willReturn([ + 'db' => [ + 'driver' => 'Pdo_Sqlite', + 'database' => 'sqlite::memory:', + 'sql_builder' => 'sqlBuilderAlias', + ], + ]); + + $adapter = $this->factory->__invoke($this->services->reveal(), Adapter::class); + $this->assertInstanceOf(Adapter::class, $adapter); + $this->assertSame($mockBuilder, $adapter->getSqlBuilder()); + } } diff --git a/test/Adapter/AdapterTest.php b/test/Adapter/AdapterTest.php index 71c7212aec..6277df5880 100644 --- a/test/Adapter/AdapterTest.php +++ b/test/Adapter/AdapterTest.php @@ -11,6 +11,7 @@ use Zend\Db\Adapter\Adapter; use Zend\Db\Adapter\Profiler; +use Zend\Db\Sql\Select; class AdapterTest extends \PHPUnit_Framework_TestCase { @@ -83,25 +84,25 @@ public function testCreateDriver() { if (extension_loaded('mysqli')) { $adapter = new Adapter(['driver' => 'mysqli'], $this->mockPlatform); - $this->assertInstanceOf('Zend\Db\Adapter\Driver\Mysqli\Mysqli', $adapter->driver); + $this->assertInstanceOf('Zend\Db\Adapter\Driver\Mysqli\Mysqli', $adapter->getDriver()); unset($adapter); } if (extension_loaded('pgsql')) { $adapter = new Adapter(['driver' => 'pgsql'], $this->mockPlatform); - $this->assertInstanceOf('Zend\Db\Adapter\Driver\Pgsql\Pgsql', $adapter->driver); + $this->assertInstanceOf('Zend\Db\Adapter\Driver\Pgsql\Pgsql', $adapter->getDriver()); unset($adapter); } if (extension_loaded('sqlsrv')) { $adapter = new Adapter(['driver' => 'sqlsrv'], $this->mockPlatform); - $this->assertInstanceOf('Zend\Db\Adapter\Driver\Sqlsrv\Sqlsrv', $adapter->driver); + $this->assertInstanceOf('Zend\Db\Adapter\Driver\Sqlsrv\Sqlsrv', $adapter->getDriver()); unset($adapter); } if (extension_loaded('pdo')) { $adapter = new Adapter(['driver' => 'pdo_sqlite'], $this->mockPlatform); - $this->assertInstanceOf('Zend\Db\Adapter\Driver\Pdo\Pdo', $adapter->driver); + $this->assertInstanceOf('Zend\Db\Adapter\Driver\Pdo\Pdo', $adapter->getDriver()); unset($adapter); } } @@ -115,49 +116,49 @@ public function testCreatePlatform() $driver = clone $this->mockDriver; $driver->expects($this->any())->method('getDatabasePlatformName')->will($this->returnValue('Mysql')); $adapter = new Adapter($driver); - $this->assertInstanceOf('Zend\Db\Adapter\Platform\Mysql', $adapter->platform); + $this->assertInstanceOf('Zend\Db\Adapter\Platform\Mysql', $adapter->getPlatform()); unset($adapter, $driver); $driver = clone $this->mockDriver; $driver->expects($this->any())->method('getDatabasePlatformName')->will($this->returnValue('SqlServer')); $adapter = new Adapter($driver); - $this->assertInstanceOf('Zend\Db\Adapter\Platform\SqlServer', $adapter->platform); + $this->assertInstanceOf('Zend\Db\Adapter\Platform\SqlServer', $adapter->getPlatform()); unset($adapter, $driver); $driver = clone $this->mockDriver; $driver->expects($this->any())->method('getDatabasePlatformName')->will($this->returnValue('Postgresql')); $adapter = new Adapter($driver); - $this->assertInstanceOf('Zend\Db\Adapter\Platform\Postgresql', $adapter->platform); + $this->assertInstanceOf('Zend\Db\Adapter\Platform\Postgresql', $adapter->getPlatform()); unset($adapter, $driver); $driver = clone $this->mockDriver; $driver->expects($this->any())->method('getDatabasePlatformName')->will($this->returnValue('Sqlite')); $adapter = new Adapter($driver); - $this->assertInstanceOf('Zend\Db\Adapter\Platform\Sqlite', $adapter->platform); + $this->assertInstanceOf('Zend\Db\Adapter\Platform\Sqlite', $adapter->getPlatform()); unset($adapter, $driver); $driver = clone $this->mockDriver; $driver->expects($this->any())->method('getDatabasePlatformName')->will($this->returnValue('IbmDb2')); $adapter = new Adapter($driver); - $this->assertInstanceOf('Zend\Db\Adapter\Platform\IbmDb2', $adapter->platform); + $this->assertInstanceOf('Zend\Db\Adapter\Platform\IbmDb2', $adapter->getPlatform()); unset($adapter, $driver); $driver = clone $this->mockDriver; $driver->expects($this->any())->method('getDatabasePlatformName')->will($this->returnValue('Oracle')); $adapter = new Adapter($driver); - $this->assertInstanceOf('Zend\Db\Adapter\Platform\Oracle', $adapter->platform); + $this->assertInstanceOf('Zend\Db\Adapter\Platform\Oracle', $adapter->getPlatform()); unset($adapter, $driver); $driver = clone $this->mockDriver; $driver->expects($this->any())->method('getDatabasePlatformName')->will($this->returnValue('Foo')); $adapter = new Adapter($driver); - $this->assertInstanceOf('Zend\Db\Adapter\Platform\Sql92', $adapter->platform); + $this->assertInstanceOf('Zend\Db\Adapter\Platform\Sql92', $adapter->getPlatform()); unset($adapter, $driver); // ensure platform can created via string, and also that it passed in options to platform object $driver = ['driver' => 'pdo_sqlite', 'platform' => 'Oracle', 'platform_options' => ['quote_identifiers' => false]]; $adapter = new Adapter($driver); - $this->assertInstanceOf('Zend\Db\Adapter\Platform\Oracle', $adapter->platform); + $this->assertInstanceOf('Zend\Db\Adapter\Platform\Oracle', $adapter->getPlatform()); $this->assertEquals('foo', $adapter->getPlatform()->quoteIdentifier('foo')); unset($adapter, $driver); } @@ -200,6 +201,36 @@ public function testGetCurrentSchema() $this->assertEquals('FooSchema', $this->adapter->getCurrentSchema()); } + /** + * @covers Zend\Db\Adapter\Adapter::getSqlBuilder + * @covers Zend\Db\Adapter\Adapter::setSqlBuilder + */ + public function testSetGetSqlBuilder() + { + $mockBuilder = $this->getMock('Zend\Db\Adapter\SqlBuilderInterface'); + + $this->assertNull($this->adapter->getSqlBuilder()); + $this->assertSame($this->adapter, $this->adapter->setSqlBuilder($mockBuilder)); + $this->assertSame($mockBuilder, $this->adapter->getSqlBuilder()); + } + + /** + * @covers Zend\Db\Adapter\Adapter::getSqlBuilder + * @covers Zend\Db\Adapter\Adapter::setSqlBuilder + */ + public function testSetSqlBuilderViaConstructor() + { + $mockBuilder = $this->getMock('Zend\Db\Adapter\SqlBuilderInterface'); + $adapter = new Adapter( + [ + 'driver' => $this->mockDriver, + 'sql_builder' => $mockBuilder, + ], + $this->mockPlatform + ); + $this->assertSame($mockBuilder, $adapter->getSqlBuilder()); + } + /** * @testdox unit test: Test query() in prepare mode produces a statement object * @covers Zend\Db\Adapter\Adapter::query @@ -278,27 +309,59 @@ public function testQueryWhenExecutedProducesAResultSetObjectWhenResultIsQuery() } /** - * @testdox unit test: Test createStatement() produces a statement object - * @covers Zend\Db\Adapter\Adapter::createStatement + * @covers Zend\Db\Adapter\Adapter::query */ - public function testCreateStatement() + public function testQueryWithObjectSql() { - $this->assertSame($this->mockStatement, $this->adapter->createStatement()); + $sql = 'SELECT bar'; + $sqlObject = new Select('bar'); + + $resultInterface = $this->getMock('Zend\Db\Adapter\Driver\ResultInterface'); + $statementInterface = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); + + $this->mockConnection->expects($this->any())->method('execute')->with($sql)->will($this->returnValue($resultInterface)); + + $mockBuilder = $this->getMock('Zend\Db\Adapter\SqlBuilderInterface'); + $mockBuilder->expects($this->any())->method('buildSqlString')->with($sqlObject)->will($this->returnValue($sql)); + $mockBuilder->expects($this->any())->method('prepareSqlStatement')->with($sqlObject)->will($this->returnValue($statementInterface)); + + $this->adapter->setSqlBuilder($mockBuilder); + + $this->assertSame( + $resultInterface, + $this->adapter->query($sqlObject, Adapter::QUERY_MODE_EXECUTE) + ); + $this->assertSame( + $statementInterface, + $this->adapter->query($sqlObject, Adapter::QUERY_MODE_PREPARE) + ); + } + + /** + * @covers Zend\Db\Adapter\Adapter::query + */ + public function testQueryExecuteObjectSqlWithoutSqlBuilder() + { + $this->setExpectedException('Zend\Db\Adapter\Exception\RuntimeException', 'sqlBuilder must be set for non string sql'); + $this->adapter->query(new Select('bar'), Adapter::QUERY_MODE_EXECUTE); } /** - * @testdox unit test: Test __get() works - * @covers Zend\Db\Adapter\Adapter::__get + * @covers Zend\Db\Adapter\Adapter::query */ - public function test__get() + public function testQueryPrepareObjectSqlWithoutSqlBuilder() { - $this->assertSame($this->mockDriver, $this->adapter->driver); - $this->assertSame($this->mockDriver, $this->adapter->DrivER); - $this->assertSame($this->mockPlatform, $this->adapter->PlatForm); - $this->assertSame($this->mockPlatform, $this->adapter->platform); + $this->setExpectedException('Zend\Db\Adapter\Exception\RuntimeException', 'sqlBuilder must be set for non string sql'); + $this->adapter->query(new Select('bar'), Adapter::QUERY_MODE_PREPARE); + } - $this->setExpectedException('InvalidArgumentException', 'Invalid magic'); - $this->adapter->foo; + /** + * @testdox unit test: Test createStatement() produces a statement object + * @covers Zend\Db\Adapter\Adapter::createStatement + */ + public function testCreateStatement() + { + $this->assertSame($this->mockStatement, $this->adapter->createStatement()); } } diff --git a/test/Adapter/Driver/Pdo/AbstractIntegrationTest.php b/test/Adapter/Driver/Pdo/AbstractIntegrationTest.php deleted file mode 100644 index 53ece0ce4b..0000000000 --- a/test/Adapter/Driver/Pdo/AbstractIntegrationTest.php +++ /dev/null @@ -1,32 +0,0 @@ -variables as $name => $value) { -// if (!getenv($value)) { -// $this->markTestSkipped('Missing required variable ' . $value . ' from phpunit.xml for this integration test'); -// } -// $this->variables[$name] = getenv($value); -// } -// -// if (!extension_loaded('sqlsrv')) { -// $this->fail('The phpunit group integration-sqlsrv was enabled, but the extension is not loaded.'); -// } -// } -//} diff --git a/test/Adapter/Driver/Pdo/ResultTest.php b/test/Adapter/Driver/Pdo/ResultTest.php index edda281648..dfd4334175 100644 --- a/test/Adapter/Driver/Pdo/ResultTest.php +++ b/test/Adapter/Driver/Pdo/ResultTest.php @@ -20,7 +20,6 @@ */ class ResultTest extends \PHPUnit_Framework_TestCase { - /** * Tests current method returns same data on consecutive calls. * diff --git a/test/RowGateway/AbstractRowGatewayTest.php b/test/RowGateway/AbstractRowGatewayTest.php index d9bdeb9763..f83d2540fe 100644 --- a/test/RowGateway/AbstractRowGatewayTest.php +++ b/test/RowGateway/AbstractRowGatewayTest.php @@ -10,6 +10,9 @@ namespace ZendTest\Db\RowGateway; use Zend\Db\RowGateway\RowGateway; +use Zend\Db\Adapter\ParameterContainer; +use ZendTest\Db\TestAsset\TrustingSql92Platform; +use Zend\Db\Sql\TableIdentifier; class AbstractRowGatewayTest extends \PHPUnit_Framework_TestCase { @@ -28,20 +31,22 @@ public function setup() $this->mockResult = $mockResult; $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); $mockStatement->expects($this->any())->method('execute')->will($this->returnValue($mockResult)); + $mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue(new ParameterContainer)); $mockConnection = $this->getMock('Zend\Db\Adapter\Driver\ConnectionInterface'); $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); $mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue($mockStatement)); $mockDriver->expects($this->any())->method('getConnection')->will($this->returnValue($mockConnection)); // setup mock adapter - $this->mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); + $this->mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver, new TrustingSql92Platform]); $this->rowGateway = $this->getMockForAbstractClass('Zend\Db\RowGateway\AbstractRowGateway'); + $table = new TableIdentifier('foo'); $rgPropertyValues = [ 'primaryKeyColumn' => 'id', - 'table' => 'foo', - 'sql' => new \Zend\Db\Sql\Sql($this->mockAdapter) + 'table' => $table, + 'sql' => new \Zend\Db\Sql\Sql($this->mockAdapter, $table) ]; $this->setRowGatewayState($rgPropertyValues); } @@ -161,7 +166,7 @@ public function testSaveInsertMultiKey() $rgPropertyValues = [ 'primaryKeyColumn' => ['one', 'two'], - 'table' => 'foo', + 'table' => new TableIdentifier('foo'), 'sql' => $mockSql ]; $this->setRowGatewayState($rgPropertyValues); @@ -209,7 +214,7 @@ public function testSaveUpdateChangingPrimaryKey() ->with($this->equalTo(['id' => 7])) ->will($this->returnValue($selectMock)); - $sqlMock = $this->getMock('Zend\Db\Sql\Sql', ['select'], [$this->mockAdapter]); + $sqlMock = $this->getMock('Zend\Db\Sql\Sql', ['select'], [$this->mockAdapter, new TableIdentifier('foo')]); $sqlMock->expects($this->any()) ->method('select') ->will($this->returnValue($selectMock)); diff --git a/test/Sql/AbstractSqlTest.php b/test/Sql/AbstractSqlTest.php deleted file mode 100644 index c8ea320a77..0000000000 --- a/test/Sql/AbstractSqlTest.php +++ /dev/null @@ -1,186 +0,0 @@ -abstractSql = $this->getMockForAbstractClass('Zend\Db\Sql\AbstractSql'); - - $this->mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $this->mockDriver - ->expects($this->any()) - ->method('getPrepareType') - ->will($this->returnValue(DriverInterface::PARAMETERIZATION_NAMED)); - $this->mockDriver - ->expects($this->any()) - ->method('formatParameterName') - ->will($this->returnCallback(function ($x) { - return ':' . $x; - })); - } - - /** - * @covers Zend\Db\Sql\AbstractSql::processExpression - */ - public function testProcessExpressionWithoutParameterContainer() - { - $expression = new Expression('? > ? AND y < ?', ['x', 5, 10], [Expression::TYPE_IDENTIFIER]); - $sqlAndParams = $this->invokeProcessExpressionMethod($expression); - - $this->assertEquals("\"x\" > '5' AND y < '10'", $sqlAndParams); - } - - /** - * @covers Zend\Db\Sql\AbstractSql::processExpression - */ - public function testProcessExpressionWithParameterContainerAndParameterizationTypeNamed() - { - $parameterContainer = new ParameterContainer; - $expression = new Expression('? > ? AND y < ?', ['x', 5, 10], [Expression::TYPE_IDENTIFIER]); - $sqlAndParams = $this->invokeProcessExpressionMethod($expression, $parameterContainer); - - $parameters = $parameterContainer->getNamedArray(); - - $this->assertRegExp('#"x" > :expr\d\d\d\dParam1 AND y < :expr\d\d\d\dParam2#', $sqlAndParams); - - // test keys and values - preg_match('#expr(\d\d\d\d)Param1#', key($parameters), $matches); - $expressionNumber = $matches[1]; - - $this->assertRegExp('#expr\d\d\d\dParam1#', key($parameters)); - $this->assertEquals(5, current($parameters)); - next($parameters); - $this->assertRegExp('#expr\d\d\d\dParam2#', key($parameters)); - $this->assertEquals(10, current($parameters)); - - // ensure next invocation increases number by 1 - $parameterContainer = new ParameterContainer; - $sqlAndParamsNext = $this->invokeProcessExpressionMethod($expression, $parameterContainer); - - $parameters = $parameterContainer->getNamedArray(); - - preg_match('#expr(\d\d\d\d)Param1#', key($parameters), $matches); - $expressionNumberNext = $matches[1]; - - $this->assertEquals(1, (int) $expressionNumberNext - (int) $expressionNumber); - } - - /** - * @covers Zend\Db\Sql\AbstractSql::processExpression - */ - public function testProcessExpressionWorksWithExpressionContainingStringParts() - { - $expression = new Predicate\Expression('x = ?', 5); - - $predicateSet = new Predicate\PredicateSet([new Predicate\PredicateSet([$expression])]); - $sqlAndParams = $this->invokeProcessExpressionMethod($predicateSet); - - $this->assertEquals("(x = '5')", $sqlAndParams); - } - - /** - * @covers Zend\Db\Sql\AbstractSql::processExpression - */ - public function testProcessExpressionWorksWithExpressionContainingSelectObject() - { - $select = new Select(); - $select->from('x')->where->like('bar', 'Foo%'); - $expression = new Predicate\In('x', $select); - - $predicateSet = new Predicate\PredicateSet([new Predicate\PredicateSet([$expression])]); - $sqlAndParams = $this->invokeProcessExpressionMethod($predicateSet); - - $this->assertEquals('("x" IN (SELECT "x".* FROM "x" WHERE "bar" LIKE \'Foo%\'))', $sqlAndParams); - } - - public function testProcessExpressionWorksWithExpressionContainingExpressionObject() - { - $expression = new Predicate\Operator( - 'release_date', - '=', - new Expression('FROM_UNIXTIME(?)', 100000000) - ); - - $sqlAndParams = $this->invokeProcessExpressionMethod($expression); - $this->assertEquals('"release_date" = FROM_UNIXTIME(\'100000000\')', $sqlAndParams); - } - - /** - * @group 7407 - */ - public function testProcessExpressionWorksWithExpressionObjectWithPercentageSigns() - { - $expressionString = 'FROM_UNIXTIME(date, "%Y-%m")'; - $expression = new Expression($expressionString); - $sqlString = $this->invokeProcessExpressionMethod($expression); - - $this->assertSame($expressionString, $sqlString); - } - - public function testProcessExpressionWorksWithNamedParameterPrefix() - { - $parameterContainer = new ParameterContainer(); - $namedParameterPrefix = uniqid(); - $expression = new Expression('FROM_UNIXTIME(?)', [10000000]); - $this->invokeProcessExpressionMethod($expression, $parameterContainer, $namedParameterPrefix); - - $this->assertSame($namedParameterPrefix . '1', key($parameterContainer->getNamedArray())); - } - - public function testProcessExpressionWorksWithNamedParameterPrefixContainingWhitespace() - { - $parameterContainer = new ParameterContainer(); - $namedParameterPrefix = "string\ncontaining white space"; - $expression = new Expression('FROM_UNIXTIME(?)', [10000000]); - $this->invokeProcessExpressionMethod($expression, $parameterContainer, $namedParameterPrefix); - - $this->assertSame('string__containing__white__space1', key($parameterContainer->getNamedArray())); - } - - /** - * @param \Zend\Db\Sql\ExpressionInterface $expression - * @param \Zend\Db\Adapter\ParameterContainer $parameterContainer - * @param string $namedParameterPrefix - * @return \Zend\Db\Adapter\StatementContainer|string - */ - protected function invokeProcessExpressionMethod( - ExpressionInterface $expression, - $parameterContainer = null, - $namedParameterPrefix = null - ) { - $method = new \ReflectionMethod($this->abstractSql, 'processExpression'); - $method->setAccessible(true); - return $method->invoke( - $this->abstractSql, - $expression, - new TrustingSql92Platform, - $this->mockDriver, - $parameterContainer, - $namedParameterPrefix - ); - } -} diff --git a/test/Sql/Builder/AbstractTestCase.php b/test/Sql/Builder/AbstractTestCase.php new file mode 100644 index 0000000000..5acac9e8d6 --- /dev/null +++ b/test/Sql/Builder/AbstractTestCase.php @@ -0,0 +1,268 @@ += 2) { + foreach (func_get_args() as $i=>$arg) { + if ($i == 0) { + continue; + } + foreach ($arg as $a) { + $data[] = $a; + } + } + } + $res = []; + foreach ($data as $index => $test) { + foreach ($test['expected'] as $platform => $expected) { + $res[$index . '->' . $platform] = [ + 'sqlObject' => $test['sqlObject'], + 'platform' => $platform, + 'expected' => $expected, + ]; + } + } + return $res; + } + + public function assertBuilder($sqlObject, $platform = null, $expected = null) + { + if ($sqlObject instanceof \Closure) { + $sqlObject = call_user_func($sqlObject); + } + $builder = new Builder\Builder(); + $adapter = $this->getAdapterForPlatform($platform); + + if (is_array($expected) && isset($expected['decorators'])) { + foreach ($expected['decorators'] as $type=>$decorator) { + $builder->setPlatformBuilder($platform, $type, $this->resolveDecorator($decorator, $builder)); + } + } + if (is_array($expected) && isset($expected['ExpectedException'])) { + if (is_array($expected['ExpectedException'])) { + $this->setExpectedException( + $expected['ExpectedException'][0], + isset($expected['ExpectedException'][1]) ? $expected['ExpectedException'][1] : '', + isset($expected['ExpectedException'][2]) ? $expected['ExpectedException'][2] : null + ); + } else { + $this->setExpectedException($expected['ExpectedException']); + } + } + + $expectedString = is_string($expected) ? $expected : (isset($expected['string']) ? $expected['string'] : null); + if ($expectedString) { + $actual = $builder->buildSqlString($sqlObject, $adapter); + $this->assertEquals($expectedString, $actual, "buildSqlString()"); + } + if (is_array($expected) && isset($expected['prepare'])) { + if ($expected['prepare'] === true) { + $expected['prepare'] = $expectedString; + } + $this->useNamedParameters = isset($expected['useNamedParams']) && $expected['useNamedParams']; + + $actual = $builder->prepareSqlStatement($sqlObject, $adapter); + $this->assertEquals($expected['prepare'], $actual->getSql(), "prepareSqlStatement()"); + if (isset($expected['parameters'])) { + $this->assertSame( + $expected['parameters'], + $actual->getParameterContainer()->getNamedArray(), + "parameterContainer()" + ); + } elseif (isset($expected['parametersEquals'])) { + $this->assertEquals( + $expected['parametersEquals'], + $actual->getParameterContainer()->getNamedArray(), + "parameterContainer()" + ); + } + } + } + + protected function getAdapterForPlatform($platformName) + { + $platformName = str_replace(' ', '', strtolower($platformName)); + if (isset($this->adapters[$platformName])) { + return $this->adapters[$platformName]; + } + + switch ($platformName) { + case 'sql92' : $platform = new TestAsset\TrustingSql92Platform(); break; + case 'mysql' : $platform = new TestAsset\TrustingMysqlPlatform(); break; + case 'oracle' : $platform = new TestAsset\TrustingOraclePlatform(); break; + case 'sqlserver' : $platform = new TestAsset\TrustingSqlServerPlatform(); break; + case 'ibmdb2' : $platform = new TestAsset\TrustingIbmDb2Platform(); break; + case 'sqlite' : $platform = new TestAsset\TrustingSqlitePlatform(); break; + default : $platform = null; + } + + $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); + $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnCallback( + function ($name) { return (($this->useNamedParameters) ? ':' . $name : '?'); } + )); + $mockDriver->expects($this->any())->method('createStatement')->will($this->returnCallback(function () { + $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); + $setSql = $this->returnCallback(function ($sql = null) { + static $thisSql; + if ($sql === null) { + return $thisSql; + } + $thisSql = $sql; + }); + $setParameterContainer = $this->returnCallback(function ($parameterContainer = null) { + static $thisParameterContainer; + if ($parameterContainer === null) { + return $thisParameterContainer; + } + $thisParameterContainer = $parameterContainer; + }); + $mockStatement->expects($this->any())->method('setSql')->will($setSql); + $mockStatement->expects($this->any())->method('getSql')->will($setSql); + $mockStatement->expects($this->any())->method('setParameterContainer')->will($setParameterContainer); + $mockStatement->expects($this->any())->method('getParameterContainer')->will($setParameterContainer); + return $mockStatement; + })); + + $this->adapters[$platformName] = new Adapter\Adapter($mockDriver, $platform); + return $this->adapters[$platformName]; + } + + protected function resolveDecorator($decorator, $builder) + { + if (!is_array($decorator)) { + return $decorator; + } + $decoratorMock = $this->getMock($decorator[0], ['build'], [$builder]); + $decoratorMock->expects($this->any())->method('build')->will($this->returnValue([$decorator[1]])); + return $decoratorMock; + } + + public function __call($name, $arguments) + { + $aliasMap = [ + 'select' => 'Zend\Db\Sql\Select', + 'delete' => 'Zend\Db\Sql\Delete', + 'update' => 'Zend\Db\Sql\Update', + 'insert' => 'Zend\Db\Sql\Insert', + 'combine' => 'Zend\Db\Sql\Combine', + 'dropTable' => 'Zend\Db\Sql\Ddl\DropTable', + 'alterTable' => 'Zend\Db\Sql\Ddl\AlterTable', + 'createTable' => 'Zend\Db\Sql\Ddl\CreateTable', + 'createColumn' => 'Zend\Db\Sql\Ddl\Column\Column', + + 'expression' => 'Zend\Db\Sql\Expression', + + 'predicate_Between' => 'Zend\Db\Sql\Predicate\Between', + 'predicate_NotBetween' => 'Zend\Db\Sql\Predicate\NotBetween', + 'predicate_Expression' => 'Zend\Db\Sql\Predicate\Expression', + 'predicate_In' => 'Zend\Db\Sql\Predicate\In', + 'predicate_IsNotNull' => 'Zend\Db\Sql\Predicate\IsNotNull', + 'predicate_IsNull' => 'Zend\Db\Sql\Predicate\IsNull', + 'predicate_Like' => 'Zend\Db\Sql\Predicate\Like', + 'predicate_Literal' => 'Zend\Db\Sql\Predicate\Literal', + 'predicate_NotIn' => 'Zend\Db\Sql\Predicate\NotIn', + 'predicate_NotLike' => 'Zend\Db\Sql\Predicate\NotLike', + 'predicate_Operator' => 'Zend\Db\Sql\Predicate\Operator', + 'predicate_Predicate' => 'Zend\Db\Sql\Predicate\Predicate', + 'predicate_PredicateSet'=> 'Zend\Db\Sql\Predicate\PredicateSet', + + 'index_Index' => 'Zend\Db\Sql\Ddl\Index\Index', + + 'constraint_Check' => 'Zend\Db\Sql\Ddl\Constraint\Check', + 'constraint_ForeignKey' => 'Zend\Db\Sql\Ddl\Constraint\ForeignKey', + 'constraint_PrimaryKey' => 'Zend\Db\Sql\Ddl\Constraint\PrimaryKey', + 'constraint_UniqueKey' => 'Zend\Db\Sql\Ddl\Constraint\UniqueKey', + 'column_BigInteger' => 'Zend\Db\Sql\Ddl\Column\BigInteger', + 'column_Binary' => 'Zend\Db\Sql\Ddl\Column\Binary', + 'column_Blob' => 'Zend\Db\Sql\Ddl\Column\Blob', + 'column_Boolean' => 'Zend\Db\Sql\Ddl\Column\Boolean', + 'column_Char' => 'Zend\Db\Sql\Ddl\Column\Char', + 'column_Column' => 'Zend\Db\Sql\Ddl\Column\Column', + 'column_Date' => 'Zend\Db\Sql\Ddl\Column\Date', + 'column_Datetime' => 'Zend\Db\Sql\Ddl\Column\Datetime', + 'column_Decimal' => 'Zend\Db\Sql\Ddl\Column\Decimal', + 'column_Floating' => 'Zend\Db\Sql\Ddl\Column\Floating', + 'column_Integer' => 'Zend\Db\Sql\Ddl\Column\Integer', + 'column_Text' => 'Zend\Db\Sql\Ddl\Column\Text', + 'column_Time' => 'Zend\Db\Sql\Ddl\Column\Time', + 'column_Timestamp' => 'Zend\Db\Sql\Ddl\Column\Timestamp', + 'column_Varbinary' => 'Zend\Db\Sql\Ddl\Column\Varbinary', + 'column_Varchar' => 'Zend\Db\Sql\Ddl\Column\Varchar', + ]; + if (!isset($aliasMap[$name])) { + throw new \Exception($name . ' method not found'); + } + $refl = new \ReflectionClass($aliasMap[$name]); + return $refl->newInstanceArgs($arguments); + } +} diff --git a/test/Sql/Builder/AllBuildersTest.php b/test/Sql/Builder/AllBuildersTest.php new file mode 100644 index 0000000000..a0154dd055 --- /dev/null +++ b/test/Sql/Builder/AllBuildersTest.php @@ -0,0 +1,197 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + 'RootDecorators::Select' => [ + 'sqlObject' => $this->select('foo')->where(['x'=>$this->select('bar')]), + 'expected' => [ + 'sql92' => [ + 'decorators' => [ + 'Zend\Db\Sql\Select' => 'ZendTest\Db\TestAsset\SelectBuilder', + ], + 'string' => 'SELECT "foo".* FROM "foo" WHERE "x" = (SELECT "bar".* FROM "bar")', + ], + 'MySql' => [ + 'decorators' => [ + 'Zend\Db\Sql\Select' => 'ZendTest\Db\TestAsset\SelectBuilder', + ], + 'string' => 'SELECT `foo`.* FROM `foo` WHERE `x` = (SELECT `bar`.* FROM `bar`)', + ], + 'Oracle' => [ + 'decorators' => [ + 'Zend\Db\Sql\Select' => 'ZendTest\Db\TestAsset\SelectBuilder', + ], + 'string' => 'SELECT "foo".* FROM "foo" WHERE "x" = (SELECT "bar".* FROM "bar")', + ], + 'SqlServer' => [ + 'decorators' => [ + 'Zend\Db\Sql\Select' => 'ZendTest\Db\TestAsset\SelectBuilder', + ], + 'string' => 'SELECT [foo].* FROM [foo] WHERE [x] = (SELECT [bar].* FROM [bar])', + ], + ], + ], + 'RootDecorators::Insert' => [ + 'sqlObject' => $this->insert('foo')->select($this->select()), + 'expected' => [ + 'sql92' => [ + 'decorators' => [ + 'Zend\Db\Sql\Insert' => 'ZendTest\Db\TestAsset\InsertBuilder', // Decorator for root sqlObject + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\sql92\SelectBuilder', '{=SELECT_Sql92=}'] + ], + 'string' => 'INSERT INTO "foo" ({=SELECT_Sql92=})', + ], + 'MySql' => [ + 'decorators' => [ + 'Zend\Db\Sql\Insert' => 'ZendTest\Db\TestAsset\InsertBuilder', // Decorator for root sqlObject + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\sql92\SelectBuilder', '{=SELECT_MySql=}'] + ], + 'string' => 'INSERT INTO `foo` ({=SELECT_MySql=})', + ], + 'Oracle' => [ + 'decorators' => [ + 'Zend\Db\Sql\Insert' => 'ZendTest\Db\TestAsset\InsertBuilder', // Decorator for root sqlObject + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\sql92\SelectBuilder', '{=SELECT_Oracle=}'] + ], + 'string' => 'INSERT INTO "foo" ({=SELECT_Oracle=})', + ], + 'SqlServer' => [ + 'decorators' => [ + 'Zend\Db\Sql\Insert' => 'ZendTest\Db\TestAsset\InsertBuilder', // Decorator for root sqlObject + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\sql92\SelectBuilder', '{=SELECT_SqlServer=}'] + ], + 'string' => 'INSERT INTO [foo] ({=SELECT_SqlServer=})', + ], + ], + ], + 'RootDecorators::Delete' => [ + 'sqlObject' => $this->delete('foo')->where(['x'=>$this->select('foo')]), + 'expected' => [ + 'sql92' => [ + 'decorators' => [ + 'Zend\Db\Sql\Delete' => 'ZendTest\Db\TestAsset\DeleteBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\sql92\SelectBuilder', '{=SELECT_Sql92=}'] + ], + 'string' => 'DELETE FROM "foo" WHERE "x" = ({=SELECT_Sql92=})', + ], + 'MySql' => [ + 'decorators' => [ + 'Zend\Db\Sql\Delete' => 'ZendTest\Db\TestAsset\DeleteBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\sql92\SelectBuilder', '{=SELECT_MySql=}'] + ], + 'string' => 'DELETE FROM `foo` WHERE `x` = ({=SELECT_MySql=})', + ], + 'Oracle' => [ + 'decorators' => [ + 'Zend\Db\Sql\Delete' => 'ZendTest\Db\TestAsset\DeleteBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\sql92\SelectBuilder', '{=SELECT_Oracle=}'] + ], + 'string' => 'DELETE FROM "foo" WHERE "x" = ({=SELECT_Oracle=})', + ], + 'SqlServer' => [ + 'decorators' => [ + 'Zend\Db\Sql\Delete' => 'ZendTest\Db\TestAsset\DeleteBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\sql92\SelectBuilder', '{=SELECT_SqlServer=}'] + ], + 'string' => 'DELETE FROM [foo] WHERE [x] = ({=SELECT_SqlServer=})', + ], + ], + ], + 'RootDecorators::Update' => [ + 'sqlObject' => $this->update('foo')->where(['x'=>$this->select('foo')]), + 'expected' => [ + 'sql92' => [ + 'decorators' => [ + 'Zend\Db\Sql\Update' => 'ZendTest\Db\TestAsset\UpdateBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\Mysql\SelectBuilder', '{=SELECT_Sql92=}'] + ], + 'string' => 'UPDATE "foo" SET WHERE "x" = ({=SELECT_Sql92=})', + ], + 'MySql' => [ + 'decorators' => [ + 'Zend\Db\Sql\Update' => 'ZendTest\Db\TestAsset\UpdateBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\Mysql\SelectBuilder', '{=SELECT_MySql=}'] + ], + 'string' => 'UPDATE `foo` SET WHERE `x` = ({=SELECT_MySql=})', + ], + 'Oracle' => [ + 'decorators' => [ + 'Zend\Db\Sql\Update' => 'ZendTest\Db\TestAsset\UpdateBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\Oracle\SelectBuilder', '{=SELECT_Oracle=}'] + ], + 'string' => 'UPDATE "foo" SET WHERE "x" = ({=SELECT_Oracle=})', + ], + 'SqlServer' => [ + 'decorators' => [ + 'Zend\Db\Sql\Update' => 'ZendTest\Db\TestAsset\UpdateBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\SqlServer\SelectBuilder', '{=SELECT_SqlServer=}'] + ], + 'string' => 'UPDATE [foo] SET WHERE [x] = ({=SELECT_SqlServer=})', + ], + ], + ], + 'DecorableExpression()' => [ + 'sqlObject' => $this->update('foo')->where(['x'=>$this->expression('?', [$this->select('foo')])]), + 'expected' => [ + 'sql92' => [ + 'decorators' => [ + 'Zend\Db\Sql\Expression' => 'ZendTest\Db\TestAsset\ExpressionBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\Mysql\SelectBuilder', '{=SELECT_Sql92=}'] + ], + 'string' => 'UPDATE "foo" SET WHERE "x" = {decorate-({=SELECT_Sql92=})-decorate}', + ], + 'MySql' => [ + 'decorators' => [ + 'Zend\Db\Sql\Expression' => 'ZendTest\Db\TestAsset\ExpressionBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\Mysql\SelectBuilder', '{=SELECT_MySql=}'] + ], + 'string' => 'UPDATE `foo` SET WHERE `x` = {decorate-({=SELECT_MySql=})-decorate}', + ], + 'Oracle' => [ + 'decorators' => [ + 'Zend\Db\Sql\Expression' => 'ZendTest\Db\TestAsset\ExpressionBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\Oracle\SelectBuilder', '{=SELECT_Oracle=}'] + ], + 'string' => 'UPDATE "foo" SET WHERE "x" = {decorate-({=SELECT_Oracle=})-decorate}', + ], + 'SqlServer' => [ + 'decorators' => [ + 'Zend\Db\Sql\Expression' => 'ZendTest\Db\TestAsset\ExpressionBuilder', + 'Zend\Db\Sql\Select' => ['Zend\Db\Sql\Builder\SqlServer\SelectBuilder', '{=SELECT_SqlServer=}'] + ], + 'string' => 'UPDATE [foo] SET WHERE [x] = {decorate-({=SELECT_SqlServer=})-decorate}', + ], + ], + ], + 'DISTINCT in columns' => [ + 'sqlObject' => $this->select('foo')->columns(['bar' => $this->expression('DISTINCT(bar)')])->limit(5)->offset(10), + 'expected' => [ + 'SqlServer' => [ + 'string' => "SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT DISTINCT(bar) AS [bar] FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > '10' AND [LIMIT_OFFSET_ROWNUM] <= '5' + '10'", + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/BuilderServiceFactoryTest.php b/test/Sql/Builder/BuilderServiceFactoryTest.php new file mode 100644 index 0000000000..629dfe8ecc --- /dev/null +++ b/test/Sql/Builder/BuilderServiceFactoryTest.php @@ -0,0 +1,95 @@ +getDependencyConfig(), + ArrayUtils::merge([ + 'services' => [ + 'config' => [], + ], + ], $config) + ); + $serviceManager = new ServiceManager(); + (new Config($config))->configureServiceManager($serviceManager); + return $serviceManager->get(SqlBuilderInterface::class); + } + + public function testFactoryWithEmptyConfig() + { + $builder = $this->getBuilder(); + + $this->assertInstanceOf(Builder::class, $builder); + $this->assertNull($builder->getDefaultAdapter()); + $this->assertInstanceOf( + Db\Sql\Builder\sql92\SelectBuilder::class, + $builder->getPlatformBuilder(new Db\Sql\Select) + ); + } + + public function testFactoryWithoutAdapterConfig() + { + $builder = $this->getBuilder(['services' => ['config' => [ + 'sql_builder' => [ + 'builders' => [ + 'sql92' => [ + Db\Sql\Select::class => Db\Sql\Builder\MySql\SelectBuilder::class, + ], + ], + ], + ]]]); + + $this->assertInstanceOf(Builder::class, $builder); + $this->assertNull($builder->getDefaultAdapter()); + $this->assertInstanceOf( + Db\Sql\Builder\MySql\SelectBuilder::class, + $builder->getPlatformBuilder(new Db\Sql\Select) + ); + } + + public function testFactoryWithFullConfig() + { + $builder = $this->getBuilder(['services' => ['config' => [ + 'db' => [ + 'driver' => 'mysqli', + ], + 'sql_builder' => [ + 'default_adapter' => Db\Adapter\AdapterInterface::class, + 'builders' => [ + 'sql92' => [ + Db\Sql\Select::class => Db\Sql\Builder\MySql\SelectBuilder::class, + ], + ], + ], + ]]]); + + $this->assertInstanceOf(Builder::class, $builder); + $this->assertInstanceOf( + Db\Adapter\Driver\Mysqli\Mysqli::class, + $builder->getDefaultAdapter()->getDriver() + ); + $this->assertInstanceOf( + Db\Sql\Builder\Mysql\SelectBuilder::class, + $builder->getPlatformBuilder(new Db\Sql\Select) + ); + } +} diff --git a/test/Sql/Builder/BuilderTest.php b/test/Sql/Builder/BuilderTest.php new file mode 100644 index 0000000000..f308b467e8 --- /dev/null +++ b/test/Sql/Builder/BuilderTest.php @@ -0,0 +1,192 @@ +builder = new Builder(); + $inheritableBuilders = new \ReflectionProperty($this->builder, 'inheritableBuilders'); + $inheritableBuilders->setAccessible(true); + $inheritableBuilders->setValue($this->builder, [ + 'Zend\Db\Sql\Select' => [ + 'sql92' => 'Zend\Db\Sql\Builder\sql92\SelectBuilder', + 'mysql' => 'Zend\Db\Sql\Builder\MySql\SelectBuilder', + ], + 'Zend\Db\Sql\Ddl\CreateTable' => [ + 'sqlserver' => 'Zend\Db\Sql\Builder\SqlServer\Ddl\CreateTableBuilder', + ], + ]); + } + + /** + * @expectedException Zend\Db\Sql\Exception\RuntimeException + */ + public function testGePlatformBuilderForNotExistsObject() + { + $this->builder->getPlatformBuilder(new Sql\Insert()); + } + + /** + * @covers Zend\Db\Sql\Builder\Builder::getPlatformBuilder + * @expectedException Zend\Db\Sql\Exception\RuntimeException + */ + public function testGePlatformBuilderForNotExistsPlatform() + { + $this->assertInstanceOf( + 'Zend\Db\Sql\Builder\sql92\SelectBuilder', + $this->builder->getPlatformBuilder(new Sql\Select(), 'NotExistingPlatform') + ); + $this->builder->getPlatformBuilder(new Sql\Ddl\CreateTable(), 'NotExistingPlatform'); + } + + /** + * @covers Zend\Db\Sql\Builder\Builder::getPlatformBuilder + */ + public function testGetPlatformBuilder() + { + $this->assertInstanceOf( + 'Zend\Db\Sql\Builder\sql92\SelectBuilder', + $this->builder->getPlatformBuilder(new Sql\Select()) + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Builder\sql92\SelectBuilder', + $this->builder->getPlatformBuilder(new Sql\Select(), 'sql92') + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Builder\MySql\SelectBuilder', + $this->builder->getPlatformBuilder(new Sql\Select(), 'mysql') + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Builder\sql92\SelectBuilder', + $this->builder->getPlatformBuilder(new Sql\Select(), 'sqlserver') + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Builder\SqlServer\Ddl\CreateTableBuilder', + $this->builder->getPlatformBuilder(new Sql\Ddl\CreateTable(), 'sqlserver') + ); + } + + /** + * @covers Zend\Db\Sql\Builder\Builder::setPlatformBuilder + */ + public function testSetPlatformBuilder() + { + $this->builder->setPlatformBuilder('ibmdb2', 'Zend\Db\Sql\Select', 'Zend\Db\Sql\Builder\IbmDb2\SelectBuilder'); + $this->assertInstanceOf( + 'Zend\Db\Sql\Builder\sql92\SelectBuilder', + $this->builder->getPlatformBuilder(new Sql\Select(), 'sql92') + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Builder\IbmDb2\SelectBuilder', + $this->builder->getPlatformBuilder(new Sql\Select(), 'ibmdb2') + ); + + $oracleSelectBuilder = new \Zend\Db\Sql\Builder\Oracle\SelectBuilder($this->builder); + $this->builder->setPlatformBuilder('oracle', 'Zend\Db\Sql\Select', $oracleSelectBuilder); + $this->assertSame( + $oracleSelectBuilder, + $this->builder->getPlatformBuilder(new Sql\Select(), 'oracle') + ); + } + + /** + * @covers Zend\Db\Sql\Builder\Builder::setPlatformBuilders + */ + public function testSetPlatformBuilders() + { + $oracleSelectBuilder = new \Zend\Db\Sql\Builder\Oracle\SelectBuilder($this->builder); + $this->builder->setPlatformBuilders([ + 'ibmdb2' => [ + 'Zend\Db\Sql\Select' => 'Zend\Db\Sql\Builder\IbmDb2\SelectBuilder', + ], + 'oracle' => [ + 'Zend\Db\Sql\Select' => $oracleSelectBuilder, + ], + ]); + + $this->assertInstanceOf( + 'Zend\Db\Sql\Builder\sql92\SelectBuilder', + $this->builder->getPlatformBuilder(new Sql\Select(), 'sql92') + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Builder\IbmDb2\SelectBuilder', + $this->builder->getPlatformBuilder(new Sql\Select(), 'ibmdb2') + ); + $this->assertSame( + $oracleSelectBuilder, + $this->builder->getPlatformBuilder(new Sql\Select(), 'oracle') + ); + } + + /** + * @expectedException Zend\Db\Sql\Exception\InvalidArgumentException + */ + public function testSetWrongPlatformBuilder() + { + $this->builder->setPlatformBuilder('oracle', 'Zend\Db\Sql\Select', new \stdClass()); + } + + /** + * @covers Zend\Db\Sql\Builder\Builder::setDefaultAdapter + * @covers Zend\Db\Sql\Builder\Builder::getDefaultAdapter + */ + public function testDefaultAdapter() + { + $builder = new Builder(); + $this->assertNull($builder->getDefaultAdapter()); + + $adapter = $this->getAdapterForPlatform('sqlserver'); + $builder = new Builder($adapter); + $this->assertSame($adapter, $builder->getDefaultAdapter()); + + $adapter = $this->getAdapterForPlatform('sql92'); + $this->assertSame($adapter, $builder->setDefaultAdapter($adapter)->getDefaultAdapter()); + + $adapter = $this->getAdapterForPlatform('mysql'); + $this->assertSame($adapter, $builder->setDefaultAdapter($adapter)->getDefaultAdapter()); + } + + /** + * @covers Zend\Db\Sql\Builder\Builder::buildSqlString + */ + public function testBuildSqlString() + { + $this->assertInternalType( + 'string', + $this->builder->buildSqlString( + new Sql\Select('foo'), + $this->getAdapterForPlatform('sql92') + ) + ); + } + + /** + * @covers Zend\Db\Sql\Builder\Builder::prepareSqlStatement + */ + public function testPrepareSqlStatement() + { + $statement = $this->builder->prepareSqlStatement( + new Sql\Select('foo'), + $this->getAdapterForPlatform('sql92') + ); + $this->assertInstanceOf('Zend\Db\Adapter\Driver\StatementInterface', $statement); + $this->assertInstanceOf('Zend\Db\Adapter\ParameterContainer', $statement->getParameterContainer()); + } +} diff --git a/test/Sql/Builder/CombineBuilderTest.php b/test/Sql/Builder/CombineBuilderTest.php new file mode 100644 index 0000000000..9a3a2c5fdb --- /dev/null +++ b/test/Sql/Builder/CombineBuilderTest.php @@ -0,0 +1,124 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ // testBuildSqlStringEmpty() + 'sqlObject' => $this->combine(), + 'expected' => [ + 'sql92' => [ + 'string' => '', + 'prepare' => '' + ], + ], + ], + [ // testBuildSqlString() + 'sqlObject' => $this->combine() + ->union($this->select('t1')) + ->intersect($this->select('t2')) + ->except($this->select('t3')) + ->union($this->select('t4')), + 'expected' => [ + 'sql92' => [ + 'string' => '(SELECT "t1".* FROM "t1") INTERSECT (SELECT "t2".* FROM "t2") EXCEPT (SELECT "t3".* FROM "t3") UNION (SELECT "t4".* FROM "t4")', + ], + ], + ], + [ // testBuildSqlStringWithModifier() + 'sqlObject' => $this->combine() + ->union($this->select('t1')) + ->union($this->select('t2'), 'ALL'), + 'expected' => [ + 'sql92' => [ + 'string' => '(SELECT "t1".* FROM "t1") UNION ALL (SELECT "t2".* FROM "t2")', + ], + ], + ], + [ + 'sqlObject' => $this->combine([ + [$this->select('t1')], + [$this->select('t2'), Combine::COMBINE_INTERSECT, 'ALL'], + [$this->select('t3'), Combine::COMBINE_EXCEPT], + ]), + 'expected' => [ + 'sql92' => [ + 'string' => '(SELECT "t1".* FROM "t1") INTERSECT ALL (SELECT "t2".* FROM "t2") EXCEPT (SELECT "t3".* FROM "t3")', + ], + ], + ], + [ + 'sqlObject' => $this->combine([ + $this->select('t1'), + $this->select('t2'), + $this->select('t3'), + ]), + 'expected' => [ + 'sql92' => [ + 'string' => '(SELECT "t1".* FROM "t1") UNION (SELECT "t2".* FROM "t2") UNION (SELECT "t3".* FROM "t3")', + ], + ], + ], + [ + 'sqlObject' => $this->combine([ + $this->select('t1')->where(['x1'=>10]), + $this->select('t2')->where(['x2'=>20]) + ]), + 'expected' => [ + 'sql92' => [ + 'string' => '(SELECT "t1".* FROM "t1" WHERE "x1" = \'10\') UNION (SELECT "t2".* FROM "t2" WHERE "x2" = \'20\')', + 'prepare' => '(SELECT "t1".* FROM "t1" WHERE "x1" = ?) UNION (SELECT "t2".* FROM "t2" WHERE "x2" = ?)' + ], + ], + ], + [ + 'sqlObject' => $this->combine($this->combine([ + $this->select('t1'), + $this->select('t2'), + ])), + 'expected' => [ + 'sql92' => [ + 'string' => '((SELECT "t1".* FROM "t1") UNION (SELECT "t2".* FROM "t2"))', + 'prepare' => '((SELECT "t1".* FROM "t1") UNION (SELECT "t2".* FROM "t2"))' + ], + ], + ], + [ + 'sqlObject' => $this->combine($this->combine([ + $this->select('foo'), + $this->select('foo'), + ])), + 'expected' => [ + 'sqlite' => [ + 'string' => '((SELECT "foo".* FROM "foo") UNION (SELECT "foo".* FROM "foo"))', + 'prepare' => '((SELECT "foo".* FROM "foo") UNION (SELECT "foo".* FROM "foo"))' + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Ddl/AlterTableBuilderTest.php b/test/Sql/Builder/Ddl/AlterTableBuilderTest.php new file mode 100644 index 0000000000..742862c9e1 --- /dev/null +++ b/test/Sql/Builder/Ddl/AlterTableBuilderTest.php @@ -0,0 +1,53 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->alterTable('foo') + ->addColumn(new Column\Varchar('another1', 10)) + ->addColumn(new Column\Varchar('another2', 20)) + ->changeColumn('name', new Column\Varchar('new_name', 50)) + ->dropColumn('foo') + ->addConstraint(new Constraint\ForeignKey('my_fk', 'other_id', 'other_table', 'id', 'CASCADE', 'CASCADE')) + ->dropConstraint('my_index'), + 'expected' => [ + 'sql92' => 'ALTER TABLE "foo" + ADD COLUMN "another1" VARCHAR(10) NOT NULL, + ADD COLUMN "another2" VARCHAR(20) NOT NULL, + CHANGE COLUMN "name" "new_name" VARCHAR(50) NOT NULL, + DROP COLUMN "foo", + ADD CONSTRAINT "my_fk" FOREIGN KEY ("other_id") REFERENCES "other_table" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + DROP CONSTRAINT "my_index"', + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Ddl/Column/ColumnBuilderTest.php b/test/Sql/Builder/Ddl/Column/ColumnBuilderTest.php new file mode 100644 index 0000000000..d871674ac1 --- /dev/null +++ b/test/Sql/Builder/Ddl/Column/ColumnBuilderTest.php @@ -0,0 +1,196 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider( + $this->dataProvider_Column(), + $this->dataProvider_OtherColumns() + ); + } + + public function dataProvider_Column() + { + return [ + [ + 'sqlObject' => $this->column_Column() + ->setName('foo'), + 'expected' => [ + 'sql92' => '"foo" INTEGER NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Column() + ->setName('foo') + ->setNullable(true), + 'expected' => [ + 'sql92' => '"foo" INTEGER', + ], + ], + [ + 'sqlObject' => $this->column_Column() + ->setName('foo') + ->setNullable(true) + ->setDefault('bar'), + 'expected' => [ + 'sql92' => '"foo" INTEGER DEFAULT \'bar\'', + ], + ], + ]; + } + + public function dataProvider_OtherColumns() + { + return [ + [ + 'sqlObject' => $this->getMockForAbstractClass('Zend\Db\Sql\Ddl\Column\AbstractLengthColumn', [ + 'foo', 4 + ]), + 'expected' => [ + 'sql92' => '"foo" INTEGER(4) NOT NULL', + ], + ], + [ + 'sqlObject' => $this->getMockForAbstractClass('Zend\Db\Sql\Ddl\Column\AbstractPrecisionColumn', [ + 'foo', 10, 5 + ]), + 'expected' => [ + 'sql92' => '"foo" INTEGER(10,5) NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_BigInteger('foo'), + 'expected' => [ + 'sql92' => '"foo" BIGINT NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Binary('foo', 10000000), + 'expected' => [ + 'sql92' => '"foo" BINARY(10000000) NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Blob('foo'), + 'expected' => [ + 'sql92' => '"foo" BLOB NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Boolean('foo'), + 'expected' => [ + 'sql92' => '"foo" BOOLEAN NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Char('foo', 20), + 'expected' => [ + 'sql92' => '"foo" CHAR(20) NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Date('foo'), + 'expected' => [ + 'sql92' => '"foo" DATE NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Datetime('foo'), + 'expected' => [ + 'sql92' => '"foo" DATETIME NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Decimal('foo', 10, 5), + 'expected' => [ + 'sql92' => '"foo" DECIMAL(10,5) NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Floating('foo', 10, 5), + 'expected' => [ + 'sql92' => '"foo" FLOAT(10,5) NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Integer('foo'), + 'expected' => [ + 'sql92' => '"foo" INTEGER NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Integer('foo')->addConstraint($this->constraint_PrimaryKey()), + 'expected' => [ + 'sql92' => '"foo" INTEGER NOT NULL PRIMARY KEY', + ], + ], + [ + 'sqlObject' => $this->column_Text('foo'), + 'expected' => [ + 'sql92' => '"foo" TEXT NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Time('foo'), + 'expected' => [ + 'sql92' => '"foo" TIME NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Timestamp('foo'), + 'expected' => [ + 'sql92' => '"foo" TIMESTAMP NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Varbinary('foo', 20), + 'expected' => [ + 'sql92' => '"foo" VARBINARY(20) NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Varchar('foo', 20), + 'expected' => [ + 'sql92' => '"foo" VARCHAR(20) NOT NULL', + ], + ], + [ + 'sqlObject' => $this->column_Varchar('foo', 20)->setDefault('bar'), + 'expected' => [ + 'sql92' => '"foo" VARCHAR(20) NOT NULL DEFAULT \'bar\'', + ], + ], + [ + 'sqlObject' => $this->column_Varchar('foo', 20)->setOption('charset', 'UTF8'), + 'expected' => [ + 'sql92' => '"foo" VARCHAR(20) NOT NULL', + 'mysql' => '`foo` VARCHAR(20) CHARACTER SET UTF8 NOT NULL', + ], + ], + ]; + } +} diff --git a/test/Sql/Builder/Ddl/Constraint/CheckBuilderTest.php b/test/Sql/Builder/Ddl/Constraint/CheckBuilderTest.php new file mode 100644 index 0000000000..e2d191e831 --- /dev/null +++ b/test/Sql/Builder/Ddl/Constraint/CheckBuilderTest.php @@ -0,0 +1,39 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->constraint_Check('id>0', 'foo'), + 'expected' => [ + 'sql92' => 'CONSTRAINT "foo" CHECK (id>0)', + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Ddl/Constraint/ForeignKeyBuilderTest.php b/test/Sql/Builder/Ddl/Constraint/ForeignKeyBuilderTest.php new file mode 100644 index 0000000000..ca5812af30 --- /dev/null +++ b/test/Sql/Builder/Ddl/Constraint/ForeignKeyBuilderTest.php @@ -0,0 +1,39 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->constraint_ForeignKey('foo', 'bar', 'baz', 'bam', 'CASCADE', 'SET NULL'), + 'expected' => [ + 'sql92' => 'CONSTRAINT "foo" FOREIGN KEY ("bar") REFERENCES "baz" ("bam") ON DELETE CASCADE ON UPDATE SET NULL', + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Ddl/Constraint/PrimaryKeyBuilderTest.php b/test/Sql/Builder/Ddl/Constraint/PrimaryKeyBuilderTest.php new file mode 100644 index 0000000000..f960774b68 --- /dev/null +++ b/test/Sql/Builder/Ddl/Constraint/PrimaryKeyBuilderTest.php @@ -0,0 +1,45 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->constraint_PrimaryKey('foo'), + 'expected' => [ + 'sql92' => 'PRIMARY KEY ("foo")', + ], + ], + [ + 'sqlObject' => $this->constraint_PrimaryKey('foo', 'bar'), + 'expected' => [ + 'sql92' => 'CONSTRAINT "bar" PRIMARY KEY ("foo")', + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Ddl/Constraint/UniqueKeyBuilderTest.php b/test/Sql/Builder/Ddl/Constraint/UniqueKeyBuilderTest.php new file mode 100644 index 0000000000..6e8d2747d0 --- /dev/null +++ b/test/Sql/Builder/Ddl/Constraint/UniqueKeyBuilderTest.php @@ -0,0 +1,45 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->constraint_UniqueKey('foo', 'my_uk'), + 'expected' => [ + 'sql92' => 'CONSTRAINT "my_uk" UNIQUE ("foo")', + ], + ], + [ + 'sqlObject' => $this->constraint_UniqueKey('foo'), + 'expected' => [ + 'sql92' => 'UNIQUE ("foo")', + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Ddl/CreateTableBuilderTest.php b/test/Sql/Builder/Ddl/CreateTableBuilderTest.php new file mode 100644 index 0000000000..da7b316b5a --- /dev/null +++ b/test/Sql/Builder/Ddl/CreateTableBuilderTest.php @@ -0,0 +1,133 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider( + $this->dataProvider_ColumnsAndConstraint(), + $this->dataProvider_Table() + ); + } + + public function dataProvider_ColumnsAndConstraint() + { + return [ + 'with options' => [ + 'sqlObject' => $this->createTable('foo') + ->addColumn($this->createColumn('col1')->setOption('identity', true)->setOption('comment', 'Comment1')) + ->addColumn($this->createColumn('col2')->setOption('identity', true)->setOption('comment', 'Comment2')), + 'expected' => [ + 'sql92' => "CREATE TABLE \"foo\" ( \n \"col1\" INTEGER NOT NULL,\n \"col2\" INTEGER NOT NULL \n)", + 'MySql' => "CREATE TABLE `foo` ( \n `col1` INTEGER NOT NULL AUTO_INCREMENT COMMENT 'Comment1',\n `col2` INTEGER NOT NULL AUTO_INCREMENT COMMENT 'Comment2' \n)", + 'Oracle' => "CREATE TABLE \"foo\" ( \n \"col1\" INTEGER NOT NULL,\n \"col2\" INTEGER NOT NULL \n)", + 'SqlServer' => "CREATE TABLE [foo] ( \n [col1] INTEGER NOT NULL,\n [col2] INTEGER NOT NULL \n)", + ], + ], + 'with options 2' => [ + 'sqlObject' => function () { + $col = new Column('bar'); + $col->setOption('zerofill', true); + $col->setOption('unsigned', true); + $col->setOption('identity', true); + $col->setOption('column-format', 'FIXED'); + $col->setOption('storage', 'MEMORY'); + $col->setOption('comment', 'baz'); + $col->addConstraint(new Constraint\PrimaryKey()); + + return $this->createTable('foo')->addColumn($col); + }, + 'expected' => [ + 'mysql' => "CREATE TABLE `foo` ( \n `bar` INTEGER UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'baz' COLUMN_FORMAT FIXED STORAGE MEMORY \n)", + ], + ], + [ + 'sqlObject' => $this->createTable('foo')->addColumn(new Column('bar')), + 'expected' => [ + 'sql92' => "CREATE TABLE \"foo\" ( \n \"bar\" INTEGER NOT NULL \n)", + 'SqlServer' => "CREATE TABLE [foo] ( \n [bar] INTEGER NOT NULL \n)", + ], + ], + [ + 'sqlObject' => $this->createTable('foo', true)->addColumn(new Column('bar')), + 'expected' => [ + 'sql92' => "CREATE TEMPORARY TABLE \"foo\" ( \n \"bar\" INTEGER NOT NULL \n)", + 'SqlServer' => "CREATE TABLE [#foo] ( \n [bar] INTEGER NOT NULL \n)", + ], + ], + [ + 'sqlObject' => $this->createTable('foo', true)->addColumn(new Column('bar'))->addColumn(new Column('baz')), + 'expected' => [ + 'sql92' => "CREATE TEMPORARY TABLE \"foo\" ( \n \"bar\" INTEGER NOT NULL,\n \"baz\" INTEGER NOT NULL \n)", + ], + ], + [ + 'sqlObject' => $this->createTable('foo')->addColumn(new Column('bar'))->addConstraint(new Constraint\PrimaryKey('bat')), + 'expected' => [ + 'sql92' => "CREATE TABLE \"foo\" ( \n \"bar\" INTEGER NOT NULL ,\n PRIMARY KEY (\"bat\") \n)", + ], + ], + [ + 'sqlObject' => $this->createTable('foo')->addConstraint(new Constraint\PrimaryKey('bar'))->addConstraint(new Constraint\PrimaryKey('bat')), + 'expected' => [ + 'sql92' => "CREATE TABLE \"foo\" ( \n PRIMARY KEY (\"bar\"),\n PRIMARY KEY (\"bat\") \n)", + ], + ], + ]; + } + + public function dataProvider_Table() + { + return [ + 'not temporary' => [ + 'sqlObject' => $this->createTable('foo'), + 'expected' => [ + 'sql92' => "CREATE TABLE \"foo\" ( \n)", + 'SqlServer' => "CREATE TABLE [foo] ( \n)", + ], + ], + 'temporary' => [ + 'sqlObject' => $this->createTable('foo')->setTemporary(true), + 'expected' => [ + 'sql92' => "CREATE TEMPORARY TABLE \"foo\" ( \n)", + 'MySql' => "CREATE TEMPORARY TABLE `foo` ( \n)", + 'Oracle' => "CREATE TEMPORARY TABLE \"foo\" ( \n)", + 'SqlServer' => "CREATE TABLE [#foo] ( \n)", + ], + ], + 'temporary via constructor' => [ + 'sqlObject' => $this->createTable('foo', true), + 'expected' => [ + 'sql92' => "CREATE TEMPORARY TABLE \"foo\" ( \n)", + 'SqlServer' => "CREATE TABLE [#foo] ( \n)", + ], + ], + ]; + } +} diff --git a/test/Sql/Builder/Ddl/DropTableBuilderTest.php b/test/Sql/Builder/Ddl/DropTableBuilderTest.php new file mode 100644 index 0000000000..9812f53990 --- /dev/null +++ b/test/Sql/Builder/Ddl/DropTableBuilderTest.php @@ -0,0 +1,46 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->dropTable('foo'), + 'expected' => [ + 'sql92' => 'DROP TABLE "foo"', + ], + ], + [ + 'sqlObject' => $this->dropTable('foo')->ifExists(true), + 'expected' => [ + 'sql92' => 'DROP TABLE IF EXISTS "foo"', + 'sqlserver' => 'IF OBJECT_ID(\'foo\', \'U\') IS NOT NULL DROP TABLE [foo];', + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Ddl/Index/IndexBuilderTest.php b/test/Sql/Builder/Ddl/Index/IndexBuilderTest.php new file mode 100644 index 0000000000..5965ec4a20 --- /dev/null +++ b/test/Sql/Builder/Ddl/Index/IndexBuilderTest.php @@ -0,0 +1,51 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->index_Index('foo', 'my_uk'), + 'expected' => [ + 'sql92' => 'INDEX "my_uk"("foo")', + ], + ], + [ + 'sqlObject' => $this->index_Index(['foo', 'bar'], 'my_uk', [10, 5]), + 'expected' => [ + 'sql92' => 'INDEX "my_uk"("foo"(10), "bar"(5))', + ], + ], + [ + 'sqlObject' => $this->index_Index(['foo', 'bar'], 'my_uk', [10]), + 'expected' => [ + 'sql92' => 'INDEX "my_uk"("foo"(10), "bar")', + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/DeleteBuilderTest.php b/test/Sql/Builder/DeleteBuilderTest.php new file mode 100644 index 0000000000..cfe55bfc35 --- /dev/null +++ b/test/Sql/Builder/DeleteBuilderTest.php @@ -0,0 +1,106 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider( + $this->dataProvider_From(), + $this->dataProvider_Subselect(), + $this->dataProvider_Where() + ); + } + + public function dataProvider_From() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->delete()->from('foo'), + 'expected' => [ + 'sql92' => [ + 'string' => 'DELETE FROM "foo"', + 'prepare' => true, + ], + ], + ], + [ + 'sqlObject' => $this->delete()->from(new TableIdentifier('foo', 'sch')), + 'expected' => [ + 'sql92' => [ + 'string' => 'DELETE FROM "sch"."foo"', + 'prepare' => true, + ], + ], + ], + ]); + } + + public function dataProvider_Subselect() + { + return [ + [ + 'sqlObject' => $this->delete('foo')->where(['x'=>$this->select('foo')->where(['x'=>'y'])]), + 'expected' => [ + 'sql92' => [ + 'string' => 'DELETE FROM "foo" WHERE "x" = (SELECT "foo".* FROM "foo" WHERE "x" = \'y\')', + 'prepare' => 'DELETE FROM "foo" WHERE "x" = (SELECT "foo".* FROM "foo" WHERE "x" = ?)', + 'parameters' => ['subselect1expr1' => 'y'], + ], + 'MySql' => [ + 'string' => 'DELETE FROM `foo` WHERE `x` = (SELECT `foo`.* FROM `foo` WHERE `x` = \'y\')', + 'prepare' => 'DELETE FROM `foo` WHERE `x` = (SELECT `foo`.* FROM `foo` WHERE `x` = ?)', + 'parameters' => ['subselect1expr1' => 'y'], + ], + 'Oracle' => [ + 'string' => 'DELETE FROM "foo" WHERE "x" = (SELECT "foo".* FROM "foo" WHERE "x" = \'y\')', + 'prepare' => 'DELETE FROM "foo" WHERE "x" = (SELECT "foo".* FROM "foo" WHERE "x" = ?)', + 'parameters' => ['subselect1expr1' => 'y'], + ], + 'SqlServer' => [ + 'string' => 'DELETE FROM [foo] WHERE [x] = (SELECT [foo].* FROM [foo] WHERE [x] = \'y\')', + 'prepare' => 'DELETE FROM [foo] WHERE [x] = (SELECT [foo].* FROM [foo] WHERE [x] = ?)', + 'parameters' => ['subselect1expr1' => 'y'], + ], + ], + ], + ]; + } + + public function dataProvider_Where() + { + return [ + [ // testPrepareSqlStatement(), testBuildSqlString() + 'sqlObject' => $this->delete()->from('foo')->where('x = y'), + 'expected' => [ + 'sql92' => [ + 'string' => 'DELETE FROM "foo" WHERE x = y', + 'prepare' => true, + ], + ], + ], + ]; + } +} diff --git a/test/Sql/Builder/ExpressionBuilderTest.php b/test/Sql/Builder/ExpressionBuilderTest.php new file mode 100644 index 0000000000..18bb6018c2 --- /dev/null +++ b/test/Sql/Builder/ExpressionBuilderTest.php @@ -0,0 +1,181 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_Expression()->setExpression('foo.bar = ? AND id != ?')->setParameters(['foo', 'bar']), + 'expected' => [ + 'sql92' => [ + 'string' => 'foo.bar = \'foo\' AND id != \'bar\'', + 'prepare' => 'foo.bar = ? AND id != ?', + 'parameters' => [ + 'expr1' => 'foo', + 'expr2' => 'bar', + ], + ], + ], + ], + [ + 'sqlObject' => $this->expression( + 'X SAME AS ? AND Y = ? BUT LITERALLY ?', + [ + ['foo', ExpressionInterface::TYPE_IDENTIFIER], + [5, ExpressionInterface::TYPE_VALUE], + ['FUNC(FF%X)', ExpressionInterface::TYPE_LITERAL], + ]), + 'expected' => [ + 'sql92' => [ + 'string' => 'X SAME AS "foo" AND Y = \'5\' BUT LITERALLY FUNC(FF%X)', + 'prepare' => 'X SAME AS "foo" AND Y = ? BUT LITERALLY FUNC(FF%X)', + 'parameters' => [ + 'expr1' => 5, + ], + ], + ], + ], + [ + 'sqlObject' => $this->expression('X LIKE "foo%"'), + 'expected' => [ + 'sql92' => [ + 'string' => 'X LIKE "foo%"', + 'prepare' => 'X LIKE "foo%"', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->expression('? LIKE "foo%"', [['X', 'literal']]), + 'expected' => [ + 'sql92' => [ + 'string' => 'X LIKE "foo%"', + 'prepare' => 'X LIKE "foo%"', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->expression( + '? > ? AND y < ?', + [ + ['x', ExpressionInterface::TYPE_IDENTIFIER], + 5, + 10 + ] + ), + 'expected' => [ + 'sql92' => [ + 'string' => '"x" > \'5\' AND y < \'10\'', + 'prepare' => '"x" > ? AND y < ?', + 'parameters' => [ + 'expr1' => 5, + 'expr2' => 10, + ], + ], + ], + ], + [ + 'sqlObject' => $this->expression( + '? > ? AND y < ?', + [ + ['x', ExpressionInterface::TYPE_IDENTIFIER], + 5, + 10 + ] + ), + 'expected' => [ + 'sql92' => [ + 'string' => '"x" > \'5\' AND y < \'10\'', + 'prepare' => '"x" > :expr1 AND y < :expr2', + 'parameters' => [ + 'expr1' => 5, + 'expr2' => 10, + ], + 'useNamedParams' => true, + ], + ], + ], + [ + 'sqlObject' => $this->predicate_PredicateSet([$this->predicate_PredicateSet([$this->predicate_Expression('x = ?', 5)])]), + 'expected' => [ + 'sql92' => [ + 'string' => "(x = '5')", + 'prepare' => "(x = ?)", + 'parameters' => [ + 'expr1' => 5, + ], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_PredicateSet([ + $this->predicate_PredicateSet([ + $this->predicate_In( + 'x', + $this->select('x')->where($this->predicate_Like('bar', 'Foo%')) + ) + ]) + ]), + 'expected' => [ + 'sql92' => [ + 'string' => '("x" IN (SELECT "x".* FROM "x" WHERE "bar" LIKE \'Foo%\'))', + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Operator( + 'release_date', + '=', + $this->expression('FROM_UNIXTIME(?)', 100000000) + ), + 'expected' => [ + 'sql92' => [ + 'string' => '"release_date" = FROM_UNIXTIME(\'100000000\')', + ], + ], + ], + [ + 'sqlObject' => $this->expression('FROM_UNIXTIME(date, "%Y-%m")'), + 'expected' => [ + 'sql92' => [ + 'string' => 'FROM_UNIXTIME(date, "%Y-%m")', + ], + ], + ], + [ + 'sqlObject' => $this->expression('uf.user_id = :user_id OR uf.friend_id = :user_id', ['user_id' => 1]), + 'expected' => [ + 'sql92' => [ + 'string' => 'uf.user_id = :user_id OR uf.friend_id = :user_id', + 'prepare' => 'uf.user_id = :user_id OR uf.friend_id = :user_id', + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/InsertBuilderTest.php b/test/Sql/Builder/InsertBuilderTest.php new file mode 100644 index 0000000000..6a73360fb0 --- /dev/null +++ b/test/Sql/Builder/InsertBuilderTest.php @@ -0,0 +1,244 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider( + $this->dataProvider_Into(), + $this->dataProvider_ColumnsAndValues() + ); + } + + public function dataProvider_Into() + { + return [ + 'into_TableIdentifier' => [ + 'sqlObject' => $this->insert()->into(new TableIdentifier('foo', 'schema'))->values(['c1' => 'v1']), + 'expected' => [ + 'sql92' => 'INSERT INTO "schema"."foo" ("c1") VALUES (\'v1\')', + ], + ], + 'into_string' => [ + 'sqlObject' => $this->insert()->into('foo')->values(['c1' => 'v1']), + 'expected' => [ + 'sql92' => 'INSERT INTO "foo" ("c1") VALUES (\'v1\')', + ], + ], + 'into_array' => [ + 'sqlObject' => $this->insert()->into(['schema', 'foo'])->values(['c1' => 'v1']), + 'expected' => [ + 'sql92' => 'INSERT INTO "schema"."foo" ("c1") VALUES (\'v1\')', + ], + ], + ]; + } + + public function dataProvider_ColumnsAndValues() + { + return [ + 'columns_in_values' => [ + 'sqlObject' => $this->insert('foo') + ->values([ + 'bar' => 'baz', + 'boo' => new Expression('NOW()'), + 'bam' => null, + 'bat' => $this->select('bad') + ]), + 'expected' => [ + 'sql92' => [ + 'string' => 'INSERT INTO "foo" ("bar", "boo", "bam", "bat") VALUES (\'baz\', NOW(), NULL, (SELECT "bad".* FROM "bad"))', + 'prepare' => 'INSERT INTO "foo" ("bar", "boo", "bam", "bat") VALUES (?, NOW(), ?, (SELECT "bad".* FROM "bad"))', + 'parameters' => ['bar' => 'baz', 'bam' => null], + ], + ], + ], + 'values with merge' => [ + 'sqlObject' => $this->insert('foo') + ->values([ + 'bar' => 'baz', + 'boo' => new Expression('NOW()'), + 'bam' => null + ]) + ->values(['qux' => 100], Insert::VALUES_MERGE), + 'expected' => [ + 'sql92' => [ + 'string' => 'INSERT INTO "foo" ("bar", "boo", "bam", "qux") VALUES (\'baz\', NOW(), NULL, \'100\')', + ], + ], + ], + 'row_with_columns' => [ + 'sqlObject' => $this->insert('foo') + ->columns(['c1']) + ->values(['v1']), + 'expected' => [ + 'sql92' => [ + 'string' => 'INSERT INTO "foo" ("c1") VALUES (\'v1\')', + 'prepare' => 'INSERT INTO "foo" ("c1") VALUES (?)', + 'parameters' => ['c1' => 'v1'], + ], + ], + ], + 'row_without_columns' => [ + 'sqlObject' => $this->insert('foo') + ->values(['v1']), + 'expected' => [ + 'sql92' => [ + 'string' => 'INSERT INTO "foo" VALUES (\'v1\')', + 'prepare' => 'INSERT INTO "foo" VALUES (\'v1\')', + 'parameters' => [], + ], + ], + ], + 'select_with_columns' => [ + 'sqlObject' => $this->insert('foo') + ->columns(['col1', 'col2']) + ->select($this->select()->from('bar')->where(['x'=>5])), + 'expected' => [ + 'sql92' => [ + 'string' => 'INSERT INTO "foo" ("col1", "col2") (SELECT "bar".* FROM "bar" WHERE "x" = \'5\')', + 'prepare' => 'INSERT INTO "foo" ("col1", "col2") (SELECT "bar".* FROM "bar" WHERE "x" = ?)', + 'parameters' => ['subselect1expr1'=>5], + ], + 'MySql' => [ + 'string' => 'INSERT INTO `foo` (`col1`, `col2`) (SELECT `bar`.* FROM `bar` WHERE `x` = \'5\')', + 'prepare' => 'INSERT INTO `foo` (`col1`, `col2`) (SELECT `bar`.* FROM `bar` WHERE `x` = ?)', + 'parameters' => ['subselect1expr1' => 5], + ], + 'Oracle' => [ + 'string' => 'INSERT INTO "foo" ("col1", "col2") (SELECT "bar".* FROM "bar" WHERE "x" = \'5\')', + 'prepare' => 'INSERT INTO "foo" ("col1", "col2") (SELECT "bar".* FROM "bar" WHERE "x" = ?)', + 'parameters' => ['subselect1expr1' => 5], + ], + 'SqlServer' => [ + 'string' => 'INSERT INTO [foo] ([col1], [col2]) (SELECT [bar].* FROM [bar] WHERE [x] = \'5\')', + 'prepare' => 'INSERT INTO [foo] ([col1], [col2]) (SELECT [bar].* FROM [bar] WHERE [x] = ?)', + 'parameters' => ['subselect1expr1' => 5], + ], + ], + ], + 'select_without_columns' => [ + 'sqlObject' => $this->insert('foo') + ->select($this->select('bar')->where(['x'=>5])), + 'expected' => [ + 'sql92' => [ + 'string' => 'INSERT INTO "foo" (SELECT "bar".* FROM "bar" WHERE "x" = \'5\')', + 'prepare' => 'INSERT INTO "foo" (SELECT "bar".* FROM "bar" WHERE "x" = ?)', + 'parameters' => ['subselect1expr1' => 5], + ], + 'MySql' => [ + 'string' => 'INSERT INTO `foo` (SELECT `bar`.* FROM `bar` WHERE `x` = \'5\')', + 'prepare' => 'INSERT INTO `foo` (SELECT `bar`.* FROM `bar` WHERE `x` = ?)', + 'parameters' => ['subselect1expr1' => 5], + ], + 'Oracle' => [ + 'string' => 'INSERT INTO "foo" (SELECT "bar".* FROM "bar" WHERE "x" = \'5\')', + 'prepare' => 'INSERT INTO "foo" (SELECT "bar".* FROM "bar" WHERE "x" = ?)', + 'parameters' => ['subselect1expr1' => 5], + ], + 'SqlServer' => [ + 'string' => 'INSERT INTO [foo] (SELECT [bar].* FROM [bar] WHERE [x] = \'5\')', + 'prepare' => 'INSERT INTO [foo] (SELECT [bar].* FROM [bar] WHERE [x] = ?)', + 'parameters' => ['subselect1expr1' => 5], + ], + ], + ], + 'select_with_combine_in_select' => [ + 'sqlObject' => $this->insert('foo') + ->select($this->combine($this->select('bar'))), + 'expected' => [ + 'sql92' => 'INSERT INTO "foo" ((SELECT "bar".* FROM "bar"))', + 'MySql' => 'INSERT INTO `foo` ((SELECT `bar`.* FROM `bar`))', + 'Oracle' => 'INSERT INTO "foo" ((SELECT "bar".* FROM "bar"))', + 'SqlServer' => 'INSERT INTO [foo] ((SELECT [bar].* FROM [bar]))', + ], + ], + 'multiple_row_with_columns' => [ + 'sqlObject' => $this->insert() + ->into('foo') + ->columns(['c1', 'c2']) + ->values([ + ['1_v1', '1_v2'], + ['2_v1', '2_v2'], + ]), + 'expected' => [ + 'sql92' => [ + 'string' => 'INSERT INTO "foo" ("c1", "c2") VALUES (\'1_v1\', \'1_v2\'), (\'2_v1\', \'2_v2\')', + 'prepare' => 'INSERT INTO "foo" ("c1", "c2") VALUES (\'1_v1\', \'1_v2\'), (\'2_v1\', \'2_v2\')', + 'parameters' => [], + ], + ], + ], + 'multiple_row_without_columns' => [ + 'sqlObject' => $this->insert() + ->into('foo') + ->values([ + ['1_v1', '1_v2'], + ['2_v1', '2_v2'], + ]), + 'expected' => [ + 'sql92' => [ + 'string' => 'INSERT INTO "foo" VALUES (\'1_v1\', \'1_v2\'), (\'2_v1\', \'2_v2\')', + 'prepare' => 'INSERT INTO "foo" VALUES (\'1_v1\', \'1_v2\'), (\'2_v1\', \'2_v2\')', + 'parameters' => [], + ], + ], + ], + 'multiple_row_with_different_values_types' => [ + 'sqlObject' => $this->insert()->into('foo') + ->values([ + [ + 'v1', + 'v2', + 'v3', + 'v4', + ], + [ + 'bar', + null, + new Expression('NOW()'), + $this->select('baz'), + ], + [ + 'v5', + 'v6', + 'v7', + 'v8', + ], + ]), + 'expected' => [ + 'sql92' => [ + 'string' => 'INSERT INTO "foo" VALUES (\'v1\', \'v2\', \'v3\', \'v4\'), (\'bar\', NULL, NOW(), (SELECT "baz".* FROM "baz")), (\'v5\', \'v6\', \'v7\', \'v8\')', + 'string' => 'INSERT INTO "foo" VALUES (\'v1\', \'v2\', \'v3\', \'v4\'), (\'bar\', NULL, NOW(), (SELECT "baz".* FROM "baz")), (\'v5\', \'v6\', \'v7\', \'v8\')', + 'parameters' => [], + ], + ], + ], + ]; + } +} diff --git a/test/Sql/Builder/LiteralBuilderTest.php b/test/Sql/Builder/LiteralBuilderTest.php new file mode 100644 index 0000000000..467323e281 --- /dev/null +++ b/test/Sql/Builder/LiteralBuilderTest.php @@ -0,0 +1,51 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_Literal('bar'), + 'expected' => [ + 'sql92' => [ + 'string' => 'bar', + 'prepare' => 'bar', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Literal('X LIKE "foo%"'), + 'expected' => [ + 'sql92' => [ + 'string' => 'X LIKE "foo%"', + 'prepare' => 'X LIKE "foo%"', + 'parameters' => [], + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Predicate/BetweenBuilderTest.php b/test/Sql/Builder/Predicate/BetweenBuilderTest.php new file mode 100644 index 0000000000..bcb54385dc --- /dev/null +++ b/test/Sql/Builder/Predicate/BetweenBuilderTest.php @@ -0,0 +1,53 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_Between('foo.bar', 5, 10), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" BETWEEN \'5\' AND \'10\'', + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Between() + ->setIdentifier([10=>ExpressionInterface::TYPE_VALUE]) + ->setMinValue(['foo.bar'=>ExpressionInterface::TYPE_IDENTIFIER]) + ->setMaxValue(['foo.baz'=>ExpressionInterface::TYPE_IDENTIFIER]), + 'expected' => [ + 'sql92' => [ + 'string' => '\'10\' BETWEEN "foo"."bar" AND "foo"."baz"', + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Predicate/InBuilderTest.php b/test/Sql/Builder/Predicate/InBuilderTest.php new file mode 100644 index 0000000000..ae09573a76 --- /dev/null +++ b/test/Sql/Builder/Predicate/InBuilderTest.php @@ -0,0 +1,98 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_In() + ->setIdentifier('foo.bar') + ->setValueSet([1, 2, 3]), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" IN (\'1\', \'2\', \'3\')', + 'prepare' => '"foo"."bar" IN (?, ?, ?)', + 'parameters' => [ + 'expr1' => 1, + 'expr2' => 2, + 'expr3' => 3, + ], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_In() + ->setIdentifier('foo.bar') + ->setValueSet([ + [1=>ExpressionInterface::TYPE_LITERAL], + [2=>ExpressionInterface::TYPE_VALUE], + [3=>ExpressionInterface::TYPE_LITERAL], + ]), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" IN (1, \'2\', 3)', + 'prepare' => '"foo"."bar" IN (1, ?, 3)', + 'parameters' => [ + 'expr1' => 2, + ], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_In('foo', $this->select('bar')), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo" IN (SELECT "bar".* FROM "bar")', + 'prepare' => '"foo" IN (SELECT "bar".* FROM "bar")', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_In('foo', $this->combine([$this->select('bar'), $this->select('baz')])), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo" IN ((SELECT "bar".* FROM "bar") UNION (SELECT "baz".* FROM "baz"))', + 'prepare' => '"foo" IN ((SELECT "bar".* FROM "bar") UNION (SELECT "baz".* FROM "baz"))', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_In(['foo', 'bar'], $this->select('bar')), + 'expected' => [ + 'sql92' => [ + 'string' => '("foo", "bar") IN (SELECT "bar".* FROM "bar")', + 'prepare' => '("foo", "bar") IN (SELECT "bar".* FROM "bar")', + 'parameters' => [], + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Predicate/IsNotNullBuilderTest.php b/test/Sql/Builder/Predicate/IsNotNullBuilderTest.php new file mode 100644 index 0000000000..909ea64f09 --- /dev/null +++ b/test/Sql/Builder/Predicate/IsNotNullBuilderTest.php @@ -0,0 +1,43 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_IsNotNull('foo.bar'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" IS NOT NULL', + 'prepare' => '"foo"."bar" IS NOT NULL', + 'parameters' => [], + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Predicate/LikeBuilderTest.php b/test/Sql/Builder/Predicate/LikeBuilderTest.php new file mode 100644 index 0000000000..a85a221614 --- /dev/null +++ b/test/Sql/Builder/Predicate/LikeBuilderTest.php @@ -0,0 +1,54 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_Like('bar', 'Foo%'), + 'expected' => [ + 'sql92' => [ + 'string' => '"bar" LIKE \'Foo%\'', + 'prepare' => '"bar" LIKE ?', + 'parameters' => ['expr1' => 'Foo%'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Like(['Foo%'=>ExpressionInterface::TYPE_VALUE], ['bar'=>ExpressionInterface::TYPE_IDENTIFIER]), + 'expected' => [ + 'sql92' => [ + 'string' => '\'Foo%\' LIKE "bar"', + 'prepare' => '? LIKE "bar"', + 'parameters' => ['expr1' => 'Foo%'], + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Predicate/NotBetweenBuilderTest.php b/test/Sql/Builder/Predicate/NotBetweenBuilderTest.php new file mode 100644 index 0000000000..0c7b8db339 --- /dev/null +++ b/test/Sql/Builder/Predicate/NotBetweenBuilderTest.php @@ -0,0 +1,53 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_NotBetween('foo.bar', 5, 10), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" NOT BETWEEN \'5\' AND \'10\'', + ], + ], + ], + [ + 'sqlObject' => $this->predicate_NotBetween() + ->setIdentifier([10=>ExpressionInterface::TYPE_VALUE]) + ->setMinValue(['foo.bar'=>ExpressionInterface::TYPE_IDENTIFIER]) + ->setMaxValue(['foo.baz'=>ExpressionInterface::TYPE_IDENTIFIER]), + 'expected' => [ + 'sql92' => [ + 'string' => '\'10\' NOT BETWEEN "foo"."bar" AND "foo"."baz"', + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Predicate/NotInBuilderTest.php b/test/Sql/Builder/Predicate/NotInBuilderTest.php new file mode 100644 index 0000000000..0783451e3f --- /dev/null +++ b/test/Sql/Builder/Predicate/NotInBuilderTest.php @@ -0,0 +1,69 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_NotIn('bar') + ->setIdentifier('foo.bar') + ->setValueSet([1, 2, 3]), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" NOT IN (\'1\', \'2\', \'3\')', + 'prepare' => '"foo"."bar" NOT IN (?, ?, ?)', + 'parameters' => [ + 'expr1' => 1, + 'expr2' => 2, + 'expr3' => 3, + ], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_NotIn('foo', $this->select('bar')), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo" NOT IN (SELECT "bar".* FROM "bar")', + 'prepare' => '"foo" NOT IN (SELECT "bar".* FROM "bar")', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_NotIn(['foo', 'bar'], $this->select('bar')), + 'expected' => [ + 'sql92' => [ + 'string' => '("foo", "bar") NOT IN (SELECT "bar".* FROM "bar")', + 'prepare' => '("foo", "bar") NOT IN (SELECT "bar".* FROM "bar")', + 'parameters' => [], + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Predicate/NotLikeBuilderTest.php b/test/Sql/Builder/Predicate/NotLikeBuilderTest.php new file mode 100644 index 0000000000..fbc8a35f6f --- /dev/null +++ b/test/Sql/Builder/Predicate/NotLikeBuilderTest.php @@ -0,0 +1,43 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_NotLike('bar', 'Foo%'), + 'expected' => [ + 'sql92' => [ + 'string' => '"bar" NOT LIKE \'Foo%\'', + 'prepare' => '"bar" NOT LIKE ?', + 'parameters' => ['expr1' => 'Foo%'], + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Predicate/OperatorBuilderTest.php b/test/Sql/Builder/Predicate/OperatorBuilderTest.php new file mode 100644 index 0000000000..1deae560ff --- /dev/null +++ b/test/Sql/Builder/Predicate/OperatorBuilderTest.php @@ -0,0 +1,65 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_Operator() + ->setLeft(['foo', ExpressionInterface::TYPE_VALUE]) + ->setOperator('>=') + ->setRight(['foo.bar', ExpressionInterface::TYPE_IDENTIFIER]), + 'expected' => [ + 'sql92' => [ + 'string' => '\'foo\' >= "foo"."bar"', + 'prepare' => '? >= "foo"."bar"', + 'parameters' => [ + 'expr1' => 'foo', + ], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Operator( + 'release_date', + '=', + $this->predicate_Expression('FROM_UNIXTIME(?)', 100000000) + ), + 'expected' => [ + 'sql92' => [ + 'string' => '"release_date" = FROM_UNIXTIME(\'100000000\')', + 'prepare' => '"release_date" = FROM_UNIXTIME(?)', + 'parameters' => [ + 'expr1' => 100000000, + ], + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Predicate/PredicateBuilderTest.php b/test/Sql/Builder/Predicate/PredicateBuilderTest.php new file mode 100644 index 0000000000..39c55c70fa --- /dev/null +++ b/test/Sql/Builder/Predicate/PredicateBuilderTest.php @@ -0,0 +1,256 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_Predicate()->equalTo('foo.bar', 'bar'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" = \'bar\'', + 'prepare' => '"foo"."bar" = ?', + 'parameters' => ['expr1' => 'bar'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->notEqualTo('foo.bar', 'bar'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" != \'bar\'', + 'prepare' => '"foo"."bar" != ?', + 'parameters' => ['expr1' => 'bar'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->lessThan('foo.bar', 'bar'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" < \'bar\'', + 'prepare' => '"foo"."bar" < ?', + 'parameters' => ['expr1' => 'bar'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->greaterThan('foo.bar', 'bar'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" > \'bar\'', + 'prepare' => '"foo"."bar" > ?', + 'parameters' => ['expr1' => 'bar'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->lessThanOrEqualTo('foo.bar', 'bar'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" <= \'bar\'', + 'prepare' => '"foo"."bar" <= ?', + 'parameters' => ['expr1' => 'bar'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->greaterThanOrEqualTo('foo.bar', 'bar'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" >= \'bar\'', + 'prepare' => '"foo"."bar" >= ?', + 'parameters' => ['expr1' => 'bar'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->like('foo.bar', 'bar%'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" LIKE \'bar%\'', + 'prepare' => '"foo"."bar" LIKE ?', + 'parameters' => ['expr1' => 'bar%'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->notLike('foo.bar', 'bar%'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" NOT LIKE \'bar%\'', + 'prepare' => '"foo"."bar" NOT LIKE ?', + 'parameters' => ['expr1' => 'bar%'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->literal('foo.bar = ?', 'bar'), + 'expected' => [ + 'sql92' => [ + 'string' => 'foo.bar = \'bar\'', + 'prepare' => 'foo.bar = ?', + 'parameters' => ['expr1' => 'bar'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->isNull('foo.bar'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" IS NULL', + 'prepare' => '"foo"."bar" IS NULL', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->isNotNull('foo.bar'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" IS NOT NULL', + 'prepare' => '"foo"."bar" IS NOT NULL', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->in('foo.bar', ['foo', 'bar']), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" IN (\'foo\', \'bar\')', + 'prepare' => '"foo"."bar" IN (?, ?)', + 'parameters' => [ + 'expr1' => 'foo', + 'expr2' => 'bar', + ], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->notIn('foo.bar', ['foo', 'bar']), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" NOT IN (\'foo\', \'bar\')', + 'prepare' => '"foo"."bar" NOT IN (?, ?)', + 'parameters' => [ + 'expr1' => 'foo', + 'expr2' => 'bar', + ], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->between('foo.bar', 1, 10), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" BETWEEN \'1\' AND \'10\'', + 'prepare' => '"foo"."bar" BETWEEN ? AND ?', + 'parameters' => [ + 'expr1' => 1, + 'expr2' => 10, + ], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->notBetween('foo.bar', 1, 10), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" NOT BETWEEN \'1\' AND \'10\'', + 'prepare' => '"foo"."bar" NOT BETWEEN ? AND ?', + 'parameters' => [ + 'expr1' => 1, + 'expr2' => 10, + ], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->expression('foo = ?', 'bar'), + 'expected' => [ + 'sql92' => [ + 'string' => 'foo = \'bar\'', + 'prepare' => 'foo = ?', + 'parameters' => ['expr1' => 'bar'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->expression('foo = ?', 0), + 'expected' => [ + 'sql92' => [ + 'string' => 'foo = \'0\'', + 'prepare' => 'foo = ?', + 'parameters' => ['expr1' => 0], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate()->expression('foo = ?'), + 'expected' => [ + 'sql92' => [ + 'string' => 'foo = \'\'', + 'prepare' => 'foo = ?', + 'parameters' => ['expr1' => null], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate() + ->isNull('foo.bar') + ->or + ->isNotNull('bar.baz') + ->and + ->equalTo('baz.bat', 'foo'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" IS NULL OR "bar"."baz" IS NOT NULL AND "baz"."bat" = \'foo\'', + 'prepare' => '"foo"."bar" IS NULL OR "bar"."baz" IS NOT NULL AND "baz"."bat" = ?', + 'parameters' => ['expr1' => 'foo'], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_Predicate() + ->isNull('foo.bar') + ->nest() + ->isNotNull('bar.baz') + ->and + ->equalTo('baz.bat', 'foo') + ->unnest(), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo"."bar" IS NULL AND ("bar"."baz" IS NOT NULL AND "baz"."bat" = \'foo\')', + 'prepare' => '"foo"."bar" IS NULL AND ("bar"."baz" IS NOT NULL AND "baz"."bat" = ?)', + 'parameters' => ['expr1' => 'foo'], + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/Predicate/PredicateSetBuilderTest.php b/test/Sql/Builder/Predicate/PredicateSetBuilderTest.php new file mode 100644 index 0000000000..4b23aa435e --- /dev/null +++ b/test/Sql/Builder/Predicate/PredicateSetBuilderTest.php @@ -0,0 +1,135 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider([ + [ + 'sqlObject' => $this->predicate_PredicateSet(), + 'expected' => [ + 'sql92' => [ + 'string' => '', + 'prepare' => '', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_PredicateSet() + ->addPredicate($this->predicate_IsNull('foo')) + ->addPredicate($this->predicate_IsNull('bar')), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo" IS NULL AND "bar" IS NULL', + 'prepare' => '"foo" IS NULL AND "bar" IS NULL', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_PredicateSet( + [ + $this->predicate_IsNull('foo'), + $this->predicate_IsNull('bar'), + ], + 'OR' + ), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo" IS NULL OR "bar" IS NULL', + 'prepare' => '"foo" IS NULL OR "bar" IS NULL', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_PredicateSet() + ->addPredicate($this->predicate_IsNull('foo'), 'OR') + ->addPredicate($this->predicate_IsNull('bar'), 'AND') + ->addPredicate($this->predicate_IsNull('baz'), 'OR') + ->addPredicate($this->predicate_IsNull('bat'), 'AND'), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo" IS NULL AND "bar" IS NULL OR "baz" IS NULL AND "bat" IS NULL', + 'prepare' => '"foo" IS NULL AND "bar" IS NULL OR "baz" IS NULL AND "bat" IS NULL', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_PredicateSet() + ->orPredicate($this->predicate_IsNull('foo')) + ->andPredicate($this->predicate_IsNull('bar')) + ->orPredicate($this->predicate_IsNull('baz')) + ->andPredicate($this->predicate_IsNull('bat')), + 'expected' => [ + 'sql92' => [ + 'string' => '"foo" IS NULL AND "bar" IS NULL OR "baz" IS NULL AND "bat" IS NULL', + 'prepare' => '"foo" IS NULL AND "bar" IS NULL OR "baz" IS NULL AND "bat" IS NULL', + 'parameters' => [], + ], + ], + ], + [ + 'sqlObject' => function () { + $select = $this->select()->from('x'); + $select->where->like('bar', 'Foo%'); + return $this->predicate_PredicateSet([ + $this->predicate_PredicateSet([ + $this->predicate_In('x', $select) + ]) + ]); + }, + 'expected' => [ + 'sql92' => [ + 'string' => '("x" IN (SELECT "x".* FROM "x" WHERE "bar" LIKE \'Foo%\'))', + 'prepare' => '("x" IN (SELECT "x".* FROM "x" WHERE "bar" LIKE ?))', + 'parameters' => [ + 'subselect1expr1' => 'Foo%', + ], + ], + ], + ], + [ + 'sqlObject' => $this->predicate_PredicateSet([ + $this->predicate_PredicateSet([ + $this->predicate_Expression('x = ?', 5) + ]) + ]), + 'expected' => [ + 'sql92' => [ + 'string' => "(x = '5')", + 'prepare' => '(x = ?)', + 'parameters' => [ + 'expr1' => 5, + ], + ], + ], + ], + ]); + } +} diff --git a/test/Sql/Builder/SelectBuilderTest.php b/test/Sql/Builder/SelectBuilderTest.php new file mode 100644 index 0000000000..0d447aad01 --- /dev/null +++ b/test/Sql/Builder/SelectBuilderTest.php @@ -0,0 +1,1078 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider( + $this->dataProvider_Columns(), + $this->dataProvider_Combine(), + $this->dataProvider_GroupBy(), + $this->dataProvider_Having(), + $this->dataProvider_Join(), + $this->dataProvider_LimitOffset(), + $this->dataProvider_Order(), + $this->dataProvider_Quantitifier(), + $this->dataProvider_SubSelects(), + $this->dataProvider_Table(), + $this->dataProvider_Where() + ); + } + + public function dataProvider_Columns() + { + return [ + [ // columns + 'sqlObject' => $this->select()->from('foo')->columns(['bar', 'baz']), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo"."bar" AS "bar", "foo"."baz" AS "baz" FROM "foo"', + 'prepare' => true, + ], + ], + ], + [ // columns with AS associative array + 'sqlObject' => $this->select()->from('foo')->columns(['bar' => 'baz']), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo"."baz" AS "bar" FROM "foo"', + 'prepare' => true, + ], + ], + ], + [ // columns with AS associative array mixed + 'sqlObject' => $this->select()->from('foo')->columns(['bar' => 'baz', 'bam']), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo"."baz" AS "bar", "foo"."bam" AS "bam" FROM "foo"', + 'prepare' => true, + ], + ], + ], + [ // columns where value is Expression, with AS + 'sqlObject' => $this->select()->from('foo')->columns(['bar' => new Expression('COUNT(some_column)')]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT COUNT(some_column) AS "bar" FROM "foo"', + 'prepare' => true, + ], + ], + ], + [ + 'sqlObject' => $this->select() + ->from('foo') + ->columns( + [ + 'bar' => new Expression( + '(COUNT(?) + ?)', + [ + ['some_column', Expression::TYPE_IDENTIFIER], + [5, Expression::TYPE_VALUE], + ] + ) + ] + ), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT (COUNT("some_column") + \'5\') AS "bar" FROM "foo"', + 'prepare' => 'SELECT (COUNT("some_column") + ?) AS "bar" FROM "foo"', + ], + ], + ], + [ + 'sqlObject' => $this->select()->from(['x' => 'foo'])->columns(['bar' => 'foo.bar'])->setPrefixColumnsWithTable(false), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo"."bar" AS "bar" FROM "foo" AS "x"', + 'prepare' => 'SELECT "foo"."bar" AS "bar" FROM "foo" AS "x"', + ], + ], + ], + [ // @author robertbasic // @link https://github.com/zendframework/zf2/pull/2714 + 'sqlObject' => $this->select()->from('foo')->columns(['bar'])->setPrefixColumnsWithTable(false), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "bar" AS "bar" FROM "foo"', + 'prepare' => true, + ], + ], + ], + [ + 'sqlObject' => $this->select('table')->columns(['*']), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "table".* FROM "table"', + ], + ], + ], + ]; + } + + public function dataProvider_Combine() + { + return [ + [ + 'sqlObject' => $this->select() + ->from('foo') + ->where('a = b') + ->combine( + $this->select()->from('bar')->where('c = d'), + Combine::COMBINE_UNION, + 'ALL' + ), + 'expected' => [ + 'sql92' => [ + 'string' => '(SELECT "foo".* FROM "foo" WHERE a = b) UNION ALL (SELECT "bar".* FROM "bar" WHERE c = d)', + 'prepare' => true, + ], + ], + ], + [ // combine and union with order at the end + 'sqlObject' => $this->select() + ->from([ + 'sub' => $this->select() + ->from('foo') + ->where('a = b') + ->combine( + $this->select()->from('bar')->where('c = d') + ) + ]) + ->order('id DESC'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "sub".* FROM ((SELECT "foo".* FROM "foo" WHERE a = b) UNION (SELECT "bar".* FROM "bar" WHERE c = d)) AS "sub" ORDER BY "id" DESC', + 'prepare' => true, + ], + ], + ], + [ // Combine + 'sqlObject' => $this->select() + ->from(['foo'=>$this->combine($this->select('bar0'))]) + ->columns(['c1'=>$this->combine($this->select('bar1'))]) + ->where(['c2'=>$this->combine($this->select('bar2'))]) + ->join(['c3'=>$this->combine($this->select('bar3'))], 'xx=yy'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT ((SELECT "bar1".* FROM "bar1")) AS "c1", "c3".* FROM ((SELECT "bar0".* FROM "bar0")) AS "foo" INNER JOIN ((SELECT "bar3".* FROM "bar3")) AS "c3" ON "xx"="yy" WHERE "c2" = ((SELECT "bar2".* FROM "bar2"))', + ], + ], + ], + ]; + } + + public function dataProvider_GroupBy() + { + return [ + [ // group + 'sqlObject' => $this->select()->from('foo')->group(['col1', 'col2']), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" GROUP BY "col1", "col2"', + 'prepare' => true, + ], + ], + ], + [ // group + 'sqlObject' => $this->select()->from('foo')->group('col1')->group('col2'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" GROUP BY "col1", "col2"', + 'prepare' => true, + ], + ], + ], + [ // group + 'sqlObject' => $this->select()->from('foo')->group(new Expression('DAY(?)', [['col1', Expression::TYPE_IDENTIFIER]])), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" GROUP BY DAY("col1")', + 'prepare' => true, + ], + ], + ], + [ // group with compound name + 'sqlObject' => $this->select()->from('foo')->group('c1.d2'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" GROUP BY "c1"."d2"', + 'prepare' => true, + ], + ], + ], + ]; + } + + public function dataProvider_Having() + { + return [ + [ // having (simple string) + 'sqlObject' => $this->select()->from('foo')->having('x = 5'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" HAVING x = 5', + 'prepare' => true, + ], + ], + ], + [ // having (returning parameters) + 'sqlObject' => $this->select()->from('foo')->having(['x = ?' => 5]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" HAVING x = \'5\'', + 'prepare' => 'SELECT "foo".* FROM "foo" HAVING x = ?', + 'parameters' => ['expr1' => 5], + ], + ], + ], + ]; + } + + public function dataProvider_Join() + { + return [ + [ // joins (plain) + 'sqlObject' => $this->select()->from('foo')->join('zac', 'm = n'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "zac".* FROM "foo" INNER JOIN "zac" ON "m" = "n"', + 'prepare' => true, + ], + ], + ], + [ // join with columns + 'sqlObject' => $this->select()->from('foo')->join('zac', 'm = n', ['bar', 'baz']), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "zac"."bar" AS "bar", "zac"."baz" AS "baz" FROM "foo" INNER JOIN "zac" ON "m" = "n"', + 'prepare' => true, + ], + ], + ], + [ // join with alternate type + 'sqlObject' => $this->select()->from('foo')->join('zac', 'm = n', ['bar', 'baz'], Joins::JOIN_OUTER), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "zac"."bar" AS "bar", "zac"."baz" AS "baz" FROM "foo" OUTER JOIN "zac" ON "m" = "n"', + 'prepare' => true, + ], + ], + ], + [ // join with column aliases + 'sqlObject' => $this->select()->from('foo')->join('zac', 'm = n', ['BAR' => 'bar', 'BAZ' => 'baz']), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "zac"."bar" AS "BAR", "zac"."baz" AS "BAZ" FROM "foo" INNER JOIN "zac" ON "m" = "n"', + 'prepare' => true, + ], + ], + ], + [ // join with table aliases + 'sqlObject' => $this->select()->from('foo')->join(['b' => 'bar'], 'b.foo_id = foo.foo_id'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "b".* FROM "foo" INNER JOIN "bar" AS "b" ON "b"."foo_id" = "foo"."foo_id"', + 'prepare' => true, + ], + ], + ], + [ // joins with a few keywords in the on clause + 'sqlObject' => $this->select()->from('foo')->join('zac', '(m = n AND c.x) BETWEEN x AND y.z OR (c.x < y.z AND c.x <= y.z AND c.x > y.z AND c.x >= y.z)'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "zac".* FROM "foo" INNER JOIN "zac" ON ("m" = "n" AND "c"."x") BETWEEN "x" AND "y"."z" OR ("c"."x" < "y"."z" AND "c"."x" <= "y"."z" AND "c"."x" > "y"."z" AND "c"."x" >= "y"."z")', + 'prepare' => true, + ], + ], + ], + [ // join with expression in ON part + 'sqlObject' => $this->select()->from('foo')->join('zac', new Expression('(m = n AND c.x) BETWEEN x AND y.z')), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "zac".* FROM "foo" INNER JOIN "zac" ON (m = n AND c.x) BETWEEN x AND y.z', + 'prepare' => true, + ], + ], + ], + [ // join with Expression object in COLUMNS part (ZF2-514) // @co-author Koen Pieters (kpieters) + 'sqlObject' => $this->select()->from('foo')->columns([])->join('bar', 'm = n', ['thecount' => new Expression("COUNT(*)")]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT COUNT(*) AS "thecount" FROM "foo" INNER JOIN "bar" ON "m" = "n"', + 'prepare' => true, + ], + ], + ], + [ // multiple joins with expressions // reported by @jdolieslager + 'sqlObject' => $this->select() + ->from('foo') + ->join('tableA', new Predicate\Operator('id', '=', 1)) + ->join('tableB', new Predicate\Operator('id', '=', 2)) + ->join('tableC', new Predicate\PredicateSet([ + new Predicate\Operator('id', '=', 3), + new Predicate\Operator('number', '>', 20) + ])), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "tableA".*, "tableB".*, "tableC".* FROM "foo" ' + . 'INNER JOIN "tableA" ON "id" = \'1\' INNER JOIN "tableB" ON "id" = \'2\' ' + . 'INNER JOIN "tableC" ON "id" = \'3\' AND "number" > \'20\'', + 'prepare' => 'SELECT "foo".*, "tableA".*, "tableB".*, "tableC".* FROM "foo"' + . ' INNER JOIN "tableA" ON "id" = :expr1 INNER JOIN "tableB" ON "id" = :expr2 ' + . 'INNER JOIN "tableC" ON "id" = :expr3 AND "number" > :expr4', + 'useNamedParams' => true, + ], + ], + ], + [ //Expression as joinName + 'sqlObject' => $this->select() + ->from(new TableIdentifier('foo')) + ->join(['bar' => new Expression('psql_function_which_returns_table')], 'foo.id = bar.fooid'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "bar".* FROM "foo" INNER JOIN psql_function_which_returns_table AS "bar" ON "foo"."id" = "bar"."fooid"', + 'prepare' => true, + ], + ], + ], + [ // @author Andrzej Lewandowski @link https://github.com/zendframework/zf2/issues/7222 + 'sqlObject' => $this->select()->from('foo')->join('zac', '(catalog_category_website.category_id = catalog_category.category_id)'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "zac".* FROM "foo" INNER JOIN "zac" ON ("catalog_category_website"."category_id" = "catalog_category"."category_id")', + 'prepare' => true, + ], + ], + ], + 'Select::processJoin()' => [ + 'sqlObject' => $this->select('a')->join(['b'=>$this->select('c')->where(['cc'=>10])], 'd=e')->where(['x'=>20]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "a".*, "b".* FROM "a" INNER JOIN (SELECT "c".* FROM "c" WHERE "cc" = \'10\') AS "b" ON "d"="e" WHERE "x" = \'20\'', + 'prepare' => 'SELECT "a".*, "b".* FROM "a" INNER JOIN (SELECT "c".* FROM "c" WHERE "cc" = ?) AS "b" ON "d"="e" WHERE "x" = ?', + 'parameters' => ['subselect1expr1'=>10, 'expr1'=>20], + ], + 'MySql' => [ + 'string' => 'SELECT `a`.*, `b`.* FROM `a` INNER JOIN (SELECT `c`.* FROM `c` WHERE `cc` = \'10\') AS `b` ON `d`=`e` WHERE `x` = \'20\'', + 'prepare' => 'SELECT `a`.*, `b`.* FROM `a` INNER JOIN (SELECT `c`.* FROM `c` WHERE `cc` = ?) AS `b` ON `d`=`e` WHERE `x` = ?', + 'parameters' => ['subselect1expr1'=>10, 'expr1'=>20], + ], + 'Oracle' => [ + 'string' => 'SELECT "a".*, "b".* FROM "a" INNER JOIN (SELECT "c".* FROM "c" WHERE "cc" = \'10\') "b" ON "d"="e" WHERE "x" = \'20\'', + 'prepare' => 'SELECT "a".*, "b".* FROM "a" INNER JOIN (SELECT "c".* FROM "c" WHERE "cc" = ?) "b" ON "d"="e" WHERE "x" = ?', + 'parameters' => ['subselect1expr1'=>10, 'expr1'=>20], + ], + 'SqlServer' => [ + 'string' => 'SELECT [a].*, [b].* FROM [a] INNER JOIN (SELECT [c].* FROM [c] WHERE [cc] = \'10\') AS [b] ON [d]=[e] WHERE [x] = \'20\'', + 'prepare' => 'SELECT [a].*, [b].* FROM [a] INNER JOIN (SELECT [c].* FROM [c] WHERE [cc] = ?) AS [b] ON [d]=[e] WHERE [x] = ?', + 'parameters' => ['subselect1expr1'=>10, 'expr1'=>20], + ], + ], + ], + // Github issue https://github.com/zendframework/zend-db/issues/98 + 'Select::processJoinNoJoinedColumns()' => [ + 'sqlObject' => $this->select('my_table') + ->join('joined_table2', 'my_table.id = joined_table2.id', $columns=[]) + ->join('joined_table3', 'my_table.id = joined_table3.id', [\Zend\Db\Sql\Select::SQL_STAR]) + ->columns([ + 'my_table_column', + 'aliased_column' => new \Zend\Db\Sql\Expression('NOW()') + ]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "my_table"."my_table_column" AS "my_table_column", NOW() AS "aliased_column", "joined_table3".* FROM "my_table" INNER JOIN "joined_table2" ON "my_table"."id" = "joined_table2"."id" INNER JOIN "joined_table3" ON "my_table"."id" = "joined_table3"."id"', + ], + 'MySql' => [ + 'string' => 'SELECT `my_table`.`my_table_column` AS `my_table_column`, NOW() AS `aliased_column`, `joined_table3`.* FROM `my_table` INNER JOIN `joined_table2` ON `my_table`.`id` = `joined_table2`.`id` INNER JOIN `joined_table3` ON `my_table`.`id` = `joined_table3`.`id`', + ], + 'Oracle' => [ + 'string' => 'SELECT "my_table"."my_table_column" AS "my_table_column", NOW() AS "aliased_column", "joined_table3".* FROM "my_table" INNER JOIN "joined_table2" ON "my_table"."id" = "joined_table2"."id" INNER JOIN "joined_table3" ON "my_table"."id" = "joined_table3"."id"', + ], + 'SqlServer' => [ + 'string' => 'SELECT [my_table].[my_table_column] AS [my_table_column], NOW() AS [aliased_column], [joined_table3].* FROM [my_table] INNER JOIN [joined_table2] ON [my_table].[id] = [joined_table2].[id] INNER JOIN [joined_table3] ON [my_table].[id] = [joined_table3].[id]', + ] + ] + ], + ]; + } + + public function dataProvider_LimitOffset() + { + return [ + 'Offset0' => [ + 'sqlObject' => $this->select('foo')->offset(0), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" OFFSET \'0\'', + 'prepare' => 'SELECT "foo".* FROM "foo" OFFSET ?', + 'parameters' => ['offset' => 0], + ], + 'MySql' => [ + 'string' => 'SELECT `foo`.* FROM `foo` LIMIT 18446744073709551615 OFFSET 0', + 'prepare' => 'SELECT `foo`.* FROM `foo` LIMIT 18446744073709551615 OFFSET ?', + 'parameters' => ['offset' => 0], + ], + 'IbmDb2' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > \'0\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ?', + 'parameters' => ['offset' => 0], + ], + 'Oracle' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > \'0\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ?', + 'parameters' => ['offset' => 0], + ], + 'SqlServer' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > \'0\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > ?', + 'parameters' => ['offset' => 0], + ], + ], + ], + 'Limit0' => [ + 'sqlObject' => $this->select()->from('foo')->limit(0), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" LIMIT \'0\'', + 'prepare' => 'SELECT "foo".* FROM "foo" LIMIT ?', + 'parameters' => ['limit' => 0], + ], + 'MySql' => [ + 'string' => 'SELECT `foo`.* FROM `foo` LIMIT 0', + 'prepare' => 'SELECT `foo`.* FROM `foo` LIMIT ?', + 'parameters' => ['limit' => 0], + ], + 'IbmDb2' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= \'0\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= ?', + 'parameters' => ['limit' => 0], + ], + 'Oracle' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= \'0\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= ?', + 'parameters' => ['limit' => 0], + ], + 'SqlServer' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] <= \'0\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] <= ?', + 'parameters' => ['limit' => 0], + ], + ], + ], + 'Offset10' => [ + 'sqlObject' => $this->select('foo')->offset(10), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" OFFSET \'10\'', + 'prepare' => 'SELECT "foo".* FROM "foo" OFFSET ?', + 'parameters' => ['offset' => 10], + ], + 'MySql' => [ + 'string' => 'SELECT `foo`.* FROM `foo` LIMIT 18446744073709551615 OFFSET 10', + 'prepare' => 'SELECT `foo`.* FROM `foo` LIMIT 18446744073709551615 OFFSET ?', + 'parameters' => ['offset' => 10], + ], + 'IbmDb2' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > \'10\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ?', + 'parameters' => ['offset' => 10], + ], + 'Oracle' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > \'10\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ?', + 'parameters' => ['offset' => 10], + ], + 'SqlServer' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > \'10\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > ?', + 'parameters' => ['offset' => 10], + ], + ], + ], + 'Offset10_Limit0' => [ + 'sqlObject' => $this->select('foo')->offset(10)->limit(0), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" LIMIT \'0\' OFFSET \'10\'', + 'prepare' => 'SELECT "foo".* FROM "foo" LIMIT ? OFFSET ?', + 'parameters' => ['limit' => 0, 'offset' => 10], + ], + 'MySql' => [ + 'string' => 'SELECT `foo`.* FROM `foo` LIMIT 0 OFFSET 10', + 'prepare' => 'SELECT `foo`.* FROM `foo` LIMIT ? OFFSET ?', + 'parameters' => ['limit' => 0, 'offset' => 10], + ], + 'IbmDb2' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > \'10\' AND "LIMIT_OFFSET_ROWNUM" <= \'0\' + \'10\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ? AND "LIMIT_OFFSET_ROWNUM" <= ? + ?', + 'parameters' => ['offset' => 10, 'limit' => 0, 'offsetForSum' => 10], + ], + 'Oracle' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > \'10\' AND "LIMIT_OFFSET_ROWNUM" <= \'0\' + \'10\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ? AND "LIMIT_OFFSET_ROWNUM" <= ? + ?', + 'parameters' => ['offset' => 10, 'limit' => 0, 'offsetForSum' => 10], + ], + 'SqlServer' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > \'10\' AND [LIMIT_OFFSET_ROWNUM] <= \'0\' + \'10\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > ? AND [LIMIT_OFFSET_ROWNUM] <= ? + ?', + 'parameters' => ['offset' => 10, 'limit' => 0, 'offsetForSum' => 10], + ], + ], + ], + 'Limit10' => [ + 'sqlObject' => $this->select()->from('foo')->limit(10), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" LIMIT \'10\'', + 'prepare' => 'SELECT "foo".* FROM "foo" LIMIT ?', + 'parameters' => ['limit' => 10], + ], + 'MySql' => [ + 'string' => 'SELECT `foo`.* FROM `foo` LIMIT 10', + 'prepare' => 'SELECT `foo`.* FROM `foo` LIMIT ?', + 'parameters' => ['limit' => 10], + ], + 'IbmDb2' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= \'10\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= ?', + 'parameters' => ['limit' => 10], + ], + 'Oracle' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= \'10\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= ?', + 'parameters' => ['limit' => 10], + ], + 'SqlServer' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] <= \'10\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] <= ?', + 'parameters' => ['limit' => 10], + ], + ], + ], + 'Limit10_Offset0' => [ + 'sqlObject' => $this->select('foo')->offset(0)->limit(10), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" LIMIT \'10\' OFFSET \'0\'', + 'prepare' => 'SELECT "foo".* FROM "foo" LIMIT ? OFFSET ?', + 'parameters' => ['limit' => 10, 'offset' => 0], + ], + 'MySql' => [ + 'string' => 'SELECT `foo`.* FROM `foo` LIMIT 10 OFFSET 0', + 'prepare' => 'SELECT `foo`.* FROM `foo` LIMIT ? OFFSET ?', + 'parameters' => ['limit' => 10, 'offset' => 0], + ], + 'IbmDb2' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > \'0\' AND "LIMIT_OFFSET_ROWNUM" <= \'10\' + \'0\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ? AND "LIMIT_OFFSET_ROWNUM" <= ? + ?', + 'parameters' => ['offset' => 0, 'limit' => 10, 'offsetForSum' => 0], + ], + 'Oracle' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > \'0\' AND "LIMIT_OFFSET_ROWNUM" <= \'10\' + \'0\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ? AND "LIMIT_OFFSET_ROWNUM" <= ? + ?', + 'parameters' => ['offset' => 0, 'limit' => 10, 'offsetForSum' => 0], + ], + 'SqlServer' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > \'0\' AND [LIMIT_OFFSET_ROWNUM] <= \'10\' + \'0\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > ? AND [LIMIT_OFFSET_ROWNUM] <= ? + ?', + 'parameters' => ['offset' => 0, 'limit' => 10, 'offsetForSum' => 0], + ], + ], + ], + 'Limit10_Offset5' => [ + 'sqlObject' => $this->select('foo')->offset(5)->limit(10), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" LIMIT \'10\' OFFSET \'5\'', + 'prepare' => 'SELECT "foo".* FROM "foo" LIMIT ? OFFSET ?', + 'parameters' => ['limit' => 10, 'offset' => 5], + ], + 'MySql' => [ + 'string' => 'SELECT `foo`.* FROM `foo` LIMIT 10 OFFSET 5', + 'prepare' => 'SELECT `foo`.* FROM `foo` LIMIT ? OFFSET ?', + 'parameters' => ['limit' => 10, 'offset' => 5], + ], + 'IbmDb2' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > \'5\' AND "LIMIT_OFFSET_ROWNUM" <= \'10\' + \'5\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ? AND "LIMIT_OFFSET_ROWNUM" <= ? + ?', + 'parameters' => ['offset' => 5, 'limit' => 10, 'offsetForSum' => 5], + ], + 'Oracle' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > \'5\' AND "LIMIT_OFFSET_ROWNUM" <= \'10\' + \'5\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ? AND "LIMIT_OFFSET_ROWNUM" <= ? + ?', + 'parameters' => ['offset' => 5, 'limit' => 10, 'offsetForSum' => 5], + ], + 'SqlServer' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > \'5\' AND [LIMIT_OFFSET_ROWNUM] <= \'10\' + \'5\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > ? AND [LIMIT_OFFSET_ROWNUM] <= ? + ?', + 'parameters' => ['offset' => 5, 'limit' => 10, 'offsetForSum' => 5], + ], + ], + ], + //================================================================== + 'Limit10_Offset5_WithStringValues' => [ + 'sqlObject' => $this->select()->from('foo')->limit("5")->offset("10"), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" LIMIT \'5\' OFFSET \'10\'', + 'prepare' => 'SELECT "foo".* FROM "foo" LIMIT ? OFFSET ?', + 'parametersEquals' => ['limit' => 5, 'offset' => 10], + ], + ], + ], + 'Limit10_Offset5_WithBigStringValues' => [ // limit with big offset and limit + 'sqlObject' => $this->select()->from('foo')->limit("10000000000000000000")->offset("10000000000000000000"), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" LIMIT \'10000000000000000000\' OFFSET \'10000000000000000000\'', + 'prepare' => 'SELECT "foo".* FROM "foo" LIMIT ? OFFSET ?', + 'parametersEquals' => ['limit' => 10000000000000000000, 'offset' => 10000000000000000000], + ], + 'Mysql' => [ + 'string' => 'SELECT `foo`.* FROM `foo` LIMIT 10000000000000000000 OFFSET 10000000000000000000', + 'prepare' => 'SELECT `foo`.* FROM `foo` LIMIT ? OFFSET ?', + 'parameters' => ['limit' => '10000000000000000000', 'offset' => '10000000000000000000'], + ], + /* TODO + 'IbmDb2' => array( + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > 5 AND "LIMIT_OFFSET_ROWNUM" <= 10 + 5', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ? AND "LIMIT_OFFSET_ROWNUM" <= ? + ?', + 'parameters' => array('offset' => 5, 'limit' => 10, 'offsetForSum' => 5), + ), + 'Oracle' => array( + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > 5 AND "LIMIT_OFFSET_ROWNUM" <= 10 + 5', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo") "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" > ? AND "LIMIT_OFFSET_ROWNUM" <= ? + ?', + 'parameters' => array('offset' => 5, 'limit' => 10, 'offsetForSum' => 5), + ), + 'SqlServer' => array( + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > 5 AND [LIMIT_OFFSET_ROWNUM] <= 10 + 5', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo]) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] > ? AND [LIMIT_OFFSET_ROWNUM] <= ? + ?', + 'parameters' => array('offset' => 5, 'limit' => 10, 'offsetForSum' => 5), + ),*/ + ], + ], + 'LimitOffset_ParametersOrder' => [ + 'sqlObject' => $this->select()->from('foo')->where(['x' => 7])->limit(5), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" WHERE "x" = \'7\' LIMIT \'5\'', + 'prepare' => 'SELECT "foo".* FROM "foo" WHERE "x" = ? LIMIT ?', + //TODO 'parameters' => array('subselect2expr1' => 7, 'limit' => 5), + ], + 'MySql' => [ + 'string' => 'SELECT `foo`.* FROM `foo` WHERE `x` = \'7\' LIMIT 5', + 'prepare' => 'SELECT `foo`.* FROM `foo` WHERE `x` = ? LIMIT ?', + //TODO 'parameters' => array('subselect2expr1' => 7, 'limit' => 5), + ], + 'IbmDb2' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo" WHERE "x" = \'7\') "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= \'5\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo" WHERE "x" = ?) "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= ?', + 'parameters' => ['subselect2expr1' => 7, 'limit' => 5], + ], + 'Oracle' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo" WHERE "x" = \'7\') "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= \'5\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS "LIMIT_OFFSET_ROWNUM" FROM (SELECT "foo".* FROM "foo" WHERE "x" = ?) "LIMIT_OFFSET_WRAP_1") "LIMIT_OFFSET_WRAP_2" WHERE "LIMIT_OFFSET_ROWNUM" <= ?', + 'parameters' => ['subselect2expr1' => 7, 'limit' => 5], + ], + 'SqlServer' => [ + 'string' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo] WHERE [x] = \'7\') AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] <= \'5\'', + 'prepare' => 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER () AS [LIMIT_OFFSET_ROWNUM] FROM (SELECT [foo].* FROM [foo] WHERE [x] = ?) AS [LIMIT_OFFSET_WRAP_1]) AS [LIMIT_OFFSET_WRAP_2] WHERE [LIMIT_OFFSET_ROWNUM] <= ?', + 'parameters' => ['subselect2expr1' => 7, 'limit' => 5], + ], + ], + ], + ]; + } + + public function dataProvider_Order() + { + return [ + [ // order + 'sqlObject' => $this->select()->from('foo')->order('c1'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" ORDER BY "c1" ASC', + 'prepare' => true, + ], + ], + ], + [ // order + 'sqlObject' => $this->select()->from('foo')->order(['c1', 'c2']), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" ORDER BY "c1" ASC, "c2" ASC', + 'prepare' => true, + ], + ], + ], + [ // order - notice partially lower case ASC + 'sqlObject' => $this->select()->from('foo')->order(['c1' => 'DESC', 'c2' => 'Asc']), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" ORDER BY "c1" DESC, "c2" ASC', + 'prepare' => true, + ], + ], + ], + [ // order + 'sqlObject' => $this->select()->from('foo')->order(['c1' => 'asc'])->order('c2 desc'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" ORDER BY "c1" ASC, "c2" DESC', + 'prepare' => true, + ], + ], + ], + [ // order with compound name + 'sqlObject' => $this->select()->from('foo')->order('c1.d2'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" ORDER BY "c1"."d2" ASC', + 'prepare' => true, + ], + ], + ], + [ // @author Demian Katz + 'sqlObject' => $this->select() + ->from('table') + ->order([ + new Expression('isnull(?) DESC', [['name', Expression::TYPE_IDENTIFIER]]), + 'name' + ]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "table".* FROM "table" ORDER BY isnull("name") DESC, "name" ASC', + 'prepare' => 'SELECT "table".* FROM "table" ORDER BY isnull("name") DESC, "name" ASC', + ], + ], + ], + ]; + } + + public function dataProvider_Quantitifier() + { + return [ + [ + 'sqlObject' => $this->select()->from('foo')->quantifier(Select::QUANTIFIER_DISTINCT), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT DISTINCT "foo".* FROM "foo"', + 'prepare' => true, + ], + ], + ], + [ + 'sqlObject' => $this->select()->from('foo')->quantifier(new Expression('TOP ?', [10])), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT TOP \'10\' "foo".* FROM "foo"', + 'prepare' => 'SELECT TOP ? "foo".* FROM "foo"', + ], + ], + ], + ]; + } + + public function dataProvider_SubSelects() + { + return [ + [ + 'sqlObject' => $this->select(['b' => $this->select(['a' => $this->select('test')])]), + 'expected' => [ + 'Oracle' => [ + 'string' => 'SELECT "b".* FROM (SELECT "a".* FROM (SELECT "test".* FROM "test") "a") "b"', + 'prepare' => true, + 'parameters' => [], + ], + ], + ], + [ // subselect in join + 'sqlObject' => function () { + $subselect = $this->select(); + $subselect->from('bar')->where->like('y', '%Foo%'); + return $this->select() + ->from('foo') + ->join( + ['z' => $subselect], + 'z.foo = bar.id' + ); + }, + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "z".* FROM "foo" INNER JOIN (SELECT "bar".* FROM "bar" WHERE "y" LIKE \'%Foo%\') AS "z" ON "z"."foo" = "bar"."id"', + 'prepare' => 'SELECT "foo".*, "z".* FROM "foo" INNER JOIN (SELECT "bar".* FROM "bar" WHERE "y" LIKE ?) AS "z" ON "z"."foo" = "bar"."id"', + ], + ], + ], + 'Select::processSubSelect()' => [ + 'sqlObject' => $this->select(['a' => $this->select(['b' => $this->select('c')->where(['cc'=>'CC'])])->where(['bb'=>'BB'])])->where(['aa'=>'AA']), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "a".* FROM (SELECT "b".* FROM (SELECT "c".* FROM "c" WHERE "cc" = \'CC\') AS "b" WHERE "bb" = \'BB\') AS "a" WHERE "aa" = \'AA\'', + 'prepare' => 'SELECT "a".* FROM (SELECT "b".* FROM (SELECT "c".* FROM "c" WHERE "cc" = ?) AS "b" WHERE "bb" = ?) AS "a" WHERE "aa" = ?', + 'parameters' => ['subselect2expr1' => 'CC', 'subselect1expr1' => 'BB', 'expr1' => 'AA'], + ], + 'MySql' => [ + 'string' => 'SELECT `a`.* FROM (SELECT `b`.* FROM (SELECT `c`.* FROM `c` WHERE `cc` = \'CC\') AS `b` WHERE `bb` = \'BB\') AS `a` WHERE `aa` = \'AA\'', + 'prepare' => 'SELECT `a`.* FROM (SELECT `b`.* FROM (SELECT `c`.* FROM `c` WHERE `cc` = ?) AS `b` WHERE `bb` = ?) AS `a` WHERE `aa` = ?', + 'parameters' => ['subselect2expr1' => 'CC', 'subselect1expr1' => 'BB', 'expr1' => 'AA'], + ], + 'Oracle' => [ + 'string' => 'SELECT "a".* FROM (SELECT "b".* FROM (SELECT "c".* FROM "c" WHERE "cc" = \'CC\') "b" WHERE "bb" = \'BB\') "a" WHERE "aa" = \'AA\'', + 'prepare' => 'SELECT "a".* FROM (SELECT "b".* FROM (SELECT "c".* FROM "c" WHERE "cc" = ?) "b" WHERE "bb" = ?) "a" WHERE "aa" = ?', + 'parameters' => ['subselect2expr1' => 'CC', 'subselect1expr1' => 'BB', 'expr1' => 'AA'], + ], + 'SqlServer' => [ + 'string' => 'SELECT [a].* FROM (SELECT [b].* FROM (SELECT [c].* FROM [c] WHERE [cc] = \'CC\') AS [b] WHERE [bb] = \'BB\') AS [a] WHERE [aa] = \'AA\'', + 'prepare' => 'SELECT [a].* FROM (SELECT [b].* FROM (SELECT [c].* FROM [c] WHERE [cc] = ?) AS [b] WHERE [bb] = ?) AS [a] WHERE [aa] = ?', + 'parameters' => ['subselect2expr1' => 'CC', 'subselect1expr1' => 'BB', 'expr1' => 'AA'], + ], + ], + ], + ]; + } + + public function dataProvider_Table() + { + return [ + 'without table' => [ + 'sqlObject' => $this->select() + ->columns([ + new Expression('SOME_DB_FUNCTION_ONE()'), + 'foo' => new Expression('SOME_DB_FUNCTION_TWO()'), + ]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT SOME_DB_FUNCTION_ONE() AS column1, SOME_DB_FUNCTION_TWO() AS "foo"', + 'prepare' => true, + ], + ], + ], + 'string table' => [ + 'sqlObject' => $this->select()->from('foo'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo"', + 'prepare' => true, + ], + 'SqlServer' => [ + 'string' => 'SELECT [foo].* FROM [foo]', + 'prepare' => true, + 'parameters' => [], + ], + ], + ], + 'string table with alias' => [ + 'sqlObject' => $this->select()->from(['x' => 'foo']), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "x".* FROM "foo" AS "x"', + 'prepare' => true, + ], + 'Oracle' => [ + 'string' => 'SELECT "x".* FROM "foo" "x"', + 'prepare' => true, + 'parameters' => [], + ], + ], + ], + 'string table with alias and schema' => [ + 'sqlObject' => $this->select()->from(['x' => ['bar', 'foo']]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "x".* FROM "bar"."foo" AS "x"', + 'prepare' => true, + ], + 'Oracle' => [ + 'string' => 'SELECT "x".* FROM "bar"."foo" "x"', + 'prepare' => true, + 'parameters' => [], + ], + ], + ], + 'table as TableIdentifier' => [ // table as TableIdentifier + 'sqlObject' => $this->select()->from(new TableIdentifier('foo', 'bar')), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "bar"."foo".* FROM "bar"."foo"', + 'prepare' => true, + ], + ], + ], + 'table with alias with table as TableIdentifier' => [ + 'sqlObject' => $this->select()->from(['f' => new TableIdentifier('foo')]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "f".* FROM "foo" AS "f"', + 'prepare' => true, + ], + ], + ], + [ // Test TableIdentifier In Joins @link https://github.com/zendframework/zf2/issues/3294 + 'sqlObject' => $this->select()->from('foo')->columns([])->join(new TableIdentifier('bar', 'baz'), 'm = n', ['thecount' => new Expression("COUNT(*)")]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT COUNT(*) AS "thecount" FROM "foo" INNER JOIN "baz"."bar" ON "m" = "n"', + 'prepare' => true, + ], + ], + ], + [ // Test TableIdentifier In Joins, with multiple joins @link https://github.com/zendframework/zf2/issues/3294 + 'sqlObject' => $this->select()->from('foo') + ->join(['a' => new TableIdentifier('another_foo', 'another_schema')], 'a.x = foo.foo_column') + ->join('bar', 'foo.colx = bar.colx'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "a".*, "bar".* FROM "foo"' + . ' INNER JOIN "another_schema"."another_foo" AS "a" ON "a"."x" = "foo"."foo_column"' + . ' INNER JOIN "bar" ON "foo"."colx" = "bar"."colx"', + 'prepare' => true, + ], + ], + ], + [ //testSelectUsingTableIdentifierWithEmptyScheme() + 'sqlObject' => $this->select() + ->from(new TableIdentifier('foo')) + ->join(new TableIdentifier('bar'), 'foo.id = bar.fooid'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".*, "bar".* FROM "foo" INNER JOIN "bar" ON "foo"."id" = "bar"."fooid"', + ], + ], + ], + ]; + } + + public function dataProvider_Where() + { + return [ + [ // Test generic predicate is appended with AND + 'sqlObject' => function () { + $select = $this->select(); + $select->from(new TableIdentifier('foo')) + ->where + ->nest + ->isNull('bar') + ->and + ->predicate(new Predicate\Literal('1=1')) + ->unnest; + return $select; + }, + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" WHERE ("bar" IS NULL AND 1=1)', + 'prepare' => true, + ], + ], + ], + [ // Test generic predicate is appended with OR + 'sqlObject' => function () { + $select = $this->select(); + $select->from(new TableIdentifier('foo')) + ->where + ->nest + ->isNull('bar') + ->or + ->predicate(new Predicate\Literal('1=1')) + ->unnest; + return $select; + }, + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" WHERE ("bar" IS NULL OR 1=1)', + 'prepare' => true, + ], + ], + ], + [ // where (simple string) + 'sqlObject' => $this->select()->from('foo')->where('x = 5'), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" WHERE x = 5', + 'prepare' => true, + ], + ], + ], + [ // where (returning parameters) + 'sqlObject' => $this->select()->from('foo')->where(['x = ?' => 5]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo" WHERE x = \'5\'', + 'prepare' => 'SELECT "foo".* FROM "foo" WHERE x = ?', + 'parameters' => ['expr1' => 5], + ], + ], + ], + [ + 'sqlObject' => function () { + $subselect = $this->select(); + $subselect->from('bar')->where->like('y', '%Foo%'); + return $this->select()->from(['x' => $subselect]); + }, + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "x".* FROM (SELECT "bar".* FROM "bar" WHERE "y" LIKE \'%Foo%\') AS "x"', + 'prepare' => 'SELECT "x".* FROM (SELECT "bar".* FROM "bar" WHERE "y" LIKE ?) AS "x"', + ], + ], + ], + [ + 'sqlObject' => $this->select('table') + ->where([ + 'c1' => null, + 'c2' => [1, 2, 3], + new \Zend\Db\Sql\Predicate\IsNotNull('c3') + ]), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "table".* FROM "table" WHERE "c1" IS NULL AND "c2" IN (\'1\', \'2\', \'3\') AND "c3" IS NOT NULL', + 'prepare' => 'SELECT "table".* FROM "table" WHERE "c1" IS NULL AND "c2" IN (?, ?, ?) AND "c3" IS NOT NULL', + ], + ], + ], + [ // empty parameters + 'sqlObject' => $this + ->select() + ->from('foo') + ->where($this->predicate_PredicateSet()), + 'expected' => [ + 'sql92' => [ + 'string' => 'SELECT "foo".* FROM "foo"', + 'prepare' => true, + ], + ], + ], + ]; + } +} diff --git a/test/Sql/Builder/UpdateBuilderTest.php b/test/Sql/Builder/UpdateBuilderTest.php new file mode 100644 index 0000000000..7ac9938424 --- /dev/null +++ b/test/Sql/Builder/UpdateBuilderTest.php @@ -0,0 +1,224 @@ +assertBuilder($sqlObject, $platform, $expected); + } + + public function dataProvider() + { + return $this->prepareDataProvider( + $this->dataProvider_Else(), + $this->dataProvider_Set(), + $this->dataProvider_SubSelectAndExpressions(), + $this->dataProvider_Table(), + $this->dataProvider_Where(), + $this->dataProvider_Joins() + ); + } + + public function dataProvider_Set() + { + return [ + [ + 'sqlObject' => $this->update() + ->table('foo') + ->set([ + 'bar' => 'baz', + 'boo' => new Expression('NOW()'), + 'bam' => null, + 'false' => false, + 'true' => true, + ]), + 'expected' => [ + 'sql92' => [ + 'string' => 'UPDATE "foo" SET "bar" = \'baz\', "boo" = NOW(), "bam" = NULL, "false" = \'\', "true" = \'1\'', + 'prepare' => 'UPDATE "foo" SET "bar" = ?, "boo" = NOW(), "bam" = ?, "false" = ?, "true" = ?', + 'parameters' => ['bar' => 'baz', 'bam' => null, 'false' => false, 'true' => true], + ], + ], + ], + ]; + } + + public function dataProvider_Table() + { + return [ + [ + 'sqlObject' => $this->update('foo')->set(['bar' => 'baz']), + 'expected' => [ + 'sql92' => [ + 'string' => 'UPDATE "foo" SET "bar" = \'baz\'', + 'prepare' => 'UPDATE "foo" SET "bar" = ?', + ], + ], + ], + [ + 'sqlObject' => $this->update(new TableIdentifier('foo', 'sch'))->set(['bar' => 'baz']), + 'expected' => [ + 'sql92' => [ + 'string' => 'UPDATE "sch"."foo" SET "bar" = \'baz\'', + 'prepare' => 'UPDATE "sch"."foo" SET "bar" = ?', + ], + ], + ], + ]; + } + + public function dataProvider_SubSelectAndExpressions() + { + return [ + [ + 'sqlObject' => $this->update('foo')->set(['x'=>$this->select('foo')]), + 'expected' => [ + 'sql92' => 'UPDATE "foo" SET "x" = (SELECT "foo".* FROM "foo")', + 'MySql' => 'UPDATE `foo` SET `x` = (SELECT `foo`.* FROM `foo`)', + 'Oracle' => 'UPDATE "foo" SET "x" = (SELECT "foo".* FROM "foo")', + 'SqlServer' => 'UPDATE [foo] SET [x] = (SELECT [foo].* FROM [foo])', + ], + ], + [ + 'sqlObject' => $this->update('foo')->set(['x'=>new Expression('?', [$this->select('foo')])]), + 'expected' => [ + 'sql92' => 'UPDATE "foo" SET "x" = (SELECT "foo".* FROM "foo")', + 'MySql' => 'UPDATE `foo` SET `x` = (SELECT `foo`.* FROM `foo`)', + 'Oracle' => 'UPDATE "foo" SET "x" = (SELECT "foo".* FROM "foo")', + 'SqlServer' => 'UPDATE [foo] SET [x] = (SELECT [foo].* FROM [foo])', + ], + ], + ]; + } + + public function dataProvider_Where() + { + return [ + [ + 'sqlObject' => $this->update('foo')->set(['bar' => 'baz'])->where(['x'=>'y']), + 'expected' => [ + 'sql92' => [ + 'string' => 'UPDATE "foo" SET "bar" = \'baz\' WHERE "x" = \'y\'', + 'prepare' => 'UPDATE "foo" SET "bar" = ? WHERE "x" = ?', + 'parameters' => ['bar' => 'baz', 'expr1' => 'y'], + ], + 'MySql' => [ + 'string' => 'UPDATE `foo` SET `bar` = \'baz\' WHERE `x` = \'y\'', + 'prepare' => 'UPDATE `foo` SET `bar` = ? WHERE `x` = ?', + 'parameters' => ['bar' => 'baz', 'expr1' => 'y'], + ], + 'Oracle' => [ + 'string' => 'UPDATE "foo" SET "bar" = \'baz\' WHERE "x" = \'y\'', + 'prepare' => 'UPDATE "foo" SET "bar" = ? WHERE "x" = ?', + 'parameters' => ['bar' => 'baz', 'expr1' => 'y'], + ], + 'SqlServer' => [ + 'string' => 'UPDATE [foo] SET [bar] = \'baz\' WHERE [x] = \'y\'', + 'prepare' => 'UPDATE [foo] SET [bar] = ? WHERE [x] = ?', + 'parameters' => ['bar' => 'baz', 'expr1' => 'y'], + ], + ], + ], + ]; + } + + public function dataProvider_Else() + { + return [ + 'clone' => [ // testCloneUpdate() + 'sqlObject' => function () { + $update1 = clone $this->update(); + $update1->table('foo') + ->set(['bar' => 'baz']) + ->where('x = y'); + + $update2 = clone $this->update(); + $update2->table('foo') + ->set(['bar' => 'baz']) + ->where([ + 'id = ?'=>1 + ]); + return $update2; + }, + 'expected' => [ + 'sql92' => [ + 'string' => 'UPDATE "foo" SET "bar" = \'baz\' WHERE id = \'1\'', + ], + ], + ], + ]; + } + + public function dataProvider_Joins() + { + return [ + 'Update::processJoins()_1' => [ + 'sqlObject' => $this->update('foo')->set(['x' => 'y'])->where(['xx' => 'yy'])->join( + 'bar', + 'bar.barId = foo.barId' + ), + 'expected' => [ + 'sql92' => [ + 'string' => 'UPDATE "foo" INNER JOIN "bar" ON "bar"."barId" = "foo"."barId" SET "x" = \'y\' WHERE "xx" = \'yy\'', + ], + 'MySql' => [ + 'string' => 'UPDATE `foo` INNER JOIN `bar` ON `bar`.`barId` = `foo`.`barId` SET `x` = \'y\' WHERE `xx` = \'yy\'', + ], + 'Oracle' => [ + 'string' => 'UPDATE "foo" INNER JOIN "bar" ON "bar"."barId" = "foo"."barId" SET "x" = \'y\' WHERE "xx" = \'yy\'', + ], + 'SqlServer' => [ + 'string' => 'UPDATE [foo] INNER JOIN [bar] ON [bar].[barId] = [foo].[barId] SET [x] = \'y\' WHERE [xx] = \'yy\'', + ], + ], + ], + 'Update::processJoins()_2' => [ + 'sqlObject' => $this->update('Document')->set(['x' => 'y']) + ->join( + 'User', // table name + 'User.UserId = Document.UserId' // expression to join on (will be quoted by platform object before insertion), + // default JOIN INNER + ) + ->join( + 'Category', + 'Category.CategoryId = Document.CategoryId', + Joins::JOIN_LEFT // (optional), one of inner, outer, left, right + ), + 'expected' => [ + 'sql92' => [ + 'string' => 'UPDATE "Document" INNER JOIN "User" ON "User"."UserId" = "Document"."UserId" LEFT JOIN "Category" ON "Category"."CategoryId" = "Document"."CategoryId" SET "x" = \'y\'', + ], + 'MySql' => [ + 'string' => 'UPDATE `Document` INNER JOIN `User` ON `User`.`UserId` = `Document`.`UserId` LEFT JOIN `Category` ON `Category`.`CategoryId` = `Document`.`CategoryId` SET `x` = \'y\'', + ], + 'Oracle' => [ + 'string' => 'UPDATE "Document" INNER JOIN "User" ON "User"."UserId" = "Document"."UserId" LEFT JOIN "Category" ON "Category"."CategoryId" = "Document"."CategoryId" SET "x" = \'y\'', + ], + 'SqlServer' => [ + 'string' => 'UPDATE [Document] INNER JOIN [User] ON [User].[UserId] = [Document].[UserId] LEFT JOIN [Category] ON [Category].[CategoryId] = [Document].[CategoryId] SET [x] = \'y\'', + ], + ], + ], + ]; + } +} diff --git a/test/Sql/CombineTest.php b/test/Sql/CombineTest.php index bc9fd0b156..c59e730459 100644 --- a/test/Sql/CombineTest.php +++ b/test/Sql/CombineTest.php @@ -9,11 +9,9 @@ namespace ZendTest\Db\Sql; -use Zend\Db\Adapter\ParameterContainer; use Zend\Db\Sql\Combine; use Zend\Db\Sql\Select; use Zend\Db\Sql\Predicate\Expression; -use Zend\Db\Adapter\StatementContainer; class CombineTest extends \PHPUnit_Framework_TestCase { @@ -31,93 +29,25 @@ protected function setUp() $this->combine = new Combine; } - public function testRejectsInvalidStatement() - { - $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException'); - - $this->combine->combine('foo'); - } - - public function testGetSqlString() - { - $this->combine - ->union(new Select('t1')) - ->intersect(new Select('t2')) - ->except(new Select('t3')) - ->union(new Select('t4')); - - $this->assertEquals( - '(SELECT "t1".* FROM "t1") INTERSECT (SELECT "t2".* FROM "t2") EXCEPT (SELECT "t3".* FROM "t3") UNION (SELECT "t4".* FROM "t4")', - $this->combine->getSqlString() - ); - } - - public function testGetSqlStringWithModifier() - { - $this->combine - ->union(new Select('t1')) - ->union(new Select('t2'), 'ALL'); - - $this->assertEquals( - '(SELECT "t1".* FROM "t1") UNION ALL (SELECT "t2".* FROM "t2")', - $this->combine->getSqlString() - ); - } - - public function testGetSqlStringFromArray() + public function testCloning() { - $this->combine->combine([ - [new Select('t1')], - [new Select('t2'), Combine::COMBINE_INTERSECT, 'ALL'], - [new Select('t3'), Combine::COMBINE_EXCEPT], - ]); - - $this->assertEquals( - '(SELECT "t1".* FROM "t1") INTERSECT ALL (SELECT "t2".* FROM "t2") EXCEPT (SELECT "t3".* FROM "t3")', - $this->combine->getSqlString() - ); - - $this->combine = new Combine(); - $this->combine->combine([ - new Select('t1'), - new Select('t2'), - new Select('t3'), - ]); + $select = new Select(); + $select->from('foo'); + $this->combine->combine($select); - $this->assertEquals( - '(SELECT "t1".* FROM "t1") UNION (SELECT "t2".* FROM "t2") UNION (SELECT "t3".* FROM "t3")', - $this->combine->getSqlString() - ); - } + $combine = clone $this->combine; + $selectCloned = $combine->combine[0]['select']; + $selectCloned->from('bar'); - public function testGetSqlStringEmpty() - { - $this->assertSame( - null, - $this->combine->getSqlString() - ); + $this->assertEquals('foo', $select->table->getSource()->getTable()); + $this->assertEquals('bar', $selectCloned->table->getSource()->getTable()); } - public function testPrepareStatementWithModifier() + public function testRejectsInvalidStatement() { - $select1 = new Select('t1'); - $select1->where(['x1'=>10]); - $select2 = new Select('t2'); - $select2->where(['x2'=>20]); - - $this->combine->combine([ - $select1, - $select2 - ]); - - $adapter = $this->getMockAdapter(); + $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException'); - $statement = $this->combine->prepareStatement($adapter, new StatementContainer); - $this->assertInstanceOf('Zend\Db\Adapter\StatementContainerInterface', $statement); - $this->assertEquals( - '(SELECT "t1".* FROM "t1" WHERE "x1" = ?) UNION (SELECT "t2".* FROM "t2" WHERE "x2" = ?)', - $statement->getSql() - ); + $this->combine->combine('foo'); } public function testAlignColumns() @@ -143,7 +73,7 @@ public function testAlignColumns() 'c1' => 'c1', 'c2' => new Expression('NULL'), ], - $select1->getRawState('columns') + $select1->columns ); $this->assertEquals( @@ -152,58 +82,7 @@ public function testAlignColumns() 'c1' => 'c1', 'c2' => 'c2', ], - $select2->getRawState('columns') - ); - } - - public function testGetRawState() - { - $select = new Select('t1'); - $this->combine->combine($select); - $this->assertSame( - [ - 'combine' => [ - [ - 'select' => $select, - 'type' => Combine::COMBINE_UNION, - 'modifier' => '' - ], - ], - 'columns' => [ - '0' => '*', - ], - ], - $this->combine->getRawState() + $select2->columns ); } - - /** - * - * @return \PHPUnit_Framework_MockObject_MockObject|\Zend\Db\Adapter\Adapter - */ - protected function getMockAdapter() - { - $parameterContainer = new ParameterContainer(); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer)); - - - $setGetSqlFunction = function ($sql = null) use ($mockStatement) { - static $sqlValue; - if ($sql) { - $sqlValue = $sql; - return $mockStatement; - } - return $sqlValue; - }; - $mockStatement->expects($this->any())->method('setSql')->will($this->returnCallback($setGetSqlFunction)); - $mockStatement->expects($this->any())->method('getSql')->will($this->returnCallback($setGetSqlFunction)); - - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue($mockStatement)); - - return $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - } } diff --git a/test/Sql/Ddl/AlterTableTest.php b/test/Sql/Ddl/AlterTableTest.php index 563b1972d9..e2b97d284c 100644 --- a/test/Sql/Ddl/AlterTableTest.php +++ b/test/Sql/Ddl/AlterTableTest.php @@ -10,8 +10,7 @@ namespace ZendTest\Db\Sql\Ddl; use Zend\Db\Sql\Ddl\AlterTable; -use Zend\Db\Sql\Ddl\Column; -use Zend\Db\Sql\Ddl\Constraint; +use Zend\Db\Sql\TableIdentifier; class AlterTableTest extends \PHPUnit_Framework_TestCase { @@ -21,9 +20,11 @@ class AlterTableTest extends \PHPUnit_Framework_TestCase public function testSetTable() { $at = new AlterTable(); - $this->assertEquals('', $at->getRawState('table')); - $this->assertSame($at, $at->setTable('test')); - $this->assertEquals('test', $at->getRawState('table')); + $this->assertEquals(null, $at->table); + + $this->assertSame(null, $at->setTable(null)->table); + $this->assertEquals('test', $at->setTable('test')->table->getTable()); + $this->assertEquals('test', $at->setTable(new TableIdentifier('test'))->table->getTable()); } /** @@ -35,7 +36,7 @@ public function testAddColumn() /** @var \Zend\Db\Sql\Ddl\Column\ColumnInterface $colMock */ $colMock = $this->getMock('Zend\Db\Sql\Ddl\Column\ColumnInterface'); $this->assertSame($at, $at->addColumn($colMock)); - $this->assertEquals([$colMock], $at->getRawState($at::ADD_COLUMNS)); + $this->assertEquals([$colMock], $at->addColumns); } /** @@ -47,7 +48,7 @@ public function testChangeColumn() /** @var \Zend\Db\Sql\Ddl\Column\ColumnInterface $colMock */ $colMock = $this->getMock('Zend\Db\Sql\Ddl\Column\ColumnInterface'); $this->assertSame($at, $at->changeColumn('newname', $colMock)); - $this->assertEquals(['newname' => $colMock], $at->getRawState($at::CHANGE_COLUMNS)); + $this->assertEquals(['newname' => $colMock], $at->changeColumns); } /** @@ -57,7 +58,7 @@ public function testDropColumn() { $at = new AlterTable(); $this->assertSame($at, $at->dropColumn('foo')); - $this->assertEquals(['foo'], $at->getRawState($at::DROP_COLUMNS)); + $this->assertEquals(['foo'], $at->dropColumns); } /** @@ -67,7 +68,7 @@ public function testDropConstraint() { $at = new AlterTable(); $this->assertSame($at, $at->dropConstraint('foo')); - $this->assertEquals(['foo'], $at->getRawState($at::DROP_CONSTRAINTS)); + $this->assertEquals(['foo'], $at->dropConstraints); } /** @@ -79,34 +80,6 @@ public function testAddConstraint() /** @var \Zend\Db\Sql\Ddl\Constraint\ConstraintInterface $conMock */ $conMock = $this->getMock('Zend\Db\Sql\Ddl\Constraint\ConstraintInterface'); $this->assertSame($at, $at->addConstraint($conMock)); - $this->assertEquals([$conMock], $at->getRawState($at::ADD_CONSTRAINTS)); - } - - /** - * @covers Zend\Db\Sql\Ddl\AlterTable::getSqlString - * @todo Implement testGetSqlString(). - */ - public function testGetSqlString() - { - $at = new AlterTable('foo'); - $at->addColumn(new Column\Varchar('another', 255)); - $at->changeColumn('name', new Column\Varchar('new_name', 50)); - $at->dropColumn('foo'); - $at->addConstraint(new Constraint\ForeignKey('my_fk', 'other_id', 'other_table', 'id', 'CASCADE', 'CASCADE')); - $at->dropConstraint('my_index'); - $expected =<<getSqlString(); - $this->assertEquals( - str_replace(["\r", "\n"], "", $expected), - str_replace(["\r", "\n"], "", $actual) - ); + $this->assertEquals([$conMock], $at->addConstraints); } } diff --git a/test/Sql/Ddl/Column/AbstractLengthColumnTest.php b/test/Sql/Ddl/Column/AbstractLengthColumnTest.php index 336b69ff40..e3573aee89 100644 --- a/test/Sql/Ddl/Column/AbstractLengthColumnTest.php +++ b/test/Sql/Ddl/Column/AbstractLengthColumnTest.php @@ -34,19 +34,4 @@ public function testGetLength() ]); $this->assertEquals(55, $column->getLength()); } - - /** - * @covers Zend\Db\Sql\Ddl\Column\AbstractLengthColumn::getExpressionData - */ - public function testGetExpressionData() - { - $column = $this->getMockForAbstractClass('Zend\Db\Sql\Ddl\Column\AbstractLengthColumn', [ - 'foo', 4 - ]); - - $this->assertEquals( - [['%s %s NOT NULL', ['foo', 'INTEGER(4)'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } } diff --git a/test/Sql/Ddl/Column/AbstractPrecisionColumnTest.php b/test/Sql/Ddl/Column/AbstractPrecisionColumnTest.php index 8b2d235155..bc6398758c 100644 --- a/test/Sql/Ddl/Column/AbstractPrecisionColumnTest.php +++ b/test/Sql/Ddl/Column/AbstractPrecisionColumnTest.php @@ -58,19 +58,4 @@ public function testGetDecimal() ]); $this->assertEquals(5, $column->getDecimal()); } - - /** - * @covers Zend\Db\Sql\Ddl\Column\AbstractPrecisionColumn::getExpressionData - */ - public function testGetExpressionData() - { - $column = $this->getMockForAbstractClass('Zend\Db\Sql\Ddl\Column\AbstractPrecisionColumn', [ - 'foo', 10, 5 - ]); - - $this->assertEquals( - [['%s %s NOT NULL', ['foo', 'INTEGER(10,5)'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } } diff --git a/test/Sql/Ddl/Column/BigIntegerTest.php b/test/Sql/Ddl/Column/BigIntegerTest.php index d2b2d8eb79..255e6f7930 100644 --- a/test/Sql/Ddl/Column/BigIntegerTest.php +++ b/test/Sql/Ddl/Column/BigIntegerTest.php @@ -21,16 +21,4 @@ public function testObjectConstruction() $integer = new BigInteger('foo'); $this->assertEquals('foo', $integer->getName()); } - - /** - * @covers Zend\Db\Sql\Ddl\Column\Column::getExpressionData - */ - public function testGetExpressionData() - { - $column = new BigInteger('foo'); - $this->assertEquals( - [['%s %s NOT NULL', ['foo', 'BIGINT'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } } diff --git a/test/Sql/Ddl/Column/BinaryTest.php b/test/Sql/Ddl/Column/BinaryTest.php deleted file mode 100644 index a67033a85e..0000000000 --- a/test/Sql/Ddl/Column/BinaryTest.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals( - [['%s %s NOT NULL', ['foo', 'BINARY(10000000)'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Column/BlobTest.php b/test/Sql/Ddl/Column/BlobTest.php deleted file mode 100644 index e8ffd4e1ee..0000000000 --- a/test/Sql/Ddl/Column/BlobTest.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals( - [['%s %s NOT NULL', ['foo', 'BLOB'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Column/BooleanTest.php b/test/Sql/Ddl/Column/BooleanTest.php index 605c649477..479104bf5f 100644 --- a/test/Sql/Ddl/Column/BooleanTest.php +++ b/test/Sql/Ddl/Column/BooleanTest.php @@ -13,31 +13,23 @@ class BooleanTest extends \PHPUnit_Framework_TestCase { - /** - * @covers Zend\Db\Sql\Ddl\Column\Boolean::getExpressionData - */ - public function testGetExpressionData() - { - $column = new Boolean('foo'); - $this->assertEquals( - [['%s %s NOT NULL', ['foo', 'BOOLEAN'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } - /** * @covers Zend\Db\Sql\Ddl\Column\Boolean * * @group 6257 */ - public function testIsAlwaysNotNullable() + public function testSetNullable() { $column = new Boolean('foo', true); + $this->assertTrue($column->isNullable()); + $column = new Boolean('foo', false); $this->assertFalse($column->isNullable()); $column->setNullable(true); + $this->assertTrue($column->isNullable()); + $column->setNullable(false); $this->assertFalse($column->isNullable()); } } diff --git a/test/Sql/Ddl/Column/CharTest.php b/test/Sql/Ddl/Column/CharTest.php deleted file mode 100644 index f59643c3fb..0000000000 --- a/test/Sql/Ddl/Column/CharTest.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals( - [['%s %s NOT NULL', ['foo', 'CHAR(20)'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Column/ColumnTest.php b/test/Sql/Ddl/Column/ColumnTest.php index c44e656dd6..0b4a222e39 100644 --- a/test/Sql/Ddl/Column/ColumnTest.php +++ b/test/Sql/Ddl/Column/ColumnTest.php @@ -99,29 +99,4 @@ public function testGetOptions(Column $column) { $this->assertEquals(['autoincrement' => true], $column->getOptions()); } - - /** - * @covers Zend\Db\Sql\Ddl\Column\Column::getExpressionData - */ - public function testGetExpressionData() - { - $column = new Column; - $column->setName('foo'); - $this->assertEquals( - [['%s %s NOT NULL', ['foo', 'INTEGER'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - - $column->setNullable(true); - $this->assertEquals( - [['%s %s', ['foo', 'INTEGER'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - - $column->setDefault('bar'); - $this->assertEquals( - [['%s %s DEFAULT %s', ['foo', 'INTEGER', 'bar'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL, $column::TYPE_VALUE]]], - $column->getExpressionData() - ); - } } diff --git a/test/Sql/Ddl/Column/DateTest.php b/test/Sql/Ddl/Column/DateTest.php deleted file mode 100644 index f4202182fb..0000000000 --- a/test/Sql/Ddl/Column/DateTest.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals( - [['%s %s NOT NULL', ['foo', 'DATE'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Column/DatetimeTest.php b/test/Sql/Ddl/Column/DatetimeTest.php deleted file mode 100644 index 0c47104337..0000000000 --- a/test/Sql/Ddl/Column/DatetimeTest.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals( - [['%s %s NOT NULL', ['foo', 'DATETIME'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Column/DecimalTest.php b/test/Sql/Ddl/Column/DecimalTest.php deleted file mode 100644 index c9c9420209..0000000000 --- a/test/Sql/Ddl/Column/DecimalTest.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals( - [['%s %s NOT NULL', ['foo', 'DECIMAL(10,5)'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Column/FloatTest.php b/test/Sql/Ddl/Column/FloatTest.php deleted file mode 100644 index b3c2d232f2..0000000000 --- a/test/Sql/Ddl/Column/FloatTest.php +++ /dev/null @@ -1,28 +0,0 @@ -=')) { - $this->markTestSkipped('Cannot test Float column under PHP 7; reserved keyword'); - } - } - - public function testRaisesDeprecationNoticeOnInstantiation() - { - $this->setExpectedException('PHPUnit_Framework_Error_Deprecated'); - new FloatColumn('foo', 10, 5); - } -} diff --git a/test/Sql/Ddl/Column/FloatingTest.php b/test/Sql/Ddl/Column/FloatingTest.php deleted file mode 100644 index 2195e0ccef..0000000000 --- a/test/Sql/Ddl/Column/FloatingTest.php +++ /dev/null @@ -1,31 +0,0 @@ -assertEquals( - [[ - '%s %s NOT NULL', - ['foo', 'FLOAT(10,5)'], - [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL] - ]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Column/IntegerTest.php b/test/Sql/Ddl/Column/IntegerTest.php index 37a2f49cd2..7de70cb9e1 100644 --- a/test/Sql/Ddl/Column/IntegerTest.php +++ b/test/Sql/Ddl/Column/IntegerTest.php @@ -10,7 +10,6 @@ namespace ZendTest\Db\Sql\Ddl\Column; use Zend\Db\Sql\Ddl\Column\Integer; -use Zend\Db\Sql\Ddl\Constraint\PrimaryKey; class IntegerTest extends \PHPUnit_Framework_TestCase { @@ -22,27 +21,4 @@ public function testObjectConstruction() $integer = new Integer('foo'); $this->assertEquals('foo', $integer->getName()); } - - /** - * @covers Zend\Db\Sql\Ddl\Column\Column::getExpressionData - */ - public function testGetExpressionData() - { - $column = new Integer('foo'); - $this->assertEquals( - [['%s %s NOT NULL', ['foo', 'INTEGER'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - - $column = new Integer('foo'); - $column->addConstraint(new PrimaryKey()); - $this->assertEquals( - [ - ['%s %s NOT NULL', ['foo', 'INTEGER'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]], - ' ', - ['PRIMARY KEY', [], []] - ], - $column->getExpressionData() - ); - } } diff --git a/test/Sql/Ddl/Column/TextTest.php b/test/Sql/Ddl/Column/TextTest.php deleted file mode 100644 index c1d09bcc66..0000000000 --- a/test/Sql/Ddl/Column/TextTest.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals( - [['%s %s NOT NULL', ['foo', 'TEXT'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Column/TimeTest.php b/test/Sql/Ddl/Column/TimeTest.php deleted file mode 100644 index f071a5a5bc..0000000000 --- a/test/Sql/Ddl/Column/TimeTest.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals( - [['%s %s NOT NULL', ['foo', 'TIME'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Column/TimestampTest.php b/test/Sql/Ddl/Column/TimestampTest.php deleted file mode 100644 index 53815e1231..0000000000 --- a/test/Sql/Ddl/Column/TimestampTest.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals( - [['%s %s NOT NULL', ['foo', 'TIMESTAMP'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Column/VarbinaryTest.php b/test/Sql/Ddl/Column/VarbinaryTest.php deleted file mode 100644 index d78171ae9e..0000000000 --- a/test/Sql/Ddl/Column/VarbinaryTest.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals( - [['%s %s NOT NULL', ['foo', 'VARBINARY(20)'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Column/VarcharTest.php b/test/Sql/Ddl/Column/VarcharTest.php deleted file mode 100644 index 20040d0d52..0000000000 --- a/test/Sql/Ddl/Column/VarcharTest.php +++ /dev/null @@ -1,33 +0,0 @@ -assertEquals( - [['%s %s NOT NULL', ['foo', 'VARCHAR(20)'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL]]], - $column->getExpressionData() - ); - - $column->setDefault('bar'); - $this->assertEquals( - [['%s %s NOT NULL DEFAULT %s', ['foo', 'VARCHAR(20)', 'bar'], [$column::TYPE_IDENTIFIER, $column::TYPE_LITERAL, $column::TYPE_VALUE]]], - $column->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Constraint/CheckTest.php b/test/Sql/Ddl/Constraint/CheckTest.php deleted file mode 100644 index aa5b6e6740..0000000000 --- a/test/Sql/Ddl/Constraint/CheckTest.php +++ /dev/null @@ -1,31 +0,0 @@ -0', 'foo'); - $this->assertEquals( - [[ - 'CONSTRAINT %s CHECK (%s)', - ['foo', 'id>0'], - [$check::TYPE_IDENTIFIER, $check::TYPE_LITERAL] - ]], - $check->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Constraint/ForeignKeyTest.php b/test/Sql/Ddl/Constraint/ForeignKeyTest.php index 1f8dc8452c..d75fd132c2 100644 --- a/test/Sql/Ddl/Constraint/ForeignKeyTest.php +++ b/test/Sql/Ddl/Constraint/ForeignKeyTest.php @@ -107,20 +107,4 @@ public function testGetOnUpdateRule(ForeignKey $fk) { $this->assertEquals('CASCADE', $fk->getOnUpdateRule()); } - - /** - * @covers Zend\Db\Sql\Ddl\Constraint\ForeignKey::getExpressionData - */ - public function testGetExpressionData() - { - $fk = new ForeignKey('foo', 'bar', 'baz', 'bam', 'CASCADE', 'SET NULL'); - $this->assertEquals( - [[ - 'CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s) ON DELETE %s ON UPDATE %s', - ['foo', 'bar', 'baz', 'bam', 'CASCADE', 'SET NULL'], - [$fk::TYPE_IDENTIFIER, $fk::TYPE_IDENTIFIER, $fk::TYPE_IDENTIFIER, $fk::TYPE_IDENTIFIER, $fk::TYPE_LITERAL, $fk::TYPE_LITERAL] - ]], - $fk->getExpressionData() - ); - } } diff --git a/test/Sql/Ddl/Constraint/PrimaryKeyTest.php b/test/Sql/Ddl/Constraint/PrimaryKeyTest.php deleted file mode 100644 index 001ff334d3..0000000000 --- a/test/Sql/Ddl/Constraint/PrimaryKeyTest.php +++ /dev/null @@ -1,31 +0,0 @@ -assertEquals( - [[ - 'PRIMARY KEY (%s)', - ['foo'], - [$pk::TYPE_IDENTIFIER] - ]], - $pk->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/Constraint/UniqueKeyTest.php b/test/Sql/Ddl/Constraint/UniqueKeyTest.php deleted file mode 100644 index 5506355d2a..0000000000 --- a/test/Sql/Ddl/Constraint/UniqueKeyTest.php +++ /dev/null @@ -1,31 +0,0 @@ -assertEquals( - [[ - 'CONSTRAINT %s UNIQUE (%s)', - ['my_uk', 'foo'], - [$uk::TYPE_IDENTIFIER, $uk::TYPE_IDENTIFIER] - ]], - $uk->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/CreateTableTest.php b/test/Sql/Ddl/CreateTableTest.php index 3189610e2c..77c5766195 100644 --- a/test/Sql/Ddl/CreateTableTest.php +++ b/test/Sql/Ddl/CreateTableTest.php @@ -9,9 +9,8 @@ namespace ZendTest\Db\Sql\Ddl; -use Zend\Db\Sql\Ddl\Column\Column; -use Zend\Db\Sql\Ddl\Constraint; use Zend\Db\Sql\Ddl\CreateTable; +use Zend\Db\Sql\TableIdentifier; class CreateTableTest extends \PHPUnit_Framework_TestCase { @@ -22,7 +21,7 @@ class CreateTableTest extends \PHPUnit_Framework_TestCase public function testObjectConstruction() { $ct = new CreateTable('foo', true); - $this->assertEquals('foo', $ct->getRawState($ct::TABLE)); + $this->assertEquals('foo', $ct->table->getTable()); $this->assertTrue($ct->isTemporary()); } @@ -39,7 +38,8 @@ public function testSetTemporary() $ct->setTemporary('yes'); $this->assertTrue($ct->isTemporary()); - $this->assertStringStartsWith("CREATE TEMPORARY TABLE", $ct->getSqlString()); + $ct = new CreateTable('foo', true); + $this->assertTrue($ct->isTemporary()); } /** @@ -59,18 +59,11 @@ public function testIsTemporary() public function testSetTable() { $ct = new CreateTable(); - $this->assertEquals('', $ct->getRawState('table')); - $ct->setTable('test'); - return $ct; - } + $this->assertEquals(null, $ct->table); - /** - * @covers Zend\Db\Sql\Ddl\CreateTable::getRawState - * @depends testSetTable - */ - public function testRawStateViaTable(CreateTable $ct) - { - $this->assertEquals('test', $ct->getRawState('table')); + $this->assertSame(null, $ct->setTable(null)->table); + $this->assertEquals('test', $ct->setTable('test')->table->getTable()); + $this->assertEquals('test', $ct->setTable(new TableIdentifier('test'))->table->getTable()); } /** @@ -85,12 +78,11 @@ public function testAddColumn() } /** - * @covers Zend\Db\Sql\Ddl\CreateTable::getRawState * @depends testAddColumn */ public function testRawStateViaColumn(CreateTable $ct) { - $state = $ct->getRawState('columns'); + $state = $ct->columns; $this->assertInternalType('array', $state); $column = array_pop($state); $this->assertInstanceOf('Zend\Db\Sql\Ddl\Column\ColumnInterface', $column); @@ -108,49 +100,13 @@ public function testAddConstraint() } /** - * @covers Zend\Db\Sql\Ddl\CreateTable::getRawState * @depends testAddConstraint */ public function testRawStateViaConstraint(CreateTable $ct) { - $state = $ct->getRawState('constraints'); + $state = $ct->constraints; $this->assertInternalType('array', $state); $constraint = array_pop($state); $this->assertInstanceOf('Zend\Db\Sql\Ddl\Constraint\ConstraintInterface', $constraint); } - - /** - * @covers Zend\Db\Sql\Ddl\CreateTable::getSqlString - */ - public function testGetSqlString() - { - $ct = new CreateTable('foo'); - $this->assertEquals("CREATE TABLE \"foo\" ( \n)", $ct->getSqlString()); - - $ct = new CreateTable('foo', true); - $this->assertEquals("CREATE TEMPORARY TABLE \"foo\" ( \n)", $ct->getSqlString()); - - $ct = new CreateTable('foo'); - $ct->addColumn(new Column('bar')); - $this->assertEquals("CREATE TABLE \"foo\" ( \n \"bar\" INTEGER NOT NULL \n)", $ct->getSqlString()); - - $ct = new CreateTable('foo', true); - $ct->addColumn(new Column('bar')); - $this->assertEquals("CREATE TEMPORARY TABLE \"foo\" ( \n \"bar\" INTEGER NOT NULL \n)", $ct->getSqlString()); - - $ct = new CreateTable('foo', true); - $ct->addColumn(new Column('bar')); - $ct->addColumn(new Column('baz')); - $this->assertEquals("CREATE TEMPORARY TABLE \"foo\" ( \n \"bar\" INTEGER NOT NULL,\n \"baz\" INTEGER NOT NULL \n)", $ct->getSqlString()); - - $ct = new CreateTable('foo'); - $ct->addColumn(new Column('bar')); - $ct->addConstraint(new Constraint\PrimaryKey('bat')); - $this->assertEquals("CREATE TABLE \"foo\" ( \n \"bar\" INTEGER NOT NULL , \n PRIMARY KEY (\"bat\") \n)", $ct->getSqlString()); - - $ct = new CreateTable('foo'); - $ct->addConstraint(new Constraint\PrimaryKey('bar')); - $ct->addConstraint(new Constraint\PrimaryKey('bat')); - $this->assertEquals("CREATE TABLE \"foo\" ( \n PRIMARY KEY (\"bar\"),\n PRIMARY KEY (\"bat\") \n)", $ct->getSqlString()); - } } diff --git a/test/Sql/Ddl/DropTableTest.php b/test/Sql/Ddl/DropTableTest.php index 0d9b028e38..14c1fa1312 100644 --- a/test/Sql/Ddl/DropTableTest.php +++ b/test/Sql/Ddl/DropTableTest.php @@ -10,15 +10,16 @@ namespace ZendTest\Db\Sql\Ddl; use Zend\Db\Sql\Ddl\DropTable; +use Zend\Db\Sql\TableIdentifier; class DropTableTest extends \PHPUnit_Framework_TestCase { - /** - * @covers Zend\Db\Sql\Ddl\DropTable::getSqlString - */ - public function testGetSqlString() + public function testObjectConstruction() { - $dt = new DropTable('foo'); - $this->assertEquals('DROP TABLE "foo"', $dt->getSqlString()); + $ct = new DropTable('foo'); + $this->assertEquals('foo', $ct->table->getTable()); + + $ct = new DropTable(new TableIdentifier('foo')); + $this->assertEquals('foo', $ct->table->getTable()); } } diff --git a/test/Sql/Ddl/Index/IndexTest.php b/test/Sql/Ddl/Index/IndexTest.php deleted file mode 100644 index c57aa85635..0000000000 --- a/test/Sql/Ddl/Index/IndexTest.php +++ /dev/null @@ -1,63 +0,0 @@ -assertEquals( - [[ - 'INDEX %s(%s)', - ['my_uk', 'foo'], - [$uk::TYPE_IDENTIFIER, $uk::TYPE_IDENTIFIER] - ]], - $uk->getExpressionData() - ); - } - - /** - * @covers Zend\Db\Sql\Ddl\Index\Index::getExpressionData - */ - public function testGetExpressionDataWithLength() - { - $key = new Index(['foo', 'bar'], 'my_uk', [10, 5]); - $this->assertEquals( - [[ - 'INDEX %s(%s(10), %s(5))', - ['my_uk', 'foo', 'bar'], - [$key::TYPE_IDENTIFIER, $key::TYPE_IDENTIFIER, $key::TYPE_IDENTIFIER] - ]], - $key->getExpressionData() - ); - } - - /** - * @covers Zend\Db\Sql\Ddl\Index\Index::getExpressionData - */ - public function testGetExpressionDataWithLengthUnmatched() - { - $key = new Index(['foo', 'bar'], 'my_uk', [10]); - $this->assertEquals( - [[ - 'INDEX %s(%s(10), %s)', - ['my_uk', 'foo', 'bar'], - [$key::TYPE_IDENTIFIER, $key::TYPE_IDENTIFIER, $key::TYPE_IDENTIFIER] - ]], - $key->getExpressionData() - ); - } -} diff --git a/test/Sql/Ddl/SqlTest.php b/test/Sql/Ddl/SqlTest.php new file mode 100644 index 0000000000..fa53ec00ec --- /dev/null +++ b/test/Sql/Ddl/SqlTest.php @@ -0,0 +1,77 @@ +getMock('Zend\Db\Adapter\Driver\DriverInterface'); + $this->mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver, new TestAsset\TrustingSql92Platform()]); + + $this->sql = new Sql\Ddl\Sql($this->mockAdapter, 'foo'); + } + + /** + * @covers Zend\Db\Sql\Ddl\Sql::alterTable + */ + public function testAlterTable() + { + $alterTable = $this->sql->alterTable(); + + $this->assertInstanceOf('Zend\Db\Sql\Ddl\AlterTable', $alterTable); + $this->assertSame('foo', $alterTable->table->getTable()); + + $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', + 'This Sql object is intended to work with only the table "foo" provided at construction time.'); + $this->sql->alterTable('bar'); + } + + /** + * @covers Zend\Db\Sql\Ddl\Sql::createTable + */ + public function testCreateTable() + { + $createTable = $this->sql->createTable(); + + $this->assertInstanceOf('Zend\Db\Sql\Ddl\CreateTable', $createTable); + $this->assertSame('foo', $createTable->table->getTable()); + + $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', + 'This Sql object is intended to work with only the table "foo" provided at construction time.'); + $this->sql->createTable('bar'); + } + + /** + * @covers Zend\Db\Sql\Ddl\Sql::dropTable + */ + public function testDropTable() + { + $dropTable = $this->sql->dropTable(); + + $this->assertInstanceOf('Zend\Db\Sql\Ddl\DropTable', $dropTable); + $this->assertSame('foo', $dropTable->table->getTable()); + + $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', + 'This Sql object is intended to work with only the table "foo" provided at construction time.'); + $this->sql->dropTable('bar'); + } +} diff --git a/test/Sql/DeleteTest.php b/test/Sql/DeleteTest.php index 30d63757b4..a36a23f021 100644 --- a/test/Sql/DeleteTest.php +++ b/test/Sql/DeleteTest.php @@ -10,9 +10,7 @@ namespace ZendTest\Db\Sql; use Zend\Db\Sql\Delete; -use Zend\Db\Sql\Predicate\IsNotNull; use Zend\Db\Sql\TableIdentifier; -use Zend\Db\Sql\Where; class DeleteTest extends \PHPUnit_Framework_TestCase { @@ -30,200 +28,25 @@ protected function setUp() $this->delete = new Delete; } - /** - * Tears down the fixture, for example, closes a network connection. - * This method is called after a test is executed. - */ - protected function tearDown() - { - } - /** * @covers Zend\Db\Sql\Delete::from */ public function testFrom() { $this->delete->from('foo', 'bar'); - $this->assertEquals('foo', $this->readAttribute($this->delete, 'table')); + $this->assertEquals('foo', $this->delete->table->getSource()->getTable()); $tableIdentifier = new TableIdentifier('foo', 'bar'); $this->delete->from($tableIdentifier); - $this->assertEquals($tableIdentifier, $this->readAttribute($this->delete, 'table')); - } - - /** - * @covers Zend\Db\Sql\Delete::where - * - * @todo REMOVE THIS IN 3.x - */ - public function testWhere() - { - $this->delete->where('x = y'); - $this->delete->where(['foo > ?' => 5]); - $this->delete->where(['id' => 2]); - $this->delete->where(['a = b'], Where::OP_OR); - $this->delete->where(['c1' => null]); - $this->delete->where(['c2' => [1, 2, 3]]); - $this->delete->where([new IsNotNull('c3')]); - $this->delete->where(['one' => 1, 'two' => 2]); - $where = $this->delete->where; - - $predicates = $this->readAttribute($where, 'predicates'); - $this->assertEquals('AND', $predicates[0][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[0][1]); - - $this->assertEquals('AND', $predicates[1][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Expression', $predicates[1][1]); - - $this->assertEquals('AND', $predicates[2][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Operator', $predicates[2][1]); - - $this->assertEquals('OR', $predicates[3][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[3][1]); - - $this->assertEquals('AND', $predicates[4][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\IsNull', $predicates[4][1]); - - $this->assertEquals('AND', $predicates[5][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\In', $predicates[5][1]); - - $this->assertEquals('AND', $predicates[6][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\IsNotNull', $predicates[6][1]); - - $this->assertEquals('AND', $predicates[7][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Operator', $predicates[7][1]); - - $this->assertEquals('AND', $predicates[8][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Operator', $predicates[8][1]); - - $where = new Where; - $this->delete->where($where); - $this->assertSame($where, $this->delete->where); - - $this->delete->where(function ($what) use ($where) { - $this->assertSame($where, $what); - }); - } - - /** - * @covers Zend\Db\Sql\Delete::prepareStatement - */ - public function testPrepareStatement() - { - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $mockStatement->expects($this->at(2)) - ->method('setSql') - ->with($this->equalTo('DELETE FROM "foo" WHERE x = y')); - - $this->delete->from('foo') - ->where('x = y'); - - $this->delete->prepareStatement($mockAdapter, $mockStatement); - - // with TableIdentifier - $this->delete = new Delete; - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $mockStatement->expects($this->at(2)) - ->method('setSql') - ->with($this->equalTo('DELETE FROM "sch"."foo" WHERE x = y')); - - $this->delete->from(new TableIdentifier('foo', 'sch')) - ->where('x = y'); - - $this->delete->prepareStatement($mockAdapter, $mockStatement); + $this->assertEquals($tableIdentifier, $this->delete->table->getSource()); } - /** - * @covers Zend\Db\Sql\Delete::getSqlString - */ - public function testGetSqlString() - { - $this->delete->from('foo') - ->where('x = y'); - $this->assertEquals('DELETE FROM "foo" WHERE x = y', $this->delete->getSqlString()); - - // with TableIdentifier - $this->delete = new Delete; - $this->delete->from(new TableIdentifier('foo', 'sch')) - ->where('x = y'); - $this->assertEquals('DELETE FROM "sch"."foo" WHERE x = y', $this->delete->getSqlString()); - } - - /** - * @coversNothing - */ - public function testSpecificationconstantsCouldBeOverridedByExtensionInPrepareStatement() - { - $deleteIgnore = new DeleteIgnore(); - - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $mockStatement->expects($this->at(2)) - ->method('setSql') - ->with($this->equalTo('DELETE IGNORE FROM "foo" WHERE x = y')); - - $deleteIgnore->from('foo') - ->where('x = y'); - - $deleteIgnore->prepareStatement($mockAdapter, $mockStatement); - - - - // with TableIdentifier - $deleteIgnore = new DeleteIgnore(); - - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $mockStatement->expects($this->at(2)) - ->method('setSql') - ->with($this->equalTo('DELETE IGNORE FROM "sch"."foo" WHERE x = y')); - - $deleteIgnore->from(new TableIdentifier('foo', 'sch')) - ->where('x = y'); - - $deleteIgnore->prepareStatement($mockAdapter, $mockStatement); - } - - /** - * @coversNothing - */ - public function testSpecificationconstantsCouldBeOverridedByExtensionInGetSqlString() - { - $deleteIgnore = new DeleteIgnore(); - - $deleteIgnore->from('foo') - ->where('x = y'); - $this->assertEquals('DELETE IGNORE FROM "foo" WHERE x = y', $deleteIgnore->getSqlString()); - - // with TableIdentifier - $deleteIgnore = new DeleteIgnore(); - $deleteIgnore->from(new TableIdentifier('foo', 'sch')) - ->where('x = y'); - $this->assertEquals('DELETE IGNORE FROM "sch"."foo" WHERE x = y', $deleteIgnore->getSqlString()); - } -} - -class DeleteIgnore extends Delete -{ - const SPECIFICATION_DELETE = 'deleteIgnore'; - - protected $specifications = [ - self::SPECIFICATION_DELETE => 'DELETE IGNORE FROM %1$s', - self::SPECIFICATION_WHERE => 'WHERE %1$s', - ]; - - protected function processdeleteIgnore(\Zend\Db\Adapter\Platform\PlatformInterface $platform, \Zend\Db\Adapter\Driver\DriverInterface $driver = null, \Zend\Db\Adapter\ParameterContainer $parameterContainer = null) + public function test__Get() { - return parent::processDelete($platform, $driver, $parameterContainer); + foreach (array_flip($this->readAttribute($this->delete, '__getProperties')) as $name) { + $this->delete->$name; + } + $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException'); + $this->delete->badPropertyName; } } diff --git a/test/Sql/ExpressionTest.php b/test/Sql/ExpressionTest.php index ac2991c6c5..8677ab3ec9 100644 --- a/test/Sql/ExpressionTest.php +++ b/test/Sql/ExpressionTest.php @@ -10,6 +10,7 @@ namespace ZendTest\Db\Sql; use Zend\Db\Sql\Expression; +use Zend\Db\Sql\ExpressionParameter; /** * This is a unit testing test case. @@ -77,79 +78,18 @@ public function testSetParametersException() * @depends testSetParameters */ public function testGetParameters(Expression $expression) - { - $this->assertEquals('foo', $expression->getParameters()); - } - - /** - * @covers Zend\Db\Sql\Expression::setTypes - */ - public function testSetTypes() - { - $expression = new Expression(); - $return = $expression->setTypes([Expression::TYPE_IDENTIFIER, Expression::TYPE_VALUE, Expression::TYPE_LITERAL]); - $this->assertSame($expression, $return); - return $expression; - } - - /** - * @covers Zend\Db\Sql\Expression::getTypes - * @depends testSetTypes - */ - public function testGetTypes(Expression $expression) { $this->assertEquals( - [Expression::TYPE_IDENTIFIER, Expression::TYPE_VALUE, Expression::TYPE_LITERAL], - $expression->getTypes() + [ + new ExpressionParameter('foo', Expression::TYPE_VALUE) + ], + $expression->getParameters() ); } /** - * @covers Zend\Db\Sql\Expression::getExpressionData + * @covers Zend\Db\Sql\Expression::__construct */ - public function testGetExpressionData() - { - $expression = new Expression( - 'X SAME AS ? AND Y = ? BUT LITERALLY ?', - ['foo', 5, 'FUNC(FF%X)'], - [Expression::TYPE_IDENTIFIER, Expression::TYPE_VALUE, Expression::TYPE_LITERAL] - ); - - $this->assertEquals( - [[ - 'X SAME AS %s AND Y = %s BUT LITERALLY %s', - ['foo', 5, 'FUNC(FF%X)'], - [Expression::TYPE_IDENTIFIER, Expression::TYPE_VALUE, Expression::TYPE_LITERAL] - ]], - $expression->getExpressionData() - ); - $expression = new Expression( - 'X SAME AS ? AND Y = ? BUT LITERALLY ?', - [ - ['foo' => Expression::TYPE_IDENTIFIER], - [5 => Expression::TYPE_VALUE], - ['FUNC(FF%X)' => Expression::TYPE_LITERAL], - ] - ); - - $expected = [[ - 'X SAME AS %s AND Y = %s BUT LITERALLY %s', - ['foo', 5, 'FUNC(FF%X)'], - [Expression::TYPE_IDENTIFIER, Expression::TYPE_VALUE, Expression::TYPE_LITERAL] - ]]; - - $this->assertEquals($expected, $expression->getExpressionData()); - } - - public function testGetExpressionDataWillEscapePercent() - { - $expression = new Expression('X LIKE "foo%"'); - $this->assertEquals( - ['X LIKE "foo%%"'], - $expression->getExpressionData() - ); - } - public function testConstructorWithLiteralZero() { $expression = new Expression('0'); @@ -166,10 +106,4 @@ public function testGetExpressionPreservesPercentageSignInFromUnixtime() $this->assertSame($expressionString, $expression->getExpression()); } - - public function testNumberOfReplacemensConsidersWhenSameVariableIsUsedManyTimes() - { - $expression = new Expression('uf.user_id = :user_id OR uf.friend_id = :user_id', ['user_id' => 1]); - $expression->getExpressionData(); - } } diff --git a/test/Sql/InsertTest.php b/test/Sql/InsertTest.php index 22647de751..c7cf7a9410 100644 --- a/test/Sql/InsertTest.php +++ b/test/Sql/InsertTest.php @@ -11,9 +11,7 @@ use Zend\Db\Sql\Insert; use Zend\Db\Sql\Select; -use Zend\Db\Sql\Expression; -use Zend\Db\Sql\TableIdentifier; -use ZendTest\Db\TestAsset\TrustingSql92Platform; +use Zend\Db\Sql\TableSource; class InsertTest extends \PHPUnit_Framework_TestCase { @@ -37,11 +35,11 @@ protected function setUp() public function testInto() { $this->insert->into('table', 'schema'); - $this->assertEquals('table', $this->insert->getRawState('table')); + $this->assertEquals('table', $this->insert->table->getSource()->getTable()); - $tableIdentifier = new TableIdentifier('table', 'schema'); + $tableIdentifier = TableSource::factory(['table', 'schema']); $this->insert->into($tableIdentifier); - $this->assertEquals($tableIdentifier, $this->insert->getRawState('table')); + $this->assertEquals($tableIdentifier, $this->insert->table); } /** @@ -51,7 +49,7 @@ public function testColumns() { $columns = ['foo', 'bar']; $this->insert->columns($columns); - $this->assertEquals($columns, $this->insert->getRawState('columns')); + $this->assertEquals($columns, $this->insert->columns); } /** @@ -60,18 +58,25 @@ public function testColumns() public function testValues() { $this->insert->values(['foo' => 'bar']); - $this->assertEquals(['foo'], $this->insert->getRawState('columns')); - $this->assertEquals(['bar'], $this->insert->getRawState('values')); + $this->assertEquals(['foo'], $this->insert->columns); + $this->assertEquals(['bar'], $this->insert->values); // test will merge cols and values of previously set stuff $this->insert->values(['foo' => 'bax'], Insert::VALUES_MERGE); $this->insert->values(['boom' => 'bam'], Insert::VALUES_MERGE); - $this->assertEquals(['foo', 'boom'], $this->insert->getRawState('columns')); - $this->assertEquals(['bax', 'bam'], $this->insert->getRawState('values')); + $this->assertEquals(['foo', 'boom'], $this->insert->columns); + $this->assertEquals(['bax', 'bam'], $this->insert->values); $this->insert->values(['foo' => 'bax']); - $this->assertEquals(['foo'], $this->insert->getRawState('columns')); - $this->assertEquals(['bax'], $this->insert->getRawState('values')); + $this->assertEquals(['foo'], $this->insert->columns); + $this->assertEquals(['bax'], $this->insert->values); + + $this->insert->columns(['c1', 'c2', 'c3']) + ->values(['bar']) + ->values(['bam'], Insert::VALUES_MERGE) + ->values(['c3' => 'baz'], Insert::VALUES_MERGE); + $this->assertEquals(['c1', 'c2', 'c3'], $this->insert->columns); + $this->assertEquals(['bar', 'bam', 'baz'], $this->insert->values); } /** @@ -81,7 +86,7 @@ public function testValuesThrowsExceptionWhenNotArrayOrSelect() { $this->setExpectedException( 'Zend\Db\Sql\Exception\InvalidArgumentException', - 'values() expects an array of values or Zend\Db\Sql\Select instance' + 'values() expects an array of values or Zend\Db\Sql\SelectableInterface instance' ); $this->insert->values(5); } @@ -95,7 +100,7 @@ public function testValuesThrowsExceptionWhenSelectMergeOverArray() $this->setExpectedException( 'Zend\Db\Sql\Exception\InvalidArgumentException', - 'A Zend\Db\Sql\Select instance cannot be provided with the merge flag' + 'A Zend\Db\Sql\SelectableInterface instance cannot be provided with the merge flag' ); $this->insert->values(new Select, Insert::VALUES_MERGE); } @@ -109,7 +114,7 @@ public function testValuesThrowsExceptionWhenArrayMergeOverSelect() $this->setExpectedException( 'Zend\Db\Sql\Exception\InvalidArgumentException', - 'An array of values cannot be provided with the merge flag when a Zend\Db\Sql\Select instance already exists as the value source' + 'An array of values cannot be provided with the merge flag when a Zend\Db\Sql\SelectableInterface instance already exists as the value source' ); $this->insert->values(['foo' => 'bar'], Insert::VALUES_MERGE); } @@ -123,265 +128,4 @@ public function testEmptyArrayValues() $this->insert->values([]); $this->assertEquals([], $this->readAttribute($this->insert, 'columns')); } - - /** - * @covers Zend\Db\Sql\Insert::prepareStatement - */ - public function testPrepareStatement() - { - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional')); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $pContainer = new \Zend\Db\Adapter\ParameterContainer([]); - $mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($pContainer)); - $mockStatement->expects($this->at(1)) - ->method('setSql') - ->with($this->equalTo('INSERT INTO "foo" ("bar", "boo") VALUES (?, NOW())')); - - $this->insert->into('foo') - ->values(['bar' => 'baz', 'boo' => new Expression('NOW()')]); - - $this->insert->prepareStatement($mockAdapter, $mockStatement); - - // with TableIdentifier - $this->insert = new Insert; - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional')); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $pContainer = new \Zend\Db\Adapter\ParameterContainer([]); - $mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($pContainer)); - $mockStatement->expects($this->at(1)) - ->method('setSql') - ->with($this->equalTo('INSERT INTO "sch"."foo" ("bar", "boo") VALUES (?, NOW())')); - - $this->insert->into(new TableIdentifier('foo', 'sch')) - ->values(['bar' => 'baz', 'boo' => new Expression('NOW()')]); - - $this->insert->prepareStatement($mockAdapter, $mockStatement); - } - - /** - * @covers Zend\Db\Sql\Insert::prepareStatement - */ - public function testPrepareStatementWithSelect() - { - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional')); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = new \Zend\Db\Adapter\StatementContainer(); - - $select = new Select('bar'); - $this->insert - ->into('foo') - ->columns(['col1']) - ->select($select->where(['x'=>5])) - ->prepareStatement($mockAdapter, $mockStatement); - - $this->assertEquals( - 'INSERT INTO "foo" ("col1") SELECT "bar".* FROM "bar" WHERE "x" = ?', - $mockStatement->getSql() - ); - $parameters = $mockStatement->getParameterContainer()->getNamedArray(); - $this->assertSame(['subselect1where1'=>5], $parameters); - } - - /** - * @covers Zend\Db\Sql\Insert::getSqlString - */ - public function testGetSqlString() - { - $this->insert->into('foo') - ->values(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]); - - $this->assertEquals('INSERT INTO "foo" ("bar", "boo", "bam") VALUES (\'baz\', NOW(), NULL)', $this->insert->getSqlString(new TrustingSql92Platform())); - - // with TableIdentifier - $this->insert = new Insert; - $this->insert->into(new TableIdentifier('foo', 'sch')) - ->values(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]); - - $this->assertEquals('INSERT INTO "sch"."foo" ("bar", "boo", "bam") VALUES (\'baz\', NOW(), NULL)', $this->insert->getSqlString(new TrustingSql92Platform())); - - // with Select - $this->insert = new Insert; - $select = new Select(); - $this->insert->into('foo')->select($select->from('bar')); - - $this->assertEquals('INSERT INTO "foo" SELECT "bar".* FROM "bar"', $this->insert->getSqlString(new TrustingSql92Platform())); - - // with Select and columns - $this->insert->columns(['col1', 'col2']); - $this->assertEquals( - 'INSERT INTO "foo" ("col1", "col2") SELECT "bar".* FROM "bar"', - $this->insert->getSqlString(new TrustingSql92Platform()) - ); - } - - public function testGetSqlStringUsingColumnsAndValuesMethods() - { - // With columns() and values() - $this->insert - ->into('foo') - ->columns(['col1', 'col2', 'col3']) - ->values(['val1', 'val2', 'val3']); - $this->assertEquals( - 'INSERT INTO "foo" ("col1", "col2", "col3") VALUES (\'val1\', \'val2\', \'val3\')', - $this->insert->getSqlString(new TrustingSql92Platform()) - ); - } - - /** - * @covers Zend\Db\Sql\Insert::__set - */ - public function test__set() - { - $this->insert->foo = 'bar'; - $this->assertEquals(['foo'], $this->insert->getRawState('columns')); - $this->assertEquals(['bar'], $this->insert->getRawState('values')); - } - - /** - * @covers Zend\Db\Sql\Insert::__unset - */ - public function test__unset() - { - $this->insert->foo = 'bar'; - $this->assertEquals(['foo'], $this->insert->getRawState('columns')); - $this->assertEquals(['bar'], $this->insert->getRawState('values')); - unset($this->insert->foo); - $this->assertEquals([], $this->insert->getRawState('columns')); - $this->assertEquals([], $this->insert->getRawState('values')); - - $this->insert->foo = NULL; - $this->assertEquals(['foo'], $this->insert->getRawState('columns')); - $this->assertEquals([NULL], $this->insert->getRawState('values')); - - unset($this->insert->foo); - $this->assertEquals([], $this->insert->getRawState('columns')); - $this->assertEquals([], $this->insert->getRawState('values')); - } - - /** - * @covers Zend\Db\Sql\Insert::__isset - */ - public function test__isset() - { - $this->insert->foo = 'bar'; - $this->assertTrue(isset($this->insert->foo)); - - $this->insert->foo = NULL; - $this->assertTrue(isset($this->insert->foo)); - } - - /** - * @covers Zend\Db\Sql\Insert::__get - */ - public function test__get() - { - $this->insert->foo = 'bar'; - $this->assertEquals('bar', $this->insert->foo); - - $this->insert->foo = NULL; - $this->assertNull($this->insert->foo); - } - - /** - * @group ZF2-536 - */ - public function testValuesMerge() - { - $this->insert->into('foo') - ->values(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]); - $this->insert->into('foo') - ->values(['qux' => 100], Insert::VALUES_MERGE); - - $this->assertEquals('INSERT INTO "foo" ("bar", "boo", "bam", "qux") VALUES (\'baz\', NOW(), NULL, \'100\')', $this->insert->getSqlString(new TrustingSql92Platform())); - } - - /** - * @coversNothing - */ - public function testSpecificationconstantsCouldBeOverridedByExtensionInPrepareStatement() - { - $replace = new Replace(); - - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional')); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $pContainer = new \Zend\Db\Adapter\ParameterContainer([]); - $mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($pContainer)); - $mockStatement->expects($this->at(1)) - ->method('setSql') - ->with($this->equalTo('REPLACE INTO "foo" ("bar", "boo") VALUES (?, NOW())')); - - $replace->into('foo') - ->values(['bar' => 'baz', 'boo' => new Expression('NOW()')]); - - $replace->prepareStatement($mockAdapter, $mockStatement); - - // with TableIdentifier - $replace = new Replace(); - - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional')); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $pContainer = new \Zend\Db\Adapter\ParameterContainer([]); - $mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($pContainer)); - $mockStatement->expects($this->at(1)) - ->method('setSql') - ->with($this->equalTo('REPLACE INTO "sch"."foo" ("bar", "boo") VALUES (?, NOW())')); - - $replace->into(new TableIdentifier('foo', 'sch')) - ->values(['bar' => 'baz', 'boo' => new Expression('NOW()')]); - - $replace->prepareStatement($mockAdapter, $mockStatement); - } - - /** - * @coversNothing - */ - public function testSpecificationconstantsCouldBeOverridedByExtensionInGetSqlString() - { - $replace = new Replace(); - $replace->into('foo') - ->values(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]); - - $this->assertEquals('REPLACE INTO "foo" ("bar", "boo", "bam") VALUES (\'baz\', NOW(), NULL)', $replace->getSqlString(new TrustingSql92Platform())); - - // with TableIdentifier - $replace = new Replace(); - $replace->into(new TableIdentifier('foo', 'sch')) - ->values(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]); - - $this->assertEquals('REPLACE INTO "sch"."foo" ("bar", "boo", "bam") VALUES (\'baz\', NOW(), NULL)', $replace->getSqlString(new TrustingSql92Platform())); - } -} - -class Replace extends Insert -{ - const SPECIFICATION_INSERT = 'replace'; - - protected $specifications = [ - self::SPECIFICATION_INSERT => 'REPLACE INTO %1$s (%2$s) VALUES (%3$s)', - self::SPECIFICATION_SELECT => 'REPLACE INTO %1$s %2$s %3$s', - ]; - - protected function processreplace(\Zend\Db\Adapter\Platform\PlatformInterface $platform, \Zend\Db\Adapter\Driver\DriverInterface $driver = null, \Zend\Db\Adapter\ParameterContainer $parameterContainer = null) - { - return parent::processInsert($platform, $driver, $parameterContainer); - } } diff --git a/test/Sql/JoinTest.php b/test/Sql/JoinsTest.php similarity index 53% rename from test/Sql/JoinTest.php rename to test/Sql/JoinsTest.php index 160120757e..3df7616c30 100644 --- a/test/Sql/JoinTest.php +++ b/test/Sql/JoinsTest.php @@ -8,31 +8,31 @@ namespace ZendTest\Db\Sql; use PHPUnit_Framework_TestCase as TestCase; -use Zend\Db\Sql\Join; +use Zend\Db\Sql\Joins; -class JoinTest extends TestCase +class JoinsTest extends TestCase { /** - * @testdox unit test: Test join() returns Join object (is chainable) - * @covers Zend\Db\Sql\Join::join + * @testdox unit test: Test join() returns Joins object (is chainable) + * @covers Zend\Db\Sql\Joins::join */ - public function testJoin() + public function testJoins() { - $join = new Join; - $return = $join->join('baz', 'foo.fooId = baz.fooId', Join::JOIN_LEFT); + $join = new Joins; + $return = $join->join('baz', 'foo.fooId = baz.fooId', Joins::JOIN_LEFT); $this->assertSame($join, $return); } /** * @testdox unit test: Test count() returns correct count - * @covers Zend\Db\Sql\Join::count - * @covers Zend\Db\Sql\Join::join + * @covers Zend\Db\Sql\Joins::count + * @covers Zend\Db\Sql\Joins::join */ public function testCount() { - $join = new Join; - $join->join('baz', 'foo.fooId = baz.fooId', Join::JOIN_LEFT); - $join->join('bar', 'foo.fooId = bar.fooId', Join::JOIN_LEFT); + $join = new Joins; + $join->join('baz', 'foo.fooId = baz.fooId', Joins::JOIN_LEFT); + $join->join('bar', 'foo.fooId = bar.fooId', Joins::JOIN_LEFT); $this->assertEquals(2, $join->count()); $this->assertEquals(count($join->getJoins()), $join->count()); @@ -40,15 +40,15 @@ public function testCount() /** * @testdox unit test: Test reset() resets the joins - * @covers Zend\Db\Sql\Join::count - * @covers Zend\Db\Sql\Join::join - * @covers Zend\Db\Sql\Join::reset + * @covers Zend\Db\Sql\Joins::count + * @covers Zend\Db\Sql\Joins::join + * @covers Zend\Db\Sql\Joins::reset */ public function testReset() { - $join = new Join; - $join->join('baz', 'foo.fooId = baz.fooId', Join::JOIN_LEFT); - $join->join('bar', 'foo.fooId = bar.fooId', Join::JOIN_LEFT); + $join = new Joins; + $join->join('baz', 'foo.fooId = baz.fooId', Joins::JOIN_LEFT); + $join->join('bar', 'foo.fooId = bar.fooId', Joins::JOIN_LEFT); $join->reset(); $this->assertEquals(0, $join->count()); diff --git a/test/Sql/LiteralTest.php b/test/Sql/LiteralTest.php index db0218a714..6c224458da 100644 --- a/test/Sql/LiteralTest.php +++ b/test/Sql/LiteralTest.php @@ -24,22 +24,4 @@ public function testGetLiteral() $literal = new Literal('bar'); $this->assertEquals('bar', $literal->getLiteral()); } - - public function testGetExpressionData() - { - $literal = new Literal('bar'); - $this->assertEquals([['bar', [], []]], $literal->getExpressionData()); - } - - public function testGetExpressionDataWillEscapePercent() - { - $expression = new Literal('X LIKE "foo%"'); - $this->assertEquals([[ - 'X LIKE "foo%%"', - [], - [] - ]], - $expression->getExpressionData() - ); - } } diff --git a/test/Sql/Platform/IbmDb2/SelectDecoratorTest.php b/test/Sql/Platform/IbmDb2/SelectDecoratorTest.php deleted file mode 100644 index 4c9e939d06..0000000000 --- a/test/Sql/Platform/IbmDb2/SelectDecoratorTest.php +++ /dev/null @@ -1,120 +0,0 @@ -getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $driver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - - // test - $adapter = $this->getMock( - 'Zend\Db\Adapter\Adapter', - null, - [ - $driver, - new IbmDb2Platform() - ] - ); - - $parameterContainer = new ParameterContainer; - $statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - - $statement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer)); - $statement->expects($this->once())->method('setSql')->with($expectedPrepareSql); - - $selectDecorator = new SelectDecorator; - $selectDecorator->setSubject($select); - $selectDecorator->prepareStatement($adapter, $statement); - - $this->assertEquals($expectedParams, $parameterContainer->getNamedArray()); - } - - /** - * @testdox integration test: Testing SelectDecorator will use Select to produce properly Ibm DB2 dialect sql statements - * @covers Zend\Db\Sql\Platform\IbmDb2\SelectDecorator::getSqlString - * @dataProvider dataProvider - */ - public function testGetSqlString(Select $select, $ignored0, $ignored1, $expectedSql) - { - $parameterContainer = new ParameterContainer; - $statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $statement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer)); - - $selectDecorator = new SelectDecorator; - $selectDecorator->setSubject($select); - - $this->assertEquals($expectedSql, @$selectDecorator->getSqlString(new IbmDb2Platform)); - } - - /** - * Data provider for testGetSqlString - * - * @return array - */ - public function dataProvider() - { - $select0 = new Select; - $select0->from(['x' => 'foo'])->limit(5); - $expectedParams0 = [ 'limit' => 5, 'offset' => 0 ]; - $expectedPrepareSql0 = 'SELECT * FROM ( SELECT "x".*, ROW_NUMBER() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN ? AND ?'; - $expectedSql0 = 'SELECT * FROM ( SELECT "x".*, ROW_NUMBER() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN 0 AND 5'; - - $select1 = new Select; - $select1->from(['x' => 'foo'])->limit(5)->offset(10); - $expectedParams1 = [ 'limit' => 15, 'offset' => 11 ]; - $expectedPrepareSql1 = 'SELECT * FROM ( SELECT "x".*, ROW_NUMBER() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN ? AND ?'; - $expectedSql1 = 'SELECT * FROM ( SELECT "x".*, ROW_NUMBER() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN 11 AND 15'; - - $select2 = new Select; - $select2->columns([new Expression('DISTINCT(id) as id')])->from(['x' => 'foo'])->limit(5)->offset(10); - $expectedParams2 = [ 'limit' => 15, 'offset' => 11]; - $expectedPrepareSql2 = 'SELECT DISTINCT(id) as id FROM ( SELECT DISTINCT(id) as id, DENSE_RANK() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN ? AND ?'; - $expectedSql2 = 'SELECT DISTINCT(id) as id FROM ( SELECT DISTINCT(id) as id, DENSE_RANK() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN 11 AND 15'; - - $select3 = new Select; - $where3 = new Where(); - $where3->greaterThan('x.id', '10')->AND->lessThan('x.id', '31'); - $select3->from(['x' => 'foo'])->where($where3)->limit(5)->offset(10); - $expectedParams3 = [ 'limit' => 15, 'offset' => 11, 'where1' => '10', 'where2' => '31' ]; - $expectedPrepareSql3 = 'SELECT * FROM ( SELECT "x".*, ROW_NUMBER() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" WHERE "x"."id" > ? AND "x"."id" < ? ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN ? AND ?'; - $expectedSql3 = 'SELECT * FROM ( SELECT "x".*, ROW_NUMBER() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" WHERE "x"."id" > \'10\' AND "x"."id" < \'31\' ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN 11 AND 15'; - - $select4 = new Select; - $where4 = $where3; - $select4->from(['x' => 'foo'])->where($where4)->limit(5); - $expectedParams4 = [ 'limit' => 5, 'offset' => 0, 'where1' => 10, 'where2' => 31 ]; - $expectedPrepareSql4 = 'SELECT * FROM ( SELECT "x".*, ROW_NUMBER() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" WHERE "x"."id" > ? AND "x"."id" < ? ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN ? AND ?'; - $expectedSql4 = 'SELECT * FROM ( SELECT "x".*, ROW_NUMBER() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" WHERE "x"."id" > \'10\' AND "x"."id" < \'31\' ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN 0 AND 5'; - - return [ - [$select0, $expectedPrepareSql0, $expectedParams0, $expectedSql0], - [$select1, $expectedPrepareSql1, $expectedParams1, $expectedSql1], - [$select2, $expectedPrepareSql2, $expectedParams2, $expectedSql2], - [$select3, $expectedPrepareSql3, $expectedParams3, $expectedSql3], - [$select4, $expectedPrepareSql4, $expectedParams4, $expectedSql4], - ]; - } -} diff --git a/test/Sql/Platform/Mysql/Ddl/CreateTableDecoratorTest.php b/test/Sql/Platform/Mysql/Ddl/CreateTableDecoratorTest.php deleted file mode 100644 index 2aabba1db9..0000000000 --- a/test/Sql/Platform/Mysql/Ddl/CreateTableDecoratorTest.php +++ /dev/null @@ -1,54 +0,0 @@ -assertSame($ctd, $ctd->setSubject($ct)); - } - - /** - * @covers Zend\Db\Sql\Platform\Mysql\Ddl\CreateTableDecorator::getSqlString - */ - public function testGetSqlString() - { - $ctd = new CreateTableDecorator(); - $ct = new CreateTable('foo'); - $ctd->setSubject($ct); - - $col = new Column('bar'); - $col->setOption('zerofill', true); - $col->setOption('unsigned', true); - $col->setOption('identity', true); - $col->setOption('column-format', 'FIXED'); - $col->setOption('storage', 'memory'); - $col->setOption('comment', 'baz'); - $col->addConstraint(new PrimaryKey()); - $ct->addColumn($col); - - $this->assertEquals( - "CREATE TABLE `foo` ( \n `bar` INTEGER UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'baz' COLUMN_FORMAT FIXED STORAGE MEMORY \n)", - @$ctd->getSqlString(new Mysql()) - ); - } -} diff --git a/test/Sql/Platform/Mysql/MysqlTest.php b/test/Sql/Platform/Mysql/MysqlTest.php deleted file mode 100644 index 726138a886..0000000000 --- a/test/Sql/Platform/Mysql/MysqlTest.php +++ /dev/null @@ -1,29 +0,0 @@ -getDecorators(); - - list($type, $decorator) = each($decorators); - $this->assertEquals('Zend\Db\Sql\Select', $type); - $this->assertInstanceOf('Zend\Db\Sql\Platform\Mysql\SelectDecorator', $decorator); - } -} diff --git a/test/Sql/Platform/Mysql/SelectDecoratorTest.php b/test/Sql/Platform/Mysql/SelectDecoratorTest.php deleted file mode 100644 index 6cc126d1c9..0000000000 --- a/test/Sql/Platform/Mysql/SelectDecoratorTest.php +++ /dev/null @@ -1,100 +0,0 @@ -getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $driver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - - // test - $adapter = $this->getMock( - 'Zend\Db\Adapter\Adapter', - null, - [ - $driver, - new MysqlPlatform() - ] - ); - - $parameterContainer = new ParameterContainer; - $statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $statement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer)); - - $statement->expects($this->once())->method('setSql')->with($expectedSql); - - $selectDecorator = new SelectDecorator; - $selectDecorator->setSubject($select); - $selectDecorator->prepareStatement($adapter, $statement); - - $this->assertEquals($expectedParams, $parameterContainer->getNamedArray()); - } - - /** - * @testdox integration test: Testing SelectDecorator will use Select an internal state to prepare a proper limit/offset sql statement - * @covers Zend\Db\Sql\Platform\Mysql\SelectDecorator::getSqlString - * @covers Zend\Db\Sql\Platform\Mysql\SelectDecorator::processLimit - * @covers Zend\Db\Sql\Platform\Mysql\SelectDecorator::processOffset - * @dataProvider dataProvider - */ - public function testGetSqlString(Select $select, $ignore, $alsoIgnore, $expectedSql) - { - $parameterContainer = new ParameterContainer; - $statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $statement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer)); - - $selectDecorator = new SelectDecorator; - $selectDecorator->setSubject($select); - $this->assertEquals($expectedSql, $selectDecorator->getSqlString(new MysqlPlatform)); - } - - public function dataProvider() - { - $select0 = new Select; - $select0->from('foo')->limit(5)->offset(10); - $expectedPrepareSql0 = 'SELECT `foo`.* FROM `foo` LIMIT ? OFFSET ?'; - $expectedParams0 = ['offset' => 10, 'limit' => 5]; - $expectedSql0 = 'SELECT `foo`.* FROM `foo` LIMIT 5 OFFSET 10'; - - // offset without limit - $select1 = new Select; - $select1->from('foo')->offset(10); - $expectedPrepareSql1 = 'SELECT `foo`.* FROM `foo` LIMIT 18446744073709551615 OFFSET ?'; - $expectedParams1 = ['offset' => 10]; - $expectedSql1 = 'SELECT `foo`.* FROM `foo` LIMIT 18446744073709551615 OFFSET 10'; - - // offset and limit are not type casted when injected into parameter container - $select2 = new Select; - $select2->from('foo')->limit('5')->offset('10000000000000000000'); - $expectedPrepareSql2 = 'SELECT `foo`.* FROM `foo` LIMIT ? OFFSET ?'; - $expectedParams2 = ['offset' => '10000000000000000000', 'limit' => '5']; - $expectedSql2 = 'SELECT `foo`.* FROM `foo` LIMIT 5 OFFSET 10000000000000000000'; - - return [ - [$select0, $expectedPrepareSql0, $expectedParams0, $expectedSql0], - [$select1, $expectedPrepareSql1, $expectedParams1, $expectedSql1], - [$select2, $expectedPrepareSql2, $expectedParams2, $expectedSql2], - ]; - } -} diff --git a/test/Sql/Platform/Oracle/OracleTest.php b/test/Sql/Platform/Oracle/OracleTest.php deleted file mode 100644 index 9d2acda98b..0000000000 --- a/test/Sql/Platform/Oracle/OracleTest.php +++ /dev/null @@ -1,29 +0,0 @@ -getDecorators(); - - list($type, $decorator) = each($decorators); - $this->assertEquals('Zend\Db\Sql\Select', $type); - $this->assertInstanceOf('Zend\Db\Sql\Platform\Oracle\SelectDecorator', $decorator); - } -} diff --git a/test/Sql/Platform/Oracle/SelectDecoratorTest.php b/test/Sql/Platform/Oracle/SelectDecoratorTest.php deleted file mode 100644 index 0123b22925..0000000000 --- a/test/Sql/Platform/Oracle/SelectDecoratorTest.php +++ /dev/null @@ -1,144 +0,0 @@ -getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $driver->expects($this->exactly($expectedFormatParamCount)) - ->method('formatParameterName') - ->will($this->returnValue('?')); - - // test - $adapter = $this->getMock( - 'Zend\Db\Adapter\Adapter', - null, - [ - $driver, - new OraclePlatform() - ] - ); - - $parameterContainer = new ParameterContainer; - $statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $statement->expects($this->any()) - ->method('getParameterContainer') - ->will($this->returnValue($parameterContainer)); - - $statement->expects($this->once())->method('setSql')->with($expectedSql); - - $selectDecorator = new SelectDecorator; - $selectDecorator->setSubject($select); - $selectDecorator->prepareStatement($adapter, $statement); - - $this->assertEquals($expectedParams, $parameterContainer->getNamedArray()); - } - - // @codingStandardsIgnoreStart - /** - * @testdox integration test: Testing SelectDecorator will use Select to produce properly Oracle dialect sql statements - * @covers Zend\Db\Sql\Platform\Oracle\SelectDecorator::getSqlString - * @dataProvider dataProvider - */ - // @codingStandardsIgnoreEnd - public function testGetSqlString(Select $select, $ignored, $alsoIgnored, $expectedSql) - { - $parameterContainer = new ParameterContainer; - $statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $statement->expects($this->any()) - ->method('getParameterContainer') - ->will($this->returnValue($parameterContainer)); - - $selectDecorator = new SelectDecorator; - $selectDecorator->setSubject($select); - $this->assertEquals($expectedSql, $selectDecorator->getSqlString(new OraclePlatform)); - } - - /** - * Data provider for testGetSqlString - * - * @return array - */ - public function dataProvider() - { - $select0 = new Select; - $select0->from(['x' => 'foo']); - $expectedSql0 = 'SELECT "x".* FROM "foo" "x"'; - $expectedFormatParamCount0 = 0; - - $select1a = new Select('test'); - $select1b = new Select(['a' => $select1a]); - $select1 = new Select(['b' => $select1b]); - $expectedSql1 = 'SELECT "b".* FROM (SELECT "a".* FROM (SELECT "test".* FROM "test") "a") "b"'; - $expectedFormatParamCount1 = 0; - - $select2a = new Select('test'); - $select2a->limit(2); - $select2b = new Select(['a' => $select2a]); - $select2 = new Select(['b' => $select2b]); - // @codingStandardsIgnoreStart - $expectedSql2_1 = 'SELECT "b".* FROM (SELECT "a".* FROM (SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "test".* FROM "test" ) b WHERE rownum <= (:offset2+:limit2)) WHERE b_rownum >= (:offset2 + 1)) "a") "b"'; - $expectedSql2_2 = 'SELECT "b".* FROM (SELECT "a".* FROM (SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "test".* FROM "test" ) b WHERE rownum <= (0+2)) WHERE b_rownum >= (0 + 1)) "a") "b"'; - // @codingStandardsIgnoreEnd - $expectedFormatParamCount2 = 0; - $expectedParams2 = ['offset2' => 0, 'limit2' => 2]; - - $select3a = new Select('test'); - $select3a->offset(2); - $select3b = new Select(['a' => $select3a]); - $select3 = new Select(['b' => $select3b]); - // @codingStandardsIgnoreStart - $expectedSql3_1 = 'SELECT "b".* FROM (SELECT "a".* FROM (SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "test".* FROM "test" ) b ) WHERE b_rownum > (:offset2)) "a") "b"'; - $expectedSql3_2 = 'SELECT "b".* FROM (SELECT "a".* FROM (SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "test".* FROM "test" ) b ) WHERE b_rownum > (2)) "a") "b"'; - // @codingStandardsIgnoreEnd - $expectedFormatParamCount3 = 0; - $expectedParams3 = ['offset2' => 2]; - - $select4a = new Select('test'); - $select4a->limit(2); - $select4a->offset(2); - $select4b = new Select(['a' => $select4a]); - $select4 = new Select(['b' => $select4b]); - // @codingStandardsIgnoreStart - $expectedSql4_1 = 'SELECT "b".* FROM (SELECT "a".* FROM (SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "test".* FROM "test" ) b WHERE rownum <= (:offset2+:limit2)) WHERE b_rownum >= (:offset2 + 1)) "a") "b"'; - $expectedSql4_2 = 'SELECT "b".* FROM (SELECT "a".* FROM (SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "test".* FROM "test" ) b WHERE rownum <= (2+2)) WHERE b_rownum >= (2 + 1)) "a") "b"'; - // @codingStandardsIgnoreEnd - $expectedFormatParamCount4 = 0; - $expectedParams4 = ['offset2' => 2, 'limit2' => 2]; - - return [ - [$select0, $expectedSql0, [], $expectedSql0, $expectedFormatParamCount0], - [$select1, $expectedSql1, [], $expectedSql1, $expectedFormatParamCount1], - [$select2, $expectedSql2_1, $expectedParams2, $expectedSql2_2, $expectedFormatParamCount2], - [$select3, $expectedSql3_1, $expectedParams3, $expectedSql3_2, $expectedFormatParamCount3], - [$select4, $expectedSql4_1, $expectedParams4, $expectedSql4_2, $expectedFormatParamCount4], - ]; - } -} diff --git a/test/Sql/Platform/PlatformTest.php b/test/Sql/Platform/PlatformTest.php deleted file mode 100644 index 2f23ce2c3b..0000000000 --- a/test/Sql/Platform/PlatformTest.php +++ /dev/null @@ -1,120 +0,0 @@ -resolveAdapter('sql92'); - $platform = new Platform($adapter); - - $reflectionMethod = new ReflectionMethod($platform, 'resolvePlatform'); - - $reflectionMethod->setAccessible(true); - - $this->assertEquals($adapter->getPlatform(), $reflectionMethod->invoke($platform, null)); - } - - public function testResolvePlatformName() - { - $platform = new Platform($this->resolveAdapter('sql92')); - - $reflectionMethod = new ReflectionMethod($platform, 'resolvePlatformName'); - - $reflectionMethod->setAccessible(true); - - $this->assertEquals('mysql', $reflectionMethod->invoke($platform, new TestAsset\TrustingMysqlPlatform())); - $this->assertEquals('sqlserver', $reflectionMethod->invoke($platform, new TestAsset\TrustingSqlServerPlatform())); - $this->assertEquals('oracle', $reflectionMethod->invoke($platform, new TestAsset\TrustingOraclePlatform())); - $this->assertEquals('sql92', $reflectionMethod->invoke($platform, new TestAsset\TrustingSql92Platform())); - } - - /** - * @group 6890 - */ - public function testAbstractPlatformCrashesGracefullyOnMissingDefaultPlatform() - { - $adapter = $this->resolveAdapter('sql92'); - $reflectionProperty = new \ReflectionProperty($adapter, 'platform'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($adapter, null); - - $platform = new Platform($adapter); - $reflectionMethod = new ReflectionMethod($platform, 'resolvePlatform'); - - $reflectionMethod->setAccessible(true); - - $this->setExpectedException('Zend\Db\Sql\Exception\RuntimeException', '$this->defaultPlatform was not set'); - - $reflectionMethod->invoke($platform, null); - } - - /** - * @group 6890 - */ - public function testAbstractPlatformCrashesGracefullyOnMissingDefaultPlatformWithGetDecorators() - { - $adapter = $this->resolveAdapter('sql92'); - $reflectionProperty = new \ReflectionProperty($adapter, 'platform'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($adapter, null); - - $platform = new Platform($adapter); - $reflectionMethod = new ReflectionMethod($platform, 'resolvePlatform'); - - $reflectionMethod->setAccessible(true); - - $this->setExpectedException('Zend\Db\Sql\Exception\RuntimeException', '$this->defaultPlatform was not set'); - - $platform->getDecorators(); - } - - /** - * @param string $platformName - * - * @return Adapter - */ - protected function resolveAdapter($platformName) - { - $platform = null; - - switch ($platformName) { - case 'sql92' : - $platform = new TestAsset\TrustingSql92Platform(); - break; - case 'MySql' : - $platform = new TestAsset\TrustingMysqlPlatform(); - break; - case 'Oracle' : - $platform = new TestAsset\TrustingOraclePlatform(); - break; - case 'SqlServer' : - $platform = new TestAsset\TrustingSqlServerPlatform(); - break; - } - - /* @var $mockDriver \Zend\Db\Adapter\Driver\DriverInterface|\PHPUnit_Framework_MockObject_MockObject */ - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockDriver->expects($this->any())->method('createStatement')->will($this->returnCallback(function () { - return new StatementContainer(); - })); - - return new Adapter($mockDriver, $platform); - } -} diff --git a/test/Sql/Platform/SqlServer/Ddl/CreateTableDecoratorTest.php b/test/Sql/Platform/SqlServer/Ddl/CreateTableDecoratorTest.php deleted file mode 100644 index 7077f8ff33..0000000000 --- a/test/Sql/Platform/SqlServer/Ddl/CreateTableDecoratorTest.php +++ /dev/null @@ -1,39 +0,0 @@ -assertEquals("CREATE TABLE \"foo\" ( \n)", $ctd->setSubject($ct)->getSqlString()); - - $ct = new CreateTable('foo', true); - $this->assertEquals("CREATE TABLE \"#foo\" ( \n)", $ctd->setSubject($ct)->getSqlString()); - - $ct = new CreateTable('foo'); - $ct->addColumn(new Column('bar')); - $this->assertEquals("CREATE TABLE \"foo\" ( \n \"bar\" INTEGER NOT NULL \n)", $ctd->setSubject($ct)->getSqlString()); - - $ct = new CreateTable('foo', true); - $ct->addColumn(new Column('bar')); - $this->assertEquals("CREATE TABLE \"#foo\" ( \n \"bar\" INTEGER NOT NULL \n)", $ctd->setSubject($ct)->getSqlString()); - } -} diff --git a/test/Sql/Platform/SqlServer/SelectDecoratorTest.php b/test/Sql/Platform/SqlServer/SelectDecoratorTest.php deleted file mode 100644 index 6b1d27a89c..0000000000 --- a/test/Sql/Platform/SqlServer/SelectDecoratorTest.php +++ /dev/null @@ -1,116 +0,0 @@ -getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $driver->expects($this->exactly($expectedFormatParamCount))->method('formatParameterName')->will($this->returnValue('?')); - - // test - $adapter = $this->getMock( - 'Zend\Db\Adapter\Adapter', - null, - [ - $driver, - new SqlServerPlatform() - ] - ); - - $parameterContainer = new ParameterContainer; - $statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $statement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer)); - - $statement->expects($this->once())->method('setSql')->with($expectedSql); - - $selectDecorator = new SelectDecorator; - $selectDecorator->setSubject($select); - $selectDecorator->prepareStatement($adapter, $statement); - - $this->assertEquals($expectedParams, $parameterContainer->getNamedArray()); - } - - /** - * @testdox integration test: Testing SelectDecorator will use Select an internal state to prepare a proper limit/offset sql statement - * @covers Zend\Db\Sql\Platform\SqlServer\SelectDecorator::getSqlString - * @covers Zend\Db\Sql\Platform\SqlServer\SelectDecorator::processLimitOffset - * @dataProvider dataProvider - */ - public function testGetSqlString(Select $select, $ignored, $alsoIgnored, $expectedSql) - { - $parameterContainer = new ParameterContainer; - $statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $statement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer)); - - $selectDecorator = new SelectDecorator; - $selectDecorator->setSubject($select); - $this->assertEquals($expectedSql, $selectDecorator->getSqlString(new SqlServerPlatform)); - } - - public function dataProvider() - { - $select0 = new Select; - $select0->from('foo')->columns(['bar', 'baz'])->order('bar')->limit(5)->offset(10); - $expectedPrepareSql0 = 'SELECT [bar], [baz] FROM ( SELECT [foo].[bar] AS [bar], [foo].[baz] AS [baz], ROW_NUMBER() OVER (ORDER BY [bar] ASC) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN ?+1 AND ?+?'; - $expectedParams0 = ['offset' => 10, 'limit' => 5, 'offsetForSum' => 10]; - $expectedSql0 = 'SELECT [bar], [baz] FROM ( SELECT [foo].[bar] AS [bar], [foo].[baz] AS [baz], ROW_NUMBER() OVER (ORDER BY [bar] ASC) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN 10+1 AND 5+10'; - $expectedFormatParamCount0 = 3; - - $select1 = new Select; - $select1->from('foo')->columns(['bar', 'bam' => 'baz'])->limit(5)->offset(10); - $expectedPrepareSql1 = 'SELECT [bar], [bam] FROM ( SELECT [foo].[bar] AS [bar], [foo].[baz] AS [bam], ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN ?+1 AND ?+?'; - $expectedParams1 = ['offset' => 10, 'limit' => 5, 'offsetForSum' => 10]; - $expectedSql1 = 'SELECT [bar], [bam] FROM ( SELECT [foo].[bar] AS [bar], [foo].[baz] AS [bam], ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN 10+1 AND 5+10'; - $expectedFormatParamCount1 = 3; - - $select2 = new Select; - $select2->from('foo')->order('bar')->limit(5)->offset(10); - $expectedPrepareSql2 = 'SELECT * FROM ( SELECT [foo].*, ROW_NUMBER() OVER (ORDER BY [bar] ASC) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN ?+1 AND ?+?'; - $expectedParams2 = ['offset' => 10, 'limit' => 5, 'offsetForSum' => 10]; - $expectedSql2 = 'SELECT * FROM ( SELECT [foo].*, ROW_NUMBER() OVER (ORDER BY [bar] ASC) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN 10+1 AND 5+10'; - $expectedFormatParamCount2 = 3; - - $select3 = new Select; - $select3->from('foo'); - $expectedPrepareSql3 = 'SELECT [foo].* FROM [foo]'; - $expectedParams3 = []; - $expectedSql3 = 'SELECT [foo].* FROM [foo]'; - $expectedFormatParamCount3 = 0; - - $select4 = new Select; - $select4->from('foo')->columns([new Expression('DISTINCT(bar) as bar')])->limit(5)->offset(10); - $expectedPrepareSql4 = 'SELECT DISTINCT(bar) as bar FROM ( SELECT DISTINCT(bar) as bar, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN ?+1 AND ?+?'; - $expectedParams4 = ['offset' => 10, 'limit' => 5, 'offsetForSum' => 10]; - $expectedSql4 = 'SELECT DISTINCT(bar) as bar FROM ( SELECT DISTINCT(bar) as bar, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN 10+1 AND 5+10'; - $expectedFormatParamCount4 = 3; - - return [ - [$select0, $expectedPrepareSql0, $expectedParams0, $expectedSql0, $expectedFormatParamCount0], - [$select1, $expectedPrepareSql1, $expectedParams1, $expectedSql1, $expectedFormatParamCount1], - [$select2, $expectedPrepareSql2, $expectedParams2, $expectedSql2, $expectedFormatParamCount2], - [$select3, $expectedPrepareSql3, $expectedParams3, $expectedSql3, $expectedFormatParamCount3], - [$select4, $expectedPrepareSql4, $expectedParams4, $expectedSql4, $expectedFormatParamCount4], - ]; - } -} diff --git a/test/Sql/Platform/SqlServer/SqlServerTest.php b/test/Sql/Platform/SqlServer/SqlServerTest.php deleted file mode 100644 index 081f21723f..0000000000 --- a/test/Sql/Platform/SqlServer/SqlServerTest.php +++ /dev/null @@ -1,29 +0,0 @@ -getDecorators(); - - list($type, $decorator) = each($decorators); - $this->assertEquals('Zend\Db\Sql\Select', $type); - $this->assertInstanceOf('Zend\Db\Sql\Platform\SqlServer\SelectDecorator', $decorator); - } -} diff --git a/test/Sql/Platform/Sqlite/SelectDecoratorTest.php b/test/Sql/Platform/Sqlite/SelectDecoratorTest.php deleted file mode 100644 index d2620f1261..0000000000 --- a/test/Sql/Platform/Sqlite/SelectDecoratorTest.php +++ /dev/null @@ -1,92 +0,0 @@ -getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $driver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - - // test - $adapter = $this->getMock( - 'Zend\Db\Adapter\Adapter', - null, - [ - $driver, - new SqlitePlatform() - ] - ); - - $parameterContainer = new ParameterContainer; - $statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $statement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer)); - - $statement->expects($this->once())->method('setSql')->with($expectedSql); - - $selectDecorator = new SelectDecorator; - $selectDecorator->setSubject($select); - $selectDecorator->prepareStatement($adapter, $statement); - - $this->assertEquals($expectedParams, $parameterContainer->getNamedArray()); - } - - /** - * @testdox integration test: Testing SelectDecorator will use Select an internal state to prepare a proper combine - * statement - * @covers Zend\Db\Sql\Platform\Sqlite\SelectDecorator::getSqlString - * @covers Zend\Db\Sql\Platform\Sqlite\SelectDecorator::processCombine - * @dataProvider dataProviderUnionSyntaxFromCombine - */ - public function testGetSqlStringPreparesUnionSyntaxFromCombine(Select $select, $ignore, $alsoIgnore, $expectedSql) - { - $parameterContainer = new ParameterContainer; - $statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $statement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer)); - - $selectDecorator = new SelectDecorator; - $selectDecorator->setSubject($select); - $this->assertEquals($expectedSql, $selectDecorator->getSqlString(new SqlitePlatform)); - } - - /** - * Create a data provider for union syntax that would come from combine - * - * @return mixed[] - */ - public function dataProviderUnionSyntaxFromCombine() - { - $select0 = new Select; - $select0->from('foo'); - $select1 = clone $select0; - $select0->combine($select1); - - $expectedPrepareSql0 = ' SELECT "foo".* FROM "foo" UNION SELECT "foo".* FROM "foo"'; - $expectedParams0 = []; - $expectedSql0 = ' SELECT "foo".* FROM "foo" UNION SELECT "foo".* FROM "foo"'; - - return [ - [$select0, $expectedPrepareSql0, $expectedParams0, $expectedSql0], - ]; - } -} diff --git a/test/Sql/Platform/Sqlite/SqliteTest.php b/test/Sql/Platform/Sqlite/SqliteTest.php deleted file mode 100644 index ea2aac1e72..0000000000 --- a/test/Sql/Platform/Sqlite/SqliteTest.php +++ /dev/null @@ -1,29 +0,0 @@ -getDecorators(); - - list($type, $decorator) = each($decorators); - $this->assertEquals('Zend\Db\Sql\Select', $type); - $this->assertInstanceOf('Zend\Db\Sql\Platform\Sqlite\SelectDecorator', $decorator); - } -} diff --git a/test/Sql/Predicate/BetweenTest.php b/test/Sql/Predicate/BetweenTest.php index 5037fff092..9e480ef844 100644 --- a/test/Sql/Predicate/BetweenTest.php +++ b/test/Sql/Predicate/BetweenTest.php @@ -46,31 +46,21 @@ public function testConstructorYieldsNullIdentifierMinimumAndMaximumValues() public function testConstructorCanPassIdentifierMinimumAndMaximumValues() { $between = new Between('foo.bar', 1, 300); - $this->assertEquals('foo.bar', $between->getIdentifier()); - $this->assertSame(1, $between->getMinValue()); - $this->assertSame(300, $between->getMaxValue()); + $this->assertEquals('foo.bar', $between->getIdentifier()->getValue()); + $this->assertSame(1, $between->getMinValue()->getValue()); + $this->assertSame(300, $between->getMaxValue()->getValue()); $between = new Between('foo.bar', 0, 1); - $this->assertEquals('foo.bar', $between->getIdentifier()); - $this->assertSame(0, $between->getMinValue()); - $this->assertSame(1, $between->getMaxValue()); + $this->assertEquals('foo.bar', $between->getIdentifier()->getValue()); + $this->assertSame(0, $between->getMinValue()->getValue()); + $this->assertSame(1, $between->getMaxValue()->getValue()); $between = new Between('foo.bar', -1, 0); - $this->assertEquals('foo.bar', $between->getIdentifier()); - $this->assertSame(-1, $between->getMinValue()); - $this->assertSame(0, $between->getMaxValue()); + $this->assertEquals('foo.bar', $between->getIdentifier()->getValue()); + $this->assertSame(-1, $between->getMinValue()->getValue()); + $this->assertSame(0, $between->getMaxValue()->getValue()); } - /** - * @covers Zend\Db\Sql\Predicate\Between::getSpecification - */ - public function testSpecificationHasSaneDefaultValue() - { - $this->assertEquals('%1$s BETWEEN %2$s AND %3$s', $this->between->getSpecification()); - } - - - /** * @covers Zend\Db\Sql\Predicate\Between::setIdentifier * @covers Zend\Db\Sql\Predicate\Between::getIdentifier @@ -78,7 +68,7 @@ public function testSpecificationHasSaneDefaultValue() public function testIdentifierIsMutable() { $this->between->setIdentifier('foo.bar'); - $this->assertEquals('foo.bar', $this->between->getIdentifier()); + $this->assertEquals('foo.bar', $this->between->getIdentifier()->getValue()); } /** @@ -88,7 +78,7 @@ public function testIdentifierIsMutable() public function testMinValueIsMutable() { $this->between->setMinValue(10); - $this->assertEquals(10, $this->between->getMinValue()); + $this->assertEquals(10, $this->between->getMinValue()->getValue()); } /** @@ -98,42 +88,6 @@ public function testMinValueIsMutable() public function testMaxValueIsMutable() { $this->between->setMaxValue(10); - $this->assertEquals(10, $this->between->getMaxValue()); - } - - /** - * @covers Zend\Db\Sql\Predicate\Between::setSpecification - * @covers Zend\Db\Sql\Predicate\Between::getSpecification - */ - public function testSpecificationIsMutable() - { - $this->between->setSpecification('%1$s IS INBETWEEN %2$s AND %3$s'); - $this->assertEquals('%1$s IS INBETWEEN %2$s AND %3$s', $this->between->getSpecification()); - } - - /** - * @covers Zend\Db\Sql\Predicate\Between::getExpressionData - */ - public function testRetrievingWherePartsReturnsSpecificationArrayOfIdentifierAndValuesAndArrayOfTypes() - { - $this->between->setIdentifier('foo.bar') - ->setMinValue(10) - ->setMaxValue(19); - $expected = [[ - $this->between->getSpecification(), - ['foo.bar', 10, 19], - [Between::TYPE_IDENTIFIER, Between::TYPE_VALUE, Between::TYPE_VALUE], - ]]; - $this->assertEquals($expected, $this->between->getExpressionData()); - - $this->between->setIdentifier([10=>Between::TYPE_VALUE]) - ->setMinValue(['foo.bar'=>Between::TYPE_IDENTIFIER]) - ->setMaxValue(['foo.baz'=>Between::TYPE_IDENTIFIER]); - $expected = [[ - $this->between->getSpecification(), - [10, 'foo.bar', 'foo.baz'], - [Between::TYPE_VALUE, Between::TYPE_IDENTIFIER, Between::TYPE_IDENTIFIER], - ]]; - $this->assertEquals($expected, $this->between->getExpressionData()); + $this->assertEquals(10, $this->between->getMaxValue()->getValue()); } } diff --git a/test/Sql/Predicate/ExpressionTest.php b/test/Sql/Predicate/ExpressionTest.php index f1833c990f..80f792e02b 100644 --- a/test/Sql/Predicate/ExpressionTest.php +++ b/test/Sql/Predicate/ExpressionTest.php @@ -12,6 +12,7 @@ use PHPUnit_Framework_TestCase as TestCase; use Zend\Db\Sql\Predicate\Expression; use Zend\Db\Sql\Predicate\IsNull; +use Zend\Db\Sql\ExpressionParameter; class ExpressionTest extends TestCase { @@ -29,7 +30,12 @@ public function testCanPassLiteralAndSingleScalarParameterToConstructor() { $expression = new Expression('foo.bar = ?', 'bar'); $this->assertEquals('foo.bar = ?', $expression->getExpression()); - $this->assertEquals(['bar'], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter('bar', Expression::TYPE_VALUE) + ], + $expression->getParameters() + ); } /** @@ -47,7 +53,12 @@ public function testCanPassNoParameterToConstructor() public function testCanPassSingleNullParameterToConstructor() { $expression = new Expression('?', null); - $this->assertEquals([null], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter(null, Expression::TYPE_VALUE), + ], + $expression->getParameters() + ); } /** @@ -56,7 +67,12 @@ public function testCanPassSingleNullParameterToConstructor() public function testCanPassSingleZeroParameterValueToConstructor() { $predicate = new Expression('?', 0); - $this->assertEquals([0], $predicate->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter(0, Expression::TYPE_VALUE), + ], + $predicate->getParameters() + ); } /** @@ -66,7 +82,12 @@ public function testCanPassSinglePredicateParameterToConstructor() { $predicate = new IsNull('foo.baz'); $expression = new Expression('?', $predicate); - $this->assertEquals([$predicate], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter($predicate, Expression::TYPE_LITERAL) + ], + $expression->getParameters() + ); } /** @@ -75,7 +96,13 @@ public function testCanPassSinglePredicateParameterToConstructor() public function testCanPassMultiScalarParametersToConstructor() { $expression = new Expression('? OR ?', 'foo', 'bar'); - $this->assertEquals(['foo', 'bar'], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter('foo', Expression::TYPE_VALUE), + new ExpressionParameter('bar', Expression::TYPE_VALUE), + ], + $expression->getParameters() + ); } /** @@ -84,7 +111,13 @@ public function testCanPassMultiScalarParametersToConstructor() public function testCanPassMultiNullParametersToConstructor() { $expression = new Expression('? OR ?', null, null); - $this->assertEquals([null, null], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter(null, Expression::TYPE_VALUE), + new ExpressionParameter(null, Expression::TYPE_VALUE), + ], + $expression->getParameters() + ); } /** @@ -94,7 +127,13 @@ public function testCanPassMultiPredicateParametersToConstructor() { $predicate = new IsNull('foo.baz'); $expression = new Expression('? OR ?', $predicate, $predicate); - $this->assertEquals([$predicate, $predicate], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter($predicate, Expression::TYPE_LITERAL), + new ExpressionParameter($predicate, Expression::TYPE_LITERAL), + ], + $expression->getParameters() + ); } /** @@ -103,7 +142,12 @@ public function testCanPassMultiPredicateParametersToConstructor() public function testCanPassArrayOfOneScalarParameterToConstructor() { $expression = new Expression('?', ['foo']); - $this->assertEquals(['foo'], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter('foo', Expression::TYPE_VALUE), + ], + $expression->getParameters() + ); } /** @@ -112,7 +156,13 @@ public function testCanPassArrayOfOneScalarParameterToConstructor() public function testCanPassArrayOfMultiScalarsParameterToConstructor() { $expression = new Expression('? OR ?', ['foo', 'bar']); - $this->assertEquals(['foo', 'bar'], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter('foo', Expression::TYPE_VALUE), + new ExpressionParameter('bar', Expression::TYPE_VALUE), + ], + $expression->getParameters() + ); } /** @@ -121,7 +171,12 @@ public function testCanPassArrayOfMultiScalarsParameterToConstructor() public function testCanPassArrayOfOneNullParameterToConstructor() { $expression = new Expression('?', [null]); - $this->assertEquals([null], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter(null, Expression::TYPE_VALUE), + ], + $expression->getParameters() + ); } /** @@ -130,7 +185,13 @@ public function testCanPassArrayOfOneNullParameterToConstructor() public function testCanPassArrayOfMultiNullsParameterToConstructor() { $expression = new Expression('? OR ?', [null, null]); - $this->assertEquals([null, null], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter(null, Expression::TYPE_VALUE), + new ExpressionParameter(null, Expression::TYPE_VALUE), + ], + $expression->getParameters() + ); } /** @@ -140,7 +201,12 @@ public function testCanPassArrayOfOnePredicateParameterToConstructor() { $predicate = new IsNull('foo.baz'); $expression = new Expression('?', [$predicate]); - $this->assertEquals([$predicate], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter($predicate, Expression::TYPE_LITERAL), + ], + $expression->getParameters() + ); } /** @@ -150,7 +216,13 @@ public function testCanPassArrayOfMultiPredicatesParameterToConstructor() { $predicate = new IsNull('foo.baz'); $expression = new Expression('? OR ?', [$predicate, $predicate]); - $this->assertEquals([$predicate, $predicate], $expression->getParameters()); + $this->assertEquals( + [ + new ExpressionParameter($predicate, Expression::TYPE_LITERAL), + new ExpressionParameter($predicate, Expression::TYPE_LITERAL), + ], + $expression->getParameters() + ); } public function testLiteralIsMutable() @@ -164,20 +236,12 @@ public function testParameterIsMutable() { $expression = new Expression(); $expression->setParameters(['foo', 'bar']); - $this->assertEquals(['foo', 'bar'], $expression->getParameters()); - } - - public function testRetrievingWherePartsReturnsSpecificationArrayOfLiteralAndParametersAndArrayOfTypes() - { - $expression = new Expression(); - $expression->setExpression('foo.bar = ? AND id != ?') - ->setParameters(['foo', 'bar']); - $expected = [[ - 'foo.bar = %s AND id != %s', - ['foo', 'bar'], - [Expression::TYPE_VALUE, Expression::TYPE_VALUE], - ]]; - $test = $expression->getExpressionData(); - $this->assertEquals($expected, $test, var_export($test, 1)); + $this->assertEquals( + [ + new ExpressionParameter('foo', Expression::TYPE_VALUE), + new ExpressionParameter('bar', Expression::TYPE_VALUE), + ], + $expression->getParameters() + ); } } diff --git a/test/Sql/Predicate/InTest.php b/test/Sql/Predicate/InTest.php index 30584f65a5..9ae1e7b208 100644 --- a/test/Sql/Predicate/InTest.php +++ b/test/Sql/Predicate/InTest.php @@ -10,8 +10,8 @@ namespace ZendTest\Db\Sql\Predicate; use PHPUnit_Framework_TestCase as TestCase; -use Zend\Db\Sql\Select; use Zend\Db\Sql\Predicate\In; +use Zend\Db\Sql\ExpressionParameter; class InTest extends TestCase { @@ -25,84 +25,33 @@ public function testEmptyConstructorYieldsNullIdentifierAndValueSet() public function testCanPassIdentifierAndValueSetToConstructor() { $in = new In('foo.bar', [1, 2]); - $this->assertEquals('foo.bar', $in->getIdentifier()); - $this->assertEquals([1, 2], $in->getValueSet()); + $this->assertEquals('foo.bar', $in->getIdentifier()->getValue()); + $this->assertEquals( + [ + new ExpressionParameter(1), + new ExpressionParameter(2), + ], + $in->getValueSet() + ); } public function testIdentifierIsMutable() { $in = new In(); $in->setIdentifier('foo.bar'); - $this->assertEquals('foo.bar', $in->getIdentifier()); + $this->assertEquals('foo.bar', $in->getIdentifier()->getValue()); } public function testValueSetIsMutable() { $in = new In(); $in->setValueSet([1, 2]); - $this->assertEquals([1, 2], $in->getValueSet()); - } - - public function testRetrievingWherePartsReturnsSpecificationArrayOfIdentifierAndValuesAndArrayOfTypes() - { - $in = new In(); - $in->setIdentifier('foo.bar') - ->setValueSet([1, 2, 3]); - $expected = [[ - '%s IN (%s, %s, %s)', - ['foo.bar', 1, 2, 3], - [In::TYPE_IDENTIFIER, In::TYPE_VALUE, In::TYPE_VALUE, In::TYPE_VALUE], - ]]; - $this->assertEquals($expected, $in->getExpressionData()); - - $in->setIdentifier('foo.bar') - ->setValueSet([ - [1=>In::TYPE_LITERAL], - [2=>In::TYPE_VALUE], - [3=>In::TYPE_LITERAL], - ]); - $expected = [[ - '%s IN (%s, %s, %s)', - ['foo.bar', 1, 2, 3], - [In::TYPE_IDENTIFIER, In::TYPE_LITERAL, In::TYPE_VALUE, In::TYPE_LITERAL], - ]]; - $qqq = $in->getExpressionData(); - $this->assertEquals($expected, $in->getExpressionData()); - } - - public function testGetExpressionDataWithSubselect() - { - $select = new Select; - $in = new In('foo', $select); - $expected = [[ - '%s IN %s', - ['foo', $select], - [$in::TYPE_IDENTIFIER, $in::TYPE_VALUE] - ]]; - $this->assertEquals($expected, $in->getExpressionData()); - } - - public function testGetExpressionDataWithSubselectAndIdentifier() - { - $select = new Select; - $in = new In('foo', $select); - $expected = [[ - '%s IN %s', - ['foo', $select], - [$in::TYPE_IDENTIFIER, $in::TYPE_VALUE] - ]]; - $this->assertEquals($expected, $in->getExpressionData()); - } - - public function testGetExpressionDataWithSubselectAndArrayIdentifier() - { - $select = new Select; - $in = new In(['foo', 'bar'], $select); - $expected = [[ - '(%s, %s) IN %s', - ['foo', 'bar', $select], - [$in::TYPE_IDENTIFIER, $in::TYPE_IDENTIFIER, $in::TYPE_VALUE] - ]]; - $this->assertEquals($expected, $in->getExpressionData()); + $this->assertEquals( + [ + new ExpressionParameter(1), + new ExpressionParameter(2), + ], + $in->getValueSet() + ); } } diff --git a/test/Sql/Predicate/IsNullTest.php b/test/Sql/Predicate/IsNullTest.php index 29b53e196f..ae8576181f 100644 --- a/test/Sql/Predicate/IsNullTest.php +++ b/test/Sql/Predicate/IsNullTest.php @@ -20,42 +20,17 @@ public function testEmptyConstructorYieldsNullIdentifier() $this->assertNull($isNotNull->getIdentifier()); } - public function testSpecificationHasSaneDefaultValue() - { - $isNotNull = new IsNotNull(); - $this->assertEquals('%1$s IS NOT NULL', $isNotNull->getSpecification()); - } - public function testCanPassIdentifierToConstructor() { $isNotNull = new IsNotNull(); $isnull = new IsNotNull('foo.bar'); - $this->assertEquals('foo.bar', $isnull->getIdentifier()); + $this->assertEquals('foo.bar', $isnull->getIdentifier()->getValue()); } public function testIdentifierIsMutable() { $isNotNull = new IsNotNull(); $isNotNull->setIdentifier('foo.bar'); - $this->assertEquals('foo.bar', $isNotNull->getIdentifier()); - } - - public function testSpecificationIsMutable() - { - $isNotNull = new IsNotNull(); - $isNotNull->setSpecification('%1$s NOT NULL'); - $this->assertEquals('%1$s NOT NULL', $isNotNull->getSpecification()); - } - - public function testRetrievingWherePartsReturnsSpecificationArrayOfIdentifierAndArrayOfTypes() - { - $isNotNull = new IsNotNull(); - $isNotNull->setIdentifier('foo.bar'); - $expected = [[ - $isNotNull->getSpecification(), - ['foo.bar'], - [IsNotNull::TYPE_IDENTIFIER], - ]]; - $this->assertEquals($expected, $isNotNull->getExpressionData()); + $this->assertEquals('foo.bar', $isNotNull->getIdentifier()->getValue()); } } diff --git a/test/Sql/Predicate/LikeTest.php b/test/Sql/Predicate/LikeTest.php index af999d5cf2..0d7b982035 100644 --- a/test/Sql/Predicate/LikeTest.php +++ b/test/Sql/Predicate/LikeTest.php @@ -23,45 +23,23 @@ public function testConstructEmptyArgs() public function testConstructWithArgs() { $like = new Like('bar', 'Foo%'); - $this->assertEquals('bar', $like->getIdentifier()); - $this->assertEquals('Foo%', $like->getLike()); + $this->assertEquals('bar', $like->getIdentifier()->getValue()); + $this->assertEquals('Foo%', $like->getLike()->getValue()); } public function testAccessorsMutators() { $like = new Like(); $like->setIdentifier('bar'); - $this->assertEquals('bar', $like->getIdentifier()); + $this->assertEquals('bar', $like->getIdentifier()->getValue()); $like->setLike('foo%'); - $this->assertEquals('foo%', $like->getLike()); - $like->setSpecification('target = target'); - $this->assertEquals('target = target', $like->getSpecification()); - } - - public function testGetExpressionData() - { - $like = new Like('bar', 'Foo%'); - $this->assertEquals( - [ - ['%1$s LIKE %2$s', ['bar', 'Foo%'], [$like::TYPE_IDENTIFIER, $like::TYPE_VALUE]] - ], - $like->getExpressionData() - ); - - $like = new Like(['Foo%'=>$like::TYPE_VALUE], ['bar'=>$like::TYPE_IDENTIFIER]); - $this->assertEquals( - [ - ['%1$s LIKE %2$s', ['Foo%', 'bar'], [$like::TYPE_VALUE, $like::TYPE_IDENTIFIER]] - ], - $like->getExpressionData() - ); + $this->assertEquals('foo%', $like->getLike()->getValue()); } public function testInstanceOfPerSetters() { $like = new Like(); $this->assertInstanceOf('Zend\Db\Sql\Predicate\Like', $like->setIdentifier('bar')); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Like', $like->setSpecification('%1$s LIKE %2$s')); $this->assertInstanceOf('Zend\Db\Sql\Predicate\Like', $like->setLike('foo%')); } } diff --git a/test/Sql/Predicate/LiteralTest.php b/test/Sql/Predicate/LiteralTest.php index 733a84477c..5698e84352 100644 --- a/test/Sql/Predicate/LiteralTest.php +++ b/test/Sql/Predicate/LiteralTest.php @@ -24,10 +24,4 @@ public function testGetLiteral() $literal = new Literal('bar'); $this->assertEquals('bar', $literal->getLiteral()); } - - public function testGetExpressionData() - { - $literal = new Literal('bar'); - $this->assertEquals([['bar', [], []]], $literal->getExpressionData()); - } } diff --git a/test/Sql/Predicate/NotBetweenTest.php b/test/Sql/Predicate/NotBetweenTest.php deleted file mode 100644 index 5c99087c26..0000000000 --- a/test/Sql/Predicate/NotBetweenTest.php +++ /dev/null @@ -1,60 +0,0 @@ -notBetween = new NotBetween(); - } - - /** - * @covers Zend\Db\Sql\Predicate\NotBetween::getSpecification - */ - public function testSpecificationHasSameDefaultValue() - { - $this->assertEquals('%1$s NOT BETWEEN %2$s AND %3$s', $this->notBetween->getSpecification()); - } - - /** - * @covers Zend\Db\Sql\Predicate\NotBetween::getExpressionData - */ - public function testRetrievingWherePartsReturnsSpecificationArrayOfIdentifierAndValuesAndArrayOfTypes() - { - $this->notBetween->setIdentifier('foo.bar') - ->setMinValue(10) - ->setMaxValue(19); - $expected = [[ - $this->notBetween->getSpecification(), - ['foo.bar', 10, 19], - [NotBetween::TYPE_IDENTIFIER, NotBetween::TYPE_VALUE, NotBetween::TYPE_VALUE], - ]]; - $this->assertEquals($expected, $this->notBetween->getExpressionData()); - - $this->notBetween->setIdentifier([10=>NotBetween::TYPE_VALUE]) - ->setMinValue(['foo.bar'=>NotBetween::TYPE_IDENTIFIER]) - ->setMaxValue(['foo.baz'=>NotBetween::TYPE_IDENTIFIER]); - $expected = [[ - $this->notBetween->getSpecification(), - [10, 'foo.bar', 'foo.baz'], - [NotBetween::TYPE_VALUE, NotBetween::TYPE_IDENTIFIER, NotBetween::TYPE_IDENTIFIER], - ]]; - $this->assertEquals($expected, $this->notBetween->getExpressionData()); - } -} diff --git a/test/Sql/Predicate/NotInTest.php b/test/Sql/Predicate/NotInTest.php deleted file mode 100644 index aa8bdcdd97..0000000000 --- a/test/Sql/Predicate/NotInTest.php +++ /dev/null @@ -1,66 +0,0 @@ -setIdentifier('foo.bar') - ->setValueSet([1, 2, 3]); - $expected = [[ - '%s NOT IN (%s, %s, %s)', - ['foo.bar', 1, 2, 3], - [NotIn::TYPE_IDENTIFIER, NotIn::TYPE_VALUE, NotIn::TYPE_VALUE, NotIn::TYPE_VALUE], - ]]; - $this->assertEquals($expected, $in->getExpressionData()); - } - - public function testGetExpressionDataWithSubselect() - { - $select = new Select; - $in = new NotIn('foo', $select); - $expected = [[ - '%s NOT IN %s', - ['foo', $select], - [$in::TYPE_IDENTIFIER, $in::TYPE_VALUE] - ]]; - $this->assertEquals($expected, $in->getExpressionData()); - } - - public function testGetExpressionDataWithSubselectAndIdentifier() - { - $select = new Select; - $in = new NotIn('foo', $select); - $expected = [[ - '%s NOT IN %s', - ['foo', $select], - [$in::TYPE_IDENTIFIER, $in::TYPE_VALUE] - ]]; - $this->assertEquals($expected, $in->getExpressionData()); - } - - public function testGetExpressionDataWithSubselectAndArrayIdentifier() - { - $select = new Select; - $in = new NotIn(['foo', 'bar'], $select); - $expected = [[ - '(%s, %s) NOT IN %s', - ['foo', 'bar', $select], - [$in::TYPE_IDENTIFIER, $in::TYPE_IDENTIFIER, $in::TYPE_VALUE] - ]]; - $this->assertEquals($expected, $in->getExpressionData()); - } -} diff --git a/test/Sql/Predicate/NotLikeTest.php b/test/Sql/Predicate/NotLikeTest.php index 5dbe3fbaa9..da9b188d33 100644 --- a/test/Sql/Predicate/NotLikeTest.php +++ b/test/Sql/Predicate/NotLikeTest.php @@ -23,41 +23,23 @@ public function testConstructEmptyArgs() public function testConstructWithArgs() { $notLike = new NotLike('bar', 'Foo%'); - $this->assertEquals('bar', $notLike->getIdentifier()); - $this->assertEquals('Foo%', $notLike->getLike()); + $this->assertEquals('bar', $notLike->getIdentifier()->getValue()); + $this->assertEquals('Foo%', $notLike->getLike()->getValue()); } public function testAccessorsMutators() { $notLike = new NotLike(); $notLike->setIdentifier('bar'); - $this->assertEquals('bar', $notLike->getIdentifier()); + $this->assertEquals('bar', $notLike->getIdentifier()->getValue()); $notLike->setLike('foo%'); - $this->assertEquals('foo%', $notLike->getLike()); - $notLike->setSpecification('target = target'); - $this->assertEquals('target = target', $notLike->getSpecification()); - } - - public function testGetExpressionData() - { - $notLike = new NotLike('bar', 'Foo%'); - $this->assertEquals( - [ - [ - '%1$s NOT LIKE %2$s', - ['bar', 'Foo%'], - [$notLike::TYPE_IDENTIFIER, $notLike::TYPE_VALUE] - ] - ], - $notLike->getExpressionData() - ); + $this->assertEquals('foo%', $notLike->getLike()->getValue()); } public function testInstanceOfPerSetters() { $notLike = new NotLike(); $this->assertInstanceOf('Zend\Db\Sql\Predicate\Like', $notLike->setIdentifier('bar')); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Like', $notLike->setSpecification('%1$s NOT LIKE %2$s')); $this->assertInstanceOf('Zend\Db\Sql\Predicate\Like', $notLike->setLike('foo%')); } } diff --git a/test/Sql/Predicate/OperatorTest.php b/test/Sql/Predicate/OperatorTest.php index 54fbc145a6..97418337e5 100644 --- a/test/Sql/Predicate/OperatorTest.php +++ b/test/Sql/Predicate/OperatorTest.php @@ -11,6 +11,7 @@ use PHPUnit_Framework_TestCase as TestCase; use Zend\Db\Sql\Predicate\Operator; +use Zend\Db\Sql\ExpressionParameter; class OperatorTest extends TestCase { @@ -21,60 +22,38 @@ public function testEmptyConstructorYieldsNullLeftAndRightValues() $this->assertNull($operator->getRight()); } - public function testEmptyConstructorYieldsDefaultsForOperatorAndLeftAndRightTypes() - { - $operator = new Operator(); - $this->assertEquals(Operator::OP_EQ, $operator->getOperator()); - $this->assertEquals(Operator::TYPE_IDENTIFIER, $operator->getLeftType()); - $this->assertEquals(Operator::TYPE_VALUE, $operator->getRightType()); - } - public function testCanPassAllValuesToConstructor() { - $operator = new Operator('bar', '>=', 'foo.bar', Operator::TYPE_VALUE, Operator::TYPE_IDENTIFIER); + $operator = new Operator(['bar', Operator::TYPE_VALUE], '>=', ['foo.bar', Operator::TYPE_IDENTIFIER]); $this->assertEquals(Operator::OP_GTE, $operator->getOperator()); - $this->assertEquals('bar', $operator->getLeft()); - $this->assertEquals('foo.bar', $operator->getRight()); - $this->assertEquals(Operator::TYPE_VALUE, $operator->getLeftType()); - $this->assertEquals(Operator::TYPE_IDENTIFIER, $operator->getRightType()); + $this->assertEquals('bar', $operator->getLeft()->getValue()); + $this->assertEquals('foo.bar', $operator->getRight()->getValue()); + $this->assertEquals(Operator::TYPE_VALUE, $operator->getLeft()->getType()); + $this->assertEquals(Operator::TYPE_IDENTIFIER, $operator->getRight()->getType()); $operator = new Operator(['bar'=>Operator::TYPE_VALUE], '>=', ['foo.bar'=>Operator::TYPE_IDENTIFIER]); $this->assertEquals(Operator::OP_GTE, $operator->getOperator()); - $this->assertEquals(['bar'=>Operator::TYPE_VALUE], $operator->getLeft()); - $this->assertEquals(['foo.bar'=>Operator::TYPE_IDENTIFIER], $operator->getRight()); - $this->assertEquals(Operator::TYPE_VALUE, $operator->getLeftType()); - $this->assertEquals(Operator::TYPE_IDENTIFIER, $operator->getRightType()); + $this->assertEquals(new ExpressionParameter('bar', Operator::TYPE_VALUE), $operator->getLeft()); + $this->assertEquals(new ExpressionParameter('foo.bar', Operator::TYPE_IDENTIFIER), $operator->getRight()); + $this->assertEquals(Operator::TYPE_VALUE, $operator->getLeft()->getType()); + $this->assertEquals(Operator::TYPE_IDENTIFIER, $operator->getRight()->getType()); $operator = new Operator('bar', '>=', 0); - $this->assertEquals(0, $operator->getRight()); + $this->assertEquals(0, $operator->getRight()->getValue()); } public function testLeftIsMutable() { $operator = new Operator(); $operator->setLeft('foo.bar'); - $this->assertEquals('foo.bar', $operator->getLeft()); + $this->assertEquals('foo.bar', $operator->getLeft()->getValue()); } public function testRightIsMutable() { $operator = new Operator(); $operator->setRight('bar'); - $this->assertEquals('bar', $operator->getRight()); - } - - public function testLeftTypeIsMutable() - { - $operator = new Operator(); - $operator->setLeftType(Operator::TYPE_VALUE); - $this->assertEquals(Operator::TYPE_VALUE, $operator->getLeftType()); - } - - public function testRightTypeIsMutable() - { - $operator = new Operator(); - $operator->setRightType(Operator::TYPE_IDENTIFIER); - $this->assertEquals(Operator::TYPE_IDENTIFIER, $operator->getRightType()); + $this->assertEquals('bar', $operator->getRight()->getValue()); } public function testOperatorIsMutable() @@ -83,21 +62,4 @@ public function testOperatorIsMutable() $operator->setOperator(Operator::OP_LTE); $this->assertEquals(Operator::OP_LTE, $operator->getOperator()); } - - public function testRetrievingWherePartsReturnsSpecificationArrayOfLeftAndRightAndArrayOfTypes() - { - $operator = new Operator(); - $operator->setLeft('foo') - ->setOperator('>=') - ->setRight('foo.bar') - ->setLeftType(Operator::TYPE_VALUE) - ->setRightType(Operator::TYPE_IDENTIFIER); - $expected = [[ - '%s >= %s', - ['foo', 'foo.bar'], - [Operator::TYPE_VALUE, Operator::TYPE_IDENTIFIER], - ]]; - $test = $operator->getExpressionData(); - $this->assertEquals($expected, $test, var_export($test, 1)); - } } diff --git a/test/Sql/Predicate/PredicateSetTest.php b/test/Sql/Predicate/PredicateSetTest.php index 52987f357f..7ff9ddbb18 100644 --- a/test/Sql/Predicate/PredicateSetTest.php +++ b/test/Sql/Predicate/PredicateSetTest.php @@ -10,7 +10,6 @@ namespace ZendTest\Db\Sql\Predicate; use PHPUnit_Framework_TestCase as TestCase; -use Zend\Db\Sql\Predicate\IsNull; use Zend\Db\Sql\Predicate\PredicateSet; class PredicateSetTest extends TestCase @@ -21,70 +20,6 @@ public function testEmptyConstructorYieldsCountOfZero() $this->assertEquals(0, count($predicateSet)); } - public function testCombinationIsAndByDefault() - { - $predicateSet = new PredicateSet(); - $predicateSet->addPredicate(new IsNull('foo')) - ->addPredicate(new IsNull('bar')); - $parts = $predicateSet->getExpressionData(); - $this->assertEquals(3, count($parts)); - $this->assertContains('AND', $parts[1]); - $this->assertNotContains('OR', $parts[1]); - } - - public function testCanPassPredicatesAndDefaultCombinationViaConstructor() - { - $predicateSet = new PredicateSet(); - $set = new PredicateSet([ - new IsNull('foo'), - new IsNull('bar'), - ], 'OR'); - $parts = $set->getExpressionData(); - $this->assertEquals(3, count($parts)); - $this->assertContains('OR', $parts[1]); - $this->assertNotContains('AND', $parts[1]); - } - - public function testCanPassBothPredicateAndCombinationToAddPredicate() - { - $predicateSet = new PredicateSet(); - $predicateSet->addPredicate(new IsNull('foo'), 'OR') - ->addPredicate(new IsNull('bar'), 'AND') - ->addPredicate(new IsNull('baz'), 'OR') - ->addPredicate(new IsNull('bat'), 'AND'); - $parts = $predicateSet->getExpressionData(); - $this->assertEquals(7, count($parts)); - - $this->assertNotContains('OR', $parts[1], var_export($parts, 1)); - $this->assertContains('AND', $parts[1]); - - $this->assertContains('OR', $parts[3]); - $this->assertNotContains('AND', $parts[3]); - - $this->assertNotContains('OR', $parts[5]); - $this->assertContains('AND', $parts[5]); - } - - public function testCanUseOrPredicateAndAndPredicateMethods() - { - $predicateSet = new PredicateSet(); - $predicateSet->orPredicate(new IsNull('foo')) - ->andPredicate(new IsNull('bar')) - ->orPredicate(new IsNull('baz')) - ->andPredicate(new IsNull('bat')); - $parts = $predicateSet->getExpressionData(); - $this->assertEquals(7, count($parts)); - - $this->assertNotContains('OR', $parts[1], var_export($parts, 1)); - $this->assertContains('AND', $parts[1]); - - $this->assertContains('OR', $parts[3]); - $this->assertNotContains('AND', $parts[3]); - - $this->assertNotContains('OR', $parts[5]); - $this->assertContains('AND', $parts[5]); - } - /** * @covers Zend\Db\Sql\Predicate\PredicateSet::addPredicates */ diff --git a/test/Sql/Predicate/PredicateTest.php b/test/Sql/Predicate/PredicateTest.php index 1e80e5f6c8..c2d842865e 100644 --- a/test/Sql/Predicate/PredicateTest.php +++ b/test/Sql/Predicate/PredicateTest.php @@ -10,279 +10,272 @@ namespace ZendTest\Db\Sql\Predicate; use PHPUnit_Framework_TestCase as TestCase; -use Zend\Db\Sql\Expression; -use Zend\Db\Sql\Predicate\IsNull; use Zend\Db\Sql\Predicate\Predicate; +use Zend\Db\Sql\Predicate\Literal as predicateLiteral; +use Zend\Db\Sql\Predicate\Expression as predicateExpression; +use Zend\Db\Sql\ExpressionParameter; class PredicateTest extends TestCase { - public function testEqualToCreatesOperatorPredicate() - { - $predicate = new Predicate(); - $predicate->equalTo('foo.bar', 'bar'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%s = %s', $parts[0]); - $this->assertContains(['foo.bar', 'bar'], $parts[0]); - } - - public function testNotEqualToCreatesOperatorPredicate() - { - $predicate = new Predicate(); - $predicate->notEqualTo('foo.bar', 'bar'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%s != %s', $parts[0]); - $this->assertContains(['foo.bar', 'bar'], $parts[0]); - } - - - public function testLessThanCreatesOperatorPredicate() - { - $predicate = new Predicate(); - $predicate->lessThan('foo.bar', 'bar'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%s < %s', $parts[0]); - $this->assertContains(['foo.bar', 'bar'], $parts[0]); - } - - public function testGreaterThanCreatesOperatorPredicate() - { - $predicate = new Predicate(); - $predicate->greaterThan('foo.bar', 'bar'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%s > %s', $parts[0]); - $this->assertContains(['foo.bar', 'bar'], $parts[0]); - } - - public function testLessThanOrEqualToCreatesOperatorPredicate() - { - $predicate = new Predicate(); - $predicate->lessThanOrEqualTo('foo.bar', 'bar'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%s <= %s', $parts[0]); - $this->assertContains(['foo.bar', 'bar'], $parts[0]); - } - - public function testGreaterThanOrEqualToCreatesOperatorPredicate() - { - $predicate = new Predicate(); - $predicate->greaterThanOrEqualTo('foo.bar', 'bar'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%s >= %s', $parts[0]); - $this->assertContains(['foo.bar', 'bar'], $parts[0]); - } - - public function testLikeCreatesLikePredicate() - { - $predicate = new Predicate(); - $predicate->like('foo.bar', 'bar%'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%1$s LIKE %2$s', $parts[0]); - $this->assertContains(['foo.bar', 'bar%'], $parts[0]); - } - - public function testNotLikeCreatesLikePredicate() - { - $predicate = new Predicate(); - $predicate->notLike('foo.bar', 'bar%'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%1$s NOT LIKE %2$s', $parts[0]); - $this->assertContains(['foo.bar', 'bar%'], $parts[0]); - } - - public function testLiteralCreatesLiteralPredicate() - { - $predicate = new Predicate(); - $predicate->literal('foo.bar = ?', 'bar'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('foo.bar = %s', $parts[0]); - $this->assertContains(['bar'], $parts[0]); - } - - public function testIsNullCreatesIsNullPredicate() - { - $predicate = new Predicate(); - $predicate->isNull('foo.bar'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%1$s IS NULL', $parts[0]); - $this->assertContains(['foo.bar'], $parts[0]); - } - - public function testIsNotNullCreatesIsNotNullPredicate() - { - $predicate = new Predicate(); - $predicate->isNotNull('foo.bar'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%1$s IS NOT NULL', $parts[0]); - $this->assertContains(['foo.bar'], $parts[0]); - } - - public function testInCreatesInPredicate() + /** + * @covers Zend\Db\Sql\Predicate\Predicate::addPredicates + * @covers Zend\Db\Sql\Predicate\Predicate::getPredicates + */ + public function testWhereArgument1IsAssociativeArrayContainingReplacementCharacter() { - $predicate = new Predicate(); - $predicate->in('foo.bar', ['foo', 'bar']); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%s IN (%s, %s)', $parts[0]); - $this->assertContains(['foo.bar', 'foo', 'bar'], $parts[0]); + $where = new Predicate; + $predicates = $where + ->addPredicates(['foo > ?' => 5]) + ->getPredicates(); + $this->assertEquals(1, count($predicates)); + $this->assertInstanceOf('Zend\Db\Sql\Predicate\Expression', $predicates[0][1]); + $this->assertEquals(Predicate::OP_AND, $predicates[0][0]); + $this->assertEquals('foo > ?', $predicates[0][1]->getExpression()); + $this->assertEquals( + [ + new ExpressionParameter(5) + ], + $predicates[0][1]->getParameters() + ); } - public function testNotInCreatesNotInPredicate() + /** + * @covers Zend\Db\Sql\Predicate\Predicate::addPredicates + * @covers Zend\Db\Sql\Predicate\Predicate::getPredicates + */ + public function testWhereArgument1IsAssociativeArrayNotContainingReplacementCharacter() { - $predicate = new Predicate(); - $predicate->notIn('foo.bar', ['foo', 'bar']); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%s NOT IN (%s, %s)', $parts[0]); - $this->assertContains(['foo.bar', 'foo', 'bar'], $parts[0]); + $where = new Predicate; + $predicates = $where + ->addPredicates(['name' => 'Ralph', 'age' => 33]) + ->getPredicates(); + $this->assertEquals(2, count($predicates)); + + $this->assertInstanceOf('Zend\Db\Sql\Predicate\Operator', $predicates[0][1]); + $this->assertEquals(Predicate::OP_AND, $predicates[0][0]); + $this->assertEquals('name', $predicates[0][1]->getLeft()->getValue()); + $this->assertEquals('Ralph', $predicates[0][1]->getRight()->getValue()); + + $this->assertInstanceOf('Zend\Db\Sql\Predicate\Operator', $predicates[1][1]); + $this->assertEquals(Predicate::OP_AND, $predicates[1][0]); + $this->assertEquals('age', $predicates[1][1]->getLeft()->getValue()); + $this->assertEquals(33, $predicates[1][1]->getRight()->getValue()); + + $where = new Predicate; + $predicates = $where + ->addPredicates(['x = y']) + ->getPredicates(); + $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[0][1]); } - public function testBetweenCreatesBetweenPredicate() + /** + * @covers Zend\Db\Sql\Predicate\Predicate::addPredicates + */ + public function testWhereArgument1IsAssociativeArrayIsPredicate() { - $predicate = new Predicate(); - $predicate->between('foo.bar', 1, 10); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%1$s BETWEEN %2$s AND %3$s', $parts[0]); - $this->assertContains(['foo.bar', 1, 10], $parts[0]); + $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', 'Using Predicate must not use string keys'); + $where = new Predicate; + $where->addPredicates([ + 'name' => new predicateLiteral("name = 'Ralph'"), + 'age' => new predicateExpression('age = ?', 33), + ]); } - public function testBetweenCreatesNotBetweenPredicate() + /** + * @covers Zend\Db\Sql\Predicate\Predicate::addPredicates + * @covers Zend\Db\Sql\Predicate\Predicate::getPredicates + */ + public function testWhereArgument1IsIndexedArray() { - $predicate = new Predicate(); - $predicate->notBetween('foo.bar', 1, 10); - $parts = $predicate->getExpressionData(); - $this->assertEquals(1, count($parts)); - $this->assertContains('%1$s NOT BETWEEN %2$s AND %3$s', $parts[0]); - $this->assertContains(['foo.bar', 1, 10], $parts[0]); + $where = new Predicate; + $predicates = $where + ->addPredicates(['name = "Ralph"']) + ->getPredicates(); + + $this->assertEquals(1, count($predicates)); + $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[0][1]); + $this->assertEquals(Predicate::OP_AND, $predicates[0][0]); + $this->assertEquals('name = "Ralph"', $predicates[0][1]->getLiteral()); } - public function testCanChainPredicateFactoriesBetweenOperators() + /** + * @covers Zend\Db\Sql\Predicate\Predicate::addPredicates + * @covers Zend\Db\Sql\Predicate\Predicate::getPredicates + */ + public function testWhereArgument1IsIndexedArrayArgument2IsOr() { - $predicate = new Predicate(); - $predicate->isNull('foo.bar') - ->or - ->isNotNull('bar.baz') - ->and - ->equalTo('baz.bat', 'foo'); - $parts = $predicate->getExpressionData(); - $this->assertEquals(5, count($parts)); - - $this->assertContains('%1$s IS NULL', $parts[0]); - $this->assertContains(['foo.bar'], $parts[0]); - - $this->assertEquals(' OR ', $parts[1]); - - $this->assertContains('%1$s IS NOT NULL', $parts[2]); - $this->assertContains(['bar.baz'], $parts[2]); - - $this->assertEquals(' AND ', $parts[3]); - - $this->assertContains('%s = %s', $parts[4]); - $this->assertContains(['baz.bat', 'foo'], $parts[4]); + $where = new Predicate; + $predicates = $where + ->addPredicates(['name = "Ralph"'], Predicate::OP_OR) + ->getPredicates(); + + $this->assertEquals(1, count($predicates)); + $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[0][1]); + $this->assertEquals(Predicate::OP_OR, $predicates[0][0]); + $this->assertEquals('name = "Ralph"', $predicates[0][1]->getLiteral()); } - public function testCanNestPredicates() + /** + * @covers Zend\Db\Sql\Predicate\Predicate::addPredicates + */ + public function testWhereArgument1IsClosure() { - $predicate = new Predicate(); - $predicate->isNull('foo.bar') - ->nest() - ->isNotNull('bar.baz') - ->and - ->equalTo('baz.bat', 'foo') - ->unnest(); - $parts = $predicate->getExpressionData(); - - $this->assertEquals(7, count($parts)); - - $this->assertContains('%1$s IS NULL', $parts[0]); - $this->assertContains(['foo.bar'], $parts[0]); - - $this->assertEquals(' AND ', $parts[1]); - - $this->assertEquals('(', $parts[2]); - - $this->assertContains('%1$s IS NOT NULL', $parts[3]); - $this->assertContains(['bar.baz'], $parts[3]); - - $this->assertEquals(' AND ', $parts[4]); - - $this->assertContains('%s = %s', $parts[5]); - $this->assertContains(['baz.bat', 'foo'], $parts[5]); - - $this->assertEquals(')', $parts[6]); + $where = new Predicate; + $test = $this; + $where->addPredicates(function ($what) use ($test, $where) { + $test->assertSame($where, $what); + }); } /** - * @testdox Unit test: Test expression() is chainable and returns proper values + * @covers Zend\Db\Sql\Predicate\Predicate::addPredicates + * @covers Zend\Db\Sql\Predicate\Predicate::getPredicates */ - public function testExpression() + public function testWhereArgument1IsString() { - $predicate = new Predicate; - - // is chainable - $this->assertSame($predicate, $predicate->expression('foo = ?', 0)); - // with parameter - $this->assertEquals( - [['foo = %s', [0], [Expression::TYPE_VALUE]]], - $predicate->getExpressionData() - ); + $where = new Predicate; + $predicates = $where + ->addPredicates('x = ?') + ->getPredicates(); + + $this->assertEquals(1, count($predicates)); + $this->assertInstanceOf('Zend\Db\Sql\Predicate\Expression', $predicates[0][1]); + $this->assertEquals(Predicate::OP_AND, $predicates[0][0]); + $this->assertEquals('x = ?', $predicates[0][1]->getExpression()); + + $where = new Predicate; + $predicates = $where + ->addPredicates('x = y') + ->getPredicates(); + + $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[0][1]); } - /** - * @testdox Unit test: Test expression() allows null $parameters - */ - public function testExpressionNullParameters() + public function testMethodsIsMutable() { $predicate = new Predicate; - $predicate->expression('foo = bar'); - $predicates = $predicate->getPredicates(); - $expression = $predicates[0][1]; - $this->assertEquals([null], $expression->getParameters()); + $this->assertSame($predicate, $predicate->equalTo('foo.bar', 'bar')); + $this->assertSame($predicate, $predicate->notEqualTo('foo.bar', 'bar')); + $this->assertSame($predicate, $predicate->lessThan('foo.bar', 'bar')); + $this->assertSame($predicate, $predicate->greaterThan('foo.bar', 'bar')); + $this->assertSame($predicate, $predicate->lessThanOrEqualTo('foo.bar', 'bar')); + $this->assertSame($predicate, $predicate->greaterThanOrEqualTo('foo.bar', 'bar')); + $this->assertSame($predicate, $predicate->like('foo.bar', 'bar%')); + $this->assertSame($predicate, $predicate->notLike('foo.bar', 'bar%')); + $this->assertSame($predicate, $predicate->literal('foo.bar = ?', 'bar')); + $this->assertSame($predicate, $predicate->isNull('foo.bar')); + $this->assertSame($predicate, $predicate->isNotNull('foo.bar')); + $this->assertSame($predicate, $predicate->in('foo.bar', ['foo', 'bar'])); + $this->assertSame($predicate, $predicate->notIn('foo.bar', ['foo', 'bar'])); + $this->assertSame($predicate, $predicate->between('foo.bar', 1, 10)); + $this->assertSame($predicate, $predicate->expression('foo = ?', 'bar')); + $this->assertSame( + $predicate, + $predicate + ->isNull('foo.bar') + ->or + ->isNotNull('bar.baz') + ->and + ->equalTo('baz.bat', 'foo') + ); + $this->assertSame( + $predicate, + $predicate + ->isNull('foo.bar') + ->nest() + ->isNotNull('bar.baz') + ->and + ->equalTo('baz.bat', 'foo') + ->unnest() + ); } /** - * @testdox Unit test: Test literal() is chainable, returns proper values, and is backwards compatible with 2.0.* + * @covers Zend\Db\Sql\Predicate\Predicate::between + * @covers Zend\Db\Sql\Predicate\Predicate::equalTo + * @covers Zend\Db\Sql\Predicate\Predicate::expression + * @covers Zend\Db\Sql\Predicate\Predicate::greaterThan + * @covers Zend\Db\Sql\Predicate\Predicate::greaterThanOrEqualTo + * @covers Zend\Db\Sql\Predicate\Predicate::in + * @covers Zend\Db\Sql\Predicate\Predicate::isNotNull + * @covers Zend\Db\Sql\Predicate\Predicate::isNull + * @covers Zend\Db\Sql\Predicate\Predicate::lessThan + * @covers Zend\Db\Sql\Predicate\Predicate::lessThanOrEqualTo + * @covers Zend\Db\Sql\Predicate\Predicate::like + * @covers Zend\Db\Sql\Predicate\Predicate::literal + * @covers Zend\Db\Sql\Predicate\Predicate::notBetween + * @covers Zend\Db\Sql\Predicate\Predicate::notEqualTo + * @covers Zend\Db\Sql\Predicate\Predicate::notIn + * @covers Zend\Db\Sql\Predicate\Predicate::notLike */ - public function testLiteral() + public function testPredicatesIsCorrectInstances() { $predicate = new Predicate; - // is chainable - $this->assertSame($predicate, $predicate->literal('foo = bar')); - // with parameter - $this->assertEquals( - [['foo = bar', [], []]], - $predicate->getExpressionData() + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\Between', + $predicate->between('p1', 'p2', 'p3')->getPredicates()[0][1] ); - - // test literal() is backwards-compatible, and works with with parameters - $predicate = new Predicate; - $predicate->expression('foo = ?', 'bar'); - // with parameter - $this->assertEquals( - [['foo = %s', ['bar'], [Expression::TYPE_VALUE]]], - $predicate->getExpressionData() + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\Operator', + $predicate->equalTo('p1', 'p2')->getPredicates()[1][1] ); - - // test literal() is backwards-compatible, and works with with parameters, even 0 which tests as false - $predicate = new Predicate; - $predicate->expression('foo = ?', 0); - // with parameter - $this->assertEquals( - [['foo = %s', [0], [Expression::TYPE_VALUE]]], - $predicate->getExpressionData() + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\Expression', + $predicate->expression('', [])->getPredicates()[2][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\Operator', + $predicate->greaterThan('p1', 'p2')->getPredicates()[3][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\Operator', + $predicate->greaterThanOrEqualTo('p1', 'p2')->getPredicates()[4][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\In', + $predicate->in('p1')->getPredicates()[5][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\IsNotNull', + $predicate->isNotNull('p1')->getPredicates()[6][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\IsNull', + $predicate->isNull('p1')->getPredicates()[7][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\Operator', + $predicate->lessThan('p1', 'p2')->getPredicates()[8][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\Operator', + $predicate->lessThanOrEqualTo('p1', 'p2')->getPredicates()[9][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\Like', + $predicate->like('p1', 'p2')->getPredicates()[10][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\Literal', + $predicate->literal('p1')->getPredicates()[11][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\NotBetween', + $predicate->notBetween('p1', 'p2', 'p3')->getPredicates()[12][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\Operator', + $predicate->notEqualTo('p1', 'p2')->getPredicates()[13][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\NotIn', + $predicate->notIn('p1')->getPredicates()[14][1] + ); + $this->assertInstanceOf( + 'Zend\Db\Sql\Predicate\NotLike', + $predicate->notLike('p1', 'p2')->getPredicates()[15][1] ); } } diff --git a/test/Sql/SelectTest.php b/test/Sql/SelectTest.php index d90585f7fe..66b6a9eab2 100644 --- a/test/Sql/SelectTest.php +++ b/test/Sql/SelectTest.php @@ -9,16 +9,13 @@ namespace ZendTest\Db\Sql; -use ReflectionObject; use Zend\Db\Sql\Select; -use Zend\Db\Sql\Expression; use Zend\Db\Sql\Where; use Zend\Db\Sql\Having; use Zend\Db\Sql\Predicate; use Zend\Db\Sql\TableIdentifier; -use Zend\Db\Adapter\ParameterContainer; -use Zend\Db\Adapter\Platform\Sql92; -use ZendTest\Db\TestAsset\TrustingSql92Platform; +use Zend\Db\Sql\TableSource; +use Zend\Db\Sql\Joins; class SelectTest extends \PHPUnit_Framework_TestCase { @@ -28,52 +25,48 @@ class SelectTest extends \PHPUnit_Framework_TestCase public function testConstruct() { $select = new Select('foo'); - $this->assertEquals('foo', $select->getRawState('table')); + $this->assertEquals('foo', $select->table->getSource()->getTable()); } - /** - * @testdox unit test: Test from() returns Select object (is chainable) - * @covers Zend\Db\Sql\Select::from - */ - public function testFrom() + public function testMethodsReturnSelf() { $select = new Select; - $return = $select->from('foo', 'bar'); - $this->assertSame($select, $return); - - return $return; - } - - /** - * @testdox unit test: Test getRawState() returns information populated via from() - * @covers Zend\Db\Sql\Select::getRawState - * @depends testFrom - */ - public function testGetRawStateViaFrom(Select $select) - { - $this->assertEquals('foo', $select->getRawState('table')); - } - - /** - * @testdox unit test: Test quantifier() returns Select object (is chainable) - * @covers Zend\Db\Sql\Select::quantifier - */ - public function testQuantifier() - { - $select = new Select; - $return = $select->quantifier($select::QUANTIFIER_DISTINCT); - $this->assertSame($select, $return); - return $return; + $this->assertSame($select, $select->from('foo', 'bar')); + $this->assertSame($select, $select->quantifier($select::QUANTIFIER_DISTINCT)); + $this->assertSame($select, $select->columns(['foo', 'bar'])); + $this->assertSame($select, $select->join('foo', 'x = y', Select::SQL_STAR, Joins::JOIN_INNER)); + $this->assertSame($select, $select->where('x = y')); + $this->assertSame($select, $select->limit(5)); + $this->assertSame($select, $select->offset(10)); + $this->assertSame($select, $select->group(['col1', 'col2'])); + $this->assertSame($select, $select->having(['x = ?' => 5])); + return $select; } /** - * @testdox unit test: Test getRawState() returns information populated via quantifier() - * @covers Zend\Db\Sql\Select::getRawState - * @depends testQuantifier + * @testdox unit test: Test __get() returns expected objects magically + * @covers Zend\Db\Sql\Select::__get + * @depends testMethodsReturnSelf */ - public function testGetRawStateViaQuantifier(Select $select) + public function testMagicAccessor(Select $select) { - $this->assertEquals(Select::QUANTIFIER_DISTINCT, $select->getRawState('quantifier')); + $this->assertInstanceOf('Zend\Db\Sql\Where', $select->where); + $this->assertEquals(['foo', 'bar'], $select->columns); + $this->assertEquals('foo', $select->table->getSource()->getTable()); + $this->assertEquals(['col1', 'col2'], $select->group); + $this->assertEquals( + [[ + 'name' => new TableSource(new TableIdentifier('foo')), + 'on' => 'x = y', + 'columns' => [Select::SQL_STAR], + 'type' => Joins::JOIN_INNER + ]], + $select->joins->getJoins() + ); + $this->assertInstanceOf('Zend\Db\Sql\Having', $select->having); + $this->assertEquals(5, $select->limit); + $this->assertEquals(10, $select->offset); + $this->assertEquals(Select::QUANTIFIER_DISTINCT, $select->quantifier); } /** @@ -87,267 +80,10 @@ public function testQuantifierParameterExpressionInterface() $select->quantifier($expr); $this->assertSame( $expr, - $select->getRawState(Select::QUANTIFIER) + $select->quantifier ); } - /** - * @testdox unit test: Test columns() returns Select object (is chainable) - * @covers Zend\Db\Sql\Select::columns - */ - public function testColumns() - { - $select = new Select; - $return = $select->columns(['foo', 'bar']); - $this->assertSame($select, $return); - - return $select; - } - - /** - * @testdox unit test: Test isTableReadOnly() returns correct state for read only - * @covers Zend\Db\Sql\Select::isTableReadOnly - */ - public function testIsTableReadOnly() - { - $select = new Select('foo'); - $this->assertTrue($select->isTableReadOnly()); - - $select = new Select; - $this->assertFalse($select->isTableReadOnly()); - } - - /** - * @testdox unit test: Test getRawState() returns information populated via columns() - * @covers Zend\Db\Sql\Select::getRawState - * @depends testColumns - */ - public function testGetRawStateViaColumns(Select $select) - { - $this->assertEquals(['foo', 'bar'], $select->getRawState('columns')); - } - - /** - * @testdox unit test: Test join() returns same Select object (is chainable) - * @covers Zend\Db\Sql\Select::join - */ - public function testJoin() - { - $select = new Select; - $return = $select->join('foo', 'x = y', Select::SQL_STAR, Select::JOIN_INNER); - $this->assertSame($select, $return); - - return $return; - } - - /** - * @testdox unit test: Test join() exception with bad join - * @covers Zend\Db\Sql\Select::join - */ - public function testBadJoin() - { - $select = new Select; - $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', "expects 'foo' as"); - $select->join(['foo'], 'x = y', Select::SQL_STAR, Select::JOIN_INNER); - } - - /** - * @testdox unit test: Test processJoins() exception with bad join name - * @covers Zend\Db\Sql\Select::processJoins - */ - public function testBadJoinName() - { - $mockExpression = $this->getMock('Zend\Db\Sql\ExpressionInterface', [], ['bar']); - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $parameterContainer = new ParameterContainer(); - - $select = new Select; - $select->join(['foo' => $mockExpression], 'x = y', Select::SQL_STAR, Select::JOIN_INNER); - - $sr = new ReflectionObject($select); - - $mr = $sr->getMethod('processJoins'); - - $mr->setAccessible(true); - - $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException'); - - $mr->invokeArgs($select, [new Sql92, $mockDriver, $parameterContainer]); - } - - /** - * @testdox unit test: Test getRawState() returns information populated via join() - * @covers Zend\Db\Sql\Select::getRawState - * @depends testJoin - */ - public function testGetRawStateViaJoin(Select $select) - { - $this->assertEquals( - [[ - 'name' => 'foo', - 'on' => 'x = y', - 'columns' => [Select::SQL_STAR], - 'type' => Select::JOIN_INNER - ]], - $select->getRawState('joins')->getJoins() - ); - } - - /** - * @testdox unit test: Test where() returns Select object (is chainable) - * @covers Zend\Db\Sql\Select::where - */ - public function testWhereReturnsSameSelectObject() - { - $select = new Select; - $this->assertSame($select, $select->where('x = y')); - } - - /** - * @testdox unit test: Test where() will accept a string for the predicate to create an expression predicate - * @covers Zend\Db\Sql\Select::where - */ - public function testWhereArgument1IsString() - { - $select = new Select; - $select->where('x = ?'); - - /** @var $where Where */ - $where = $select->getRawState('where'); - $predicates = $where->getPredicates(); - $this->assertEquals(1, count($predicates)); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Expression', $predicates[0][1]); - $this->assertEquals(Where::OP_AND, $predicates[0][0]); - $this->assertEquals('x = ?', $predicates[0][1]->getExpression()); - - $select = new Select; - $select->where('x = y'); - - /** @var $where Where */ - $where = $select->getRawState('where'); - $predicates = $where->getPredicates(); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[0][1]); - } - - /** - * @testdox unit test: Test where() will accept an array with a string key (containing ?) used as an expression with placeholder - * @covers Zend\Db\Sql\Select::where - */ - public function testWhereArgument1IsAssociativeArrayContainingReplacementCharacter() - { - $select = new Select; - $select->where(['foo > ?' => 5]); - - /** @var $where Where */ - $where = $select->getRawState('where'); - $predicates = $where->getPredicates(); - $this->assertEquals(1, count($predicates)); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Expression', $predicates[0][1]); - $this->assertEquals(Where::OP_AND, $predicates[0][0]); - $this->assertEquals('foo > ?', $predicates[0][1]->getExpression()); - $this->assertEquals([5], $predicates[0][1]->getParameters()); - } - - /** - * @testdox unit test: Test where() will accept any array with string key (without ?) to be used as Operator predicate - * @covers Zend\Db\Sql\Select::where - */ - public function testWhereArgument1IsAssociativeArrayNotContainingReplacementCharacter() - { - $select = new Select; - $select->where(['name' => 'Ralph', 'age' => 33]); - - /** @var $where Where */ - $where = $select->getRawState('where'); - $predicates = $where->getPredicates(); - $this->assertEquals(2, count($predicates)); - - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Operator', $predicates[0][1]); - $this->assertEquals(Where::OP_AND, $predicates[0][0]); - $this->assertEquals('name', $predicates[0][1]->getLeft()); - $this->assertEquals('Ralph', $predicates[0][1]->getRight()); - - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Operator', $predicates[1][1]); - $this->assertEquals(Where::OP_AND, $predicates[1][0]); - $this->assertEquals('age', $predicates[1][1]->getLeft()); - $this->assertEquals(33, $predicates[1][1]->getRight()); - - $select = new Select; - $select->where(['x = y']); - - $where = $select->getRawState('where'); - $predicates = $where->getPredicates(); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[0][1]); - } - - /** - * @testdox unit test: Test where() will accept any array with string key (without ?) with Predicate throw Exception - * @covers Zend\Db\Sql\Select::where - */ - public function testWhereArgument1IsAssociativeArrayIsPredicate() - { - $select = new Select; - $where = [ - 'name' => new Predicate\Literal("name = 'Ralph'"), - 'age' => new Predicate\Expression('age = ?', 33), - ]; - $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', 'Using Predicate must not use string keys'); - $select->where($where); - } - - /** - * @testdox unit test: Test where() will accept an indexed array to be used by joining string expressions - * @covers Zend\Db\Sql\Select::where - */ - public function testWhereArgument1IsIndexedArray() - { - $select = new Select; - $select->where(['name = "Ralph"']); - - /** @var $where Where */ - $where = $select->getRawState('where'); - $predicates = $where->getPredicates(); - $this->assertEquals(1, count($predicates)); - - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[0][1]); - $this->assertEquals(Where::OP_AND, $predicates[0][0]); - $this->assertEquals('name = "Ralph"', $predicates[0][1]->getLiteral()); - } - - /** - * @testdox unit test: Test where() will accept an indexed array to be used by joining string expressions, combined by OR - * @covers Zend\Db\Sql\Select::where - */ - public function testWhereArgument1IsIndexedArrayArgument2IsOr() - { - $select = new Select; - $select->where(['name = "Ralph"'], Where::OP_OR); - - /** @var $where Where */ - $where = $select->getRawState('where'); - $predicates = $where->getPredicates(); - $this->assertEquals(1, count($predicates)); - - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[0][1]); - $this->assertEquals(Where::OP_OR, $predicates[0][0]); - $this->assertEquals('name = "Ralph"', $predicates[0][1]->getLiteral()); - } - - /** - * @testdox unit test: Test where() will accept a closure to be executed with Where object as argument - * @covers Zend\Db\Sql\Select::where - */ - public function testWhereArgument1IsClosure() - { - $select = new Select; - $where = $select->getRawState('where'); - - $select->where(function ($what) use ($where) { - $this->assertSame($where, $what); - }); - } - /** * @testdox unit test: Test where() will accept any Predicate object as-is * @covers Zend\Db\Sql\Select::where @@ -361,12 +97,9 @@ public function testWhereArgument1IsPredicate() ]); $select->where($predicate); - /** @var $where Where */ - $where = $select->getRawState('where'); - $predicates = $where->getPredicates(); + $predicates = $select->where->getPredicates(); $this->assertSame($predicate, $predicates[0][1]); } - /** * @testdox unit test: Test where() will accept a Where object * @covers Zend\Db\Sql\Select::where @@ -375,7 +108,7 @@ public function testWhereArgument1IsWhereObject() { $select = new Select; $select->where($newWhere = new Where); - $this->assertSame($newWhere, $select->getRawState('where')); + $this->assertSame($newWhere, $select->where); } /** @@ -388,61 +121,17 @@ public function testOrder() $select = new Select; $return = $select->order('id DESC'); $this->assertSame($select, $return); // test fluent interface - $this->assertEquals(['id DESC'], $select->getRawState('order')); + $this->assertEquals(['id DESC'], $select->order); $select = new Select; $select->order('id DESC') ->order('name ASC, age DESC'); - $this->assertEquals(['id DESC', 'name ASC', 'age DESC'], $select->getRawState('order')); + $this->assertEquals(['id DESC', 'name ASC', 'age DESC'], $select->order); $select = new Select; $select->order(['name ASC', 'age DESC']); - $this->assertEquals(['name ASC', 'age DESC'], $select->getRawState('order')); - - $select = new Select; - $select->order(new Expression('RAND()')); - $sr = new ReflectionObject($select); - $method = $sr->getMethod('processOrder'); - $method->setAccessible(true); - $this->assertEquals( - [[['RAND()']]], - $method->invokeArgs($select, [new TrustingSql92Platform()]) - ); - - $select = new Select; - $select->order( - $this->getMock('Zend\Db\Sql\Predicate\Operator', null, ['rating', '<', '10']) - ); - $sr = new ReflectionObject($select); - $method = $sr->getMethod('processOrder'); - $method->setAccessible(true); - $this->assertEquals( - [[['"rating" < \'10\'']]], - $method->invokeArgs($select, [new TrustingSql92Platform()]) - ); - } - - /** - * @testdox: unit test: test limit() - * @covers Zend\Db\Sql\Select::limit - */ - public function testLimit() - { - $select = new Select; - $this->assertSame($select, $select->limit(5)); - return $select; + $this->assertEquals(['name ASC', 'age DESC'], $select->order); } - - /** - * @testdox: unit test: Test getRawState() returns information populated via limit() - * @covers Zend\Db\Sql\Select::getRawState - * @depends testLimit - */ - public function testGetRawStateViaLimit(Select $select) - { - $this->assertEquals(5, $select->getRawState($select::LIMIT)); - } - /** * @testdox: unit test: test limit() throws execption when invalid parameter passed * @covers Zend\Db\Sql\Select::limit @@ -454,27 +143,6 @@ public function testLimitExceptionOnInvalidParameter() $select->limit('foobar'); } - /** - * @testdox: unit test: test offset() - * @covers Zend\Db\Sql\Select::offset - */ - public function testOffset() - { - $select = new Select; - $this->assertSame($select, $select->offset(10)); - return $select; - } - - /** - * @testdox: unit test: Test getRawState() returns information populated via offset() - * @covers Zend\Db\Sql\Select::getRawState - * @depends testOffset - */ - public function testGetRawStateViaOffset(Select $select) - { - $this->assertEquals(10, $select->getRawState($select::OFFSET)); - } - /** * @testdox: unit test: test offset() throws exception when invalid parameter passed * @covers Zend\Db\Sql\Select::offset @@ -486,46 +154,6 @@ public function testOffsetExceptionOnInvalidParameter() $select->offset('foobar'); } - - /** - * @testdox unit test: Test group() returns same Select object (is chainable) - * @covers Zend\Db\Sql\Select::group - */ - public function testGroup() - { - $select = new Select; - $return = $select->group(['col1', 'col2']); - $this->assertSame($select, $return); - - return $return; - } - - /** - * @testdox unit test: Test getRawState() returns information populated via group() - * @covers Zend\Db\Sql\Select::getRawState - * @depends testGroup - */ - public function testGetRawStateViaGroup(Select $select) - { - $this->assertEquals( - ['col1', 'col2'], - $select->getRawState('group') - ); - } - - /** - * @testdox unit test: Test having() returns same Select object (is chainable) - * @covers Zend\Db\Sql\Select::having - */ - public function testHaving() - { - $select = new Select; - $return = $select->having(['x = ?' => 5]); - $this->assertSame($select, $return); - - return $return; - } - /** * @testdox unit test: Test having() returns same Select object (is chainable) * @covers Zend\Db\Sql\Select::having @@ -536,176 +164,44 @@ public function testHavingArgument1IsHavingObject() $having = new Having(); $return = $select->having($having); $this->assertSame($select, $return); - $this->assertSame($having, $select->getRawState('having')); - - return $return; - } - - /** - * @testdox unit test: Test getRawState() returns information populated via having() - * @covers Zend\Db\Sql\Select::getRawState - * @depends testHaving - */ - public function testGetRawStateViaHaving(Select $select) - { - $this->assertInstanceOf('Zend\Db\Sql\Having', $select->getRawState('having')); - } - - /** - * @testdox unit test: Test combine() returns same Select object (is chainable) - * @covers Zend\Db\Sql\Select::combine - */ - public function testCombine() - { - $select = new Select; - $combine = new Select; - $return = $select->combine($combine, $select::COMBINE_UNION, 'ALL'); - $this->assertSame($select, $return); + $this->assertSame($having, $select->having); return $return; } - /** - * @testdox unit test: Test getRawState() returns information populated via combine() - * @covers Zend\Db\Sql\Select::getRawState - * @depends testCombine - */ - public function testGetRawStateViaCombine(Select $select) - { - $state = $select->getRawState('combine'); - $this->assertInstanceOf('Zend\Db\Sql\Select', $state['select']); - $this->assertNotSame($select, $state['select']); - $this->assertEquals(Select::COMBINE_UNION, $state['type']); - $this->assertEquals('ALL', $state['modifier']); - } - /** * @testdox unit test: Test reset() resets internal stat of Select object, based on input - * @covers Zend\Db\Sql\Select::reset + * @covers Zend\Db\Sql\Select::__unset */ - public function testReset() + public function testMagicUnset() { $select = new Select; - // table - $select->from('foo'); - $this->assertEquals('foo', $select->getRawState(Select::TABLE)); - $select->reset(Select::TABLE); - $this->assertNull($select->getRawState(Select::TABLE)); - - // columns - $select->columns(['foo']); - $this->assertEquals(['foo'], $select->getRawState(Select::COLUMNS)); - $select->reset(Select::COLUMNS); - $this->assertEmpty($select->getRawState(Select::COLUMNS)); - - // joins - $select->join('foo', 'id = boo'); - $this->assertEquals([['name' => 'foo', 'on' => 'id = boo', 'columns' => ['*'], 'type' => 'inner']], $select->getRawState(Select::JOINS)->getJoins()); - $select->reset(Select::JOINS); - $this->assertEmpty($select->getRawState(Select::JOINS)->getJoins()); - - // where - $select->where('foo = bar'); - $where1 = $select->getRawState(Select::WHERE); - $this->assertEquals(1, $where1->count()); - $select->reset(Select::WHERE); - $where2 = $select->getRawState(Select::WHERE); - $this->assertEquals(0, $where2->count()); - $this->assertNotSame($where1, $where2); - - // group - $select->group(['foo']); - $this->assertEquals(['foo'], $select->getRawState(Select::GROUP)); - $select->reset(Select::GROUP); - $this->assertEmpty($select->getRawState(Select::GROUP)); - - // having - $select->having('foo = bar'); - $having1 = $select->getRawState(Select::HAVING); - $this->assertEquals(1, $having1->count()); - $select->reset(Select::HAVING); - $having2 = $select->getRawState(Select::HAVING); - $this->assertEquals(0, $having2->count()); - $this->assertNotSame($having1, $having2); - - // limit - $select->limit(5); - $this->assertEquals(5, $select->getRawState(Select::LIMIT)); - $select->reset(Select::LIMIT); - $this->assertNull($select->getRawState(Select::LIMIT)); - - // offset - $select->offset(10); - $this->assertEquals(10, $select->getRawState(Select::OFFSET)); - $select->reset(Select::OFFSET); - $this->assertNull($select->getRawState(Select::OFFSET)); - - // order - $select->order('foo asc'); - $this->assertEquals(['foo asc'], $select->getRawState(Select::ORDER)); - $select->reset(Select::ORDER); - $this->assertEmpty($select->getRawState(Select::ORDER)); - } - - /** - * @testdox unit test: Test prepareStatement() will produce expected sql and parameters based on a variety of provided arguments [uses data provider] - * @covers Zend\Db\Sql\Select::prepareStatement - * @dataProvider providerData - */ - public function testPrepareStatement(Select $select, $expectedSqlString, $expectedParameters, $unused1, $unused2, $useNamedParameters = false) - { - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnCallback( - function ($name) use ($useNamedParameters) { - return (($useNamedParameters) ? ':' . $name : '?'); - } - )); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $parameterContainer = new ParameterContainer(); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer)); - $mockStatement->expects($this->any())->method('setSql')->with($this->equalTo($expectedSqlString)); - - $select->prepareStatement($mockAdapter, $mockStatement); - - if ($expectedParameters) { - $this->assertEquals($expectedParameters, $parameterContainer->getNamedArray()); + $originalValues = []; + $clonedSelect = clone $select; + foreach (array_flip($this->readAttribute($clonedSelect, '__getProperties')) as $name) { + $originalValues[$name] = $clonedSelect->$name; } - } - - /** - * @group ZF2-5192 - */ - public function testSelectUsingTableIdentifierWithEmptyScheme() - { - $select = new Select; - $select->from(new TableIdentifier('foo')); - $select->join(new TableIdentifier('bar'), 'foo.id = bar.fooid'); - - $this->assertEquals('SELECT "foo".*, "bar".* FROM "foo" INNER JOIN "bar" ON "foo"."id" = "bar"."fooid"', $select->getSqlString(new TrustingSql92Platform())); - } - - /** - * @testdox unit test: Test getSqlString() will produce expected sql and parameters based on a variety of provided arguments [uses data provider] - * @covers Zend\Db\Sql\Select::getSqlString - * @dataProvider providerData - */ - public function testGetSqlString(Select $select, $unused, $unused2, $expectedSqlString) - { - $this->assertEquals($expectedSqlString, $select->getSqlString(new TrustingSql92Platform())); - } - /** - * @testdox unit test: Test __get() returns expected objects magically - * @covers Zend\Db\Sql\Select::__get - */ - public function testMagicAccessor() - { - $select = new Select; - $this->assertInstanceOf('Zend\Db\Sql\Where', $select->where); + $select + ->from('foo', 'bar') + ->quantifier(Select::QUANTIFIER_DISTINCT) + ->columns(['foo', 'bar']) + ->setPrefixColumnsWithTable(false) + ->join('foo', 'x = y', Select::SQL_STAR, Joins::JOIN_INNER) + ->where('x = y') + ->limit(5) + ->offset(10) + ->group(['col1', 'col2']) + ->having(['x = ?' => 5]) + ->order(Select::ORDER_ASCENDING) + ->combine(new Select('xxx')); + + foreach ($originalValues as $name => $value) { + $this->assertNotEquals($value, $select->$name, 'notEqual : ' . $name); + unset($select->$name); + $this->assertEquals($value, $select->$name, 'Equal : ' . $name); + } } /** @@ -726,675 +222,28 @@ public function testCloning() $this->assertEquals(1, $select1->having->count()); } - /** - * @testdox unit test: Text process*() methods will return proper array when internally called, part of extension API - * @dataProvider providerData - * @covers Zend\Db\Sql\Select::processSelect - * @covers Zend\Db\Sql\Select::processJoins - * @covers Zend\Db\Sql\Select::processWhere - * @covers Zend\Db\Sql\Select::processGroup - * @covers Zend\Db\Sql\Select::processHaving - * @covers Zend\Db\Sql\Select::processOrder - * @covers Zend\Db\Sql\Select::processLimit - * @covers Zend\Db\Sql\Select::processOffset - * @covers Zend\Db\Sql\Select::processCombine - */ - public function testProcessMethods(Select $select, $unused, $unused2, $unused3, $internalTests) - { - if (!$internalTests) { - return; - } - - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $parameterContainer = new ParameterContainer(); - - $sr = new ReflectionObject($select); - - foreach ($internalTests as $method => $expected) { - $mr = $sr->getMethod($method); - $mr->setAccessible(true); - $return = $mr->invokeArgs($select, [new Sql92, $mockDriver, $parameterContainer]); - $this->assertEquals($expected, $return); - } - } - - public function providerData() + public function testCloningWithCombine() { - // basic table - $select0 = new Select; - $select0->from('foo'); - $sqlPrep0 = // same - $sqlStr0 = 'SELECT "foo".* FROM "foo"'; - $internalTests0 = [ - 'processSelect' => [[['"foo".*']], '"foo"'] - ]; - - // table as TableIdentifier - $select1 = new Select; - $select1->from(new TableIdentifier('foo', 'bar')); - $sqlPrep1 = // same - $sqlStr1 = 'SELECT "bar"."foo".* FROM "bar"."foo"'; - $internalTests1 = [ - 'processSelect' => [[['"bar"."foo".*']], '"bar"."foo"'] - ]; - - // table with alias - $select2 = new Select; - $select2->from(['f' => 'foo']); - $sqlPrep2 = // same - $sqlStr2 = 'SELECT "f".* FROM "foo" AS "f"'; - $internalTests2 = [ - 'processSelect' => [[['"f".*']], '"foo" AS "f"'] - ]; - - // table with alias with table as TableIdentifier - $select3 = new Select; - $select3->from(['f' => new TableIdentifier('foo')]); - $sqlPrep3 = // same - $sqlStr3 = 'SELECT "f".* FROM "foo" AS "f"'; - $internalTests3 = [ - 'processSelect' => [[['"f".*']], '"foo" AS "f"'] - ]; - - // columns - $select4 = new Select; - $select4->from('foo')->columns(['bar', 'baz']); - $sqlPrep4 = // same - $sqlStr4 = 'SELECT "foo"."bar" AS "bar", "foo"."baz" AS "baz" FROM "foo"'; - $internalTests4 = [ - 'processSelect' => [[['"foo"."bar"', '"bar"'], ['"foo"."baz"', '"baz"']], '"foo"'] - ]; - - // columns with AS associative array - $select5 = new Select; - $select5->from('foo')->columns(['bar' => 'baz']); - $sqlPrep5 = // same - $sqlStr5 = 'SELECT "foo"."baz" AS "bar" FROM "foo"'; - $internalTests5 = [ - 'processSelect' => [[['"foo"."baz"', '"bar"']], '"foo"'] - ]; - - // columns with AS associative array mixed - $select6 = new Select; - $select6->from('foo')->columns(['bar' => 'baz', 'bam']); - $sqlPrep6 = // same - $sqlStr6 = 'SELECT "foo"."baz" AS "bar", "foo"."bam" AS "bam" FROM "foo"'; - $internalTests6 = [ - 'processSelect' => [[['"foo"."baz"', '"bar"'], ['"foo"."bam"', '"bam"'] ], '"foo"'] - ]; - - // columns where value is Expression, with AS - $select7 = new Select; - $select7->from('foo')->columns(['bar' => new Expression('COUNT(some_column)')]); - $sqlPrep7 = // same - $sqlStr7 = 'SELECT COUNT(some_column) AS "bar" FROM "foo"'; - $internalTests7 = [ - 'processSelect' => [[['COUNT(some_column)', '"bar"']], '"foo"'] - ]; - - // columns where value is Expression - $select8 = new Select; - $select8->from('foo')->columns([new Expression('COUNT(some_column) AS bar')]); - $sqlPrep8 = // same - $sqlStr8 = 'SELECT COUNT(some_column) AS bar FROM "foo"'; - $internalTests8 = [ - 'processSelect' => [[['COUNT(some_column) AS bar']], '"foo"'] - ]; - - // columns where value is Expression with parameters - $select9 = new Select; - $select9->from('foo')->columns( - [ - new Expression( - '(COUNT(?) + ?) AS ?', - ['some_column', 5, 'bar'], - [Expression::TYPE_IDENTIFIER, Expression::TYPE_VALUE, Expression::TYPE_IDENTIFIER] - ) - ] - ); - $sqlPrep9 = 'SELECT (COUNT("some_column") + ?) AS "bar" FROM "foo"'; - $sqlStr9 = 'SELECT (COUNT("some_column") + \'5\') AS "bar" FROM "foo"'; - $params9 = ['column1' => 5]; - $internalTests9 = [ - 'processSelect' => [[['(COUNT("some_column") + ?) AS "bar"']], '"foo"'] - ]; - - // joins (plain) - $select10 = new Select; - $select10->from('foo')->join('zac', 'm = n'); - $sqlPrep10 = // same - $sqlStr10 = 'SELECT "foo".*, "zac".* FROM "foo" INNER JOIN "zac" ON "m" = "n"'; - $internalTests10 = [ - 'processSelect' => [[['"foo".*'], ['"zac".*']], '"foo"'], - 'processJoins' => [[['INNER', '"zac"', '"m" = "n"']]] - ]; + $selectInCombine = new Select; + $selectInCombine->from('subFoo'); - // join with columns - $select11 = new Select; - $select11->from('foo')->join('zac', 'm = n', ['bar', 'baz']); - $sqlPrep11 = // same - $sqlStr11 = 'SELECT "foo".*, "zac"."bar" AS "bar", "zac"."baz" AS "baz" FROM "foo" INNER JOIN "zac" ON "m" = "n"'; - $internalTests11 = [ - 'processSelect' => [[['"foo".*'], ['"zac"."bar"', '"bar"'], ['"zac"."baz"', '"baz"']], '"foo"'], - 'processJoins' => [[['INNER', '"zac"', '"m" = "n"']]] - ]; - - // join with alternate type - $select12 = new Select; - $select12->from('foo')->join('zac', 'm = n', ['bar', 'baz'], Select::JOIN_OUTER); - $sqlPrep12 = // same - $sqlStr12 = 'SELECT "foo".*, "zac"."bar" AS "bar", "zac"."baz" AS "baz" FROM "foo" OUTER JOIN "zac" ON "m" = "n"'; - $internalTests12 = [ - 'processSelect' => [[['"foo".*'], ['"zac"."bar"', '"bar"'], ['"zac"."baz"', '"baz"']], '"foo"'], - 'processJoins' => [[['OUTER', '"zac"', '"m" = "n"']]] - ]; - - // join with column aliases - $select13 = new Select; - $select13->from('foo')->join('zac', 'm = n', ['BAR' => 'bar', 'BAZ' => 'baz']); - $sqlPrep13 = // same - $sqlStr13 = 'SELECT "foo".*, "zac"."bar" AS "BAR", "zac"."baz" AS "BAZ" FROM "foo" INNER JOIN "zac" ON "m" = "n"'; - $internalTests13 = [ - 'processSelect' => [[['"foo".*'], ['"zac"."bar"', '"BAR"'], ['"zac"."baz"', '"BAZ"']], '"foo"'], - 'processJoins' => [[['INNER', '"zac"', '"m" = "n"']]] - ]; - - // join with table aliases - $select14 = new Select; - $select14->from('foo')->join(['b' => 'bar'], 'b.foo_id = foo.foo_id'); - $sqlPrep14 = // same - $sqlStr14 = 'SELECT "foo".*, "b".* FROM "foo" INNER JOIN "bar" AS "b" ON "b"."foo_id" = "foo"."foo_id"'; - $internalTests14 = [ - 'processSelect' => [[['"foo".*'], ['"b".*']], '"foo"'], - 'processJoins' => [[['INNER', '"bar" AS "b"', '"b"."foo_id" = "foo"."foo_id"']]] - ]; - - // where (simple string) - $select15 = new Select; - $select15->from('foo')->where('x = 5'); - $sqlPrep15 = // same - $sqlStr15 = 'SELECT "foo".* FROM "foo" WHERE x = 5'; - $internalTests15 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processWhere' => ['x = 5'] - ]; - - // where (returning parameters) - $select16 = new Select; - $select16->from('foo')->where(['x = ?' => 5]); - $sqlPrep16 = 'SELECT "foo".* FROM "foo" WHERE x = ?'; - $sqlStr16 = 'SELECT "foo".* FROM "foo" WHERE x = \'5\''; - $params16 = ['where1' => 5]; - $internalTests16 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processWhere' => ['x = ?'] - ]; - - // group - $select17 = new Select; - $select17->from('foo')->group(['col1', 'col2']); - $sqlPrep17 = // same - $sqlStr17 = 'SELECT "foo".* FROM "foo" GROUP BY "col1", "col2"'; - $internalTests17 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processGroup' => [['"col1"', '"col2"']] - ]; - - $select18 = new Select; - $select18->from('foo')->group('col1')->group('col2'); - $sqlPrep18 = // same - $sqlStr18 = 'SELECT "foo".* FROM "foo" GROUP BY "col1", "col2"'; - $internalTests18 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processGroup' => [['"col1"', '"col2"']] - ]; - - $select19 = new Select; - $select19->from('foo')->group(new Expression('DAY(?)', ['col1'], [Expression::TYPE_IDENTIFIER])); - $sqlPrep19 = // same - $sqlStr19 = 'SELECT "foo".* FROM "foo" GROUP BY DAY("col1")'; - $internalTests19 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processGroup' => [['DAY("col1")']] - ]; - - // having (simple string) - $select20 = new Select; - $select20->from('foo')->having('x = 5'); - $sqlPrep20 = // same - $sqlStr20 = 'SELECT "foo".* FROM "foo" HAVING x = 5'; - $internalTests20 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processHaving' => ['x = 5'] - ]; - - // having (returning parameters) - $select21 = new Select; - $select21->from('foo')->having(['x = ?' => 5]); - $sqlPrep21 = 'SELECT "foo".* FROM "foo" HAVING x = ?'; - $sqlStr21 = 'SELECT "foo".* FROM "foo" HAVING x = \'5\''; - $params21 = ['having1' => 5]; - $internalTests21 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processHaving' => ['x = ?'] - ]; - - // order - $select22 = new Select; - $select22->from('foo')->order('c1'); - $sqlPrep22 = // - $sqlStr22 = 'SELECT "foo".* FROM "foo" ORDER BY "c1" ASC'; - $internalTests22 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processOrder' => [[['"c1"', Select::ORDER_ASCENDING]]] - ]; - - $select23 = new Select; - $select23->from('foo')->order(['c1', 'c2']); - $sqlPrep23 = // same - $sqlStr23 = 'SELECT "foo".* FROM "foo" ORDER BY "c1" ASC, "c2" ASC'; - $internalTests23 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processOrder' => [[['"c1"', Select::ORDER_ASCENDING], ['"c2"', Select::ORDER_ASCENDING]]] - ]; - - $select24 = new Select; - $select24->from('foo')->order(['c1' => 'DESC', 'c2' => 'Asc']); // notice partially lower case ASC - $sqlPrep24 = // same - $sqlStr24 = 'SELECT "foo".* FROM "foo" ORDER BY "c1" DESC, "c2" ASC'; - $internalTests24 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processOrder' => [[['"c1"', Select::ORDER_DESCENDING], ['"c2"', Select::ORDER_ASCENDING]]] - ]; - - $select25 = new Select; - $select25->from('foo')->order(['c1' => 'asc'])->order('c2 desc'); // notice partially lower case ASC - $sqlPrep25 = // same - $sqlStr25 = 'SELECT "foo".* FROM "foo" ORDER BY "c1" ASC, "c2" DESC'; - $internalTests25 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processOrder' => [[['"c1"', Select::ORDER_ASCENDING], ['"c2"', Select::ORDER_DESCENDING]]] - ]; - - // limit - $select26 = new Select; - $select26->from('foo')->limit(5); - $sqlPrep26 = 'SELECT "foo".* FROM "foo" LIMIT ?'; - $sqlStr26 = 'SELECT "foo".* FROM "foo" LIMIT \'5\''; - $params26 = ['limit' => 5]; - $internalTests26 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processLimit' => ['?'] - ]; - - // limit with offset - $select27 = new Select; - $select27->from('foo')->limit(5)->offset(10); - $sqlPrep27 = 'SELECT "foo".* FROM "foo" LIMIT ? OFFSET ?'; - $sqlStr27 = 'SELECT "foo".* FROM "foo" LIMIT \'5\' OFFSET \'10\''; - $params27 = ['limit' => 5, 'offset' => 10]; - $internalTests27 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processLimit' => ['?'], - 'processOffset' => ['?'] - ]; - - // joins with a few keywords in the on clause - $select28 = new Select; - $select28->from('foo')->join('zac', '(m = n AND c.x) BETWEEN x AND y.z OR (c.x < y.z AND c.x <= y.z AND c.x > y.z AND c.x >= y.z)'); - $sqlPrep28 = // same - $sqlStr28 = 'SELECT "foo".*, "zac".* FROM "foo" INNER JOIN "zac" ON ("m" = "n" AND "c"."x") BETWEEN "x" AND "y"."z" OR ("c"."x" < "y"."z" AND "c"."x" <= "y"."z" AND "c"."x" > "y"."z" AND "c"."x" >= "y"."z")'; - $internalTests28 = [ - 'processSelect' => [[['"foo".*'], ['"zac".*']], '"foo"'], - 'processJoins' => [[['INNER', '"zac"', '("m" = "n" AND "c"."x") BETWEEN "x" AND "y"."z" OR ("c"."x" < "y"."z" AND "c"."x" <= "y"."z" AND "c"."x" > "y"."z" AND "c"."x" >= "y"."z")']]] - ]; - - // order with compound name - $select29 = new Select; - $select29->from('foo')->order('c1.d2'); - $sqlPrep29 = // - $sqlStr29 = 'SELECT "foo".* FROM "foo" ORDER BY "c1"."d2" ASC'; - $internalTests29 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processOrder' => [[['"c1"."d2"', Select::ORDER_ASCENDING]]] - ]; - - // group with compound name - $select30 = new Select; - $select30->from('foo')->group('c1.d2'); - $sqlPrep30 = // same - $sqlStr30 = 'SELECT "foo".* FROM "foo" GROUP BY "c1"."d2"'; - $internalTests30 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processGroup' => [['"c1"."d2"']] - ]; - - // join with expression in ON part - $select31 = new Select; - $select31->from('foo')->join('zac', new Expression('(m = n AND c.x) BETWEEN x AND y.z')); - $sqlPrep31 = // same - $sqlStr31 = 'SELECT "foo".*, "zac".* FROM "foo" INNER JOIN "zac" ON (m = n AND c.x) BETWEEN x AND y.z'; - $internalTests31 = [ - 'processSelect' => [[['"foo".*'], ['"zac".*']], '"foo"'], - 'processJoins' => [[['INNER', '"zac"', '(m = n AND c.x) BETWEEN x AND y.z']]] - ]; - - $select32subselect = new Select; - $select32subselect->from('bar')->where->like('y', '%Foo%'); - $select32 = new Select; - $select32->from(['x' => $select32subselect]); - $sqlPrep32 = 'SELECT "x".* FROM (SELECT "bar".* FROM "bar" WHERE "y" LIKE ?) AS "x"'; - $sqlStr32 = 'SELECT "x".* FROM (SELECT "bar".* FROM "bar" WHERE "y" LIKE \'%Foo%\') AS "x"'; - $internalTests32 = [ - 'processSelect' => [[['"x".*']], '(SELECT "bar".* FROM "bar" WHERE "y" LIKE ?) AS "x"'], - ]; - - $select33 = new Select; - $select33->from('table')->columns(['*'])->where([ - 'c1' => null, - 'c2' => [1, 2, 3], - new \Zend\Db\Sql\Predicate\IsNotNull('c3') - ]); - $sqlPrep33 = 'SELECT "table".* FROM "table" WHERE "c1" IS NULL AND "c2" IN (?, ?, ?) AND "c3" IS NOT NULL'; - $sqlStr33 = 'SELECT "table".* FROM "table" WHERE "c1" IS NULL AND "c2" IN (\'1\', \'2\', \'3\') AND "c3" IS NOT NULL'; - $internalTests33 = [ - 'processSelect' => [[['"table".*']], '"table"'], - 'processWhere' => ['"c1" IS NULL AND "c2" IN (?, ?, ?) AND "c3" IS NOT NULL'] - ]; - - // @author Demian Katz - $select34 = new Select; - $select34->from('table')->order([ - new Expression('isnull(?) DESC', ['name'], [Expression::TYPE_IDENTIFIER]), - 'name' - ]); - $sqlPrep34 = 'SELECT "table".* FROM "table" ORDER BY isnull("name") DESC, "name" ASC'; - $sqlStr34 = 'SELECT "table".* FROM "table" ORDER BY isnull("name") DESC, "name" ASC'; - $internalTests34 = [ - 'processOrder' => [[['isnull("name") DESC'], ['"name"', Select::ORDER_ASCENDING]]] - ]; - - // join with Expression object in COLUMNS part (ZF2-514) - // @co-author Koen Pieters (kpieters) - $select35 = new Select; - $select35->from('foo')->columns([])->join('bar', 'm = n', ['thecount' => new Expression("COUNT(*)")]); - $sqlPrep35 = // same - $sqlStr35 = 'SELECT COUNT(*) AS "thecount" FROM "foo" INNER JOIN "bar" ON "m" = "n"'; - $internalTests35 = [ - 'processSelect' => [[['COUNT(*)', '"thecount"']], '"foo"'], - 'processJoins' => [[['INNER', '"bar"', '"m" = "n"']]] - ]; - - // multiple joins with expressions - // reported by @jdolieslager - $select36 = new Select; - $select36->from('foo') - ->join('tableA', new Predicate\Operator('id', '=', 1)) - ->join('tableB', new Predicate\Operator('id', '=', 2)) - ->join('tableC', new Predicate\PredicateSet([ - new Predicate\Operator('id', '=', 3), - new Predicate\Operator('number', '>', 20) - ])); - $sqlPrep36 = 'SELECT "foo".*, "tableA".*, "tableB".*, "tableC".* FROM "foo"' - . ' INNER JOIN "tableA" ON "id" = :join1part1 INNER JOIN "tableB" ON "id" = :join2part1 ' - . 'INNER JOIN "tableC" ON "id" = :join3part1 AND "number" > :join3part2'; - $sqlStr36 = 'SELECT "foo".*, "tableA".*, "tableB".*, "tableC".* FROM "foo" ' - . 'INNER JOIN "tableA" ON "id" = \'1\' INNER JOIN "tableB" ON "id" = \'2\' ' - . 'INNER JOIN "tableC" ON "id" = \'3\' AND "number" > \'20\''; - $internalTests36 = []; - $useNamedParams36 = true; - - /** - * @author robertbasic - * @link https://github.com/zendframework/zf2/pull/2714 - */ - $select37 = new Select; - $select37->from('foo')->columns(['bar'], false); - $sqlPrep37 = // same - $sqlStr37 = 'SELECT "bar" AS "bar" FROM "foo"'; - $internalTests37 = [ - 'processSelect' => [[['"bar"', '"bar"']], '"foo"'] - ]; - - // @link https://github.com/zendframework/zf2/issues/3294 - // Test TableIdentifier In Joins - $select38 = new Select; - $select38->from('foo')->columns([])->join(new TableIdentifier('bar', 'baz'), 'm = n', ['thecount' => new Expression("COUNT(*)")]); - $sqlPrep38 = // same - $sqlStr38 = 'SELECT COUNT(*) AS "thecount" FROM "foo" INNER JOIN "baz"."bar" ON "m" = "n"'; - $internalTests38 = [ - 'processSelect' => [[['COUNT(*)', '"thecount"']], '"foo"'], - 'processJoins' => [[['INNER', '"baz"."bar"', '"m" = "n"']]] - ]; - - // subselect in join - $select39subselect = new Select; - $select39subselect->from('bar')->where->like('y', '%Foo%'); - $select39 = new Select; - $select39->from('foo')->join(['z' => $select39subselect], 'z.foo = bar.id'); - $sqlPrep39 = 'SELECT "foo".*, "z".* FROM "foo" INNER JOIN (SELECT "bar".* FROM "bar" WHERE "y" LIKE ?) AS "z" ON "z"."foo" = "bar"."id"'; - $sqlStr39 = 'SELECT "foo".*, "z".* FROM "foo" INNER JOIN (SELECT "bar".* FROM "bar" WHERE "y" LIKE \'%Foo%\') AS "z" ON "z"."foo" = "bar"."id"'; - $internalTests39 = [ - 'processJoins' => [[['INNER', '(SELECT "bar".* FROM "bar" WHERE "y" LIKE ?) AS "z"', '"z"."foo" = "bar"."id"']]] - ]; - - // @link https://github.com/zendframework/zf2/issues/3294 - // Test TableIdentifier In Joins, with multiple joins - $select40 = new Select; - $select40->from('foo') - ->join(['a' => new TableIdentifier('another_foo', 'another_schema')], 'a.x = foo.foo_column') - ->join('bar', 'foo.colx = bar.colx'); - $sqlPrep40 = // same - $sqlStr40 = 'SELECT "foo".*, "a".*, "bar".* FROM "foo"' - . ' INNER JOIN "another_schema"."another_foo" AS "a" ON "a"."x" = "foo"."foo_column"' - . ' INNER JOIN "bar" ON "foo"."colx" = "bar"."colx"'; - $internalTests40 = [ - 'processSelect' => [[['"foo".*'], ['"a".*'], ['"bar".*']], '"foo"'], - 'processJoins' => [[ - ['INNER', '"another_schema"."another_foo" AS "a"', '"a"."x" = "foo"."foo_column"'], - ['INNER', '"bar"', '"foo"."colx" = "bar"."colx"'] - ]] - ]; - - $select41 = new Select; - $select41->from('foo')->quantifier(Select::QUANTIFIER_DISTINCT); - $sqlPrep41 = // same - $sqlStr41 = 'SELECT DISTINCT "foo".* FROM "foo"'; - $internalTests41 = [ - 'processSelect' => [SELECT::QUANTIFIER_DISTINCT, [['"foo".*']], '"foo"'], - ]; - - $select42 = new Select; - $select42->from('foo')->quantifier(new Expression('TOP ?', [10])); - $sqlPrep42 = 'SELECT TOP ? "foo".* FROM "foo"'; - $sqlStr42 = 'SELECT TOP \'10\' "foo".* FROM "foo"'; - $internalTests42 = [ - 'processSelect' => ['TOP ?', [['"foo".*']], '"foo"'], - ]; - - $select43 = new Select(); - $select43->from(['x' => 'foo'])->columns(['bar' => 'foo.bar'], false); - $sqlPrep43 = 'SELECT "foo"."bar" AS "bar" FROM "foo" AS "x"'; - $sqlStr43 = 'SELECT "foo"."bar" AS "bar" FROM "foo" AS "x"'; - $internalTests43 = [ - 'processSelect' => [[['"foo"."bar"', '"bar"']], '"foo" AS "x"'] - ]; - - $select44 = new Select; - $select44->from('foo')->where('a = b'); - $select44b = new Select; - $select44b->from('bar')->where('c = d'); - $select44->combine($select44b, Select::COMBINE_UNION, 'ALL'); - $sqlPrep44 = // same - $sqlStr44 = '( SELECT "foo".* FROM "foo" WHERE a = b ) UNION ALL ( SELECT "bar".* FROM "bar" WHERE c = d )'; - $internalTests44 = [ - 'processCombine' => ['UNION ALL', 'SELECT "bar".* FROM "bar" WHERE c = d'] - ]; - - // limit with offset - $select45 = new Select; - $select45->from('foo')->limit("5")->offset("10"); - $sqlPrep45 = 'SELECT "foo".* FROM "foo" LIMIT ? OFFSET ?'; - $sqlStr45 = 'SELECT "foo".* FROM "foo" LIMIT \'5\' OFFSET \'10\''; - $params45 = ['limit' => 5, 'offset' => 10]; - $internalTests45 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processLimit' => ['?'], - 'processOffset' => ['?'] - ]; - - // functions without table - $select46 = new Select; - $select46->columns([ - new Expression('SOME_DB_FUNCTION_ONE()'), - 'foo' => new Expression('SOME_DB_FUNCTION_TWO()'), - ]); - $sqlPrep46 = 'SELECT SOME_DB_FUNCTION_ONE() AS Expression1, SOME_DB_FUNCTION_TWO() AS "foo"'; - $sqlStr46 = 'SELECT SOME_DB_FUNCTION_ONE() AS Expression1, SOME_DB_FUNCTION_TWO() AS "foo"'; - $params46 = []; - $internalTests46 = []; - - // limit with big offset and limit - $select47 = new Select; - $select47->from('foo')->limit("10000000000000000000")->offset("10000000000000000000"); - $sqlPrep47 = 'SELECT "foo".* FROM "foo" LIMIT ? OFFSET ?'; - $sqlStr47 = 'SELECT "foo".* FROM "foo" LIMIT \'10000000000000000000\' OFFSET \'10000000000000000000\''; - $params47 = ['limit' => 10000000000000000000, 'offset' => 10000000000000000000]; - $internalTests47 = [ - 'processSelect' => [[['"foo".*']], '"foo"'], - 'processLimit' => ['?'], - 'processOffset' => ['?'] - ]; - - //combine and union with order at the end - $select48 = new Select; - $select48->from('foo')->where('a = b'); - $select48b = new Select; - $select48b->from('bar')->where('c = d'); - $select48->combine($select48b); - - $select48combined = new Select(); - $select48 = $select48combined->from(['sub' => $select48])->order('id DESC'); - $sqlPrep48 = // same - $sqlStr48 = 'SELECT "sub".* FROM (( SELECT "foo".* FROM "foo" WHERE a = b ) UNION ( SELECT "bar".* FROM "bar" WHERE c = d )) AS "sub" ORDER BY "id" DESC'; - $internalTests48 = [ - 'processCombine' => null, - ]; - - //Expression as joinName - $select49 = new Select; - $select49->from(new TableIdentifier('foo')) - ->join(['bar' => new Expression('psql_function_which_returns_table')], 'foo.id = bar.fooid'); - $sqlPrep49 = // same - $sqlStr49 = 'SELECT "foo".*, "bar".* FROM "foo" INNER JOIN psql_function_which_returns_table AS "bar" ON "foo"."id" = "bar"."fooid"'; - $internalTests49 = [ - 'processSelect' => [[['"foo".*'], ['"bar".*']], '"foo"'], - 'processJoins' => [[['INNER', 'psql_function_which_returns_table AS "bar"', '"foo"."id" = "bar"."fooid"']]] - ]; - - // Test generic predicate is appended with AND - $select50 = new Select; - $select50->from(new TableIdentifier('foo')) - ->where - ->nest - ->isNull('bar') - ->and - ->predicate(new Predicate\Literal('1=1')) - ->unnest; - $sqlPrep50 = // same - $sqlStr50 = 'SELECT "foo".* FROM "foo" WHERE ("bar" IS NULL AND 1=1)'; - $internalTests50 = []; + $select = new Select; + $select + ->from('foo') + ->combine($selectInCombine); - // Test generic predicate is appended with OR - $select51 = new Select; - $select51->from(new TableIdentifier('foo')) - ->where - ->nest - ->isNull('bar') - ->or - ->predicate(new Predicate\Literal('1=1')) - ->unnest; - $sqlPrep51 = // same - $sqlStr51 = 'SELECT "foo".* FROM "foo" WHERE ("bar" IS NULL OR 1=1)'; - $internalTests51 = []; + $selectCloned = clone $select; + $selectCloned->from('bar'); - /** - * @author Andrzej Lewandowski - * @link https://github.com/zendframework/zf2/issues/7222 - */ - $select52 = new Select; - $select52->from('foo')->join('zac', '(catalog_category_website.category_id = catalog_category.category_id)'); - $sqlPrep52 = // same - $sqlStr52 = 'SELECT "foo".*, "zac".* FROM "foo" INNER JOIN "zac" ON ("catalog_category_website"."category_id" = "catalog_category"."category_id")'; - $internalTests52 = [ - 'processSelect' => [[['"foo".*'], ['"zac".*']], '"foo"'], - 'processJoins' => [[['INNER', '"zac"', '("catalog_category_website"."category_id" = "catalog_category"."category_id")']]] - ]; + $this->assertEquals('foo', $select->table->getSource()->getTable()); + $this->assertEquals('bar', $selectCloned->table->getSource()->getTable()); - /** - * $select = the select object - * $sqlPrep = the sql as a result of preparation - * $params = the param container contents result of preparation - * $sqlStr = the sql as a result of getting a string back - * $internalTests what the internal functions should return (safe-guarding extension) - */ + $selectCloned0 = $selectCloned->combine->combine[0]['select']; + $this->assertEquals('bar', $selectCloned0->table->getSource()->getTable()); - return [ - // $select $sqlPrep $params $sqlStr $internalTests // use named param - [$select0, $sqlPrep0, [], $sqlStr0, $internalTests0], - [$select1, $sqlPrep1, [], $sqlStr1, $internalTests1], - [$select2, $sqlPrep2, [], $sqlStr2, $internalTests2], - [$select3, $sqlPrep3, [], $sqlStr3, $internalTests3], - [$select4, $sqlPrep4, [], $sqlStr4, $internalTests4], - [$select5, $sqlPrep5, [], $sqlStr5, $internalTests5], - [$select6, $sqlPrep6, [], $sqlStr6, $internalTests6], - [$select7, $sqlPrep7, [], $sqlStr7, $internalTests7], - [$select8, $sqlPrep8, [], $sqlStr8, $internalTests8], - [$select9, $sqlPrep9, $params9, $sqlStr9, $internalTests9], - [$select10, $sqlPrep10, [], $sqlStr10, $internalTests10], - [$select11, $sqlPrep11, [], $sqlStr11, $internalTests11], - [$select12, $sqlPrep12, [], $sqlStr12, $internalTests12], - [$select13, $sqlPrep13, [], $sqlStr13, $internalTests13], - [$select14, $sqlPrep14, [], $sqlStr14, $internalTests14], - [$select15, $sqlPrep15, [], $sqlStr15, $internalTests15], - [$select16, $sqlPrep16, $params16, $sqlStr16, $internalTests16], - [$select17, $sqlPrep17, [], $sqlStr17, $internalTests17], - [$select18, $sqlPrep18, [], $sqlStr18, $internalTests18], - [$select19, $sqlPrep19, [], $sqlStr19, $internalTests19], - [$select20, $sqlPrep20, [], $sqlStr20, $internalTests20], - [$select21, $sqlPrep21, $params21, $sqlStr21, $internalTests21], - [$select22, $sqlPrep22, [], $sqlStr22, $internalTests22], - [$select23, $sqlPrep23, [], $sqlStr23, $internalTests23], - [$select24, $sqlPrep24, [], $sqlStr24, $internalTests24], - [$select25, $sqlPrep25, [], $sqlStr25, $internalTests25], - [$select26, $sqlPrep26, $params26, $sqlStr26, $internalTests26], - [$select27, $sqlPrep27, $params27, $sqlStr27, $internalTests27], - [$select28, $sqlPrep28, [], $sqlStr28, $internalTests28], - [$select29, $sqlPrep29, [], $sqlStr29, $internalTests29], - [$select30, $sqlPrep30, [], $sqlStr30, $internalTests30], - [$select31, $sqlPrep31, [], $sqlStr31, $internalTests31], - [$select32, $sqlPrep32, [], $sqlStr32, $internalTests32], - [$select33, $sqlPrep33, [], $sqlStr33, $internalTests33], - [$select34, $sqlPrep34, [], $sqlStr34, $internalTests34], - [$select35, $sqlPrep35, [], $sqlStr35, $internalTests35], - [$select36, $sqlPrep36, [], $sqlStr36, $internalTests36, $useNamedParams36], - [$select37, $sqlPrep37, [], $sqlStr37, $internalTests37], - [$select38, $sqlPrep38, [], $sqlStr38, $internalTests38], - [$select39, $sqlPrep39, [], $sqlStr39, $internalTests39], - [$select40, $sqlPrep40, [], $sqlStr40, $internalTests40], - [$select41, $sqlPrep41, [], $sqlStr41, $internalTests41], - [$select42, $sqlPrep42, [], $sqlStr42, $internalTests42], - [$select43, $sqlPrep43, [], $sqlStr43, $internalTests43], - [$select44, $sqlPrep44, [], $sqlStr44, $internalTests44], - [$select45, $sqlPrep45, $params45, $sqlStr45, $internalTests45], - [$select46, $sqlPrep46, $params46, $sqlStr46, $internalTests46], - [$select47, $sqlPrep47, $params47, $sqlStr47, $internalTests47], - [$select48, $sqlPrep48, [], $sqlStr48, $internalTests48], - [$select49, $sqlPrep49, [], $sqlStr49, $internalTests49], - [$select50, $sqlPrep50, [], $sqlStr50, $internalTests50], - [$select51, $sqlPrep51, [], $sqlStr51, $internalTests51], - [$select52, $sqlPrep52, [], $sqlStr52, $internalTests52], - ]; + $selectCloned1 = $selectCloned->combine->combine[1]['select']; + $selectCloned1->from('subBar'); + $this->assertEquals('subFoo', $selectInCombine->table->getSource()->getTable()); + $this->assertEquals('subBar', $selectCloned1->table->getSource()->getTable()); } } diff --git a/test/Sql/SqlFunctionalTest.php b/test/Sql/SqlFunctionalTest.php deleted file mode 100644 index 628ee74848..0000000000 --- a/test/Sql/SqlFunctionalTest.php +++ /dev/null @@ -1,566 +0,0 @@ - [ - 'sqlObject' => $this->select('foo')->offset(10), - 'expected' => [ - 'sql92' => [ - 'string' => 'SELECT "foo".* FROM "foo" OFFSET \'10\'', - 'prepare' => 'SELECT "foo".* FROM "foo" OFFSET ?', - 'parameters' => ['offset' => 10], - ], - 'MySql' => [ - 'string' => 'SELECT `foo`.* FROM `foo` LIMIT 18446744073709551615 OFFSET 10', - 'prepare' => 'SELECT `foo`.* FROM `foo` LIMIT 18446744073709551615 OFFSET ?', - 'parameters' => ['offset' => 10], - ], - 'Oracle' => [ - 'string' => 'SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "foo".* FROM "foo" ) b ) WHERE b_rownum > (10)', - 'prepare' => 'SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "foo".* FROM "foo" ) b ) WHERE b_rownum > (:offset)', - 'parameters' => ['offset' => 10], - ], - 'SqlServer' => [ - 'string' => 'SELECT * FROM ( SELECT [foo].*, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN 10+1 AND 0+10', - 'prepare' => 'SELECT * FROM ( SELECT [foo].*, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN ?+1 AND ?+?', - 'parameters' => ['offset' => 10, 'limit' => null, 'offsetForSum' => 10], - ], - ], - ], - 'Select::processLimit()' => [ - 'sqlObject' => $this->select('foo')->limit(10), - 'expected' => [ - 'sql92' => [ - 'string' => 'SELECT "foo".* FROM "foo" LIMIT \'10\'', - 'prepare' => 'SELECT "foo".* FROM "foo" LIMIT ?', - 'parameters' => ['limit' => 10], - ], - 'MySql' => [ - 'string' => 'SELECT `foo`.* FROM `foo` LIMIT 10', - 'prepare' => 'SELECT `foo`.* FROM `foo` LIMIT ?', - 'parameters' => ['limit' => 10], - ], - 'Oracle' => [ - 'string' => 'SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "foo".* FROM "foo" ) b WHERE rownum <= (0+10)) WHERE b_rownum >= (0 + 1)', - 'prepare' => 'SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "foo".* FROM "foo" ) b WHERE rownum <= (:offset+:limit)) WHERE b_rownum >= (:offset + 1)', - 'parameters' => ['offset' => 0, 'limit' => 10], - ], - 'SqlServer' => [ - 'string' => 'SELECT * FROM ( SELECT [foo].*, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN 0+1 AND 10+0', - 'prepare' => 'SELECT * FROM ( SELECT [foo].*, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN ?+1 AND ?+?', - 'parameters' => ['offset' => null, 'limit' => 10, 'offsetForSum' => null], - ], - ], - ], - 'Select::processLimitOffset()' => [ - 'sqlObject' => $this->select('foo')->limit(10)->offset(5), - 'expected' => [ - 'sql92' => [ - 'string' => 'SELECT "foo".* FROM "foo" LIMIT \'10\' OFFSET \'5\'', - 'prepare' => 'SELECT "foo".* FROM "foo" LIMIT ? OFFSET ?', - 'parameters' => ['limit' => 10, 'offset' => 5], - ], - 'MySql' => [ - 'string' => 'SELECT `foo`.* FROM `foo` LIMIT 10 OFFSET 5', - 'prepare' => 'SELECT `foo`.* FROM `foo` LIMIT ? OFFSET ?', - 'parameters' => ['limit' => 10, 'offset' => 5], - ], - 'Oracle' => [ - 'string' => 'SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "foo".* FROM "foo" ) b WHERE rownum <= (5+10)) WHERE b_rownum >= (5 + 1)', - 'prepare' => 'SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "foo".* FROM "foo" ) b WHERE rownum <= (:offset+:limit)) WHERE b_rownum >= (:offset + 1)', - 'parameters' => ['offset' => 5, 'limit' => 10], - ], - 'SqlServer' => [ - 'string' => 'SELECT * FROM ( SELECT [foo].*, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN 5+1 AND 10+5', - 'prepare' => 'SELECT * FROM ( SELECT [foo].*, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [__ZEND_ROW_NUMBER] FROM [foo] ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN ?+1 AND ?+?', - 'parameters' => ['offset' => 5, 'limit' => 10, 'offsetForSum' => 5], - ], - ], - ], - // Github issue https://github.com/zendframework/zend-db/issues/98 - 'Select::processJoinNoJoinedColumns()' => [ - 'sqlObject' => $this->select('my_table') - ->join('joined_table2', 'my_table.id = joined_table2.id', $columns=[]) - ->join('joined_table3', 'my_table.id = joined_table3.id', [\Zend\Db\Sql\Select::SQL_STAR]) - ->columns([ - 'my_table_column', - 'aliased_column' => new \Zend\Db\Sql\Expression('NOW()') - ]), - 'expected' => [ - 'sql92' => [ - 'string' => 'SELECT "my_table"."my_table_column" AS "my_table_column", NOW() AS "aliased_column", "joined_table3".* FROM "my_table" INNER JOIN "joined_table2" ON "my_table"."id" = "joined_table2"."id" INNER JOIN "joined_table3" ON "my_table"."id" = "joined_table3"."id"', - ], - 'MySql' => [ - 'string' => 'SELECT `my_table`.`my_table_column` AS `my_table_column`, NOW() AS `aliased_column`, `joined_table3`.* FROM `my_table` INNER JOIN `joined_table2` ON `my_table`.`id` = `joined_table2`.`id` INNER JOIN `joined_table3` ON `my_table`.`id` = `joined_table3`.`id`', - ], - 'Oracle' => [ - 'string' => 'SELECT "my_table"."my_table_column" AS "my_table_column", NOW() AS "aliased_column", "joined_table3".* FROM "my_table" INNER JOIN "joined_table2" ON "my_table"."id" = "joined_table2"."id" INNER JOIN "joined_table3" ON "my_table"."id" = "joined_table3"."id"', - ], - 'SqlServer' => [ - 'string' => 'SELECT [my_table].[my_table_column] AS [my_table_column], NOW() AS [aliased_column], [joined_table3].* FROM [my_table] INNER JOIN [joined_table2] ON [my_table].[id] = [joined_table2].[id] INNER JOIN [joined_table3] ON [my_table].[id] = [joined_table3].[id]', - ] - ] - ], - 'Select::processJoin()' => [ - 'sqlObject' => $this->select('a')->join(['b'=>$this->select('c')->where(['cc'=>10])], 'd=e')->where(['x'=>20]), - 'expected' => [ - 'sql92' => [ - 'string' => 'SELECT "a".*, "b".* FROM "a" INNER JOIN (SELECT "c".* FROM "c" WHERE "cc" = \'10\') AS "b" ON "d"="e" WHERE "x" = \'20\'', - 'prepare' => 'SELECT "a".*, "b".* FROM "a" INNER JOIN (SELECT "c".* FROM "c" WHERE "cc" = ?) AS "b" ON "d"="e" WHERE "x" = ?', - 'parameters' => ['subselect1where1'=>10, 'where1'=>20], - ], - 'MySql' => [ - 'string' => 'SELECT `a`.*, `b`.* FROM `a` INNER JOIN (SELECT `c`.* FROM `c` WHERE `cc` = \'10\') AS `b` ON `d`=`e` WHERE `x` = \'20\'', - 'prepare' => 'SELECT `a`.*, `b`.* FROM `a` INNER JOIN (SELECT `c`.* FROM `c` WHERE `cc` = ?) AS `b` ON `d`=`e` WHERE `x` = ?', - 'parameters' => ['subselect2where1'=>10, 'where2'=>20], - ], - 'Oracle' => [ - 'string' => 'SELECT "a".*, "b".* FROM "a" INNER JOIN (SELECT "c".* FROM "c" WHERE "cc" = \'10\') "b" ON "d"="e" WHERE "x" = \'20\'', - 'prepare' => 'SELECT "a".*, "b".* FROM "a" INNER JOIN (SELECT "c".* FROM "c" WHERE "cc" = ?) "b" ON "d"="e" WHERE "x" = ?', - 'parameters' => ['subselect2where1'=>10, 'where2'=>20], - ], - 'SqlServer' => [ - 'string' => 'SELECT [a].*, [b].* FROM [a] INNER JOIN (SELECT [c].* FROM [c] WHERE [cc] = \'10\') AS [b] ON [d]=[e] WHERE [x] = \'20\'', - 'prepare' => 'SELECT [a].*, [b].* FROM [a] INNER JOIN (SELECT [c].* FROM [c] WHERE [cc] = ?) AS [b] ON [d]=[e] WHERE [x] = ?', - 'parameters' => ['subselect2where1'=>10, 'where2'=>20], - ], - ], - ], - 'Ddl::CreateTable::processColumns()' => [ - 'sqlObject' => $this->createTable('foo') - ->addColumn($this->createColumn('col1')->setOption('identity', true)->setOption('comment', 'Comment1')) - ->addColumn($this->createColumn('col2')->setOption('identity', true)->setOption('comment', 'Comment2')), - 'expected' => [ - 'sql92' => "CREATE TABLE \"foo\" ( \n \"col1\" INTEGER NOT NULL,\n \"col2\" INTEGER NOT NULL \n)", - 'MySql' => "CREATE TABLE `foo` ( \n `col1` INTEGER NOT NULL AUTO_INCREMENT COMMENT 'Comment1',\n `col2` INTEGER NOT NULL AUTO_INCREMENT COMMENT 'Comment2' \n)", - 'Oracle' => "CREATE TABLE \"foo\" ( \n \"col1\" INTEGER NOT NULL,\n \"col2\" INTEGER NOT NULL \n)", - 'SqlServer' => "CREATE TABLE [foo] ( \n [col1] INTEGER NOT NULL,\n [col2] INTEGER NOT NULL \n)", - ], - ], - 'Ddl::CreateTable::processTable()' => [ - 'sqlObject' => $this->createTable('foo')->setTemporary(true), - 'expected' => [ - 'sql92' => "CREATE TEMPORARY TABLE \"foo\" ( \n)", - 'MySql' => "CREATE TEMPORARY TABLE `foo` ( \n)", - 'Oracle' => "CREATE TEMPORARY TABLE \"foo\" ( \n)", - 'SqlServer' => "CREATE TABLE [#foo] ( \n)", - ], - ], - 'Select::processSubSelect()' => [ - 'sqlObject' => $this->select(['a' => $this->select(['b' => $this->select('c')->where(['cc'=>'CC'])])->where(['bb'=>'BB'])])->where(['aa'=>'AA']), - 'expected' => [ - 'sql92' => [ - 'string' => 'SELECT "a".* FROM (SELECT "b".* FROM (SELECT "c".* FROM "c" WHERE "cc" = \'CC\') AS "b" WHERE "bb" = \'BB\') AS "a" WHERE "aa" = \'AA\'', - 'prepare' => 'SELECT "a".* FROM (SELECT "b".* FROM (SELECT "c".* FROM "c" WHERE "cc" = ?) AS "b" WHERE "bb" = ?) AS "a" WHERE "aa" = ?', - 'parameters' => ['subselect2where1' => 'CC', 'subselect1where1' => 'BB', 'where1' => 'AA'], - ], - 'MySql' => [ - 'string' => 'SELECT `a`.* FROM (SELECT `b`.* FROM (SELECT `c`.* FROM `c` WHERE `cc` = \'CC\') AS `b` WHERE `bb` = \'BB\') AS `a` WHERE `aa` = \'AA\'', - 'prepare' => 'SELECT `a`.* FROM (SELECT `b`.* FROM (SELECT `c`.* FROM `c` WHERE `cc` = ?) AS `b` WHERE `bb` = ?) AS `a` WHERE `aa` = ?', - 'parameters' => ['subselect4where1' => 'CC', 'subselect3where1' => 'BB', 'where2' => 'AA'], - ], - 'Oracle' => [ - 'string' => 'SELECT "a".* FROM (SELECT "b".* FROM (SELECT "c".* FROM "c" WHERE "cc" = \'CC\') "b" WHERE "bb" = \'BB\') "a" WHERE "aa" = \'AA\'', - 'prepare' => 'SELECT "a".* FROM (SELECT "b".* FROM (SELECT "c".* FROM "c" WHERE "cc" = ?) "b" WHERE "bb" = ?) "a" WHERE "aa" = ?', - 'parameters' => ['subselect4where1' => 'CC', 'subselect3where1' => 'BB', 'where2' => 'AA'], - ], - 'SqlServer' => [ - 'string' => 'SELECT [a].* FROM (SELECT [b].* FROM (SELECT [c].* FROM [c] WHERE [cc] = \'CC\') AS [b] WHERE [bb] = \'BB\') AS [a] WHERE [aa] = \'AA\'', - 'prepare' => 'SELECT [a].* FROM (SELECT [b].* FROM (SELECT [c].* FROM [c] WHERE [cc] = ?) AS [b] WHERE [bb] = ?) AS [a] WHERE [aa] = ?', - 'parameters' => ['subselect4where1' => 'CC', 'subselect3where1' => 'BB', 'where2' => 'AA'], - ], - ], - ], - 'Delete::processSubSelect()' => [ - 'sqlObject' => $this->delete('foo')->where(['x'=>$this->select('foo')->where(['x'=>'y'])]), - 'expected' => [ - 'sql92' => [ - 'string' => 'DELETE FROM "foo" WHERE "x" = (SELECT "foo".* FROM "foo" WHERE "x" = \'y\')', - 'prepare' => 'DELETE FROM "foo" WHERE "x" = (SELECT "foo".* FROM "foo" WHERE "x" = ?)', - 'parameters' => ['subselect1where1' => 'y'], - ], - 'MySql' => [ - 'string' => 'DELETE FROM `foo` WHERE `x` = (SELECT `foo`.* FROM `foo` WHERE `x` = \'y\')', - 'prepare' => 'DELETE FROM `foo` WHERE `x` = (SELECT `foo`.* FROM `foo` WHERE `x` = ?)', - 'parameters' => ['subselect2where1' => 'y'], - ], - 'Oracle' => [ - 'string' => 'DELETE FROM "foo" WHERE "x" = (SELECT "foo".* FROM "foo" WHERE "x" = \'y\')', - 'prepare' => 'DELETE FROM "foo" WHERE "x" = (SELECT "foo".* FROM "foo" WHERE "x" = ?)', - 'parameters' => ['subselect3where1' => 'y'], - ], - 'SqlServer' => [ - 'string' => 'DELETE FROM [foo] WHERE [x] = (SELECT [foo].* FROM [foo] WHERE [x] = \'y\')', - 'prepare' => 'DELETE FROM [foo] WHERE [x] = (SELECT [foo].* FROM [foo] WHERE [x] = ?)', - 'parameters' => ['subselect4where1' => 'y'], - ], - ], - ], - 'Update::processSubSelect()' => [ - 'sqlObject' => $this->update('foo')->set(['x'=>$this->select('foo')]), - 'expected' => [ - 'sql92' => 'UPDATE "foo" SET "x" = (SELECT "foo".* FROM "foo")', - 'MySql' => 'UPDATE `foo` SET `x` = (SELECT `foo`.* FROM `foo`)', - 'Oracle' => 'UPDATE "foo" SET "x" = (SELECT "foo".* FROM "foo")', - 'SqlServer' => 'UPDATE [foo] SET [x] = (SELECT [foo].* FROM [foo])', - ], - ], - 'Insert::processSubSelect()' => [ - 'sqlObject' => $this->insert('foo')->select($this->select('foo')->where(['x'=>'y'])), - 'expected' => [ - 'sql92' => [ - 'string' => 'INSERT INTO "foo" SELECT "foo".* FROM "foo" WHERE "x" = \'y\'', - 'prepare' => 'INSERT INTO "foo" SELECT "foo".* FROM "foo" WHERE "x" = ?', - 'parameters' => ['subselect1where1' => 'y'], - ], - 'MySql' => [ - 'string' => 'INSERT INTO `foo` SELECT `foo`.* FROM `foo` WHERE `x` = \'y\'', - 'prepare' => 'INSERT INTO `foo` SELECT `foo`.* FROM `foo` WHERE `x` = ?', - 'parameters' => ['subselect2where1' => 'y'], - ], - 'Oracle' => [ - 'string' => 'INSERT INTO "foo" SELECT "foo".* FROM "foo" WHERE "x" = \'y\'', - 'prepare' => 'INSERT INTO "foo" SELECT "foo".* FROM "foo" WHERE "x" = ?', - 'parameters' => ['subselect3where1' => 'y'], - ], - 'SqlServer' => [ - 'string' => 'INSERT INTO [foo] SELECT [foo].* FROM [foo] WHERE [x] = \'y\'', - 'prepare' => 'INSERT INTO [foo] SELECT [foo].* FROM [foo] WHERE [x] = ?', - 'parameters' => ['subselect4where1' => 'y'], - ], - ], - ], - 'Update::processExpression()' => [ - 'sqlObject' => $this->update('foo')->set(['x'=>new Sql\Expression('?', [$this->select('foo')->where(['x'=>'y'])])]), - 'expected' => [ - 'sql92' => [ - 'string' => 'UPDATE "foo" SET "x" = (SELECT "foo".* FROM "foo" WHERE "x" = \'y\')', - 'prepare' => 'UPDATE "foo" SET "x" = (SELECT "foo".* FROM "foo" WHERE "x" = ?)', - 'parameters' => ['subselect1where1' => 'y'], - ], - 'MySql' => [ - 'string' => 'UPDATE `foo` SET `x` = (SELECT `foo`.* FROM `foo` WHERE `x` = \'y\')', - 'prepare' => 'UPDATE `foo` SET `x` = (SELECT `foo`.* FROM `foo` WHERE `x` = ?)', - 'parameters' => ['subselect2where1' => 'y'], - ], - 'Oracle' => [ - 'string' => 'UPDATE "foo" SET "x" = (SELECT "foo".* FROM "foo" WHERE "x" = \'y\')', - 'prepare' => 'UPDATE "foo" SET "x" = (SELECT "foo".* FROM "foo" WHERE "x" = ?)', - 'parameters' => ['subselect3where1' => 'y'], - ], - 'SqlServer' => [ - 'string' => 'UPDATE [foo] SET [x] = (SELECT [foo].* FROM [foo] WHERE [x] = \'y\')', - 'prepare' => 'UPDATE [foo] SET [x] = (SELECT [foo].* FROM [foo] WHERE [x] = ?)', - 'parameters' => ['subselect4where1' => 'y'], - ], - ], - ], - 'Update::processJoins()' => [ - 'sqlObject' => $this->update('foo')->set(['x' => 'y'])->where(['xx' => 'yy'])->join( - 'bar', - 'bar.barId = foo.barId' - ), - 'expected' => [ - 'sql92' => [ - 'string' => 'UPDATE "foo" INNER JOIN "bar" ON "bar"."barId" = "foo"."barId" SET "x" = \'y\' WHERE "xx" = \'yy\'', - ], - 'MySql' => [ - 'string' => 'UPDATE `foo` INNER JOIN `bar` ON `bar`.`barId` = `foo`.`barId` SET `x` = \'y\' WHERE `xx` = \'yy\'', - ], - 'Oracle' => [ - 'string' => 'UPDATE "foo" INNER JOIN "bar" ON "bar"."barId" = "foo"."barId" SET "x" = \'y\' WHERE "xx" = \'yy\'', - ], - 'SqlServer' => [ - 'string' => 'UPDATE [foo] INNER JOIN [bar] ON [bar].[barId] = [foo].[barId] SET [x] = \'y\' WHERE [xx] = \'yy\'', - ], - ], - ], - ]; - } - - protected function dataProvider_Decorators() - { - return [ - 'RootDecorators::Select' => [ - 'sqlObject' => $this->select('foo')->where(['x'=>$this->select('bar')]), - 'expected' => [ - 'sql92' => [ - 'decorators' => [ - 'Zend\Db\Sql\Select' => new TestAsset\SelectDecorator, - ], - 'string' => 'SELECT "foo".* FROM "foo" WHERE "x" = (SELECT "bar".* FROM "bar")', - ], - 'MySql' => [ - 'decorators' => [ - 'Zend\Db\Sql\Select' => new TestAsset\SelectDecorator, - ], - 'string' => 'SELECT `foo`.* FROM `foo` WHERE `x` = (SELECT `bar`.* FROM `bar`)', - ], - 'Oracle' => [ - 'decorators' => [ - 'Zend\Db\Sql\Select' => new TestAsset\SelectDecorator, - ], - 'string' => 'SELECT "foo".* FROM "foo" WHERE "x" = (SELECT "bar".* FROM "bar")', - ], - 'SqlServer' => [ - 'decorators' => [ - 'Zend\Db\Sql\Select' => new TestAsset\SelectDecorator, - ], - 'string' => 'SELECT [foo].* FROM [foo] WHERE [x] = (SELECT [bar].* FROM [bar])', - ], - ], - ], - /* TODO - should be implemeted - 'RootDecorators::Insert' => array( - 'sqlObject' => $this->insert('foo')->select($this->select()), - 'expected' => array( - 'sql92' => array( - 'decorators' => array( - 'Zend\Db\Sql\Insert' => new TestAsset\InsertDecorator, // Decorator for root sqlObject - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Mysql\SelectDecorator', '{=SELECT_Sql92=}') - ), - 'string' => 'INSERT INTO "foo" {=SELECT_Sql92=}', - ), - 'MySql' => array( - 'decorators' => array( - 'Zend\Db\Sql\Insert' => new TestAsset\InsertDecorator, // Decorator for root sqlObject - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Mysql\SelectDecorator', '{=SELECT_MySql=}') - ), - 'string' => 'INSERT INTO `foo` {=SELECT_MySql=}', - ), - 'Oracle' => array( - 'decorators' => array( - 'Zend\Db\Sql\Insert' => new TestAsset\InsertDecorator, // Decorator for root sqlObject - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Oracle\SelectDecorator', '{=SELECT_Oracle=}') - ), - 'string' => 'INSERT INTO "foo" {=SELECT_Oracle=}', - ), - 'SqlServer' => array( - 'decorators' => array( - 'Zend\Db\Sql\Insert' => new TestAsset\InsertDecorator, // Decorator for root sqlObject - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\SqlServer\SelectDecorator', '{=SELECT_SqlServer=}') - ), - 'string' => 'INSERT INTO [foo] {=SELECT_SqlServer=}', - ), - ), - ), - 'RootDecorators::Delete' => array( - 'sqlObject' => $this->delete('foo')->where(array('x'=>$this->select('foo'))), - 'expected' => array( - 'sql92' => array( - 'decorators' => array( - 'Zend\Db\Sql\Delete' => new TestAsset\DeleteDecorator, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Mysql\SelectDecorator', '{=SELECT_Sql92=}') - ), - 'string' => 'DELETE FROM "foo" WHERE "x" = ({=SELECT_Sql92=})', - ), - 'MySql' => array( - 'decorators' => array( - 'Zend\Db\Sql\Delete' => new TestAsset\DeleteDecorator, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Mysql\SelectDecorator', '{=SELECT_MySql=}') - ), - 'string' => 'DELETE FROM `foo` WHERE `x` = ({=SELECT_MySql=})', - ), - 'Oracle' => array( - 'decorators' => array( - 'Zend\Db\Sql\Delete' => new TestAsset\DeleteDecorator, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Oracle\SelectDecorator', '{=SELECT_Oracle=}') - ), - 'string' => 'DELETE FROM "foo" WHERE "x" = ({=SELECT_Oracle=})', - ), - 'SqlServer' => array( - 'decorators' => array( - 'Zend\Db\Sql\Delete' => new TestAsset\DeleteDecorator, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\SqlServer\SelectDecorator', '{=SELECT_SqlServer=}') - ), - 'string' => 'DELETE FROM [foo] WHERE [x] = ({=SELECT_SqlServer=})', - ), - ), - ), - 'RootDecorators::Update' => array( - 'sqlObject' => $this->update('foo')->where(array('x'=>$this->select('foo'))), - 'expected' => array( - 'sql92' => array( - 'decorators' => array( - 'Zend\Db\Sql\Update' => new TestAsset\UpdateDecorator, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Mysql\SelectDecorator', '{=SELECT_Sql92=}') - ), - 'string' => 'UPDATE "foo" SET WHERE "x" = ({=SELECT_Sql92=})', - ), - 'MySql' => array( - 'decorators' => array( - 'Zend\Db\Sql\Update' => new TestAsset\UpdateDecorator, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Mysql\SelectDecorator', '{=SELECT_MySql=}') - ), - 'string' => 'UPDATE `foo` SET WHERE `x` = ({=SELECT_MySql=})', - ), - 'Oracle' => array( - 'decorators' => array( - 'Zend\Db\Sql\Update' => new TestAsset\UpdateDecorator, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Oracle\SelectDecorator', '{=SELECT_Oracle=}') - ), - 'string' => 'UPDATE "foo" SET WHERE "x" = ({=SELECT_Oracle=})', - ), - 'SqlServer' => array( - 'decorators' => array( - 'Zend\Db\Sql\Update' => new TestAsset\UpdateDecorator, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\SqlServer\SelectDecorator', '{=SELECT_SqlServer=}') - ), - 'string' => 'UPDATE [foo] SET WHERE [x] = ({=SELECT_SqlServer=})', - ), - ), - ), - 'DecorableExpression()' => array( - 'sqlObject' => $this->update('foo')->where(array('x'=>new Sql\Expression('?', array($this->select('foo'))))), - 'expected' => array( - 'sql92' => array( - 'decorators' => array( - 'Zend\Db\Sql\Expression' => new TestAsset\DecorableExpression, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Mysql\SelectDecorator', '{=SELECT_Sql92=}') - ), - 'string' => 'UPDATE "foo" SET WHERE "x" = {decorate-({=SELECT_Sql92=})-decorate}', - ), - 'MySql' => array( - 'decorators' => array( - 'Zend\Db\Sql\Expression' => new TestAsset\DecorableExpression, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Mysql\SelectDecorator', '{=SELECT_MySql=}') - ), - 'string' => 'UPDATE `foo` SET WHERE `x` = {decorate-({=SELECT_MySql=})-decorate}', - ), - 'Oracle' => array( - 'decorators' => array( - 'Zend\Db\Sql\Expression' => new TestAsset\DecorableExpression, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\Oracle\SelectDecorator', '{=SELECT_Oracle=}') - ), - 'string' => 'UPDATE "foo" SET WHERE "x" = {decorate-({=SELECT_Oracle=})-decorate}', - ), - 'SqlServer' => array( - 'decorators' => array( - 'Zend\Db\Sql\Expression' => new TestAsset\DecorableExpression, - 'Zend\Db\Sql\Select' => array('Zend\Db\Sql\Platform\SqlServer\SelectDecorator', '{=SELECT_SqlServer=}') - ), - 'string' => 'UPDATE [foo] SET WHERE [x] = {decorate-({=SELECT_SqlServer=})-decorate}', - ), - ), - ),*/ - ]; - } - - public function dataProvider() - { - $data = array_merge( - $this->dataProvider_CommonProcessMethods(), - $this->dataProvider_Decorators() - ); - - $res = []; - foreach ($data as $index => $test) { - foreach ($test['expected'] as $platform => $expected) { - $res[$index . '->' . $platform] = [ - 'sqlObject' => $test['sqlObject'], - 'platform' => $platform, - 'expected' => $expected, - ]; - } - } - return $res; - } - - /** - * @param type $sqlObject - * @param type $platform - * @param type $expected - * @dataProvider dataProvider - */ - public function test($sqlObject, $platform, $expected) - { - $sql = new Sql\Sql($this->resolveAdapter($platform)); - - if (is_array($expected) && isset($expected['decorators'])) { - foreach ($expected['decorators'] as $type=>$decorator) { - $sql->getSqlPlatform()->setTypeDecorator($type, $this->resolveDecorator($decorator)); - } - } - - $expectedString = is_string($expected) ? $expected : (isset($expected['string']) ? $expected['string'] : null); - if ($expectedString) { - $actual = $sql->getSqlStringForSqlObject($sqlObject); - $this->assertEquals($expectedString, $actual, "getSqlString()"); - } - if (is_array($expected) && isset($expected['prepare'])) { - $actual = $sql->prepareStatementForSqlObject($sqlObject); - $this->assertEquals($expected['prepare'], $actual->getSql(), "prepareStatement()"); - if (isset($expected['parameters'])) { - $actual = $actual->getParameterContainer()->getNamedArray(); - $this->assertSame($expected['parameters'], $actual, "parameterContainer()"); - } - } - } - - protected function resolveDecorator($decorator) - { - if (is_array($decorator)) { - $decoratorMock = $this->getMock($decorator[0], ['buildSqlString'], [null]); - $decoratorMock->expects($this->any())->method('buildSqlString')->will($this->returnValue($decorator[1])); - return $decoratorMock; - } - if ($decorator instanceof Sql\Platform\PlatformDecoratorInterface) { - return $decorator; - } - return; - } - - protected function resolveAdapter($platform) - { - switch ($platform) { - case 'sql92' : $platform = new TestAsset\TrustingSql92Platform(); break; - case 'MySql' : $platform = new TestAsset\TrustingMysqlPlatform(); break; - case 'Oracle' : $platform = new TestAsset\TrustingOraclePlatform(); break; - case 'SqlServer' : $platform = new TestAsset\TrustingSqlServerPlatform(); break; - default : $platform = null; - } - - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockDriver->expects($this->any())->method('createStatement')->will($this->returnCallback(function () {return new Adapter\StatementContainer;})); - - return new Adapter\Adapter($mockDriver, $platform); - } - - public function __call($name, $arguments) - { - $arg0 = isset($arguments[0]) ? $arguments[0] : null; - switch ($name) { - case 'select' : return new Sql\Select($arg0); - case 'delete' : return new Sql\Delete($arg0); - case 'update' : return new Sql\Update($arg0); - case 'insert' : return new Sql\Insert($arg0); - case 'createTable' : return new Sql\Ddl\CreateTable($arg0); - case 'createColumn' : return new Sql\Ddl\Column\Column($arg0); - } - } -} diff --git a/test/Sql/SqlTest.php b/test/Sql/SqlTest.php index eb24175721..b4b2374a82 100644 --- a/test/Sql/SqlTest.php +++ b/test/Sql/SqlTest.php @@ -11,7 +11,7 @@ use Zend\Db\Sql\Sql; use ZendTest\Db\TestAsset; -use Zend\Db\Adapter\Adapter; +use Zend\Db\Sql\TableIdentifier; class SqlTest extends \PHPUnit_Framework_TestCase { @@ -26,14 +26,9 @@ class SqlTest extends \PHPUnit_Framework_TestCase public function setup() { // mock the adapter, driver, and parts - $mockResult = $this->getMock('Zend\Db\Adapter\Driver\ResultInterface'); $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $mockStatement->expects($this->any())->method('execute')->will($this->returnValue($mockResult)); - $mockConnection = $this->getMock('Zend\Db\Adapter\Driver\ConnectionInterface'); $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); $mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue($mockStatement)); - $mockDriver->expects($this->any())->method('getConnection')->will($this->returnValue($mockConnection)); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); // setup mock adapter $this->mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver, new TestAsset\TrustingSql92Platform()]); @@ -51,12 +46,29 @@ public function test__construct() $this->assertFalse($sql->hasTable()); $sql->setTable('foo'); - $this->assertSame('foo', $sql->getTable()); + $this->assertSame('foo', $sql->getTable()->getTable()); $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', 'Table must be a string, array or instance of TableIdentifier.'); $sql->setTable(null); } + /** + * @covers Zend\Db\Sql\Sql::setTable + */ + public function testSetTable() + { + $sql = new Sql($this->mockAdapter); + + $this->assertEquals('test', $sql->setTable('test')->getTable()->getTable()); + $this->assertEquals('test', $sql->setTable(new TableIdentifier('test'))->getTable()->getTable()); + + $this->setExpectedException( + 'Zend\Db\Sql\Exception\InvalidArgumentException', + 'Table must be a string, array or instance of TableIdentifier.' + ); + $sql->setTable(null); + } + /** * @covers Zend\Db\Sql\Sql::select */ @@ -64,7 +76,7 @@ public function testSelect() { $select = $this->sql->select(); $this->assertInstanceOf('Zend\Db\Sql\Select', $select); - $this->assertSame('foo', $select->getRawState('table')); + $this->assertSame('foo', $select->table->getSource()->getTable()); $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', 'This Sql object is intended to work with only the table "foo" provided at construction time.'); @@ -78,7 +90,7 @@ public function testInsert() { $insert = $this->sql->insert(); $this->assertInstanceOf('Zend\Db\Sql\Insert', $insert); - $this->assertSame('foo', $insert->getRawState('table')); + $this->assertSame('foo', $insert->table->getSource()->getTable()); $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', 'This Sql object is intended to work with only the table "foo" provided at construction time.'); @@ -92,7 +104,7 @@ public function testUpdate() { $update = $this->sql->update(); $this->assertInstanceOf('Zend\Db\Sql\Update', $update); - $this->assertSame('foo', $update->getRawState('table')); + $this->assertSame('foo', $update->table->getSource()->getTable()); $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', 'This Sql object is intended to work with only the table "foo" provided at construction time.'); @@ -107,7 +119,7 @@ public function testDelete() $delete = $this->sql->delete(); $this->assertInstanceOf('Zend\Db\Sql\Delete', $delete); - $this->assertSame('foo', $delete->getRawState('table')); + $this->assertSame('foo', $delete->table->getSource()->getTable()); $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', 'This Sql object is intended to work with only the table "foo" provided at construction time.'); @@ -115,95 +127,23 @@ public function testDelete() } /** - * @covers Zend\Db\Sql\Sql::prepareStatementForSqlObject + * @covers Zend\Db\Sql\Sql::getDdl */ - public function testPrepareStatementForSqlObject() + public function testGetDdl() { - $insert = $this->sql->insert()->columns(['foo'])->values(['foo'=>'bar']); - $stmt = $this->sql->prepareStatementForSqlObject($insert); - $this->assertInstanceOf('Zend\Db\Adapter\Driver\StatementInterface', $stmt); + $ddl = $this->sql->getDdl(); + $this->assertSame($this->sql->getTable(), $ddl->getTable()); + $this->assertSame($this->sql->getAdapter(), $ddl->getAdapter()); + $this->assertSame($this->sql->getBuilder(), $ddl->getBuilder()); } /** - * @group 6890 + * @covers Zend\Db\Sql\Sql::prepareSqlStatement */ - public function testForDifferentAdapters() + public function testPrepareSqlStatement() { - $adapterSql92 = $this->getAdapterForPlatform('sql92'); - $adapterMySql = $this->getAdapterForPlatform('MySql'); - $adapterOracle = $this->getAdapterForPlatform('Oracle'); - $adapterSqlServer = $this->getAdapterForPlatform('SqlServer'); - - $select = $this->sql->select()->offset(10); - - // Default - $this->assertEquals( - 'SELECT "foo".* FROM "foo" OFFSET \'10\'', - $this->sql->buildSqlString($select) - ); - $this->mockAdapter->getDriver()->createStatement()->expects($this->any())->method('setSql') - ->with($this->equalTo('SELECT "foo".* FROM "foo" OFFSET ?')); - $this->sql->prepareStatementForSqlObject($select); - - // Sql92 - $this->assertEquals( - 'SELECT "foo".* FROM "foo" OFFSET \'10\'', - $this->sql->buildSqlString($select, $adapterSql92) - ); - $adapterSql92->getDriver()->createStatement()->expects($this->any())->method('setSql') - ->with($this->equalTo('SELECT "foo".* FROM "foo" OFFSET ?')); - $this->sql->prepareStatementForSqlObject($select, null, $adapterSql92); - - // MySql - $this->assertEquals( - 'SELECT `foo`.* FROM `foo` LIMIT 18446744073709551615 OFFSET 10', - $this->sql->buildSqlString($select, $adapterMySql) - ); - $adapterMySql->getDriver()->createStatement()->expects($this->any())->method('setSql') - ->with($this->equalTo('SELECT `foo`.* FROM `foo` LIMIT 18446744073709551615 OFFSET ?')); - $this->sql->prepareStatementForSqlObject($select, null, $adapterMySql); - - // Oracle - $this->assertEquals( - 'SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "foo".* FROM "foo" ) b ) WHERE b_rownum > (10)', - $this->sql->buildSqlString($select, $adapterOracle) - ); - $adapterOracle->getDriver()->createStatement()->expects($this->any())->method('setSql') - ->with($this->equalTo('SELECT * FROM (SELECT b.*, rownum b_rownum FROM ( SELECT "foo".* FROM "foo" ) b ) WHERE b_rownum > (:offset)')); - $this->sql->prepareStatementForSqlObject($select, null, $adapterOracle); - - // SqlServer - $this->assertContains( - 'WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN 10+1 AND 0+10', - $this->sql->buildSqlString($select, $adapterSqlServer) - ); - $adapterSqlServer->getDriver()->createStatement()->expects($this->any())->method('setSql') - ->with($this->stringContains('WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN ?+1 AND ?+?')); - $this->sql->prepareStatementForSqlObject($select, null, $adapterSqlServer); - } - - /** - * Data provider - * - * @param string $platform - * - * @return Adapter - */ - protected function getAdapterForPlatform($platform) - { - switch ($platform) { - case 'sql92' : $platform = new TestAsset\TrustingSql92Platform(); break; - case 'MySql' : $platform = new TestAsset\TrustingMysqlPlatform(); break; - case 'Oracle' : $platform = new TestAsset\TrustingOraclePlatform(); break; - case 'SqlServer' : $platform = new TestAsset\TrustingSqlServerPlatform(); break; - default : $platform = null; - } - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue($mockStatement)); - - return new Adapter($mockDriver, $platform); + $insert = $this->sql->insert()->columns(['foo'])->values(['foo'=>'bar']); + $stmt = $this->sql->prepareSqlStatement($insert); + $this->assertInstanceOf('Zend\Db\Adapter\Driver\StatementInterface', $stmt); } } diff --git a/test/Sql/TableIdentifierTest.php b/test/Sql/TableIdentifierTest.php index feb5c22cc6..fdaa6d1a4b 100644 --- a/test/Sql/TableIdentifierTest.php +++ b/test/Sql/TableIdentifierTest.php @@ -96,7 +96,7 @@ public function testRejectsInvalidSchema($invalidSchema) public function invalidTableProvider() { return array_merge( - [[null]], + [/*[null]*/], $this->invalidSchemaProvider() ); } diff --git a/test/Sql/TableSourceTest.php b/test/Sql/TableSourceTest.php new file mode 100644 index 0000000000..51c0ec70cc --- /dev/null +++ b/test/Sql/TableSourceTest.php @@ -0,0 +1,83 @@ +assertEquals( + ['schema', 'table', 'alias'], + [$t->getSource()->getSchema(), $t->getSource()->getTable(), $t->getAlias()] + ); + + $t = TableSource::factory(['alias'=>['schema', 'table']]); + $this->assertEquals( + ['schema', 'table', 'alias'], + [$t->getSource()->getSchema(), $t->getSource()->getTable(), $t->getAlias()] + ); + + $t = TableSource::factory(['alias'=>'table']); + $this->assertEquals( + [null, 'table', 'alias'], + [$t->getSource()->getSchema(), $t->getSource()->getTable(), $t->getAlias()] + ); + + $t = TableSource::factory(new TableIdentifier('table', 'schema')); + $this->assertEquals( + ['schema', 'table', null], + [$t->getSource()->getSchema(), $t->getSource()->getTable(), $t->getAlias()] + ); + + $t = TableSource::factory(['alias' => new TableIdentifier('table', 'schema')]); + $this->assertEquals( + ['schema', 'table', 'alias'], + [$t->getSource()->getSchema(), $t->getSource()->getTable(), $t->getAlias()] + ); + + $t = TableSource::factory(['schema', 'table']); + $this->assertEquals( + ['schema', 'table', null], + [$t->getSource()->getSchema(), $t->getSource()->getTable(), $t->getAlias()] + ); + + $t = TableSource::factory('table'); + $this->assertEquals( + [null, 'table', null], + [$t->getSource()->getSchema(), $t->getSource()->getTable(), $t->getAlias()] + ); + + $select = new Select(); + $t = TableSource::factory(['alias'=>$select]); + $this->assertEquals( + [null, $select, 'alias'], + [null, $t->getSource(), $t->getAlias()] + ); + + $t = TableSource::factory($select); + $this->assertEquals( + [null, $select, null], + [null, $t->getSource(), $t->getAlias()] + ); + + $expression = new Expression('psql_function_which_returns_table'); + $t = TableSource::factory(['alias' => $expression]); + $this->assertEquals( + [null, $expression, 'alias'], + [null, $t->getSource(), $t->getAlias()] + ); + } +} diff --git a/test/Sql/UpdateTest.php b/test/Sql/UpdateTest.php index a2e9b8a3d4..146f810bb7 100644 --- a/test/Sql/UpdateTest.php +++ b/test/Sql/UpdateTest.php @@ -9,12 +9,10 @@ namespace ZendTest\Db\Sql; -use Zend\Db\Sql\Join; +use Zend\Db\Sql\Joins; use Zend\Db\Sql\Update; use Zend\Db\Sql\Where; -use Zend\Db\Sql\Expression; use Zend\Db\Sql\TableIdentifier; -use ZendTest\Db\TestAsset\TrustingSql92Platform; class UpdateTest extends \PHPUnit_Framework_TestCase { @@ -46,11 +44,11 @@ protected function tearDown() public function testTable() { $this->update->table('foo', 'bar'); - $this->assertEquals('foo', $this->readAttribute($this->update, 'table')); + $this->assertEquals('foo', $this->update->table->getSource()->getTable()); $tableIdentifier = new TableIdentifier('foo', 'bar'); $this->update->table($tableIdentifier); - $this->assertEquals($tableIdentifier, $this->readAttribute($this->update, 'table')); + $this->assertEquals($tableIdentifier, $this->update->table->getSource()); } /** @@ -59,7 +57,7 @@ public function testTable() public function testConstruct() { $update = new Update('foo'); - $this->assertEquals('foo', $this->readAttribute($update, 'table')); + $this->assertEquals('foo', $update->table->getSource()->getTable()); } /** @@ -68,7 +66,7 @@ public function testConstruct() public function testSet() { $this->update->set(['foo' => 'bar']); - $this->assertEquals(['foo' => 'bar'], $this->update->getRawState('set')); + $this->assertEquals(['foo' => 'bar'], $this->update->set->toArray()); } /** @@ -88,171 +86,31 @@ public function testSortableSet() 'two' => 'с_two', 'three' => 'с_three', ], - $this->update->getRawState('set') + $this->update->set->toArray() ); } /** - * @covers Zend\Db\Sql\Update::where - */ - public function testWhere() - { - $this->update->where('x = y'); - $this->update->where(['foo > ?' => 5]); - $this->update->where(['id' => 2]); - $this->update->where(['a = b'], Where::OP_OR); - $this->update->where(['c1' => null]); - $this->update->where(['c2' => [1, 2, 3]]); - $this->update->where([new \Zend\Db\Sql\Predicate\IsNotNull('c3')]); - $where = $this->update->where; - - $predicates = $this->readAttribute($where, 'predicates'); - $this->assertEquals('AND', $predicates[0][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[0][1]); - - $this->assertEquals('AND', $predicates[1][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Expression', $predicates[1][1]); - - $this->assertEquals('AND', $predicates[2][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Operator', $predicates[2][1]); - - $this->assertEquals('OR', $predicates[3][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\Literal', $predicates[3][1]); - - $this->assertEquals('AND', $predicates[4][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\IsNull', $predicates[4][1]); - - $this->assertEquals('AND', $predicates[5][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\In', $predicates[5][1]); - - $this->assertEquals('AND', $predicates[6][0]); - $this->assertInstanceOf('Zend\Db\Sql\Predicate\IsNotNull', $predicates[6][1]); - - $where = new Where; - $this->update->where($where); - $this->assertSame($where, $this->update->where); - - $this->update->where(function ($what) use ($where) { - $this->assertSame($where, $what); - }); - - $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException', 'Predicate cannot be null'); - $this->update->where(null); - } - - /** - * @group ZF2-240 - * @covers Zend\Db\Sql\Update::where - */ - public function testPassingMultipleKeyValueInWhereClause() - { - $update = clone $this->update; - $update->table('table'); - $update->set(['fld1' => 'val1']); - $update->where(['id1' => 'val1', 'id2' => 'val2']); - $this->assertEquals('UPDATE "table" SET "fld1" = \'val1\' WHERE "id1" = \'val1\' AND "id2" = \'val2\'', $update->getSqlString(new TrustingSql92Platform())); - } - - /** - * @covers Zend\Db\Sql\Update::getRawState + * @covers Zend\Db\Sql\Update::__get */ - public function testGetRawState() + public function test__Get() { $this->update->table('foo') ->set(['bar' => 'baz']) ->where('x = y'); - $this->assertEquals('foo', $this->update->getRawState('table')); - $this->assertEquals(true, $this->update->getRawState('emptyWhereProtection')); - $this->assertEquals(['bar' => 'baz'], $this->update->getRawState('set')); - $this->assertInstanceOf('Zend\Db\Sql\Where', $this->update->getRawState('where')); - } - - /** - * @covers Zend\Db\Sql\Update::prepareStatement - */ - public function testPrepareStatement() - { - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional')); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $pContainer = new \Zend\Db\Adapter\ParameterContainer([]); - $mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($pContainer)); - - $mockStatement->expects($this->at(1)) - ->method('setSql') - ->with($this->equalTo('UPDATE "foo" SET "bar" = ?, "boo" = NOW() WHERE x = y')); - - $this->update->table('foo') - ->set(['bar' => 'baz', 'boo' => new Expression('NOW()')]) - ->where('x = y'); - - $this->update->prepareStatement($mockAdapter, $mockStatement); - - // with TableIdentifier - $this->update = new Update; - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional')); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $pContainer = new \Zend\Db\Adapter\ParameterContainer([]); - $mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($pContainer)); - - $mockStatement->expects($this->at(1)) - ->method('setSql') - ->with($this->equalTo('UPDATE "sch"."foo" SET "bar" = ?, "boo" = NOW() WHERE x = y')); - - $this->update->table(new TableIdentifier('foo', 'sch')) - ->set(['bar' => 'baz', 'boo' => new Expression('NOW()')]) - ->where('x = y'); - - $this->update->prepareStatement($mockAdapter, $mockStatement); - } - - /** - * @covers Zend\Db\Sql\Update::getSqlString - */ - public function testGetSqlString() - { - $this->update->table('foo') - ->set(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]) - ->where('x = y'); - - $this->assertEquals('UPDATE "foo" SET "bar" = \'baz\', "boo" = NOW(), "bam" = NULL WHERE x = y', $this->update->getSqlString(new TrustingSql92Platform())); - - // with TableIdentifier - $this->update = new Update; - $this->update->table(new TableIdentifier('foo', 'sch')) - ->set(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]) - ->where('x = y'); - - $this->assertEquals('UPDATE "sch"."foo" SET "bar" = \'baz\', "boo" = NOW(), "bam" = NULL WHERE x = y', $this->update->getSqlString(new TrustingSql92Platform())); + $this->assertEquals('foo', $this->update->table->getSource()->getTable()); + $this->assertEquals(['bar' => 'baz'], $this->update->set->toArray()); + $this->assertInstanceOf('Zend\Db\Sql\Where', $this->update->where); } - /** - * @group 6768 - * @group 6773 - */ - public function testGetSqlStringForFalseUpdateValueParameter() - { - $this->update = new Update; - $this->update->table(new TableIdentifier('foo', 'sch')) - ->set(['bar' => false, 'boo' => 'test', 'bam' => true]) - ->where('x = y'); - $this->assertEquals('UPDATE "sch"."foo" SET "bar" = \'\', "boo" = \'test\', "bam" = \'1\' WHERE x = y', $this->update->getSqlString(new TrustingSql92Platform())); - } /** * @covers Zend\Db\Sql\Update::__get */ public function testGetUpdate() { - $getWhere = $this->update->__get('where'); + $getWhere = $this->update->where; $this->assertInstanceOf('Zend\Db\Sql\Where', $getWhere); } @@ -261,123 +119,18 @@ public function testGetUpdate() */ public function testGetUpdateFails() { + $this->setExpectedException('Zend\Db\Sql\Exception\InvalidArgumentException'); $getWhat = $this->update->__get('what'); $this->assertNull($getWhat); } - /** - * @covers Zend\Db\Sql\Update::__clone - */ - public function testCloneUpdate() - { - $update1 = clone $this->update; - $update1->table('foo') - ->set(['bar' => 'baz']) - ->where('x = y'); - - $update2 = clone $this->update; - $update2->table('foo') - ->set(['bar' => 'baz']) - ->where([ - 'id = ?'=>1 - ]); - $this->assertEquals('UPDATE "foo" SET "bar" = \'baz\' WHERE id = \'1\'', $update2->getSqlString(new TrustingSql92Platform)); - } - - /** - * @coversNothing - */ - public function testSpecificationconstantsCouldBeOverridedByExtensionInPrepareStatement() - { - $updateIgnore = new UpdateIgnore(); - - $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional')); - $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); - $mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $pContainer = new \Zend\Db\Adapter\ParameterContainer([]); - $mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($pContainer)); - - $mockStatement->expects($this->at(1)) - ->method('setSql') - ->with($this->equalTo('UPDATE IGNORE "foo" SET "bar" = ?, "boo" = NOW() WHERE x = y')); - - $updateIgnore->table('foo') - ->set(['bar' => 'baz', 'boo' => new Expression('NOW()')]) - ->where('x = y'); - - $updateIgnore->prepareStatement($mockAdapter, $mockStatement); - } - - /** - * @coversNothing - */ - public function testSpecificationconstantsCouldBeOverridedByExtensionInGetSqlString() - { - $this->update = new UpdateIgnore(); - - $this->update->table('foo') - ->set(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]) - ->where('x = y'); - - $this->assertEquals('UPDATE IGNORE "foo" SET "bar" = \'baz\', "boo" = NOW(), "bam" = NULL WHERE x = y', $this->update->getSqlString(new TrustingSql92Platform())); - - // with TableIdentifier - $this->update = new UpdateIgnore(); - $this->update->table(new TableIdentifier('foo', 'sch')) - ->set(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]) - ->where('x = y'); - - $this->assertEquals('UPDATE IGNORE "sch"."foo" SET "bar" = \'baz\', "boo" = NOW(), "bam" = NULL WHERE x = y', $this->update->getSqlString(new TrustingSql92Platform())); - } - - /** - * @covers Zend\Db\Sql\Update::where - */ - public function testJoin() - { - $this->update->table('Document'); - $this->update->set(['x' => 'y']) - ->join( - 'User', // table name - 'User.UserId = Document.UserId' // expression to join on (will be quoted by platform object before insertion), - // default JOIN INNER - ) - ->join( - 'Category', - 'Category.CategoryId = Document.CategoryId', - Join::JOIN_LEFT // (optional), one of inner, outer, left, right - ); - - $this->assertEquals('UPDATE "Document" INNER JOIN "User" ON "User"."UserId" = "Document"."UserId" LEFT JOIN "Category" ON "Category"."CategoryId" = "Document"."CategoryId" SET "x" = \'y\'', - $this->update->getSqlString(new TrustingSql92Platform())); - } - /** * @testdox unit test: Test join() returns Update object (is chainable) * @covers Zend\Db\Sql\Update::join */ - public function testJoinChainable() + public function testJoinsChainable() { - $return = $this->update->join('baz', 'foo.fooId = baz.fooId', Join::JOIN_LEFT); + $return = $this->update->join('baz', 'foo.fooId = baz.fooId', Joins::JOIN_LEFT); $this->assertSame($this->update, $return); } } - -class UpdateIgnore extends Update -{ - const SPECIFICATION_UPDATE = 'updateIgnore'; - - protected $specifications = [ - self::SPECIFICATION_UPDATE => 'UPDATE IGNORE %1$s', - self::SPECIFICATION_SET => 'SET %1$s', - self::SPECIFICATION_WHERE => 'WHERE %1$s' - ]; - - protected function processupdateIgnore(\Zend\Db\Adapter\Platform\PlatformInterface $platform, \Zend\Db\Adapter\Driver\DriverInterface $driver = null, \Zend\Db\Adapter\ParameterContainer $parameterContainer = null) - { - return parent::processUpdate($platform, $driver, $parameterContainer); - } -} diff --git a/test/TableGateway/AbstractTableGatewayTest.php b/test/TableGateway/AbstractTableGatewayTest.php index c6b9305b6f..d37cff9dc1 100644 --- a/test/TableGateway/AbstractTableGatewayTest.php +++ b/test/TableGateway/AbstractTableGatewayTest.php @@ -11,7 +11,9 @@ use Zend\Db\TableGateway\AbstractTableGateway; use Zend\Db\Sql; +use Zend\Db\Adapter\ParameterContainer; use Zend\Db\ResultSet\ResultSet; +use Zend\Db\Sql\TableSource; /** * Generated by PHPUnit_SkeletonGenerator on 2012-03-01 at 21:02:22. @@ -23,6 +25,11 @@ class AbstractTableGatewayTest extends \PHPUnit_Framework_TestCase */ protected $mockAdapter = null; + /** + * @var \Zend\Db\Adapter\Driver\StatementInterface + */ + protected $mockStatement; + /** * @var \PHPUnit_Framework_MockObject_Generator */ @@ -43,22 +50,30 @@ protected function setUp() $mockResult = $this->getMock('Zend\Db\Adapter\Driver\ResultInterface'); $mockResult->expects($this->any())->method('getAffectedRows')->will($this->returnValue(5)); - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); - $mockStatement->expects($this->any())->method('execute')->will($this->returnValue($mockResult)); + $this->mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); + $stmtSQL = function ($sql = null) { + static $data; + if ($sql === null) { + return $data; + } + $data = $sql; + }; + + $this->mockStatement->expects($this->any())->method('setSql')->will($this->returnCallback($stmtSQL)); + $this->mockStatement->expects($this->any())->method('getSql')->will($this->returnCallback($stmtSQL)); + $this->mockStatement->expects($this->any())->method('execute')->will($this->returnValue($mockResult)); + $this->mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue(new ParameterContainer)); $mockConnection = $this->getMock('Zend\Db\Adapter\Driver\ConnectionInterface'); $mockConnection->expects($this->any())->method('getLastGeneratedValue')->will($this->returnValue(10)); $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); - $mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue($mockStatement)); + $mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue($this->mockStatement)); $mockDriver->expects($this->any())->method('getConnection')->will($this->returnValue($mockConnection)); + $mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?')); $this->mockAdapter = $this->getMock('Zend\Db\Adapter\Adapter', null, [$mockDriver]); - $this->mockSql = $this->getMock('Zend\Db\Sql\Sql', ['select', 'insert', 'update', 'delete'], [$this->mockAdapter, 'foo']); - $this->mockSql->expects($this->any())->method('select')->will($this->returnValue($this->getMock('Zend\Db\Sql\Select', ['where', 'getRawSate'], ['foo']))); - $this->mockSql->expects($this->any())->method('insert')->will($this->returnValue($this->getMock('Zend\Db\Sql\Insert', ['prepareStatement', 'values'], ['foo']))); - $this->mockSql->expects($this->any())->method('update')->will($this->returnValue($this->getMock('Zend\Db\Sql\Update', ['where', 'join'], ['foo']))); - $this->mockSql->expects($this->any())->method('delete')->will($this->returnValue($this->getMock('Zend\Db\Sql\Delete', ['where'], ['foo']))); + $this->mockSql = new \Zend\Db\Sql\Sql($this->mockAdapter, 'foo'); $this->table = $this->getMockForAbstractClass( 'Zend\Db\TableGateway\AbstractTableGateway' @@ -69,7 +84,7 @@ protected function setUp() $tgPropReflection->setAccessible(true); switch ($tgPropReflection->getName()) { case 'table': - $tgPropReflection->setValue($this->table, 'foo'); + $tgPropReflection->setValue($this->table, new TableSource('foo')); break; case 'adapter': $tgPropReflection->setValue($this->table, $this->mockAdapter); @@ -97,7 +112,7 @@ protected function tearDown() */ public function testGetTable() { - $this->assertEquals('foo', $this->table->getTable()); + $this->assertEquals('foo', $this->table->getTable()->getSource()->getTable()); } /** @@ -136,6 +151,7 @@ public function testSelectWithNoWhere() // check return types $this->assertInstanceOf('Zend\Db\ResultSet\ResultSet', $resultSet); $this->assertNotSame($this->table->getResultSetPrototype(), $resultSet); + $this->assertEquals('SELECT "foo".* FROM "foo"', $this->mockStatement->getSql()); } /** @@ -145,21 +161,9 @@ public function testSelectWithNoWhere() */ public function testSelectWithWhereString() { - $mockSelect = $this->mockSql->select(); - - $mockSelect->expects($this->any()) - ->method('getRawState') - ->will($this->returnValue([ - 'table' => $this->table->getTable(), - ]) - ); - - // assert select::from() is called - $mockSelect->expects($this->once()) - ->method('where') - ->with($this->equalTo('foo')); - - $this->table->select('foo'); + $resultSet = $this->table->select('whereCondition'); + $this->assertInstanceOf('Zend\Db\ResultSet\ResultSet', $resultSet); + $this->assertEquals('SELECT "foo".* FROM "foo" WHERE whereCondition', $this->mockStatement->getSql()); } /** @@ -183,27 +187,18 @@ public function testSelectWithArrayTable() { // Case 1 - $select1 = $this->getMock('Zend\Db\Sql\Select', ['getRawState']); - $select1->expects($this->once()) - ->method('getRawState') - ->will($this->returnValue([ - 'table' => 'foo', // Standard table name format, valid according to Select::from() - 'columns' => null, - ])); + $select1 = new \Zend\Db\Sql\Select('foo'); + $return = $this->table->selectWith($select1); $this->assertNotNull($return); + $this->assertEquals('SELECT "foo".* FROM "foo"', $this->mockStatement->getSql()); // Case 2 - $select1 = $this->getMock('Zend\Db\Sql\Select', ['getRawState']); - $select1->expects($this->once()) - ->method('getRawState') - ->will($this->returnValue([ - 'table' => ['f' => 'foo'], // Alias table name format, valid according to Select::from() - 'columns' => null, - ])); + $select1 = new \Zend\Db\Sql\Select(['f' => 'foo']); $return = $this->table->selectWith($select1); $this->assertNotNull($return); + $this->assertEquals('SELECT "f".* FROM "foo" AS "f"', $this->mockStatement->getSql()); } /** @@ -213,19 +208,9 @@ public function testSelectWithArrayTable() */ public function testInsert() { - $mockInsert = $this->mockSql->insert(); - - $mockInsert->expects($this->once()) - ->method('prepareStatement') - ->with($this->mockAdapter); - - - $mockInsert->expects($this->once()) - ->method('values') - ->with($this->equalTo(['foo' => 'bar'])); - $affectedRows = $this->table->insert(['foo' => 'bar']); $this->assertEquals(5, $affectedRows); + $this->assertEquals('INSERT INTO "foo" ("foo") VALUES (?)', $this->mockStatement->getSql()); } /** @@ -235,15 +220,9 @@ public function testInsert() */ public function testUpdate() { - $mockUpdate = $this->mockSql->update(); - - // assert select::from() is called - $mockUpdate->expects($this->once()) - ->method('where') - ->with($this->equalTo('id = 2')); - $affectedRows = $this->table->update(['foo' => 'bar'], 'id = 2'); $this->assertEquals(5, $affectedRows); + $this->assertEquals('UPDATE "foo" SET "foo" = ? WHERE id = 2', $this->mockStatement->getSql()); } /** @@ -253,27 +232,16 @@ public function testUpdate() */ public function testUpdateWithJoin() { - $mockUpdate = $this->mockSql->update(); - $joins = [ [ 'name' => 'baz', 'on' => 'foo.fooId = baz.fooId', - 'type' => Sql\Join::JOIN_LEFT + 'type' => Sql\Joins::JOIN_LEFT ] ]; - - // assert select::from() is called - $mockUpdate->expects($this->once()) - ->method('where') - ->with($this->equalTo('id = 2')); - - $mockUpdate->expects($this->once()) - ->method('join') - ->with($joins[0]['name'], $joins[0]['on'], $joins[0]['type']); - $affectedRows = $this->table->update(['foo.field' => 'bar'], 'id = 2', $joins); $this->assertEquals(5, $affectedRows); + $this->assertEquals('UPDATE "foo" LEFT JOIN "baz" ON "foo"."fooId" = "baz"."fooId" SET "foo.field" = ? WHERE id = 2', $this->mockStatement->getSql()); } /** @@ -283,26 +251,16 @@ public function testUpdateWithJoin() */ public function testUpdateWithJoinDefaultType() { - $mockUpdate = $this->mockSql->update(); - - $joins = [ - [ + $affectedRows = $this->table->update( + ['foo.field' => 'bar'], + 'id = 2', + [[ 'name' => 'baz', 'on' => 'foo.fooId = baz.fooId', - ] - ]; - - // assert select::from() is called - $mockUpdate->expects($this->once()) - ->method('where') - ->with($this->equalTo('id = 2')); - - $mockUpdate->expects($this->once()) - ->method('join') - ->with($joins[0]['name'], $joins[0]['on'], Sql\Join::JOIN_INNER); - - $affectedRows = $this->table->update(['foo.field' => 'bar'], 'id = 2', $joins); + ]] + ); $this->assertEquals(5, $affectedRows); + $this->assertEquals('UPDATE "foo" INNER JOIN "baz" ON "foo"."fooId" = "baz"."fooId" SET "foo.field" = ? WHERE id = 2', $this->mockStatement->getSql()); } /** @@ -312,10 +270,9 @@ public function testUpdateWithJoinDefaultType() */ public function testUpdateWithNoCriteria() { - $mockUpdate = $this->mockSql->update(); - $affectedRows = $this->table->update(['foo' => 'bar']); $this->assertEquals(5, $affectedRows); + $this->assertEquals('UPDATE "foo" SET "foo" = ?', $this->mockStatement->getSql()); } /** @@ -325,15 +282,9 @@ public function testUpdateWithNoCriteria() */ public function testDelete() { - $mockDelete = $this->mockSql->delete(); - - // assert select::from() is called - $mockDelete->expects($this->once()) - ->method('where') - ->with($this->equalTo('foo')); - - $affectedRows = $this->table->delete('foo'); + $affectedRows = $this->table->delete('whereCondition'); $this->assertEquals(5, $affectedRows); + $this->assertEquals('DELETE FROM "foo" WHERE whereCondition', $this->mockStatement->getSql()); } /** @@ -343,6 +294,7 @@ public function testGetLastInsertValue() { $this->table->insert(['foo' => 'bar']); $this->assertEquals(10, $this->table->getLastInsertValue()); + $this->assertEquals('INSERT INTO "foo" ("foo") VALUES (?)', $this->mockStatement->getSql()); } /** @@ -350,11 +302,11 @@ public function testGetLastInsertValue() */ public function test__get() { - $this->table->insert(['foo']); // trigger last insert id update - + $affectedRows = $this->table->insert(['foo' => 'bar']); // trigger last insert id update + $this->assertEquals('INSERT INTO "foo" ("foo") VALUES (?)', $this->mockStatement->getSql()); + $this->assertEquals(5, $affectedRows); $this->assertEquals(10, $this->table->lastInsertValue); $this->assertSame($this->mockAdapter, $this->table->adapter); - //$this->assertEquals('foo', $this->table->table); } /** diff --git a/test/TableGateway/Feature/MasterSlaveFeatureTest.php b/test/TableGateway/Feature/MasterSlaveFeatureTest.php index d66f66a8ad..fa0b9b8298 100644 --- a/test/TableGateway/Feature/MasterSlaveFeatureTest.php +++ b/test/TableGateway/Feature/MasterSlaveFeatureTest.php @@ -28,25 +28,19 @@ class MasterSlaveFeatureTest extends \PHPUnit_Framework_TestCase public function setup() { - $this->mockMasterAdapter = $this->getMock('Zend\Db\Adapter\AdapterInterface'); - $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); $mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue( $mockStatement )); - $this->mockMasterAdapter->expects($this->any())->method('getDriver')->will($this->returnValue($mockDriver)); - $this->mockMasterAdapter->expects($this->any())->method('getPlatform')->will($this->returnValue(new \Zend\Db\Adapter\Platform\Sql92())); - - $this->mockSlaveAdapter = $this->getMock('Zend\Db\Adapter\AdapterInterface'); + $this->mockMasterAdapter = new \Zend\Db\Adapter\Adapter($mockDriver, new \Zend\Db\Adapter\Platform\Sql92()); $mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface'); $mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface'); $mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue( $mockStatement )); - $this->mockSlaveAdapter->expects($this->any())->method('getDriver')->will($this->returnValue($mockDriver)); - $this->mockSlaveAdapter->expects($this->any())->method('getPlatform')->will($this->returnValue(new \Zend\Db\Adapter\Platform\Sql92())); + $this->mockSlaveAdapter = new \Zend\Db\Adapter\Adapter($mockDriver, new \Zend\Db\Adapter\Platform\Sql92()); $this->feature = new MasterSlaveFeature($this->mockSlaveAdapter); } diff --git a/test/TableGateway/TableGatewayTest.php b/test/TableGateway/TableGatewayTest.php index b19596a5eb..fb5b6b55fb 100644 --- a/test/TableGateway/TableGatewayTest.php +++ b/test/TableGateway/TableGatewayTest.php @@ -16,6 +16,7 @@ use Zend\Db\Sql\Update; use Zend\Db\Sql\Sql; use Zend\Db\Sql\TableIdentifier; +use Zend\Db\Sql\TableSource; /** * Generated by PHPUnit_SkeletonGenerator on 2012-03-01 at 21:02:22. @@ -50,7 +51,7 @@ public function testConstructor() $this->mockAdapter ); - $this->assertEquals('foo', $table->getTable()); + $this->assertEquals('foo', $table->getTable()->getSource()->getTable()); $this->assertSame($this->mockAdapter, $table->getAdapter()); $this->assertInstanceOf('Zend\Db\TableGateway\Feature\FeatureSet', $table->getFeatureSet()); $this->assertInstanceOf('Zend\Db\ResultSet\ResultSet', $table->getResultSetPrototype()); @@ -65,7 +66,7 @@ public function testConstructor() $sql = new Sql($this->mockAdapter, 'foo') ); - $this->assertEquals('foo', $table->getTable()); + $this->assertEquals('foo', $table->getTable()->getSource()->getTable()); $this->assertSame($this->mockAdapter, $table->getAdapter()); $this->assertSame($featureSet, $table->getFeatureSet()); $this->assertSame($resultSet, $table->getResultSetPrototype()); @@ -95,7 +96,7 @@ public function testTableAsString() $this->mockAdapter ); - $this->assertEquals($ti, $table->getTable()); + $this->assertEquals($ti, $table->getTable()->getSource()->getTable()); } /** @@ -111,7 +112,7 @@ public function testTableAsTableIdentifierObject() $this->mockAdapter ); - $this->assertEquals($ti, $table->getTable()); + $this->assertEquals($ti, $table->getTable()->getSource()); } /** @@ -127,7 +128,10 @@ public function testTableAsAliasedTableIdentifierObject() $this->mockAdapter ); - $this->assertEquals($aliasedTI, $table->getTable()); + $this->assertEquals( + ['foo', 'fooTable', 'barSchema'], + [$table->getTable()->getAlias(), $table->getTable()->getSource()->getTable(), $table->getTable()->getSource()->getSchema()] + ); } public function aliasedTables() @@ -163,8 +167,10 @@ public function testInsertShouldResetTableToUnaliasedTable($tableValue, $expecte ->will($this->returnValue($result)); $statementExpectation = function ($insert) use ($phpunit, $expected, $statement) { - $state = $insert->getRawState(); - $phpunit->assertSame($expected, $state['table']); + if ($expected instanceof TableIdentifier) { + $expected = $expected->getTable(); + } + $phpunit->assertSame($expected, $insert->table->getSource()->getTable()); return $statement; }; @@ -173,12 +179,12 @@ public function testInsertShouldResetTableToUnaliasedTable($tableValue, $expecte ->getMock(); $sql->expects($this->atLeastOnce()) ->method('getTable') - ->will($this->returnValue($tableValue)); + ->will($this->returnValue(TableSource::factory($tableValue)->getSource())); $sql->expects($this->once()) ->method('insert') ->will($this->returnValue($insert)); $sql->expects($this->once()) - ->method('prepareStatementForSqlObject') + ->method('prepareSqlStatement') ->with($this->equalTo($insert)) ->will($this->returnCallback($statementExpectation)); @@ -194,11 +200,10 @@ public function testInsertShouldResetTableToUnaliasedTable($tableValue, $expecte 'foo' => 'FOO', ]); - $state = $insert->getRawState(); - $this->assertInternalType('array', $state['table']); + $this->assertInstanceOf('Zend\Db\Sql\TableSource', $insert->table); $this->assertEquals( - $tableValue, - $state['table'] + TableSource::factory($tableValue), + $insert->table ); } @@ -225,8 +230,10 @@ public function testUpdateShouldResetTableToUnaliasedTable($tableValue, $expecte ->will($this->returnValue($result)); $statementExpectation = function ($update) use ($phpunit, $expected, $statement) { - $state = $update->getRawState(); - $phpunit->assertSame($expected, $state['table']); + if ($expected instanceof TableIdentifier) { + $expected = $expected->getTable(); + } + $phpunit->assertSame($expected, $update->table->getSource()->getTable()); return $statement; }; @@ -235,12 +242,12 @@ public function testUpdateShouldResetTableToUnaliasedTable($tableValue, $expecte ->getMock(); $sql->expects($this->atLeastOnce()) ->method('getTable') - ->will($this->returnValue($tableValue)); + ->will($this->returnValue(TableSource::factory($tableValue)->getSource())); $sql->expects($this->once()) ->method('update') ->will($this->returnValue($update)); $sql->expects($this->once()) - ->method('prepareStatementForSqlObject') + ->method('prepareSqlStatement') ->with($this->equalTo($update)) ->will($this->returnCallback($statementExpectation)); @@ -258,11 +265,10 @@ public function testUpdateShouldResetTableToUnaliasedTable($tableValue, $expecte 'bar' => 'BAR' ]); - $state = $update->getRawState(); - $this->assertInternalType('array', $state['table']); + $this->assertInstanceOf('Zend\Db\Sql\TableSource', $update->table); $this->assertEquals( - $tableValue, - $state['table'] + TableSource::factory($tableValue), + $update->table ); } } diff --git a/test/TestAsset/InsertDecorator.php b/test/TestAsset/DeleteBuilder.php similarity index 58% rename from test/TestAsset/InsertDecorator.php rename to test/TestAsset/DeleteBuilder.php index 7a97ecfa1c..ccc8269967 100644 --- a/test/TestAsset/InsertDecorator.php +++ b/test/TestAsset/DeleteBuilder.php @@ -9,15 +9,6 @@ namespace ZendTest\Db\TestAsset; -use Zend\Db\Sql; - -class InsertDecorator extends Sql\Insert implements Sql\Platform\PlatformDecoratorInterface +class DeleteBuilder extends \Zend\Db\Sql\Builder\sql92\DeleteBuilder { - protected $subject = null; - - public function setSubject($subject) - { - $this->subject = $subject; - return $this; - } } diff --git a/test/TestAsset/ExpressionBuilder.php b/test/TestAsset/ExpressionBuilder.php new file mode 100644 index 0000000000..edbfdbcc77 --- /dev/null +++ b/test/TestAsset/ExpressionBuilder.php @@ -0,0 +1,24 @@ +getExpression(); + $expression->setExpression('{decorate-' . $expressionString . '-decorate}'); + $result = parent::build($expression, $context); + $expression->setExpression($expressionString); + return $result; + } +} diff --git a/test/TestAsset/InsertBuilder.php b/test/TestAsset/InsertBuilder.php new file mode 100644 index 0000000000..1bd51c7a98 --- /dev/null +++ b/test/TestAsset/InsertBuilder.php @@ -0,0 +1,14 @@ +subject = $subject; - return $this; - } -} diff --git a/test/TestAsset/TrustingIbmDb2Platform.php b/test/TestAsset/TrustingIbmDb2Platform.php new file mode 100644 index 0000000000..9543676399 --- /dev/null +++ b/test/TestAsset/TrustingIbmDb2Platform.php @@ -0,0 +1,20 @@ +quoteTrustedValue($value); + } +} diff --git a/test/TestAsset/DeleteDecorator.php b/test/TestAsset/TrustingSqlitePlatform.php similarity index 60% rename from test/TestAsset/DeleteDecorator.php rename to test/TestAsset/TrustingSqlitePlatform.php index 13f21def41..847a35df74 100644 --- a/test/TestAsset/DeleteDecorator.php +++ b/test/TestAsset/TrustingSqlitePlatform.php @@ -9,15 +9,15 @@ namespace ZendTest\Db\TestAsset; -use Zend\Db\Sql; +use Zend\Db\Adapter\Platform\Sqlite; -class DeleteDecorator extends Sql\Delete implements Sql\Platform\PlatformDecoratorInterface +class TrustingSqlitePlatform extends Sqlite { - protected $subject = null; - - public function setSubject($subject) + /** + * {@inheritDoc} + */ + public function quoteValue($value) { - $this->subject = $subject; - return $this; + return $this->quoteTrustedValue($value); } } diff --git a/test/TestAsset/UpdateBuilder.php b/test/TestAsset/UpdateBuilder.php new file mode 100644 index 0000000000..028747ac89 --- /dev/null +++ b/test/TestAsset/UpdateBuilder.php @@ -0,0 +1,14 @@ +subject = $subject; - return $this; - } -}