@@ -36,7 +36,7 @@ use Tracy\Helpers;
explain
|
- = DbHelpers::dumpSql($sql, $params, $connection) ?>
+ | = DbHelpers::dumpSql($query, $connection) ?>
@@ -61,6 +61,6 @@ use Tracy\Helpers;
- ...and more
+ ...and more
diff --git a/src/Database/Connection.php b/src/Database/Connection.php
deleted file mode 100644
index 4d66a05a1..000000000
--- a/src/Database/Connection.php
+++ /dev/null
@@ -1,321 +0,0 @@
- Occurs after connection is established */
- public array $onConnect = [];
-
- /** @var array Occurs after query is executed */
- public array $onQuery = [];
- private Driver $driver;
- private SqlPreprocessor $preprocessor;
- private ?PDO $pdo = null;
-
- /** @var callable(array, ResultSet): array */
- private $rowNormalizer = [Helpers::class, 'normalizeRow'];
- private ?string $sql = null;
- private int $transactionDepth = 0;
-
-
- public function __construct(
- private readonly string $dsn,
- #[\SensitiveParameter]
- private readonly ?string $user = null,
- #[\SensitiveParameter]
- private readonly ?string $password = null,
- private readonly array $options = [],
- ) {
- if (!empty($options['newDateTime'])) {
- $this->rowNormalizer = fn($row, $resultSet) => Helpers::normalizeRow($row, $resultSet, DateTime::class);
- }
- if (empty($options['lazy'])) {
- $this->connect();
- }
- }
-
-
- public function connect(): void
- {
- if ($this->pdo) {
- return;
- }
-
- try {
- $this->pdo = new PDO($this->dsn, $this->user, $this->password, $this->options);
- } catch (PDOException $e) {
- throw ConnectionException::from($e);
- }
-
- $class = empty($this->options['driverClass'])
- ? 'Nette\Database\Drivers\\' . ucfirst(str_replace('sql', 'Sql', $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME))) . 'Driver'
- : $this->options['driverClass'];
- $this->driver = new $class;
- $this->preprocessor = new SqlPreprocessor($this);
- $this->driver->initialize($this, $this->options);
- Arrays::invoke($this->onConnect, $this);
- }
-
-
- public function reconnect(): void
- {
- $this->disconnect();
- $this->connect();
- }
-
-
- public function disconnect(): void
- {
- $this->pdo = null;
- }
-
-
- public function getDsn(): string
- {
- return $this->dsn;
- }
-
-
- public function getPdo(): PDO
- {
- $this->connect();
- return $this->pdo;
- }
-
-
- public function getDriver(): Driver
- {
- $this->connect();
- return $this->driver;
- }
-
-
- /** @deprecated use getDriver() */
- public function getSupplementalDriver(): Driver
- {
- $this->connect();
- return $this->driver;
- }
-
-
- public function getReflection(): Reflection
- {
- return new Reflection($this->getDriver());
- }
-
-
- public function setRowNormalizer(?callable $normalizer): static
- {
- $this->rowNormalizer = $normalizer;
- return $this;
- }
-
-
- public function getInsertId(?string $sequence = null): string
- {
- try {
- $res = $this->getPdo()->lastInsertId($sequence);
- return $res === false ? '0' : $res;
- } catch (PDOException $e) {
- throw $this->driver->convertException($e);
- }
- }
-
-
- public function quote(string $string, int $type = PDO::PARAM_STR): string
- {
- try {
- return $this->getPdo()->quote($string, $type);
- } catch (PDOException $e) {
- throw DriverException::from($e);
- }
- }
-
-
- public function beginTransaction(): void
- {
- if ($this->transactionDepth !== 0) {
- throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
- }
-
- $this->query('::beginTransaction');
- }
-
-
- public function commit(): void
- {
- if ($this->transactionDepth !== 0) {
- throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
- }
-
- $this->query('::commit');
- }
-
-
- public function rollBack(): void
- {
- if ($this->transactionDepth !== 0) {
- throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
- }
-
- $this->query('::rollBack');
- }
-
-
- public function transaction(callable $callback): mixed
- {
- if ($this->transactionDepth === 0) {
- $this->beginTransaction();
- }
-
- $this->transactionDepth++;
- try {
- $res = $callback($this);
- } catch (\Throwable $e) {
- $this->transactionDepth--;
- if ($this->transactionDepth === 0) {
- $this->rollback();
- }
-
- throw $e;
- }
-
- $this->transactionDepth--;
- if ($this->transactionDepth === 0) {
- $this->commit();
- }
-
- return $res;
- }
-
-
- /**
- * Generates and executes SQL query.
- * @param literal-string $sql
- */
- public function query(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): ResultSet
- {
- [$this->sql, $params] = $this->preprocess($sql, ...$params);
- try {
- $result = new ResultSet($this, $this->sql, $params, $this->rowNormalizer);
- } catch (PDOException $e) {
- Arrays::invoke($this->onQuery, $this, $e);
- throw $e;
- }
-
- Arrays::invoke($this->onQuery, $this, $result);
- return $result;
- }
-
-
- /** @deprecated use query() */
- public function queryArgs(string $sql, array $params): ResultSet
- {
- return $this->query($sql, ...$params);
- }
-
-
- /**
- * @param literal-string $sql
- * @return array{string, array}
- */
- public function preprocess(string $sql, ...$params): array
- {
- $this->connect();
- return $params
- ? $this->preprocessor->process(func_get_args())
- : [$sql, []];
- }
-
-
- public function getLastQueryString(): ?string
- {
- return $this->sql;
- }
-
-
- /********************* shortcuts ****************d*g**/
-
-
- /**
- * Shortcut for query()->fetch()
- * @param literal-string $sql
- */
- public function fetch(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): ?Row
- {
- return $this->query($sql, ...$params)->fetch();
- }
-
-
- /**
- * Shortcut for query()->fetchAssoc()
- * @param literal-string $sql
- */
- public function fetchAssoc(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): ?array
- {
- return $this->query($sql, ...$params)->fetchAssoc();
- }
-
-
- /**
- * Shortcut for query()->fetchField()
- * @param literal-string $sql
- */
- public function fetchField(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): mixed
- {
- return $this->query($sql, ...$params)->fetchField();
- }
-
-
- /**
- * Shortcut for query()->fetchFields()
- * @param literal-string $sql
- */
- public function fetchFields(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): ?array
- {
- return $this->query($sql, ...$params)->fetchFields();
- }
-
-
- /**
- * Shortcut for query()->fetchPairs()
- * @param literal-string $sql
- */
- public function fetchPairs(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): array
- {
- return $this->query($sql, ...$params)->fetchPairs();
- }
-
-
- /**
- * Shortcut for query()->fetchAll()
- * @param literal-string $sql
- */
- public function fetchAll(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): array
- {
- return $this->query($sql, ...$params)->fetchAll();
- }
-
-
- public static function literal(string $value, ...$params): SqlLiteral
- {
- return new SqlLiteral($value, $params);
- }
-}
diff --git a/src/Database/Conventions.php b/src/Database/Conventions.php
index 3e7a68710..72e743667 100644
--- a/src/Database/Conventions.php
+++ b/src/Database/Conventions.php
@@ -39,6 +39,3 @@ function getHasManyReference(string $table, string $key): ?array;
*/
function getBelongsToReference(string $table, string $key): ?array;
}
-
-
-interface_exists(IConventions::class);
diff --git a/src/Database/Conventions/DiscoveredConventions.php b/src/Database/Conventions/DiscoveredConventions.php
index 272b942ac..930a889b4 100644
--- a/src/Database/Conventions/DiscoveredConventions.php
+++ b/src/Database/Conventions/DiscoveredConventions.php
@@ -10,7 +10,7 @@
namespace Nette\Database\Conventions;
use Nette\Database\Conventions;
-use Nette\Database\IStructure;
+use Nette\Database\Structure;
/**
@@ -19,7 +19,7 @@
class DiscoveredConventions implements Conventions
{
public function __construct(
- protected readonly IStructure $structure,
+ protected readonly Structure $structure,
) {
}
diff --git a/src/Database/Driver.php b/src/Database/Driver.php
deleted file mode 100644
index 030674007..000000000
--- a/src/Database/Driver.php
+++ /dev/null
@@ -1,98 +0,0 @@
- */
- function getTables(): array;
-
- /** @return list */
- function getColumns(string $table): array;
-
- /** @return list, unique: bool, primary: bool}> */
- function getIndexes(string $table): array;
-
- /** @return list */
- function getForeignKeys(string $table): array;
-
- /**
- * Returns associative array of detected types (IStructure::FIELD_*) in result set.
- * @return array
- */
- function getColumnTypes(\PDOStatement $statement): array;
-
- /**
- * Cheks if driver supports specific property
- * @param self::Support* $item
- */
- function isSupported(string $item): bool;
-}
-
-
-interface_exists(ISupplementalDriver::class);
diff --git a/src/Database/DriverException.php b/src/Database/DriverException.php
index aad02cd6e..700c01186 100644
--- a/src/Database/DriverException.php
+++ b/src/Database/DriverException.php
@@ -13,51 +13,54 @@
/**
* Base class for all errors in the driver or SQL server.
*/
-class DriverException extends \PDOException
+class DriverException extends \Exception
{
- public ?string $queryString = null;
- public ?array $params = null;
+ public static function from(self $e): static
+ {
+ return new static($e->getMessage(), $e->sqlState, $e->getCode(), $e->query, $e);
+ }
- public static function from(\PDOException $src): static
- {
- $e = new static($src->message, 0, $src);
- $e->file = $src->file;
- $e->line = $src->line;
- if (!$src->errorInfo && preg_match('#SQLSTATE\[(.*?)\] \[(.*?)\] (.*)#A', $src->message, $m)) {
- $m[2] = (int) $m[2];
- $e->errorInfo = array_slice($m, 1);
- $e->code = $m[1];
- } else {
- $e->errorInfo = $src->errorInfo;
- $e->code = $src->code;
- $e->code = $e->errorInfo[0] ?? $src->code;
- }
-
- return $e;
+ public function __construct(
+ string $message,
+ private readonly ?string $sqlState = null,
+ int $code = 0,
+ private readonly ?SqlLiteral $query = null,
+ ?\Throwable $previous = null,
+ ) {
+ parent::__construct($message, $code, $previous);
}
- public function getDriverCode(): int|string|null
+ /** @deprecated use getCode() */
+ public function getDriverCode(): int
{
- return $this->errorInfo[1] ?? null;
+ return $this->getCode();
}
public function getSqlState(): ?string
{
- return $this->errorInfo[0] ?? null;
+ return $this->sqlState;
+ }
+
+
+ public function getQuery(): ?SqlLiteral
+ {
+ return $this->query;
}
+ /** @deprecated use getQuery()->getSql() */
public function getQueryString(): ?string
{
- return $this->queryString;
+ return $this->query?->getSql();
}
+ /** @deprecated use getQuery()->getParameters() */
public function getParameters(): ?array
{
- return $this->params;
+ return $this->query?->getParameters();
}
}
diff --git a/src/Database/Drivers/Accessory/LazyConnection.php b/src/Database/Drivers/Accessory/LazyConnection.php
new file mode 100644
index 000000000..2755def89
--- /dev/null
+++ b/src/Database/Drivers/Accessory/LazyConnection.php
@@ -0,0 +1,81 @@
+callback)();
+ }
+
+
+ public function query(string $sql, array $params = []): Drivers\Result
+ {
+ return $this->getConnection()->query($sql, $params);
+ }
+
+
+ public function execute(string $sql): int
+ {
+ return $this->getConnection()->execute($sql);
+ }
+
+
+ public function getNativeConnection(): mixed
+ {
+ return $this->getConnection()->getNativeConnection();
+ }
+
+
+ public function beginTransaction(): void
+ {
+ $this->getConnection()->beginTransaction();
+ }
+
+
+ public function commit(): void
+ {
+ $this->getConnection()->commit();
+ }
+
+
+ public function rollBack(): void
+ {
+ $this->getConnection()->rollBack();
+ }
+
+
+ public function getInsertId(?string $sequence = null): int|string
+ {
+ return $this->getConnection()->getInsertId($sequence);
+ }
+
+
+ public function quote(string $string): string
+ {
+ return $this->getConnection()->quote($string);
+ }
+
+
+ public function getServerVersion(): string
+ {
+ return $this->getConnection()->getServerVersion();
+ }
+}
diff --git a/src/Database/Drivers/Connection.php b/src/Database/Drivers/Connection.php
new file mode 100644
index 000000000..03dd4d412
--- /dev/null
+++ b/src/Database/Drivers/Connection.php
@@ -0,0 +1,45 @@
+
+ */
+ function getTables(): array;
+
+ /**
+ * Returns detailed information about columns in a table.
+ * @return list
+ */
+ function getColumns(string $table): array;
+
+ /**
+ * Returns information about indexes in a table.
+ * @return list, unique: bool, primary: bool}>
+ */
+ function getIndexes(string $table): array;
+
+ /**
+ * Returns information about foreign keys in a table.
+ * @return list, table: string, foreign: list}>
+ */
+ function getForeignKeys(string $table): array;
+}
diff --git a/src/Database/Drivers/MsSqlDriver.php b/src/Database/Drivers/Engines/MSSQLEngine.php
similarity index 76%
rename from src/Database/Drivers/MsSqlDriver.php
rename to src/Database/Drivers/Engines/MSSQLEngine.php
index 4ef886921..afbdca0c6 100644
--- a/src/Database/Drivers/MsSqlDriver.php
+++ b/src/Database/Drivers/Engines/MSSQLEngine.php
@@ -7,35 +7,41 @@
declare(strict_types=1);
-namespace Nette\Database\Drivers;
+namespace Nette\Database\Drivers\Engines;
use Nette;
+use Nette\Database\Drivers\Connection;
+use Nette\Database\Drivers\Engine;
+use Nette\Database\TypeConverter;
/**
- * Supplemental MS SQL database driver.
+ * MS SQL database platform.
*/
-class MsSqlDriver implements Nette\Database\Driver
+class MSSQLEngine implements Engine
{
- private Nette\Database\Connection $connection;
+ public function __construct(
+ private readonly Connection $connection,
+ ) {
+ }
- public function initialize(Nette\Database\Connection $connection, array $options): void
+ public function isSupported(string $feature): bool
{
- $this->connection = $connection;
+ return $feature === self::SupportSubselect;
}
- public function convertException(\PDOException $e): Nette\Database\DriverException
+ public function classifyException(Nette\Database\DriverException $e): ?string
{
- return Nette\Database\DriverException::from($e);
+ return null;
}
/********************* SQL ****************d*g**/
- public function delimite(string $name): string
+ public function delimit(string $name): string
{
// @see https://msdn.microsoft.com/en-us/library/ms176027.aspx
return '[' . str_replace(['[', ']'], ['[[', ']]'], $name) . ']';
@@ -54,14 +60,7 @@ public function formatDateInterval(\DateInterval $value): string
}
- public function formatLike(string $value, int $pos): string
- {
- $value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
- return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
- }
-
-
- public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
+ public function applyLimit(string $sql, ?int $limit, ?int $offset): string
{
if ($offset) {
throw new Nette\NotSupportedException('Offset is not supported by this database.');
@@ -75,6 +74,8 @@ public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
throw new Nette\InvalidArgumentException('SQL query must begin with SELECT, UPDATE or DELETE command.');
}
}
+
+ return $sql;
}
@@ -107,6 +108,7 @@ public function getColumns(string $table): array
DATA_TYPE,
CHARACTER_MAXIMUM_LENGTH,
NUMERIC_PRECISION,
+ NUMERIC_SCALE,
IS_NULLABLE,
COLUMN_DEFAULT,
DOMAIN_NAME
@@ -115,20 +117,21 @@ public function getColumns(string $table): array
WHERE
TABLE_SCHEMA = ?
AND TABLE_NAME = ?
- X, $table_schema, $table_name);
+ X, [$table_schema, $table_name]);
while ($row = $rows->fetch()) {
$columns[] = [
'name' => $row['COLUMN_NAME'],
'table' => $table,
- 'nativetype' => strtoupper($row['DATA_TYPE']),
+ 'nativeType' => strtoupper($row['DATA_TYPE']),
'size' => $row['CHARACTER_MAXIMUM_LENGTH'] ?? $row['NUMERIC_PRECISION'],
+ 'scale' => $row['NUMERIC_SCALE'],
'unsigned' => false,
'nullable' => $row['IS_NULLABLE'] === 'YES',
'default' => $row['COLUMN_DEFAULT'],
- 'autoincrement' => $row['DOMAIN_NAME'] === 'COUNTER',
+ 'autoIncrement' => $row['DOMAIN_NAME'] === 'COUNTER',
'primary' => $row['COLUMN_NAME'] === 'ID',
- 'vendor' => (array) $row,
+ 'vendor' => $row,
];
}
@@ -157,7 +160,7 @@ public function getIndexes(string $table): array
t.name = ?
ORDER BY
t.name, ind.name, ind.index_id, ic.index_column_id
- X, $table_name);
+ X, [$table_name]);
while ($row = $rows->fetch()) {
$id = $row['name_index'];
@@ -198,28 +201,22 @@ public function getForeignKeys(string $table): array
ON col2.column_id = referenced_column_id AND col2.object_id = tab2.object_id
WHERE
tab1.name = ?
- X, $table_name);
+ X, [$table_name]);
- $id = 0;
while ($row = $rows->fetch()) {
- $keys[$id]['name'] = $row['fk_name'];
- $keys[$id]['local'] = $row['column'];
+ $id = $row['fk_name'];
+ $keys[$id]['name'] = $id;
+ $keys[$id]['local'][] = $row['column'];
$keys[$id]['table'] = $table_schema . '.' . $row['referenced_table'];
- $keys[$id++]['foreign'] = $row['referenced_column'];
+ $keys[$id]['foreign'][] = $row['referenced_column'];
}
return array_values($keys);
}
- public function getColumnTypes(\PDOStatement $statement): array
- {
- return Nette\Database\Helpers::detectTypes($statement);
- }
-
-
- public function isSupported(string $item): bool
+ public function convertToPhp(mixed $value, array $meta, TypeConverter $converter): mixed
{
- return $item === self::SupportSubselect;
+ return $converter->convertToPhp($value, $meta);
}
}
diff --git a/src/Database/Drivers/Engines/MySQLEngine.php b/src/Database/Drivers/Engines/MySQLEngine.php
new file mode 100644
index 000000000..40c0f0dc4
--- /dev/null
+++ b/src/Database/Drivers/Engines/MySQLEngine.php
@@ -0,0 +1,185 @@
+getCode();
+ return match (true) {
+ in_array($code, [1216, 1217, 1451, 1452, 1701], strict: true) => Nette\Database\ForeignKeyConstraintViolationException::class,
+ in_array($code, [1062, 1557, 1569, 1586], strict: true) => Nette\Database\UniqueConstraintViolationException::class,
+ $code >= 2001 && $code <= 2028 => Nette\Database\ConnectionException::class,
+ in_array($code, [1048, 1121, 1138, 1171, 1252, 1263, 1566], strict: true) => Nette\Database\NotNullConstraintViolationException::class,
+ default => null,
+ };
+ }
+
+
+ /********************* SQL ****************d*g**/
+
+
+ public function delimit(string $name): string
+ {
+ // @see http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
+ return '`' . str_replace('`', '``', $name) . '`';
+ }
+
+
+ public function formatDateTime(\DateTimeInterface $value): string
+ {
+ return $value->format("'Y-m-d H:i:s'");
+ }
+
+
+ public function formatDateInterval(\DateInterval $value): string
+ {
+ return $value->format("'%r%h:%I:%S'");
+ }
+
+
+ public function applyLimit(string $sql, ?int $limit, ?int $offset): string
+ {
+ if ($limit < 0 || $offset < 0) {
+ throw new Nette\InvalidArgumentException('Negative offset or limit.');
+
+ } elseif ($limit !== null || $offset) {
+ // see http://dev.mysql.com/doc/refman/5.0/en/select.html
+ $sql .= ' LIMIT ' . ($limit ?? '18446744073709551615')
+ . ($offset ? ' OFFSET ' . $offset : '');
+ }
+
+ return $sql;
+ }
+
+
+ /********************* reflection ****************d*g**/
+
+
+ public function getTables(): array
+ {
+ $tables = [];
+ $rows = $this->connection->query('SHOW FULL TABLES');
+ while ($row = $rows->fetch()) {
+ $row = array_values($row);
+ $tables[] = [
+ 'name' => $row[0],
+ 'view' => ($row[1] ?? null) === 'VIEW',
+ ];
+ }
+
+ return $tables;
+ }
+
+
+ public function getColumns(string $table): array
+ {
+ $columns = [];
+ $rows = $this->connection->query('SHOW FULL COLUMNS FROM ' . $this->delimit($table));
+ while ($row = $rows->fetch()) {
+ $row = array_change_key_case($row);
+ $typeInfo = Nette\Database\Helpers::parseColumnType($row['type']);
+ $columns[] = [
+ 'name' => $row['field'],
+ 'table' => $table,
+ 'nativeType' => strtoupper($typeInfo['type']),
+ 'size' => $typeInfo['size'],
+ 'scale' => $typeInfo['scale'],
+ 'nullable' => $row['null'] === 'YES',
+ 'default' => $row['default'],
+ 'autoIncrement' => $row['extra'] === 'auto_increment',
+ 'primary' => $row['key'] === 'PRI',
+ 'vendor' => $row,
+ ];
+ }
+
+ return $columns;
+ }
+
+
+ public function getIndexes(string $table): array
+ {
+ $indexes = [];
+ $rows = $this->connection->query('SHOW INDEX FROM ' . $this->delimit($table));
+ while ($row = $rows->fetch()) {
+ $id = $row['Key_name'];
+ $indexes[$id]['name'] = $id;
+ $indexes[$id]['unique'] = !$row['Non_unique'];
+ $indexes[$id]['primary'] = $row['Key_name'] === 'PRIMARY';
+ $indexes[$id]['columns'][$row['Seq_in_index'] - 1] = $row['Column_name'];
+ }
+
+ return array_values($indexes);
+ }
+
+
+ public function getForeignKeys(string $table): array
+ {
+ $keys = [];
+ $rows = $this->connection->query(<<<'X'
+ SELECT CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
+ FROM information_schema.KEY_COLUMN_USAGE
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND REFERENCED_TABLE_NAME IS NOT NULL
+ AND TABLE_NAME = ?
+ X, [$table]);
+
+ while ($row = $rows->fetch()) {
+ $id = $row['CONSTRAINT_NAME'];
+ $keys[$id]['name'] = $id;
+ $keys[$id]['local'][] = $row['COLUMN_NAME'];
+ $keys[$id]['table'] = $row['REFERENCED_TABLE_NAME'];
+ $keys[$id]['foreign'][] = $row['REFERENCED_COLUMN_NAME'];
+ }
+
+ return array_values($keys);
+ }
+
+
+ public function convertToPhp(mixed $value, array $meta, TypeConverter $converter): mixed
+ {
+ return match ($meta['nativeType']) {
+ 'TINY' => $meta['size'] === 1 && $converter->convertBoolean
+ ? $converter->toBool($value)
+ : $converter->toInt($value),
+ 'TIME' => $converter->convertDateTime ? $converter->toInterval($value) : $value,
+ 'DATE', 'DATETIME', 'TIMESTAMP' => $converter->convertDateTime
+ ? (str_starts_with($value, '0000-00') ? null : $converter->toDateTime($value))
+ : $value,
+ default => $converter->convertToPhp($value, $meta),
+ };
+ }
+}
diff --git a/src/Database/Drivers/OdbcDriver.php b/src/Database/Drivers/Engines/ODBCEngine.php
similarity index 63%
rename from src/Database/Drivers/OdbcDriver.php
rename to src/Database/Drivers/Engines/ODBCEngine.php
index 078a202cc..f6842367a 100644
--- a/src/Database/Drivers/OdbcDriver.php
+++ b/src/Database/Drivers/Engines/ODBCEngine.php
@@ -7,31 +7,34 @@
declare(strict_types=1);
-namespace Nette\Database\Drivers;
+namespace Nette\Database\Drivers\Engines;
use Nette;
+use Nette\Database\Drivers\Engine;
+use Nette\Database\TypeConverter;
/**
- * Supplemental ODBC database driver.
+ * Microsoft ODBC database platform.
*/
-class OdbcDriver implements Nette\Database\Driver
+class ODBCEngine implements Engine
{
- public function initialize(Nette\Database\Connection $connection, array $options): void
+ public function isSupported(string $feature): bool
{
+ return $feature === self::SupportSubselect;
}
- public function convertException(\PDOException $e): Nette\Database\DriverException
+ public function classifyException(Nette\Database\DriverException $e): ?string
{
- return Nette\Database\DriverException::from($e);
+ return null;
}
/********************* SQL ****************d*g**/
- public function delimite(string $name): string
+ public function delimit(string $name): string
{
return '[' . str_replace(['[', ']'], ['[[', ']]'], $name) . ']';
}
@@ -49,14 +52,7 @@ public function formatDateInterval(\DateInterval $value): string
}
- public function formatLike(string $value, int $pos): string
- {
- $value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
- return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
- }
-
-
- public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
+ public function applyLimit(string $sql, ?int $limit, ?int $offset): string
{
if ($offset) {
throw new Nette\NotSupportedException('Offset is not supported by this database.');
@@ -70,6 +66,8 @@ public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
throw new Nette\InvalidArgumentException('SQL query must begin with SELECT, UPDATE or DELETE command.');
}
}
+
+ return $sql;
}
@@ -100,14 +98,8 @@ public function getForeignKeys(string $table): array
}
- public function getColumnTypes(\PDOStatement $statement): array
- {
- return [];
- }
-
-
- public function isSupported(string $item): bool
+ public function convertToPhp(mixed $value, array $meta, TypeConverter $converter): mixed
{
- return $item === self::SupportSubselect;
+ return $converter->convertToPhp($value, $meta);
}
}
diff --git a/src/Database/Drivers/OciDriver.php b/src/Database/Drivers/Engines/OracleEngine.php
similarity index 55%
rename from src/Database/Drivers/OciDriver.php
rename to src/Database/Drivers/Engines/OracleEngine.php
index 6f5fc7e57..ead792035 100644
--- a/src/Database/Drivers/OciDriver.php
+++ b/src/Database/Drivers/Engines/OracleEngine.php
@@ -7,49 +7,50 @@
declare(strict_types=1);
-namespace Nette\Database\Drivers;
+namespace Nette\Database\Drivers\Engines;
use Nette;
+use Nette\Database\Drivers\Connection;
+use Nette\Database\Drivers\Engine;
+use Nette\Database\TypeConverter;
/**
- * Supplemental Oracle database driver.
+ * Oracle database platform.
*/
-class OciDriver implements Nette\Database\Driver
+class OracleEngine implements Engine
{
- private Nette\Database\Connection $connection;
- private string $fmtDateTime;
+ public string $formatDateTime = 'U';
- public function initialize(Nette\Database\Connection $connection, array $options): void
- {
- $this->connection = $connection;
- $this->fmtDateTime = $options['formatDateTime'] ?? 'U';
+ public function __construct(
+ private readonly Connection $connection,
+ ) {
}
- public function convertException(\PDOException $e): Nette\Database\DriverException
+ public function isSupported(string $feature): bool
{
- $code = $e->errorInfo[1] ?? null;
- if (in_array($code, [1, 2299, 38911], strict: true)) {
- return Nette\Database\UniqueConstraintViolationException::from($e);
-
- } elseif (in_array($code, [1400], strict: true)) {
- return Nette\Database\NotNullConstraintViolationException::from($e);
+ return $feature === self::SupportSequence || $feature === self::SupportSubselect;
+ }
- } elseif (in_array($code, [2266, 2291, 2292], strict: true)) {
- return Nette\Database\ForeignKeyConstraintViolationException::from($e);
- } else {
- return Nette\Database\DriverException::from($e);
- }
+ public function classifyException(Nette\Database\DriverException $e): ?string
+ {
+ $code = $e->getCode();
+ return match (true) {
+ in_array($code, [1, 2299, 38911], strict: true) => Nette\Database\UniqueConstraintViolationException::class,
+ in_array($code, [1400], strict: true) => Nette\Database\NotNullConstraintViolationException::class,
+ in_array($code, [2266, 2291, 2292], strict: true) => Nette\Database\ForeignKeyConstraintViolationException::class,
+ default => null,
+ };
}
/********************* SQL ****************d*g**/
- public function delimite(string $name): string
+ public function delimit(string $name): string
{
// @see http://download.oracle.com/docs/cd/B10500_01/server.920/a96540/sql_elements9a.htm
return '"' . str_replace('"', '""', $name) . '"';
@@ -58,7 +59,7 @@ public function delimite(string $name): string
public function formatDateTime(\DateTimeInterface $value): string
{
- return $value->format($this->fmtDateTime);
+ return $value->format($this->formatDateTime);
}
@@ -68,13 +69,7 @@ public function formatDateInterval(\DateInterval $value): string
}
- public function formatLike(string $value, int $pos): string
- {
- throw new Nette\NotImplementedException;
- }
-
-
- public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
+ public function applyLimit(string $sql, ?int $limit, ?int $offset): string
{
if ($limit < 0 || $offset < 0) {
throw new Nette\InvalidArgumentException('Negative offset or limit.');
@@ -88,6 +83,8 @@ public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
} elseif ($limit !== null) {
$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . $limit;
}
+
+ return $sql;
}
@@ -99,6 +96,7 @@ public function getTables(): array
$tables = [];
$rows = $this->connection->query('SELECT * FROM cat');
while ($row = $rows->fetch()) {
+ $row = array_values($row);
if ($row[1] === 'TABLE' || $row[1] === 'VIEW') {
$tables[] = [
'name' => $row[0],
@@ -129,14 +127,8 @@ public function getForeignKeys(string $table): array
}
- public function getColumnTypes(\PDOStatement $statement): array
- {
- return [];
- }
-
-
- public function isSupported(string $item): bool
+ public function convertToPhp(mixed $value, array $meta, TypeConverter $converter): mixed
{
- return $item === self::SupportSequence || $item === self::SupportSubselect;
+ return $converter->convertToPhp($value, $meta);
}
}
diff --git a/src/Database/Drivers/PgSqlDriver.php b/src/Database/Drivers/Engines/PostgreSQLEngine.php
similarity index 69%
rename from src/Database/Drivers/PgSqlDriver.php
rename to src/Database/Drivers/Engines/PostgreSQLEngine.php
index bda0fce9a..b297025ec 100644
--- a/src/Database/Drivers/PgSqlDriver.php
+++ b/src/Database/Drivers/Engines/PostgreSQLEngine.php
@@ -7,53 +7,48 @@
declare(strict_types=1);
-namespace Nette\Database\Drivers;
+namespace Nette\Database\Drivers\Engines;
use Nette;
+use Nette\Database\Drivers\Connection;
+use Nette\Database\Drivers\Engine;
+use Nette\Database\TypeConverter;
/**
- * Supplemental PostgreSQL database driver.
+ * PostgreSQL database platform.
*/
-class PgSqlDriver implements Nette\Database\Driver
+class PostgreSQLEngine implements Engine
{
- private Nette\Database\Connection $connection;
+ public function __construct(
+ private readonly Connection $connection,
+ ) {
+ }
- public function initialize(Nette\Database\Connection $connection, array $options): void
+ public function isSupported(string $feature): bool
{
- $this->connection = $connection;
+ return $feature === self::SupportSequence || $feature === self::SupportSubselect || $feature === self::SupportSchema;
}
- public function convertException(\PDOException $e): Nette\Database\DriverException
+ public function classifyException(Nette\Database\DriverException $e): ?string
{
- $code = $e->errorInfo[0] ?? null;
- if ($code === '0A000' && str_contains($e->getMessage(), 'truncate')) {
- return Nette\Database\ForeignKeyConstraintViolationException::from($e);
-
- } elseif ($code === '23502') {
- return Nette\Database\NotNullConstraintViolationException::from($e);
-
- } elseif ($code === '23503') {
- return Nette\Database\ForeignKeyConstraintViolationException::from($e);
-
- } elseif ($code === '23505') {
- return Nette\Database\UniqueConstraintViolationException::from($e);
-
- } elseif ($code === '08006') {
- return Nette\Database\ConnectionException::from($e);
-
- } else {
- return Nette\Database\DriverException::from($e);
- }
+ return match ($e->getSqlState()) {
+ '0A000' => str_contains($e->getMessage(), 'truncate') ? Nette\Database\ForeignKeyConstraintViolationException::class : null,
+ '23502' => Nette\Database\NotNullConstraintViolationException::class,
+ '23503' => Nette\Database\ForeignKeyConstraintViolationException::class,
+ '23505' => Nette\Database\UniqueConstraintViolationException::class,
+ '08006' => Nette\Database\ConnectionException::class,
+ default => null,
+ };
}
/********************* SQL ****************d*g**/
- public function delimite(string $name): string
+ public function delimit(string $name): string
{
// @see http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
return '"' . str_replace('"', '""', $name) . '"';
@@ -72,16 +67,7 @@ public function formatDateInterval(\DateInterval $value): string
}
- public function formatLike(string $value, int $pos): string
- {
- $bs = substr($this->connection->quote('\\'), 1, -1); // standard_conforming_strings = on/off
- $value = substr($this->connection->quote($value), 1, -1);
- $value = strtr($value, ['%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\']);
- return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
- }
-
-
- public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
+ public function applyLimit(string $sql, ?int $limit, ?int $offset): string
{
if ($limit < 0 || $offset < 0) {
throw new Nette\InvalidArgumentException('Negative offset or limit.');
@@ -94,6 +80,8 @@ public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
if ($offset) {
$sql .= ' OFFSET ' . $offset;
}
+
+ return $sql;
}
@@ -119,7 +107,7 @@ public function getTables(): array
X);
while ($row = $rows->fetch()) {
- $tables[] = (array) $row;
+ $tables[] = $row;
}
return $tables;
@@ -133,16 +121,20 @@ public function getColumns(string $table): array
SELECT
a.attname::varchar AS name,
c.relname::varchar AS table,
- upper(t.typname) AS nativetype,
+ upper(t.typname) AS "nativeType",
CASE
WHEN a.atttypid IN (1700, 1231) THEN ((a.atttypmod - 4) >> 16) & 65535 -- precision for numeric/decimal
WHEN a.atttypmod > 0 THEN a.atttypmod - 4 -- length for varchar etc.
WHEN t.typlen > 0 THEN t.typlen -- length for fixed-length types
ELSE NULL
END AS size,
+ CASE
+ WHEN a.atttypid IN (1700, 1231) THEN (a.atttypmod - 4) & 65535
+ ELSE null
+ END AS scale,
NOT (a.attnotnull OR t.typtype = 'd' AND t.typnotnull) AS nullable,
pg_catalog.pg_get_expr(ad.adbin, 'pg_catalog.pg_attrdef'::regclass)::varchar AS default,
- coalesce(co.contype = 'p' AND (seq.relname IS NOT NULL OR strpos(pg_catalog.pg_get_expr(ad.adbin, ad.adrelid), 'nextval') = 1), FALSE) AS autoincrement,
+ coalesce(co.contype = 'p' AND (seq.relname IS NOT NULL OR strpos(pg_catalog.pg_get_expr(ad.adbin, ad.adrelid), 'nextval') = 1), FALSE) AS "autoIncrement",
coalesce(co.contype = 'p', FALSE) AS primary,
coalesce(seq.relname, substring(pg_catalog.pg_get_expr(ad.adbin, 'pg_catalog.pg_attrdef'::regclass) from 'nextval[(]''"?([^''"]+)')) AS sequence
FROM
@@ -160,10 +152,10 @@ public function getColumns(string $table): array
AND NOT a.attisdropped
ORDER BY
a.attnum
- X, $this->delimiteFQN($table));
+ X, [$this->delimitFQN($table)]);
while ($row = $rows->fetch()) {
- $column = (array) $row;
+ $column = $row;
$column['vendor'] = $column;
unset($column['sequence']);
@@ -191,7 +183,7 @@ public function getIndexes(string $table): array
WHERE
c1.relkind IN ('r', 'p')
AND c1.oid = ?::regclass
- X, $this->delimiteFQN($table));
+ X, [$this->delimitFQN($table)]);
while ($row = $rows->fetch()) {
$id = $row['name'];
@@ -226,35 +218,33 @@ public function getForeignKeys(string $table): array
co.contype = 'f'
AND cl.oid = ?::regclass
AND nf.nspname = ANY (pg_catalog.current_schemas(FALSE))
- X, $this->delimiteFQN($table));
+ X, [$this->delimitFQN($table)]);
while ($row = $rows->fetch()) {
- $keys[] = (array) $row;
+ $id = $row['name'];
+ $keys[$id]['name'] = $id;
+ $keys[$id]['local'][] = $row['local'];
+ $keys[$id]['table'] = $row['table'];
+ $keys[$id]['foreign'][] = $row['foreign'];
}
- return $keys;
- }
-
- public function getColumnTypes(\PDOStatement $statement): array
- {
- static $cache;
- $item = &$cache[$statement->queryString];
- $item ??= Nette\Database\Helpers::detectTypes($statement);
- return $item;
+ return array_values($keys);
}
- public function isSupported(string $item): bool
+ public function convertToPhp(mixed $value, array $meta, TypeConverter $converter): mixed
{
- return $item === self::SupportSequence || $item === self::SupportSubselect || $item === self::SupportSchema;
+ return $meta['nativeType'] === 'bool'
+ ? ($value && $value !== 'f' && $value !== 'F')
+ : $converter->convertToPhp($value, $meta);
}
/**
* Converts: schema.name => "schema"."name"
*/
- private function delimiteFQN(string $name): string
+ private function delimitFQN(string $name): string
{
- return implode('.', array_map([$this, 'delimite'], explode('.', $name)));
+ return implode('.', array_map([$this, 'delimit'], explode('.', $name)));
}
}
diff --git a/src/Database/Drivers/SqlsrvDriver.php b/src/Database/Drivers/Engines/SQLServerEngine.php
similarity index 70%
rename from src/Database/Drivers/SqlsrvDriver.php
rename to src/Database/Drivers/Engines/SQLServerEngine.php
index f5e45b360..89f3489d2 100644
--- a/src/Database/Drivers/SqlsrvDriver.php
+++ b/src/Database/Drivers/Engines/SQLServerEngine.php
@@ -7,35 +7,41 @@
declare(strict_types=1);
-namespace Nette\Database\Drivers;
+namespace Nette\Database\Drivers\Engines;
use Nette;
+use Nette\Database\Drivers\Connection;
+use Nette\Database\Drivers\Engine;
+use Nette\Database\TypeConverter;
/**
- * Supplemental SQL Server 2005 and later database driver.
+ * Microsoft SQL Server database platform.
*/
-class SqlsrvDriver implements Nette\Database\Driver
+class SQLServerEngine implements Engine
{
- private Nette\Database\Connection $connection;
+ public function __construct(
+ private readonly Connection $connection,
+ ) {
+ }
- public function initialize(Nette\Database\Connection $connection, array $options): void
+ public function isSupported(string $feature): bool
{
- $this->connection = $connection;
+ return $feature === self::SupportSubselect;
}
- public function convertException(\PDOException $e): Nette\Database\DriverException
+ public function classifyException(Nette\Database\DriverException $e): ?string
{
- return Nette\Database\DriverException::from($e);
+ return null;
}
/********************* SQL ****************d*g**/
- public function delimite(string $name): string
+ public function delimit(string $name): string
{
/** @see https://msdn.microsoft.com/en-us/library/ms176027.aspx */
return '[' . str_replace(']', ']]', $name) . ']';
@@ -55,15 +61,7 @@ public function formatDateInterval(\DateInterval $value): string
}
- public function formatLike(string $value, int $pos): string
- {
- /** @see https://msdn.microsoft.com/en-us/library/ms179859.aspx */
- $value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
- return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
- }
-
-
- public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
+ public function applyLimit(string $sql, ?int $limit, ?int $offset): string
{
if ($limit < 0 || $offset < 0) {
throw new Nette\InvalidArgumentException('Negative offset or limit.');
@@ -73,6 +71,8 @@ public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
$sql .= ' OFFSET ' . (int) $offset . ' ROWS '
. 'FETCH NEXT ' . (int) $limit . ' ROWS ONLY';
}
+
+ return $sql;
}
@@ -113,15 +113,16 @@ public function getColumns(string $table): array
SELECT
c.name AS name,
o.name AS [table],
- UPPER(t.name) AS nativetype,
+ UPPER(t.name) AS nativeType,
CASE
WHEN c.precision <> 0 THEN c.precision
WHEN c.max_length <> -1 THEN c.max_length
ELSE NULL
END AS size,
+ c.scale AS scale,
c.is_nullable AS nullable,
OBJECT_DEFINITION(c.default_object_id) AS [default],
- c.is_identity AS autoincrement,
+ c.is_identity AS autoIncrement,
CASE WHEN i.index_id IS NULL
THEN 0
ELSE 1
@@ -135,13 +136,14 @@ public function getColumns(string $table): array
WHERE
o.type IN ('U', 'V')
AND o.name = ?
- X, $table);
+ X, [$table]);
while ($row = $rows->fetch()) {
- $row = (array) $row;
$row['vendor'] = $row;
+ $row['size'] = $row['size'] ? (int) $row['size'] : null;
+ $row['scale'] = $row['scale'] ? (int) $row['scale'] : null;
$row['nullable'] = (bool) $row['nullable'];
- $row['autoincrement'] = (bool) $row['autoincrement'];
+ $row['autoIncrement'] = (bool) $row['autoIncrement'];
$row['primary'] = (bool) $row['primary'];
$columns[] = $row;
@@ -173,7 +175,7 @@ public function getIndexes(string $table): array
ORDER BY
i.index_id,
ic.index_column_id
- X, $table);
+ X, [$table]);
while ($row = $rows->fetch()) {
$id = $row['name'];
@@ -206,38 +208,26 @@ public function getForeignKeys(string $table): array
JOIN sys.columns cf ON fkc.referenced_object_id = cf.object_id AND fkc.referenced_column_id = cf.column_id
WHERE
tl.name = ?
- X, $table);
+ X, [$table]);
while ($row = $rows->fetch()) {
- $keys[$row['name']] = (array) $row;
+ $id = $row['name'];
+ $keys[$id]['name'] = $id;
+ $keys[$id]['local'][] = $row['local'];
+ $keys[$id]['table'] = $row['table'];
+ $keys[$id]['foreign'][] = $row['foreign'];
}
return array_values($keys);
}
- public function getColumnTypes(\PDOStatement $statement): array
- {
- $types = [];
- $count = $statement->columnCount();
- for ($col = 0; $col < $count; $col++) {
- $meta = $statement->getColumnMeta($col);
- if (
- isset($meta['sqlsrv:decl_type'])
- && $meta['sqlsrv:decl_type'] !== 'timestamp'
- ) { // timestamp does not mean time in sqlsrv
- $types[$meta['name']] = Nette\Database\Helpers::detectType($meta['sqlsrv:decl_type']);
- } elseif (isset($meta['native_type'])) {
- $types[$meta['name']] = Nette\Database\Helpers::detectType($meta['native_type']);
- }
- }
-
- return $types;
- }
-
-
- public function isSupported(string $item): bool
+ public function convertToPhp(mixed $value, array $meta, TypeConverter $converter): mixed
{
- return $item === self::SupportSubselect;
+ return match ($meta['nativeType']) {
+ 'timestamp' => $value, // timestamp does not mean time in sqlsrv
+ 'bit' => $converter->convertBoolean ? $converter->toBool($value) : $converter->toInt($value),
+ default => $converter->convertToPhp($value, $meta),
+ };
}
}
diff --git a/src/Database/Drivers/SqliteDriver.php b/src/Database/Drivers/Engines/SQLiteEngine.php
similarity index 57%
rename from src/Database/Drivers/SqliteDriver.php
rename to src/Database/Drivers/Engines/SQLiteEngine.php
index 801329fb7..52e582a46 100644
--- a/src/Database/Drivers/SqliteDriver.php
+++ b/src/Database/Drivers/Engines/SQLiteEngine.php
@@ -7,55 +7,62 @@
declare(strict_types=1);
-namespace Nette\Database\Drivers;
+namespace Nette\Database\Drivers\Engines;
use Nette;
+use Nette\Database\DateTime;
+use Nette\Database\Drivers\Connection;
+use Nette\Database\Drivers\Engine;
+use Nette\Database\TypeConverter;
/**
- * Supplemental SQLite3 database driver.
+ * SQLite database platform.
*/
-class SqliteDriver implements Nette\Database\Driver
+class SQLiteEngine implements Engine
{
- private Nette\Database\Connection $connection;
- private string $fmtDateTime;
+ public string $formatDateTime = 'U';
- public function initialize(Nette\Database\Connection $connection, array $options): void
+ public function __construct(
+ private readonly Connection $connection,
+ ) {
+ }
+
+
+ public function isSupported(string $feature): bool
{
- $this->connection = $connection;
- $this->fmtDateTime = $options['formatDateTime'] ?? 'U';
+ return $feature === self::SupportMultiInsertAsSelect || $feature === self::SupportSubselect || $feature === self::SupportMultiColumnAsOrCondition;
}
- public function convertException(\PDOException $e): Nette\Database\DriverException
+ public function classifyException(Nette\Database\DriverException $e): ?string
{
- $code = $e->errorInfo[1] ?? null;
- $msg = $e->getMessage();
- if ($code !== 19) {
- return Nette\Database\DriverException::from($e);
+ $message = $e->getMessage();
+ if ($e->getCode() !== 19) {
+ return null;
} elseif (
- str_contains($msg, 'must be unique')
- || str_contains($msg, 'is not unique')
- || str_contains($msg, 'UNIQUE constraint failed')
+ str_contains($message, 'must be unique')
+ || str_contains($message, 'is not unique')
+ || str_contains($message, 'UNIQUE constraint failed')
) {
- return Nette\Database\UniqueConstraintViolationException::from($e);
+ return Nette\Database\UniqueConstraintViolationException::class;
} elseif (
- str_contains($msg, 'may not be null')
- || str_contains($msg, 'NOT NULL constraint failed')
+ str_contains($message, 'may not be null')
+ || str_contains($message, 'NOT NULL constraint failed')
) {
- return Nette\Database\NotNullConstraintViolationException::from($e);
+ return Nette\Database\NotNullConstraintViolationException::class;
} elseif (
- str_contains($msg, 'foreign key constraint failed')
- || str_contains($msg, 'FOREIGN KEY constraint failed')
+ str_contains($message, 'foreign key constraint failed')
+ || str_contains($message, 'FOREIGN KEY constraint failed')
) {
- return Nette\Database\ForeignKeyConstraintViolationException::from($e);
+ return Nette\Database\ForeignKeyConstraintViolationException::class;
} else {
- return Nette\Database\ConstraintViolationException::from($e);
+ return Nette\Database\ConstraintViolationException::class;
}
}
@@ -63,7 +70,7 @@ public function convertException(\PDOException $e): Nette\Database\DriverExcepti
/********************* SQL ****************d*g**/
- public function delimite(string $name): string
+ public function delimit(string $name): string
{
return '[' . strtr($name, '[]', ' ') . ']';
}
@@ -71,7 +78,7 @@ public function delimite(string $name): string
public function formatDateTime(\DateTimeInterface $value): string
{
- return $value->format($this->fmtDateTime);
+ return $value->format($this->formatDateTime);
}
@@ -81,14 +88,7 @@ public function formatDateInterval(\DateInterval $value): string
}
- public function formatLike(string $value, int $pos): string
- {
- $value = addcslashes(substr($this->connection->quote($value), 1, -1), '%_\\');
- return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
- }
-
-
- public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
+ public function applyLimit(string $sql, ?int $limit, ?int $offset): string
{
if ($limit < 0 || $offset < 0) {
throw new Nette\InvalidArgumentException('Negative offset or limit.');
@@ -97,6 +97,8 @@ public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
$sql .= ' LIMIT ' . ($limit ?? '-1')
. ($offset ? ' OFFSET ' . $offset : '');
}
+
+ return $sql;
}
@@ -138,10 +140,10 @@ public function getColumns(string $table): array
SELECT sql
FROM sqlite_temp_master
WHERE type = 'table' AND name = ?
- X, $table, $table)->fetch();
+ X, [$table, $table])->fetch();
$columns = [];
- $rows = $this->connection->query("PRAGMA table_info({$this->delimite($table)})");
+ $rows = $this->connection->query("PRAGMA table_info({$this->delimit($table)})");
while ($row = $rows->fetch()) {
$column = $row['name'];
$pattern = "/(\"$column\"|`$column`|\\[$column\\]|$column)\\s+[^,]+\\s+PRIMARY\\s+KEY\\s+AUTOINCREMENT/Ui";
@@ -149,13 +151,14 @@ public function getColumns(string $table): array
$columns[] = [
'name' => $column,
'table' => $table,
- 'nativetype' => strtoupper($typeInfo['type']),
- 'size' => $typeInfo['length'],
+ 'nativeType' => strtoupper($typeInfo['type']),
+ 'size' => $typeInfo['size'],
+ 'scale' => $typeInfo['scale'],
'nullable' => $row['notnull'] == 0,
'default' => $row['dflt_value'],
- 'autoincrement' => $createSql && preg_match($pattern, $createSql['sql']),
+ 'autoIncrement' => $createSql && preg_match($pattern, $createSql['sql']),
'primary' => $row['pk'] > 0,
- 'vendor' => (array) $row,
+ 'vendor' => $row,
];
}
@@ -166,7 +169,7 @@ public function getColumns(string $table): array
public function getIndexes(string $table): array
{
$indexes = [];
- $rows = $this->connection->query("PRAGMA index_list({$this->delimite($table)})");
+ $rows = $this->connection->query("PRAGMA index_list({$this->delimit($table)})");
while ($row = $rows->fetch()) {
$id = $row['name'];
$indexes[$id]['name'] = $id;
@@ -175,7 +178,7 @@ public function getIndexes(string $table): array
}
foreach ($indexes as $index => $values) {
- $res = $this->connection->query("PRAGMA index_info({$this->delimite($index)})");
+ $res = $this->connection->query("PRAGMA index_info({$this->delimit($index)})");
while ($row = $res->fetch()) {
$indexes[$index]['columns'][] = $row['name'];
}
@@ -213,40 +216,26 @@ public function getIndexes(string $table): array
public function getForeignKeys(string $table): array
{
$keys = [];
- $rows = $this->connection->query("PRAGMA foreign_key_list({$this->delimite($table)})");
+ $rows = $this->connection->query("PRAGMA foreign_key_list({$this->delimit($table)})");
while ($row = $rows->fetch()) {
$id = $row['id'];
$keys[$id]['name'] = $id;
- $keys[$id]['local'] = $row['from'];
+ $keys[$id]['local'][] = $row['from'];
$keys[$id]['table'] = $row['table'];
- $keys[$id]['foreign'] = $row['to'];
- }
-
- return array_values($keys);
- }
-
-
- public function getColumnTypes(\PDOStatement $statement): array
- {
- $types = [];
- $count = $statement->columnCount();
- for ($col = 0; $col < $count; $col++) {
- $meta = $statement->getColumnMeta($col);
- if (isset($meta['sqlite:decl_type'])) {
- $types[$meta['name']] = $this->fmtDateTime === 'U' && in_array($meta['sqlite:decl_type'], ['DATE', 'DATETIME'], strict: true)
- ? Nette\Database\IStructure::FIELD_UNIX_TIMESTAMP
- : Nette\Database\Helpers::detectType($meta['sqlite:decl_type']);
- } elseif (isset($meta['native_type'])) {
- $types[$meta['name']] = Nette\Database\Helpers::detectType($meta['native_type']);
+ $keys[$id]['foreign'][] = $row['to'];
+ if ($keys[$id]['foreign'][0] == null) {
+ $keys[$id]['foreign'] = [];
}
}
- return $types;
+ return array_values($keys);
}
- public function isSupported(string $item): bool
+ public function convertToPhp(mixed $value, array $meta, TypeConverter $converter): mixed
{
- return $item === self::SupportMultiInsertAsSelect || $item === self::SupportSubselect || $item === self::SupportMultiColumnAsOrCond;
+ return $converter->convertDateTime && in_array($meta['nativeType'], ['DATE', 'DATETIME'], true)
+ ? (is_int($value) ? (new DateTime)->setTimestamp($value) : new DateTime($value))
+ : $converter->convertToPhp($value, $meta);
}
}
diff --git a/src/Database/Drivers/MySqlDriver.php b/src/Database/Drivers/MySqlDriver.php
deleted file mode 100644
index cca8735b4..000000000
--- a/src/Database/Drivers/MySqlDriver.php
+++ /dev/null
@@ -1,224 +0,0 @@
- character encoding to set (default is utf8mb4)
- * - sqlmode => see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
- * - convertBoolean => converts INT(1) to boolean
- */
- public function initialize(Nette\Database\Connection $connection, array $options): void
- {
- $this->connection = $connection;
- $charset = $options['charset'] ?? 'utf8mb4';
- if ($charset) {
- $connection->query('SET NAMES ?', $charset);
- }
-
- if (isset($options['sqlmode'])) {
- $connection->query('SET sql_mode=?', $options['sqlmode']);
- }
-
- $this->convertBoolean = (bool) ($options['convertBoolean'] ?? $options['supportBooleans'] ?? false);
- }
-
-
- public function convertException(\PDOException $e): Nette\Database\DriverException
- {
- $code = $e->errorInfo[1] ?? null;
- if (in_array($code, [1216, 1217, 1451, 1452, 1701], strict: true)) {
- return Nette\Database\ForeignKeyConstraintViolationException::from($e);
-
- } elseif (in_array($code, [1062, 1557, 1569, 1586], strict: true)) {
- return Nette\Database\UniqueConstraintViolationException::from($e);
-
- } elseif ($code >= 2001 && $code <= 2028) {
- return Nette\Database\ConnectionException::from($e);
-
- } elseif (in_array($code, [1048, 1121, 1138, 1171, 1252, 1263, 1566], strict: true)) {
- return Nette\Database\NotNullConstraintViolationException::from($e);
-
- } else {
- return Nette\Database\DriverException::from($e);
- }
- }
-
-
- /********************* SQL ****************d*g**/
-
-
- public function delimite(string $name): string
- {
- // @see http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
- return '`' . str_replace('`', '``', $name) . '`';
- }
-
-
- public function formatDateTime(\DateTimeInterface $value): string
- {
- return $value->format("'Y-m-d H:i:s'");
- }
-
-
- public function formatDateInterval(\DateInterval $value): string
- {
- return $value->format("'%r%h:%I:%S'");
- }
-
-
- public function formatLike(string $value, int $pos): string
- {
- $value = str_replace('\\', '\\\\', $value);
- $value = addcslashes(substr($this->connection->quote($value), 1, -1), '%_');
- return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
- }
-
-
- public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
- {
- if ($limit < 0 || $offset < 0) {
- throw new Nette\InvalidArgumentException('Negative offset or limit.');
-
- } elseif ($limit !== null || $offset) {
- // see http://dev.mysql.com/doc/refman/5.0/en/select.html
- $sql .= ' LIMIT ' . ($limit ?? '18446744073709551615')
- . ($offset ? ' OFFSET ' . $offset : '');
- }
- }
-
-
- /********************* reflection ****************d*g**/
-
-
- public function getTables(): array
- {
- $tables = [];
- $rows = $this->connection->query('SHOW FULL TABLES');
- while ($row = $rows->fetch()) {
- $tables[] = [
- 'name' => $row[0],
- 'view' => ($row[1] ?? null) === 'VIEW',
- ];
- }
-
- return $tables;
- }
-
-
- public function getColumns(string $table): array
- {
- $columns = [];
- $rows = $this->connection->query('SHOW FULL COLUMNS FROM ' . $this->delimite($table));
- while ($row = $rows->fetch()) {
- $row = array_change_key_case((array) $row, CASE_LOWER);
- $typeInfo = Nette\Database\Helpers::parseColumnType($row['type']);
- $columns[] = [
- 'name' => $row['field'],
- 'table' => $table,
- 'nativetype' => strtoupper($typeInfo['type']),
- 'size' => $typeInfo['length'],
- 'nullable' => $row['null'] === 'YES',
- 'default' => $row['default'],
- 'autoincrement' => $row['extra'] === 'auto_increment',
- 'primary' => $row['key'] === 'PRI',
- 'vendor' => $row,
- ];
- }
-
- return $columns;
- }
-
-
- public function getIndexes(string $table): array
- {
- $indexes = [];
- $rows = $this->connection->query('SHOW INDEX FROM ' . $this->delimite($table));
- while ($row = $rows->fetch()) {
- $id = $row['Key_name'];
- $indexes[$id]['name'] = $id;
- $indexes[$id]['unique'] = !$row['Non_unique'];
- $indexes[$id]['primary'] = $row['Key_name'] === 'PRIMARY';
- $indexes[$id]['columns'][$row['Seq_in_index'] - 1] = $row['Column_name'];
- }
-
- return array_values($indexes);
- }
-
-
- public function getForeignKeys(string $table): array
- {
- $keys = [];
- $rows = $this->connection->query(<<<'X'
- SELECT CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
- FROM information_schema.KEY_COLUMN_USAGE
- WHERE TABLE_SCHEMA = DATABASE()
- AND REFERENCED_TABLE_NAME IS NOT NULL
- AND TABLE_NAME = ?
- X, $table);
-
- $id = 0;
- while ($row = $rows->fetch()) {
- $keys[$id]['name'] = $row['CONSTRAINT_NAME'];
- $keys[$id]['local'] = $row['COLUMN_NAME'];
- $keys[$id]['table'] = $row['REFERENCED_TABLE_NAME'];
- $keys[$id++]['foreign'] = $row['REFERENCED_COLUMN_NAME'];
- }
-
- return array_values($keys);
- }
-
-
- public function getColumnTypes(\PDOStatement $statement): array
- {
- $types = [];
- $count = $statement->columnCount();
- for ($col = 0; $col < $count; $col++) {
- $meta = $statement->getColumnMeta($col);
- if (isset($meta['native_type'])) {
- $types[$meta['name']] = match (true) {
- $meta['native_type'] === 'NEWDECIMAL' && $meta['precision'] === 0 => Nette\Database\IStructure::FIELD_INTEGER,
- $meta['native_type'] === 'TINY' && $meta['len'] === 1 && $this->convertBoolean => Nette\Database\IStructure::FIELD_BOOL,
- $meta['native_type'] === 'TIME' => Nette\Database\IStructure::FIELD_TIME_INTERVAL,
- default => Nette\Database\Helpers::detectType($meta['native_type']),
- };
- }
- }
-
- return $types;
- }
-
-
- public function isSupported(string $item): bool
- {
- // MULTI_COLUMN_AS_OR_COND due to mysql bugs:
- // - http://bugs.mysql.com/bug.php?id=31188
- // - http://bugs.mysql.com/bug.php?id=35819
- // and more.
- return $item === self::SupportSelectUngroupedColumns || $item === self::SupportMultiColumnAsOrCond;
- }
-}
diff --git a/src/Database/Drivers/PDO/Connection.php b/src/Database/Drivers/PDO/Connection.php
new file mode 100644
index 000000000..540b725d5
--- /dev/null
+++ b/src/Database/Drivers/PDO/Connection.php
@@ -0,0 +1,121 @@
+ PDO::PARAM_BOOL, 'integer' => PDO::PARAM_INT, 'resource' => PDO::PARAM_LOB, 'NULL' => PDO::PARAM_NULL];
+
+ try {
+ $statement = $this->pdo->prepare($sql);
+ foreach ($params as $key => $value) {
+ $statement->bindValue(is_int($key) ? $key + 1 : $key, $value, $types[gettype($value)] ?? PDO::PARAM_STR);
+ }
+ $statement->execute();
+ return new ($this->resultClass)($statement, $this);
+
+ } catch (PDOException $e) {
+ throw new DriverException(...Driver::exceptionArgs($e, new SqlLiteral($sql, $params)));
+ }
+ }
+
+
+ public function execute(string $sql): int
+ {
+ try {
+ return $this->pdo->exec($sql);
+ } catch (PDOException $e) {
+ throw new DriverException(...Driver::exceptionArgs($e, new SqlLiteral($sql)));
+ }
+ }
+
+
+ public function beginTransaction(): void
+ {
+ try {
+ $this->pdo->beginTransaction();
+ } catch (PDOException $e) {
+ throw new DriverException(...Driver::exceptionArgs($e));
+ }
+ }
+
+
+ public function commit(): void
+ {
+ try {
+ $this->pdo->commit();
+ } catch (PDOException $e) {
+ throw new DriverException(...Driver::exceptionArgs($e));
+ }
+ }
+
+
+ public function rollBack(): void
+ {
+ try {
+ $this->pdo->rollBack();
+ } catch (PDOException $e) {
+ throw new DriverException(...Driver::exceptionArgs($e));
+ }
+ }
+
+
+ public function getInsertId(?string $sequence = null): int|string
+ {
+ try {
+ $id = $this->pdo->lastInsertId($sequence);
+ if ($id === '0' || $id === '' || $id === false) {
+ throw new DriverException('Cannot retrieve last generated ID.');
+ }
+ $int = (int) $id;
+ return $id === (string) $int ? $int : $id;
+
+ } catch (PDOException $e) {
+ throw new DriverException(...Driver::exceptionArgs($e));
+ }
+ }
+
+
+ public function quote(string $string): string
+ {
+ return $this->pdo->quote($string);
+ }
+
+
+ public function getServerVersion(): string
+ {
+ return $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
+ }
+
+
+ public function getNativeConnection(): PDO
+ {
+ return $this->pdo;
+ }
+}
diff --git a/src/Database/Drivers/PDO/Driver.php b/src/Database/Drivers/PDO/Driver.php
new file mode 100644
index 000000000..21b2f1139
--- /dev/null
+++ b/src/Database/Drivers/PDO/Driver.php
@@ -0,0 +1,48 @@
+dsn, $this->username, $this->password, $this->options);
+ } catch (PDOException $e) {
+ throw new DriverException(...self::exceptionArgs($e));
+ }
+ return new Connection($pdo);
+ }
+
+
+ public static function exceptionArgs(PDOException $e, ?SqlLiteral $query = null): array
+ {
+ return [$e->getMessage(), $e->errorInfo[0] ?? null, $e->errorInfo[1] ?? 0, $query, $e];
+ }
+}
diff --git a/src/Database/Drivers/PDO/MSSQL/Driver.php b/src/Database/Drivers/PDO/MSSQL/Driver.php
new file mode 100644
index 000000000..4c3acd205
--- /dev/null
+++ b/src/Database/Drivers/PDO/MSSQL/Driver.php
@@ -0,0 +1,25 @@
+charset) {
+ $connection->execute('SET NAMES ' . $connection->quote($this->charset));
+ }
+ if ($this->sqlmode) {
+ $connection->execute('SET sql_mode=' . $connection->quote($this->sqlmode));
+ }
+ return $connection;
+ }
+
+
+ public function createEngine(Drivers\Connection $connection): MySQLEngine
+ {
+ return new MySQLEngine($connection);
+ }
+}
diff --git a/src/Database/Drivers/PDO/OCI/Driver.php b/src/Database/Drivers/PDO/OCI/Driver.php
new file mode 100644
index 000000000..606f7df6a
--- /dev/null
+++ b/src/Database/Drivers/PDO/OCI/Driver.php
@@ -0,0 +1,40 @@
+formatDateTime) {
+ $engine->formatDateTime = $this->formatDateTime;
+ }
+ return $engine;
+ }
+}
diff --git a/src/Database/Drivers/PDO/ODBC/Driver.php b/src/Database/Drivers/PDO/ODBC/Driver.php
new file mode 100644
index 000000000..47371287e
--- /dev/null
+++ b/src/Database/Drivers/PDO/ODBC/Driver.php
@@ -0,0 +1,25 @@
+resultClass = Result::class;
+ return $connection;
+ }
+
+
+ public function createEngine(Drivers\Connection $connection): PostgreSQLEngine
+ {
+ return new PostgreSQLEngine($connection);
+ }
+}
diff --git a/src/Database/Drivers/PDO/PgSQL/Result.php b/src/Database/Drivers/PDO/PgSQL/Result.php
new file mode 100644
index 000000000..482161829
--- /dev/null
+++ b/src/Database/Drivers/PDO/PgSQL/Result.php
@@ -0,0 +1,24 @@
+result->queryString] ??= parent::collectColumnsInfo();
+ }
+}
diff --git a/src/Database/Drivers/PDO/Result.php b/src/Database/Drivers/PDO/Result.php
new file mode 100644
index 000000000..f17b88cef
--- /dev/null
+++ b/src/Database/Drivers/PDO/Result.php
@@ -0,0 +1,107 @@
+fetchList();
+ if (!$row) {
+ return null;
+ }
+
+ $res = [];
+ foreach ($this->getColumnsInfo() as $i => $meta) {
+ $res[$meta['name']] = $row[$i];
+ }
+ return $res;
+ }
+
+
+ public function fetchList(): ?array
+ {
+ try {
+ $row = $this->result->fetch(\PDO::FETCH_NUM);
+ if (!$row) {
+ $this->free();
+ return null;
+ }
+ return $row;
+
+ } catch (PDOException $e) {
+ throw new DriverException(...Driver::exceptionArgs($e));
+ }
+ }
+
+
+ public function getColumnCount(): int
+ {
+ try {
+ return $this->result->columnCount();
+ } catch (PDOException $e) {
+ throw new DriverException(...Driver::exceptionArgs($e));
+ }
+ }
+
+
+ public function getRowCount(): int
+ {
+ try {
+ return $this->result->rowCount();
+ } catch (PDOException $e) {
+ throw new DriverException(...Driver::exceptionArgs($e));
+ }
+ }
+
+
+ public function getColumnsInfo(): array
+ {
+ return $this->columns ??= $this->collectColumnsInfo();
+ }
+
+
+ protected function collectColumnsInfo(): array
+ {
+ $res = [];
+ $count = $this->result->columnCount();
+ for ($i = 0; $i < $count; $i++) {
+ $meta = $this->result->getColumnMeta($i) ?: throw new DriverException('Cannot fetch column metadata');
+ $res[] = [
+ 'name' => $meta['name'],
+ 'nativeType' => $meta[$this->connection->metaTypeKey] ?? null,
+ 'size' => $meta['len'],
+ 'scale' => $meta['precision'],
+ ];
+ }
+ return $res;
+ }
+
+
+ public function free(): void
+ {
+ $this->result->closeCursor();
+ }
+}
diff --git a/src/Database/Drivers/PDO/SQLSrv/Driver.php b/src/Database/Drivers/PDO/SQLSrv/Driver.php
new file mode 100644
index 000000000..46909e970
--- /dev/null
+++ b/src/Database/Drivers/PDO/SQLSrv/Driver.php
@@ -0,0 +1,35 @@
+ converts BIT to boolean
+ */
+class Driver extends Drivers\PDO\Driver
+{
+ public function connect(): Drivers\PDO\Connection
+ {
+ $connection = parent::connect();
+ $connection->metaTypeKey = 'sqlsrv:decl_type';
+ return $connection;
+ }
+
+
+ public function createEngine(Drivers\Connection $connection): SQLServerEngine
+ {
+ return new SQLServerEngine($connection);
+ }
+}
diff --git a/src/Database/Drivers/PDO/SQLite/Driver.php b/src/Database/Drivers/PDO/SQLite/Driver.php
new file mode 100644
index 000000000..f73619b0c
--- /dev/null
+++ b/src/Database/Drivers/PDO/SQLite/Driver.php
@@ -0,0 +1,48 @@
+metaTypeKey = 'sqlite:decl_type';
+ return $connection;
+ }
+
+
+ public function createEngine(Drivers\Connection $connection): SQLiteEngine
+ {
+ $engine = new SQLiteEngine($connection);
+ if ($this->formatDateTime) {
+ $engine->formatDateTime = $this->formatDateTime;
+ }
+ return $engine;
+ }
+}
diff --git a/src/Database/Drivers/Result.php b/src/Database/Drivers/Result.php
new file mode 100644
index 000000000..e17895e1f
--- /dev/null
+++ b/src/Database/Drivers/Result.php
@@ -0,0 +1,38 @@
+
+ */
+ function getColumnsInfo(): array;
+
+ /** Frees the result set. */
+ function free(): void;
+}
diff --git a/src/Database/Explorer.php b/src/Database/Explorer.php
index 12cbd3f25..e500345ea 100644
--- a/src/Database/Explorer.php
+++ b/src/Database/Explorer.php
@@ -11,54 +11,268 @@
use JetBrains\PhpStorm\Language;
use Nette;
-use Nette\Database\Conventions\StaticConventions;
+use Nette\Caching\Cache;
+use Nette\Utils\Arrays;
/**
- * Database explorer.
+ * The central access point to Nette Database functionality.
*/
class Explorer
{
- private readonly Conventions $conventions;
+ private const Drivers = [
+ 'pdo-mssql' => Drivers\PDO\MSSQL\Driver::class,
+ 'pdo-mysql' => Drivers\PDO\MySQL\Driver::class,
+ 'pdo-oci' => Drivers\PDO\OCI\Driver::class,
+ 'pdo-odbc' => Drivers\PDO\ODBC\Driver::class,
+ 'pdo-pgsql' => Drivers\PDO\PgSQL\Driver::class,
+ 'pdo-sqlite' => Drivers\PDO\SQLite\Driver::class,
+ 'pdo-sqlsrv' => Drivers\PDO\SQLSrv\Driver::class,
+ ];
+ private const TypeConverterOptions = ['convertBoolean', 'convertDateTime', 'convertDecimal', 'newDateTime'];
+
+ /** @var array Occurs after connection is established */
+ public array $onConnect = [];
+
+ /** @var array Occurs after query is executed */
+ public array $onQuery = [];
+ private Drivers\Driver $driver;
+ private ?Drivers\Connection $connection = null;
+ private Drivers\Engine $engine;
+ private SqlPreprocessor $preprocessor;
+ private TypeConverter $typeConverter;
+ private ?SqlLiteral $lastQuery = null;
+ private int $transactionDepth = 0;
+ private ?Cache $cache = null;
+ private ?Conventions $conventions = null;
+ private ?Structure $structure = null;
+
+
+ public static function createFromParameters(
+ #[\SensitiveParameter]
+ ...$params,
+ ): self
+ {
+ $params = count($params) === 1 && is_array($params[0] ?? null) ? $params[0] : $params;
+
+ if ($class = $params['driverClass'] ?? null) {
+ if (!is_subclass_of($class, Drivers\Driver::class)) {
+ throw new \LogicException("Driver class '$class' is not subclass of " . Drivers\Driver::class);
+ }
+ unset($params['driverClass']);
+
+ } elseif ($driver = $params['driver'] ?? null) {
+ $class = self::Drivers[$driver] ?? throw new \LogicException("Unknown driver '$driver'.");
+ unset($params['driver']);
+
+ } elseif ($dsn = $params['dsn'] ?? null) {
+ $driver = explode(':', $dsn)[0];
+ $class = self::Drivers['pdo-' . $driver] ?? throw new \LogicException("Unknown PDO driver '$driver'.");
+
+ } else {
+ throw new \LogicException("Missing options 'driver', 'driverClass' or 'dsn'.");
+ }
+
+ $args = array_diff_key($params, array_flip(self::TypeConverterOptions));
+ $explorer = new self(new $class(...$args));
+ array_map(fn($opt) => isset($params[$opt]) && ($explorer->typeConverter->$opt = (bool) $params[$opt]), self::TypeConverterOptions);
+ return $explorer;
+ }
+
+
+ public static function createFromDsn(
+ string $dsn,
+ ?string $username = null,
+ #[\SensitiveParameter]
+ ?string $password = null,
+ array $options = [],
+ ): self
+ {
+ $params = compact('dsn', 'username', 'password', 'options');
+ foreach ($options as $key => $value) {
+ if (!is_int($key) && $value !== null) {
+ $params[$key] = $value;
+ unset($params['options'][$key]);
+ }
+ }
+ unset($params['lazy']);
+ return self::createFromParameters($params);
+ }
public function __construct(
- private readonly Connection $connection,
- private readonly IStructure $structure,
- ?Conventions $conventions = null,
- private readonly ?Nette\Caching\Storage $cacheStorage = null,
+ Drivers\Driver|string $driver,
) {
- $this->conventions = $conventions ?: new StaticConventions;
+ if (is_string($driver)) { // back compatibility with version 3.x
+ $explorer = self::createFromDsn(...func_get_args());
+ [$this->driver, $this->typeConverter] = [$explorer->driver, $explorer->typeConverter];
+ } else {
+ $this->driver = $driver;
+ $this->typeConverter = new TypeConverter;
+ }
}
- public function beginTransaction(): void
+ public function connect(): void
{
- $this->connection->beginTransaction();
+ if ($this->connection) {
+ return;
+ }
+
+ try {
+ $this->connection = $this->driver->connect();
+ } catch (DriverException $e) {
+ throw ConnectionException::from($e);
+ }
+
+ Arrays::invoke($this->onConnect, $this);
}
- public function commit(): void
+ public function reconnect(): void
{
- $this->connection->commit();
+ $this->disconnect();
+ $this->connect();
}
- public function rollBack(): void
+ public function disconnect(): void
{
- $this->connection->rollBack();
+ $this->connection = null;
}
- public function transaction(callable $callback): mixed
+ /** @deprecated */
+ public function getDsn(): string
+ {
+ throw new Nette\DeprecatedException(__METHOD__ . '() is deprecated.');
+ }
+
+
+ /** @deprecated use getConnection()->getNativeConnection() */
+ public function getPdo(): \PDO
+ {
+ trigger_error(__METHOD__ . '() is deprecated, use getConnection()->getNativeConnection()', E_USER_DEPRECATED);
+ return $this->getConnection()->getNativeConnection();
+ }
+
+
+ public function getConnection(): Drivers\Connection
{
- return $this->connection->transaction(fn() => $callback($this));
+ $this->connect();
+ return $this->connection;
}
- public function getInsertId(?string $sequence = null): string
+ /** @deprecated use getConnection() */
+ public function getSupplementalDriver(): Drivers\Connection
{
- return $this->connection->getInsertId($sequence);
+ trigger_error(__METHOD__ . '() is deprecated, use getConnection()', E_USER_DEPRECATED);
+ return $this->getConnection();
+ }
+
+
+ public function getDatabaseEngine(): Drivers\Engine
+ {
+ return $this->engine ??= $this->driver->createEngine(new Drivers\Accessory\LazyConnection($this->getConnection(...)));
+ }
+
+
+ public function getServerVersion(): string
+ {
+ return $this->getConnection()->getServerVersion();
+ }
+
+
+ public function getReflection(): Reflection
+ {
+ return new Reflection($this->getDatabaseEngine());
+ }
+
+
+ public function getTypeConverter(): TypeConverter
+ {
+ return $this->typeConverter;
+ }
+
+
+ /** @deprecated */
+ public function setRowNormalizer(?callable $normalizer): static
+ {
+ throw new Nette\DeprecatedException(__METHOD__ . "() is deprecated, configure 'convert*' options instead.");
+ }
+
+
+ public function getInsertId(?string $sequence = null): int|string
+ {
+ try {
+ return $this->getConnection()->getInsertId($sequence);
+ } catch (DriverException $e) {
+ throw $this->convertException($e);
+ }
+ }
+
+
+ public function quote(string $string): string
+ {
+ return $this->getConnection()->quote($string);
+ }
+
+
+ public function beginTransaction(): void
+ {
+ if ($this->transactionDepth !== 0) {
+ throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
+ }
+
+ $this->logOperation($this->getConnection()->beginTransaction(...), new SqlLiteral('BEGIN TRANSACTION'));
+ }
+
+
+ public function commit(): void
+ {
+ if ($this->transactionDepth !== 0) {
+ throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
+ }
+
+ $this->logOperation($this->getConnection()->commit(...), new SqlLiteral('COMMIT'));
+ }
+
+
+ public function rollBack(): void
+ {
+ if ($this->transactionDepth !== 0) {
+ throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
+ }
+
+ $this->logOperation($this->getConnection()->rollBack(...), new SqlLiteral('ROLLBACK'));
+ }
+
+
+ public function transaction(callable $callback): mixed
+ {
+ if ($this->transactionDepth === 0) {
+ $this->beginTransaction();
+ }
+
+ $this->transactionDepth++;
+ try {
+ $res = $callback($this);
+ } catch (\Throwable $e) {
+ $this->transactionDepth--;
+ if ($this->transactionDepth === 0) {
+ $this->rollback();
+ }
+
+ throw $e;
+ }
+
+ $this->transactionDepth--;
+ if ($this->transactionDepth === 0) {
+ $this->commit();
+ }
+
+ return $res;
}
@@ -66,40 +280,74 @@ public function getInsertId(?string $sequence = null): string
* Generates and executes SQL query.
* @param literal-string $sql
*/
- public function query(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): ResultSet
+ public function query(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): Result
{
- return $this->connection->query($sql, ...$params);
+ [$sql, $params] = $this->preprocess($sql, ...$params);
+ return $this->logOperation(
+ fn() => $this->connection->query($sql, $params),
+ $this->lastQuery = new SqlLiteral($sql, $params),
+ );
}
/** @deprecated use query() */
- public function queryArgs(string $sql, array $params): ResultSet
+ public function queryArgs(string $sql, array $params): Result
{
- return $this->connection->query($sql, ...$params);
+ trigger_error(__METHOD__ . '() is deprecated, use query()', E_USER_DEPRECATED);
+ return $this->query($sql, ...$params);
}
- public function table(string $table): Table\Selection
+ /**
+ * @param literal-string $sql
+ * @return array{string, array}
+ */
+ public function preprocess(string $sql, ...$params): array
{
- return new Table\Selection($this, $this->conventions, $table, $this->cacheStorage);
+ $this->connect();
+ $this->preprocessor ??= new SqlPreprocessor($this);
+ return $params
+ ? $this->preprocessor->process(func_get_args())
+ : [$sql, []];
}
- public function getConnection(): Connection
+ private function logOperation(\Closure $callback, SqlLiteral $query): Result
{
- return $this->connection;
+ try {
+ $time = microtime(true);
+ $result = $callback();
+ $time = microtime(true) - $time;
+ } catch (DriverException $e) {
+ $e = $this->convertException($e);
+ Arrays::invoke($this->onQuery, $this, $e);
+ throw $e;
+ }
+
+ $result = new Result($this, $query, $result, $time);
+ Arrays::invoke($this->onQuery, $this, $result);
+ return $result;
}
- public function getStructure(): IStructure
+ public function getLastQuery(): ?SqlLiteral
{
- return $this->structure;
+ return $this->lastQuery;
}
- public function getConventions(): Conventions
+ /** @deprecated use getLastQuery()->getSql() */
+ public function getLastQueryString(): ?string
+ {
+ trigger_error(__METHOD__ . '() is deprecated, use getLastQuery()->getSql()', E_USER_DEPRECATED);
+ return $this->lastQuery?->getSql();
+ }
+
+
+ private function convertException(DriverException $e): DriverException
{
- return $this->conventions;
+ $class = $this->getDatabaseEngine()->classifyException($e);
+ return $class ? $class::from($e) : $e;
}
@@ -112,7 +360,7 @@ public function getConventions(): Conventions
*/
public function fetch(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): ?Row
{
- return $this->connection->query($sql, ...$params)->fetch();
+ return $this->query($sql, ...$params)->fetch();
}
@@ -122,7 +370,7 @@ public function fetch(#[Language('SQL')] string $sql, #[Language('GenericSQL')]
*/
public function fetchAssoc(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): ?array
{
- return $this->connection->query($sql, ...$params)->fetchAssoc();
+ return $this->query($sql, ...$params)->fetchAssoc();
}
@@ -132,17 +380,27 @@ public function fetchAssoc(#[Language('SQL')] string $sql, #[Language('GenericSQ
*/
public function fetchField(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): mixed
{
- return $this->connection->query($sql, ...$params)->fetchField();
+ return $this->query($sql, ...$params)->fetchField();
+ }
+
+
+ /**
+ * Shortcut for query()->fetchList()
+ * @param literal-string $sql
+ */
+ public function fetchList(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): ?array
+ {
+ return $this->query($sql, ...$params)->fetchList();
}
/**
- * Shortcut for query()->fetchFields()
+ * Shortcut for query()->fetchList()
* @param literal-string $sql
*/
public function fetchFields(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): ?array
{
- return $this->connection->query($sql, ...$params)->fetchFields();
+ return $this->query($sql, ...$params)->fetchList();
}
@@ -152,7 +410,7 @@ public function fetchFields(#[Language('SQL')] string $sql, #[Language('GenericS
*/
public function fetchPairs(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): array
{
- return $this->connection->query($sql, ...$params)->fetchPairs();
+ return $this->query($sql, ...$params)->fetchPairs();
}
@@ -162,7 +420,7 @@ public function fetchPairs(#[Language('SQL')] string $sql, #[Language('GenericSQ
*/
public function fetchAll(#[Language('SQL')] string $sql, #[Language('GenericSQL')] ...$params): array
{
- return $this->connection->query($sql, ...$params)->fetchAll();
+ return $this->query($sql, ...$params)->fetchAll();
}
@@ -170,7 +428,57 @@ public static function literal(string $value, ...$params): SqlLiteral
{
return new SqlLiteral($value, $params);
}
+
+
+ /********************* active row ****************d*g**/
+
+
+ public function table(string $table): Table\Selection
+ {
+ return new Table\Selection($this, $table);
+ }
+
+
+ public function setCache(Cache $cache): static
+ {
+ if (isset($this->structure)) {
+ throw new \LogicException('Cannot set cache after structure is created.');
+ }
+ $this->cache = $cache;
+ return $this;
+ }
+
+
+ /** @internal */
+ public function getCache(): ?Cache
+ {
+ return $this->cache;
+ }
+
+
+ public function setConventions(Conventions $conventions): static
+ {
+ if (isset($this->conventions)) {
+ throw new \LogicException('Conventions are already set.');
+ }
+ $this->conventions = $conventions;
+ return $this;
+ }
+
+
+ /** @internal */
+ public function getConventions(): Conventions
+ {
+ return $this->conventions ??= new Conventions\DiscoveredConventions($this->getStructure());
+ }
+
+
+ /** @internal */
+ public function getStructure(): Structure
+ {
+ return $this->structure ??= new Structure($this->getDatabaseEngine(), $this->getCache());
+ }
}
-class_exists(Context::class);
+class_exists(Connection::class);
diff --git a/src/Database/Helpers.php b/src/Database/Helpers.php
index 7f9cf0623..588356ff0 100644
--- a/src/Database/Helpers.php
+++ b/src/Database/Helpers.php
@@ -24,25 +24,13 @@ class Helpers
/** maximum SQL length */
public static int $maxLength = 100;
- public static array $typePatterns = [
- '^_' => IStructure::FIELD_TEXT, // PostgreSQL arrays
- '(TINY|SMALL|SHORT|MEDIUM|BIG|LONG)(INT)?|INT(EGER|\d+| IDENTITY| UNSIGNED)?|(SMALL|BIG|)SERIAL\d*|COUNTER|YEAR|BYTE|LONGLONG|UNSIGNED BIG INT' => IStructure::FIELD_INTEGER,
- '(NEW)?DEC(IMAL)?(\(.*)?|NUMERIC|(SMALL)?MONEY|CURRENCY|NUMBER' => IStructure::FIELD_DECIMAL,
- 'REAL|DOUBLE( PRECISION)?|FLOAT\d*' => IStructure::FIELD_FLOAT,
- 'BOOL(EAN)?' => IStructure::FIELD_BOOL,
- 'TIME' => IStructure::FIELD_TIME,
- 'DATE' => IStructure::FIELD_DATE,
- '(SMALL)?DATETIME(OFFSET)?\d*|TIME(STAMP.*)?' => IStructure::FIELD_DATETIME,
- 'BYTEA|(TINY|MEDIUM|LONG|)BLOB|(LONG )?(VAR)?BINARY|IMAGE' => IStructure::FIELD_BINARY,
- ];
-
/**
* Displays complete result set as HTML table for debug purposes.
*/
- public static function dumpResult(ResultSet $result): void
+ public static function dumpResult(Result $result): void
{
- echo "\n\n" . htmlspecialchars($result->getQueryString(), ENT_IGNORE, 'UTF-8') . "\n";
+ echo "\n\n" . htmlspecialchars($result->getQuery()->getSql(), ENT_IGNORE, 'UTF-8') . "\n";
if (!$result->getColumnCount()) {
echo "\t\n\t\tAffected rows: | \n\t\t", $result->getRowCount(), " | \n\t \n \n";
return;
@@ -87,12 +75,13 @@ public static function dumpResult(ResultSet $result): void
/**
* Returns syntax highlighted SQL command.
*/
- public static function dumpSql(string $sql, ?array $params = null, ?Connection $connection = null): string
+ public static function dumpSql(SqlLiteral $query, ?Explorer $explorer = null): string
{
$keywords1 = 'SELECT|(?:ON\s+DUPLICATE\s+KEY)?UPDATE|INSERT(?:\s+INTO)?|REPLACE(?:\s+INTO)?|DELETE|CALL|UNION|FROM|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|OFFSET|SET|VALUES|LEFT\s+JOIN|INNER\s+JOIN|TRUNCATE';
$keywords2 = 'ALL|DISTINCT|DISTINCTROW|IGNORE|AS|USING|ON|AND|OR|IN|IS|NOT|NULL|[RI]?LIKE|REGEXP|TRUE|FALSE';
// insert new lines
+ $sql = $query->getSql();
$sql = " $sql ";
$sql = preg_replace("#(?<=[\\s,(])($keywords1)(?=[\\s,)])#i", "\n\$1", $sql);
@@ -120,14 +109,14 @@ public static function dumpSql(string $sql, ?array $params = null, ?Connection $
}, $sql);
// parameters
- $sql = preg_replace_callback('#\?#', function () use ($params, $connection): string {
+ $params = $query->getParameters();
+ $sql = preg_replace_callback('#\?#', function () use ($params, $explorer): string {
static $i = 0;
- if (!isset($params[$i])) {
+ $param = $params[$i++] ?? null;
+ if ($param === null) {
return '?';
- }
- $param = $params[$i++];
- if (
+ } elseif (
is_string($param)
&& (
preg_match('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', $param)
@@ -139,7 +128,7 @@ public static function dumpSql(string $sql, ?array $params = null, ?Connection $
} elseif (is_string($param)) {
$length = Nette\Utils\Strings::length($param);
$truncated = Nette\Utils\Strings::truncate($param, self::$maxLength);
- $text = htmlspecialchars($connection ? $connection->quote($truncated) : '\'' . $truncated . '\'', ENT_NOQUOTES, 'UTF-8');
+ $text = htmlspecialchars($explorer ? $explorer->quote($truncated) : '\'' . $truncated . '\'', ENT_NOQUOTES, 'UTF-8');
return '' . $text . '';
} elseif (is_resource($param)) {
@@ -163,93 +152,12 @@ public static function dumpSql(string $sql, ?array $params = null, ?Connection $
}
- /**
- * Common column type detection.
- */
- public static function detectTypes(\PDOStatement $statement): array
- {
- $types = [];
- $count = $statement->columnCount(); // driver must be meta-aware, see PHP bugs #53782, #54695
- for ($col = 0; $col < $count; $col++) {
- $meta = $statement->getColumnMeta($col);
- if (isset($meta['native_type'])) {
- $types[$meta['name']] = self::detectType($meta['native_type']);
- }
- }
-
- return $types;
- }
-
-
- /**
- * Heuristic column type detection.
- * @internal
- */
- public static function detectType(string $type): string
- {
- static $cache;
- if (!isset($cache[$type])) {
- $cache[$type] = 'string';
- foreach (self::$typePatterns as $s => $val) {
- if (preg_match("#^($s)$#i", $type)) {
- return $cache[$type] = $val;
- }
- }
- }
-
- return $cache[$type];
- }
-
-
- /** @internal */
- public static function normalizeRow(
- array $row,
- ResultSet $resultSet,
- $dateTimeClass = Nette\Utils\DateTime::class,
- ): array
- {
- foreach ($resultSet->getColumnTypes() as $key => $type) {
- $value = $row[$key];
- if ($value === null || $value === false || $type === IStructure::FIELD_TEXT) {
- // do nothing
- } elseif ($type === IStructure::FIELD_INTEGER) {
- $row[$key] = is_float($tmp = $value * 1) ? $value : $tmp;
-
- } elseif ($type === IStructure::FIELD_FLOAT || $type === IStructure::FIELD_DECIMAL) {
- $row[$key] = (float) $value;
-
- } elseif ($type === IStructure::FIELD_BOOL) {
- $row[$key] = $value && $value !== 'f' && $value !== 'F';
-
- } elseif ($type === IStructure::FIELD_DATETIME || $type === IStructure::FIELD_DATE) {
- $row[$key] = str_starts_with($value, '0000-00')
- ? null
- : new $dateTimeClass($value);
-
- } elseif ($type === IStructure::FIELD_TIME) {
- $row[$key] = (new $dateTimeClass($value))->setDate(1, 1, 1);
-
- } elseif ($type === IStructure::FIELD_TIME_INTERVAL) {
- preg_match('#^(-?)(\d+)\D(\d+)\D(\d+)(\.\d+)?$#D', $value, $m);
- $row[$key] = new \DateInterval("PT$m[2]H$m[3]M$m[4]S");
- $row[$key]->f = isset($m[5]) ? (float) $m[5] : 0.0;
- $row[$key]->invert = (int) (bool) $m[1];
-
- } elseif ($type === IStructure::FIELD_UNIX_TIMESTAMP) {
- $row[$key] = (new $dateTimeClass)->setTimestamp($value);
- }
- }
-
- return $row;
- }
-
-
/**
* Import SQL dump from file - extremely fast.
* @param ?array $onProgress
* @return int count of commands
*/
- public static function loadFromFile(Connection $connection, string $file, ?callable $onProgress = null): int
+ public static function loadFromFile(Explorer $explorer, string $file, ?callable $onProgress = null): int
{
@set_time_limit(0); // @ function may be disabled
@@ -262,7 +170,7 @@ public static function loadFromFile(Connection $connection, string $file, ?calla
$count = $size = 0;
$delimiter = ';';
$sql = '';
- $pdo = $connection->getPdo(); // native query without logging
+ $connection = $explorer->getConnection(); // native query without logging
while (($s = fgets($handle)) !== false) {
$size += strlen($s);
if (!strncasecmp($s, 'DELIMITER ', 10)) {
@@ -270,7 +178,7 @@ public static function loadFromFile(Connection $connection, string $file, ?calla
} elseif (str_ends_with($ts = rtrim($s), $delimiter)) {
$sql .= substr($ts, 0, -strlen($delimiter));
- $pdo->exec($sql);
+ $connection->execute($sql);
$sql = '';
$count++;
if ($onProgress) {
@@ -282,7 +190,7 @@ public static function loadFromFile(Connection $connection, string $file, ?calla
}
if (rtrim($sql) !== '') {
- $pdo->exec($sql);
+ $connection->execute($sql);
$count++;
if ($onProgress) {
$onProgress($count, isset($stat['size']) ? 100 : null);
@@ -296,20 +204,21 @@ public static function loadFromFile(Connection $connection, string $file, ?calla
/** @deprecated use Nette\Bridges\DatabaseTracy\ConnectionPanel::initialize() */
public static function createDebugPanel(
- Connection $connection,
+ Explorer $connection,
bool $explain,
string $name,
Tracy\Bar $bar,
Tracy\BlueScreen $blueScreen,
): ?ConnectionPanel
{
+ trigger_error(__METHOD__ . '() is deprecated, use Nette\Bridges\DatabaseTracy\ConnectionPanel::initialize()', E_USER_DEPRECATED);
return ConnectionPanel::initialize($connection, true, $name, $explain, $bar, $blueScreen);
}
/** @deprecated use Nette\Bridges\DatabaseTracy\ConnectionPanel::initialize() */
public static function initializeTracy(
- Connection $connection,
+ Explorer $connection,
bool $addBarPanel = false,
string $name = '',
bool $explain = true,
@@ -317,6 +226,7 @@ public static function initializeTracy(
?Tracy\BlueScreen $blueScreen = null,
): ?ConnectionPanel
{
+ trigger_error(__METHOD__ . '() is deprecated, use Nette\Bridges\DatabaseTracy\ConnectionPanel::initialize()', E_USER_DEPRECATED);
return ConnectionPanel::initialize($connection, $addBarPanel, $name, $explain, $bar, $blueScreen);
}
@@ -365,36 +275,13 @@ public static function toPairs(array $rows, string|int|\Closure|null $key, strin
}
- /**
- * Finds duplicate columns in select statement
- */
- public static function findDuplicates(\PDOStatement $statement): string
- {
- $cols = [];
- for ($i = 0; $i < $statement->columnCount(); $i++) {
- $meta = $statement->getColumnMeta($i);
- $cols[$meta['name']][] = $meta['table'] ?? '';
- }
-
- $duplicates = [];
- foreach ($cols as $name => $tables) {
- if (count($tables) > 1) {
- $tables = array_filter(array_unique($tables));
- $duplicates[] = "'$name'" . ($tables ? ' (from ' . implode(', ', $tables) . ')' : '');
- }
- }
-
- return implode(', ', $duplicates);
- }
-
-
- /** @return array{type: string, length: ?null, scale: ?null, parameters: ?string} */
+ /** @return array{type: string, size: ?int, scale: ?int, parameters: ?string} */
public static function parseColumnType(string $type): array
{
preg_match('/^([^(]+)(?:\((?:(\d+)(?:,(\d+))?|([^)]+))\))?/', $type, $m, PREG_UNMATCHED_AS_NULL);
return [
'type' => $m[1],
- 'length' => isset($m[2]) ? (int) $m[2] : null,
+ 'size' => isset($m[2]) ? (int) $m[2] : null,
'scale' => isset($m[3]) ? (int) $m[3] : null,
'parameters' => $m[4] ?? null,
];
diff --git a/src/Database/IRow.php b/src/Database/IRow.php
deleted file mode 100644
index 8c5ab16f5..000000000
--- a/src/Database/IRow.php
+++ /dev/null
@@ -1,16 +0,0 @@
-tables);
}
@@ -67,16 +67,16 @@ private function getFullName(string $name): string
/** @internal */
- public function getDriver(): Driver
+ public function getDatabaseEngine(): Drivers\Engine
{
- return $this->driver;
+ return $this->engine;
}
private function initTables(): void
{
$res = [];
- foreach ($this->driver->getTables() as $row) {
+ foreach ($this->engine->getTables() as $row) {
$res[$row['fullName'] ?? $row['name']] = new Table($this, $row['name'], $row['view'], $row['fullName'] ?? null);
}
$this->tables = $res;
diff --git a/src/Database/Reflection/Column.php b/src/Database/Reflection/Column.php
index 48eaa87c7..acb0043e0 100644
--- a/src/Database/Reflection/Column.php
+++ b/src/Database/Reflection/Column.php
@@ -21,6 +21,7 @@ public function __construct(
public readonly ?Table $table = null,
public readonly string $nativeType = '',
public readonly ?int $size = null,
+ public readonly ?int $scale = null,
public readonly bool $nullable = false,
public readonly mixed $default = null,
public readonly bool $autoIncrement = false,
diff --git a/src/Database/Reflection/Table.php b/src/Database/Reflection/Table.php
index d4beb4cc3..948ee2e03 100644
--- a/src/Database/Reflection/Table.php
+++ b/src/Database/Reflection/Table.php
@@ -48,8 +48,9 @@ public function getColumn(string $name): Column
private function initColumns(): void
{
$res = [];
- foreach ($this->reflection->getDriver()->getColumns($this->name) as $row) {
- $res[$row['name']] = new Column($row['name'], $this, $row['nativetype'], $row['size'], $row['nullable'], $row['default'], $row['autoincrement'], $row['primary'], $row['vendor']);
+ foreach ($this->reflection->getDatabaseEngine()->getColumns($this->name) as $row) {
+ $row['table'] = $this;
+ $res[$row['name']] = new Column(...$row);
}
$this->columns = $res;
}
@@ -64,7 +65,7 @@ private function initIndexes(): void
$row['primary'],
is_string($row['name']) ? $row['name'] : null,
),
- $this->reflection->getDriver()->getIndexes($this->name),
+ $this->reflection->getDatabaseEngine()->getIndexes($this->name),
);
}
@@ -82,12 +83,12 @@ private function initPrimaryKey(): void
private function initForeignKeys(): void
{
$tmp = [];
- foreach ($this->reflection->getDriver()->getForeignKeys($this->name) as $row) {
+ foreach ($this->reflection->getDatabaseEngine()->getForeignKeys($this->name) as $row) {
$id = $row['name'];
$foreignTable = $this->reflection->getTable($row['table']);
$tmp[$id][0] = $foreignTable;
- $tmp[$id][1][] = $this->getColumn($row['local']);
- $tmp[$id][2][] = $foreignTable->getColumn($row['foreign']);
+ $tmp[$id][1] = array_map(fn($name) => $this->getColumn($name), $row['local']);
+ $tmp[$id][2] = array_map(fn($name) => $foreignTable->getColumn($name), $row['foreign']);
$tmp[$id][3] = is_string($id) ? $id : null;
}
$this->foreignKeys = array_map(fn($row) => new ForeignKey(...$row), array_values($tmp));
diff --git a/src/Database/Result.php b/src/Database/Result.php
new file mode 100644
index 000000000..3de8d3ff2
--- /dev/null
+++ b/src/Database/Result.php
@@ -0,0 +1,223 @@
+explorer;
+ }
+
+
+ public function getQuery(): SqlLiteral
+ {
+ return $this->query;
+ }
+
+
+ /** @deprecated use getQuery()->getSql() */
+ public function getQueryString(): string
+ {
+ return $this->query->getSql();
+ }
+
+
+ /** @deprecated use getQuery()->getParameters() */
+ public function getParameters(): array
+ {
+ return $this->query->getParameters();
+ }
+
+
+ public function getColumnCount(): ?int
+ {
+ return $this->result?->getColumnCount();
+ }
+
+
+ public function getRowCount(): ?int
+ {
+ return $this->result?->getRowCount();
+ }
+
+
+ public function getTime(): float
+ {
+ return $this->time;
+ }
+
+
+ /********************* misc tools ****************d*g**/
+
+
+ /**
+ * Displays complete result set as HTML table for debug purposes.
+ */
+ public function dump(): void
+ {
+ Helpers::dumpResult($this);
+ }
+
+
+ /********************* interface IteratorAggregate ****************d*g**/
+
+
+ /** @return \Generator */
+ public function getIterator(): \Generator
+ {
+ if ($this->fetched) {
+ throw new Nette\InvalidStateException(self::class . ' implements only one way iterator.');
+ }
+
+ $counter = 0;
+ while (($row = $this->fetch()) !== null) {
+ yield $counter++ => $row;
+ }
+ }
+
+
+ /********************* fetch ****************d*g**/
+
+
+ /**
+ * Returns the next row as an associative array or null if there are no more rows.
+ */
+ public function fetchAssoc(?string $path = null): ?array
+ {
+ if ($path !== null) {
+ return Arrays::associate($this->fetchAll(), $path);
+ }
+
+ $data = $this->result?->fetch();
+ if ($data === null) {
+ $this->fetched = true;
+ return null;
+
+ } elseif (!$this->fetched && count($data) !== $this->result->getColumnCount()) {
+ $duplicates = array_filter(array_count_values(array_column($this->result->getColumnsInfo(), 'name')), fn($val) => $val > 1);
+ trigger_error("Found duplicate columns in database result set: '" . implode("', '", array_keys($duplicates)) . "'.");
+ }
+
+ $this->fetched = true;
+ return $this->normalizeRow($data);
+ }
+
+
+ /**
+ * Returns the next row as an object Row or null if there are no more rows.
+ */
+ public function fetch(): ?Row
+ {
+ $data = $this->fetchAssoc();
+ return $data === null ? null : Arrays::toObject($data, new Row);
+ }
+
+
+ /**
+ * Returns the first field of the next row or null if there are no more rows.
+ */
+ public function fetchField(): mixed
+ {
+ $row = $this->fetchAssoc();
+ return $row ? reset($row) : null;
+ }
+
+
+ /**
+ * Returns the next row as indexes array or null if there are no more rows.
+ */
+ public function fetchList(): ?array
+ {
+ $row = $this->fetchAssoc();
+ return $row ? array_values($row) : null;
+ }
+
+
+ /**
+ * Alias for fetchList().
+ */
+ public function fetchFields(): ?array
+ {
+ return $this->fetchList();
+ }
+
+
+ /**
+ * Fetches all rows as associative array.
+ */
+ public function fetchPairs(string|int|\Closure|null $keyOrCallback = null, string|int|null $value = null): array
+ {
+ return Helpers::toPairs($this->fetchAll(), $keyOrCallback, $value);
+ }
+
+
+ /**
+ * Fetches all rows.
+ * @return Row[]
+ */
+ public function fetchAll(): array
+ {
+ return $this->rows ??= iterator_to_array($this);
+ }
+
+
+ private function normalizeRow(array $row): array
+ {
+ $engine = $this->explorer->getDatabaseEngine();
+ $converter = $this->explorer->getTypeConverter();
+ $columnsMeta = $this->meta ??= $this->getColumnsMeta();
+ foreach ($row as $key => $value) {
+ $row[$key] = isset($value, $columnsMeta[$key])
+ ? $engine->convertToPhp($value, $columnsMeta[$key], $converter)
+ : $value;
+ }
+
+ return $row;
+ }
+
+
+ private function getColumnsMeta(): array
+ {
+ $res = [];
+ foreach ($this->result->getColumnsInfo() as $meta) {
+ $res[$meta['name']] = $meta;
+ }
+ return $res;
+ }
+}
+
+
+class_exists(ResultSet::class);
diff --git a/src/Database/ResultSet.php b/src/Database/ResultSet.php
deleted file mode 100644
index 6c8c1cfe2..000000000
--- a/src/Database/ResultSet.php
+++ /dev/null
@@ -1,261 +0,0 @@
-normalizer = $normalizer;
- $types = ['boolean' => PDO::PARAM_BOOL, 'integer' => PDO::PARAM_INT, 'resource' => PDO::PARAM_LOB, 'NULL' => PDO::PARAM_NULL];
-
- try {
- if (str_starts_with($queryString, '::')) {
- $connection->getPdo()->{substr($queryString, 2)}();
- } else {
- $this->pdoStatement = $connection->getPdo()->prepare($queryString);
- foreach ($params as $key => $value) {
- $type = gettype($value);
- $this->pdoStatement->bindValue(is_int($key) ? $key + 1 : $key, $value, $types[$type] ?? PDO::PARAM_STR);
- }
-
- $this->pdoStatement->setFetchMode(PDO::FETCH_ASSOC);
- $this->pdoStatement->execute();
- }
- } catch (\PDOException $e) {
- $e = $connection->getDriver()->convertException($e);
- $e->queryString = $queryString;
- $e->params = $params;
- throw $e;
- }
-
- $this->time = microtime(true) - $time;
- }
-
-
- /** @deprecated */
- public function getConnection(): Connection
- {
- return $this->connection;
- }
-
-
- /**
- * @internal
- */
- public function getPdoStatement(): ?\PDOStatement
- {
- return $this->pdoStatement;
- }
-
-
- public function getQueryString(): string
- {
- return $this->queryString;
- }
-
-
- public function getParameters(): array
- {
- return $this->params;
- }
-
-
- public function getColumnCount(): ?int
- {
- return $this->pdoStatement ? $this->pdoStatement->columnCount() : null;
- }
-
-
- public function getRowCount(): ?int
- {
- return $this->pdoStatement ? $this->pdoStatement->rowCount() : null;
- }
-
-
- public function getColumnTypes(): array
- {
- $this->types ??= $this->connection->getDriver()->getColumnTypes($this->pdoStatement);
- return $this->types;
- }
-
-
- public function getTime(): float
- {
- return $this->time;
- }
-
-
- /** @internal */
- public function normalizeRow(array $row): array
- {
- return $this->normalizer
- ? ($this->normalizer)($row, $this)
- : $row;
- }
-
-
- /********************* misc tools ****************d*g**/
-
-
- /**
- * Displays complete result set as HTML table for debug purposes.
- */
- public function dump(): void
- {
- Helpers::dumpResult($this);
- }
-
-
- /********************* interface Iterator ****************d*g**/
-
-
- public function rewind(): void
- {
- if ($this->lastRow === false) {
- throw new Nette\InvalidStateException(self::class . ' implements only one way iterator.');
- }
- }
-
-
- public function current(): Row|false|null
- {
- return $this->lastRow;
- }
-
-
- public function key(): int
- {
- return $this->lastRowKey;
- }
-
-
- public function next(): void
- {
- $this->lastRow = false;
- }
-
-
- public function valid(): bool
- {
- if ($this->lastRow) {
- return true;
- }
-
- return $this->fetch() !== null;
- }
-
-
- /********************* fetch ****************d*g**/
-
-
- /**
- * Returns the next row as an associative array or null if there are no more rows.
- */
- public function fetchAssoc(?string $path = null): ?array
- {
- if ($path !== null) {
- return Arrays::associate($this->fetchAll(), $path);
- }
-
- $data = $this->pdoStatement ? $this->pdoStatement->fetch() : null;
- if (!$data) {
- $this->pdoStatement->closeCursor();
- return null;
-
- } elseif ($this->lastRow === null && count($data) !== $this->pdoStatement->columnCount()) {
- $duplicates = Helpers::findDuplicates($this->pdoStatement);
- trigger_error("Found duplicate columns in database result set: $duplicates.");
- }
-
- return $this->normalizeRow($data);
- }
-
-
- /**
- * Returns the next row as an object Row or null if there are no more rows.
- */
- public function fetch(): ?Row
- {
- $data = $this->fetchAssoc();
- if ($data === null) {
- return null;
- }
-
- $this->lastRowKey++;
- return $this->lastRow = Arrays::toObject($data, new Row);
- }
-
-
- /**
- * Fetches single field.
- */
- public function fetchField(): mixed
- {
- $row = $this->fetchAssoc();
- return $row ? reset($row) : null;
- }
-
-
- /**
- * Fetches array of fields.
- */
- public function fetchFields(): ?array
- {
- $row = $this->fetchAssoc();
- return $row ? array_values($row) : null;
- }
-
-
- /**
- * Fetches all rows as associative array.
- */
- public function fetchPairs(string|int|\Closure|null $keyOrCallback = null, string|int|null $value = null): array
- {
- return Helpers::toPairs($this->fetchAll(), $keyOrCallback, $value);
- }
-
-
- /**
- * Fetches all rows.
- * @return Row[]
- */
- public function fetchAll(): array
- {
- $this->rows ??= iterator_to_array($this);
- return $this->rows;
- }
-}
diff --git a/src/Database/Row.php b/src/Database/Row.php
index 38bad424c..b6e5bb7a4 100644
--- a/src/Database/Row.php
+++ b/src/Database/Row.php
@@ -15,7 +15,7 @@
/**
* Represents a single table row.
*/
-class Row extends Nette\Utils\ArrayHash implements IRow
+class Row extends Nette\Utils\ArrayHash
{
public function __get(mixed $key): mixed
{
@@ -62,3 +62,6 @@ public function offsetExists($key): bool
return parent::offsetExists($key);
}
}
+
+
+class_alias(Row::class, IRow::class);
diff --git a/src/Database/SqlPreprocessor.php b/src/Database/SqlPreprocessor.php
index 876ef3ca3..f9fb1d0ac 100644
--- a/src/Database/SqlPreprocessor.php
+++ b/src/Database/SqlPreprocessor.php
@@ -48,8 +48,8 @@ class SqlPreprocessor
'EXPLAIN' => 1,
];
- private readonly Connection $connection;
- private readonly Driver $driver;
+ private readonly Drivers\Connection $connection;
+ private readonly Drivers\Engine $engine;
private array $params;
private array $remaining;
private int $counter;
@@ -59,10 +59,10 @@ class SqlPreprocessor
private ?string $arrayMode;
- public function __construct(Connection $connection)
+ public function __construct(Explorer $explorer)
{
- $this->connection = $connection;
- $this->driver = $connection->getDriver();
+ $this->connection = $explorer->getConnection();
+ $this->engine = $explorer->getDatabaseEngine();
}
@@ -177,10 +177,10 @@ private function formatValue(mixed $value, ?string $mode = null): string
return $res;
} elseif ($value instanceof \DateTimeInterface) {
- return $this->driver->formatDateTime($value);
+ return $this->engine->formatDateTime($value);
} elseif ($value instanceof \DateInterval) {
- return $this->driver->formatDateInterval($value);
+ return $this->engine->formatDateInterval($value);
} elseif ($value instanceof \BackedEnum && is_scalar($value->value)) {
$this->remaining[] = $value->value;
@@ -231,7 +231,7 @@ private function formatValue(mixed $value, ?string $mode = null): string
$vx[] = implode(', ', $vx2);
}
- $select = $this->driver->isSupported(Driver::SupportMultiInsertAsSelect);
+ $select = $this->engine->isSupported(Drivers\Engine::SupportMultiInsertAsSelect);
return '(' . implode(', ', $kx) . ($select ? ') SELECT ' : ') VALUES (')
. implode($select ? ' UNION ALL SELECT ' : '), (', $vx) . ($select ? '' : ')');
}
@@ -320,6 +320,6 @@ private function formatValue(mixed $value, ?string $mode = null): string
private function delimite(string $name): string
{
- return implode('.', array_map($this->driver->delimite(...), explode('.', $name)));
+ return implode('.', array_map($this->engine->delimit(...), explode('.', $name)));
}
}
diff --git a/src/Database/Structure.php b/src/Database/Structure.php
index bd5b7a3ce..41427c684 100644
--- a/src/Database/Structure.php
+++ b/src/Database/Structure.php
@@ -14,21 +14,19 @@
/**
* Cached reflection of database structure.
+ * @internal
*/
-class Structure implements IStructure
+class Structure
{
- protected readonly Connection $connection;
- protected readonly Nette\Caching\Cache $cache;
-
/** @var array{tables: array, columns: array, primary: array, aliases: array, hasMany: array, belongsTo: array} */
protected array $structure;
protected bool $isRebuilt = false;
- public function __construct(Connection $connection, Nette\Caching\Storage $cacheStorage)
- {
- $this->connection = $connection;
- $this->cache = new Nette\Caching\Cache($cacheStorage, 'Nette.Database.Structure.' . hash('xxh128', $connection->getDsn()));
+ public function __construct(
+ protected readonly Drivers\Engine $engine,
+ protected readonly Nette\Caching\Cache $cache,
+ ) {
}
@@ -66,11 +64,11 @@ public function getPrimaryAutoincrementKey(string $table): ?string
return null;
}
- // Search for autoincrement key from multi primary key
+ // Search for autoIncrement key from multi primary key
if (is_array($primaryKey)) {
$keys = array_flip($primaryKey);
foreach ($this->getColumns($table) as $column) {
- if (isset($keys[$column['name']]) && $column['autoincrement']) {
+ if (isset($keys[$column['name']]) && $column['autoIncrement']) {
return $column['name'];
}
}
@@ -78,10 +76,10 @@ public function getPrimaryAutoincrementKey(string $table): ?string
return null;
}
- // Search for autoincrement key from simple primary key
+ // Search for auto-increment key from simple primary key
foreach ($this->getColumns($table) as $column) {
if ($column['name'] === $primaryKey) {
- return $column['autoincrement'] ? $column['name'] : null;
+ return $column['autoIncrement'] ? $column['name'] : null;
}
}
@@ -94,18 +92,18 @@ public function getPrimaryKeySequence(string $table): ?string
$this->needStructure();
$table = $this->resolveFQTableName($table);
- if (!$this->connection->getDriver()->isSupported(Driver::SupportSequence)) {
+ if (!$this->engine->isSupported(Drivers\Engine::SupportSequence)) {
return null;
}
- $autoincrementPrimaryKeyName = $this->getPrimaryAutoincrementKey($table);
- if (!$autoincrementPrimaryKeyName) {
+ $autoIncrementPrimaryKeyName = $this->getPrimaryAutoincrementKey($table);
+ if (!$autoIncrementPrimaryKeyName) {
return null;
}
// Search for sequence from simple primary key
foreach ($this->structure['columns'][$table] as $columnMeta) {
- if ($columnMeta['name'] === $autoincrementPrimaryKeyName) {
+ if ($columnMeta['name'] === $autoIncrementPrimaryKeyName) {
return $columnMeta['vendor']['sequence'] ?? null;
}
}
@@ -177,10 +175,8 @@ protected function needStructure(): void
protected function loadStructure(): array
{
- $driver = $this->connection->getDriver();
-
$structure = [];
- $structure['tables'] = $driver->getTables();
+ $structure['tables'] = $this->engine->getTables();
foreach ($structure['tables'] as $tablePair) {
if (isset($tablePair['fullName'])) {
@@ -190,7 +186,7 @@ protected function loadStructure(): array
$table = $tablePair['name'];
}
- $structure['columns'][strtolower($table)] = $columns = $driver->getColumns($table);
+ $structure['columns'][strtolower($table)] = $columns = $this->engine->getColumns($table);
if (!$tablePair['view']) {
$structure['primary'][strtolower($table)] = $this->analyzePrimaryKey($columns);
@@ -233,19 +229,13 @@ protected function analyzeForeignKeys(array &$structure, string $table): void
{
$lowerTable = strtolower($table);
- $foreignKeys = $this->connection->getDriver()->getForeignKeys($table);
-
- $fksColumnsCounts = [];
- foreach ($foreignKeys as $foreignKey) {
- $tmp = &$fksColumnsCounts[$foreignKey['name']];
- $tmp++;
- }
+ $foreignKeys = $this->engine->getForeignKeys($table);
- usort($foreignKeys, fn($a, $b): int => $fksColumnsCounts[$b['name']] <=> $fksColumnsCounts[$a['name']]);
+ usort($foreignKeys, fn($a, $b): int => count($b['local']) <=> count($a['local']));
foreach ($foreignKeys as $row) {
- $structure['belongsTo'][$lowerTable][$row['local']] = $row['table'];
- $structure['hasMany'][strtolower($row['table'])][$table][] = $row['local'];
+ $structure['belongsTo'][$lowerTable][$row['local'][0]] = $row['table'];
+ $structure['hasMany'][strtolower($row['table'])][$table][] = $row['local'][0];
}
if (isset($structure['belongsTo'][$lowerTable])) {
diff --git a/src/Database/Table/ActiveRow.php b/src/Database/Table/ActiveRow.php
index 91778c96a..268ae73ff 100644
--- a/src/Database/Table/ActiveRow.php
+++ b/src/Database/Table/ActiveRow.php
@@ -16,7 +16,7 @@
* Single row representation.
* ActiveRow is based on the great library NotORM http://www.notorm.com written by Jakub Vrana.
*/
-class ActiveRow implements \IteratorAggregate, IRow
+class ActiveRow implements \IteratorAggregate, \ArrayAccess
{
private bool $dataRefreshed = false;
@@ -61,7 +61,7 @@ public function toArray(): array
/**
* Returns primary key value.
- * @return mixed possible int, string, array, object (Nette\Utils\DateTime)
+ * @return mixed possible int, string, array, object (Nette\Database\DateTime)
*/
public function getPrimary(bool $throw = true): mixed
{
diff --git a/src/Database/Table/GroupedSelection.php b/src/Database/Table/GroupedSelection.php
index 507ac298a..fa29a86d0 100644
--- a/src/Database/Table/GroupedSelection.php
+++ b/src/Database/Table/GroupedSelection.php
@@ -10,7 +10,6 @@
namespace Nette\Database\Table;
use Nette;
-use Nette\Database\Conventions;
use Nette\Database\Explorer;
@@ -38,15 +37,13 @@ class GroupedSelection extends Selection
*/
public function __construct(
Explorer $explorer,
- Conventions $conventions,
string $tableName,
string $column,
Selection $refTable,
- ?Nette\Caching\Storage $cacheStorage = null,
) {
$this->refTable = $refTable;
$this->column = $column;
- parent::__construct($explorer, $conventions, $tableName, $cacheStorage);
+ parent::__construct($explorer, $tableName);
}
diff --git a/src/Database/Table/IRow.php b/src/Database/Table/IRow.php
deleted file mode 100644
index 1a507557f..000000000
--- a/src/Database/Table/IRow.php
+++ /dev/null
@@ -1,18 +0,0 @@
-
+ * @implements \IteratorAggregate
* @implements \ArrayAccess
*/
-class Selection implements \Iterator, IRowContainer, \ArrayAccess, \Countable
+class Selection implements \IteratorAggregate, \ArrayAccess, \Countable
{
protected readonly Explorer $explorer;
-
- /** back compatibility */
- protected Explorer $context;
- protected readonly Conventions $conventions;
protected readonly ?Nette\Caching\Cache $cache;
protected SqlBuilder $sqlBuilder;
@@ -63,27 +58,18 @@ class Selection implements \Iterator, IRowContainer, \ArrayAccess, \Countable
/** should instance observe accessed columns caching */
protected ?self $observeCache = null;
- /** of primary key values */
- protected array $keys = [];
-
/**
* Creates filtered table representation.
*/
public function __construct(
Explorer $explorer,
- Conventions $conventions,
string $tableName,
- ?Nette\Caching\Storage $cacheStorage = null,
) {
- $this->explorer = $this->context = $explorer;
- $this->conventions = $conventions;
+ $this->explorer = $explorer;
$this->name = $tableName;
-
- $this->cache = $cacheStorage
- ? new Nette\Caching\Cache($cacheStorage, 'Nette.Database.' . hash('xxh128', $explorer->getConnection()->getDsn()))
- : null;
- $this->primary = $conventions->getPrimary($tableName);
+ $this->cache = $explorer->getCache();
+ $this->primary = $explorer->getConventions()->getPrimary($tableName);
$this->sqlBuilder = new SqlBuilder($tableName, $explorer);
$this->refCache = &$this->getRefTable($refPath)->globalRefCache[$refPath];
}
@@ -528,13 +514,13 @@ protected function execute(): void
}
}
+ $key = 0;
$this->rows = [];
$usedPrimary = true;
- foreach ($result->getPdoStatement() as $key => $row) {
- $row = $this->createRow($result->normalizeRow($row));
- $primary = $row->getSignature(false);
- $usedPrimary = $usedPrimary && $primary !== '';
- $this->rows[$usedPrimary ? $primary : $key] = $row;
+ while ($row = @$result->fetchAssoc()) { // @ may contain duplicate columns
+ $row = $this->createRow($row);
+ $usedPrimary = $usedPrimary && ($primary = $row->getSignature(false)) !== '';
+ $this->rows[$usedPrimary ? $primary : $key++] = $row;
}
$this->data = $this->rows;
@@ -555,17 +541,17 @@ protected function createRow(array $row): ActiveRow
public function createSelectionInstance(?string $table = null): self
{
- return new self($this->explorer, $this->conventions, $table ?: $this->name, $this->cache?->getStorage());
+ return new self($this->explorer, $table ?: $this->name);
}
protected function createGroupedSelectionInstance(string $table, string $column): GroupedSelection
{
- return new GroupedSelection($this->explorer, $this->conventions, $table, $column, $this, $this->cache?->getStorage());
+ return new GroupedSelection($this->explorer, $table, $column, $this);
}
- protected function query(string $query): Nette\Database\ResultSet
+ protected function query(string $query): Nette\Database\Result
{
return $this->explorer->query($query, ...$this->sqlBuilder->getParameters());
}
@@ -801,7 +787,7 @@ public function insert(iterable $data): ActiveRow|array|int|bool
// First check sequence
if (!empty($primarySequenceName) && $primaryAutoincrementKey) {
- $primaryKey[$primaryAutoincrementKey] = $this->explorer->getInsertId($this->explorer->getConnection()->getDriver()->delimite($primarySequenceName));
+ $primaryKey[$primaryAutoincrementKey] = $this->explorer->getInsertId($this->explorer->getDatabaseEngine()->delimit($primarySequenceName));
// Autoincrement primary without sequence
} elseif ($primaryAutoincrementKey) {
@@ -886,7 +872,7 @@ public function delete(): int
public function getReferencedTable(ActiveRow $row, ?string $table, ?string $column = null): ActiveRow|false|null
{
if (!$column) {
- $belongsTo = $this->conventions->getBelongsToReference($this->name, $table);
+ $belongsTo = $this->explorer->getConventions()->getBelongsToReference($this->name, $table);
if (!$belongsTo) {
return false;
}
@@ -939,7 +925,7 @@ public function getReferencingTable(
if (str_contains($table, '.')) {
[$table, $column] = explode('.', $table);
} elseif (!$column) {
- $hasMany = $this->conventions->getHasManyReference($this->name, $table);
+ $hasMany = $this->explorer->getConventions()->getHasManyReference($this->name, $table);
if (!$hasMany) {
return null;
}
@@ -959,43 +945,18 @@ public function getReferencingTable(
}
- /********************* interface Iterator ****************d*g**/
+ /********************* interface IteratorAggregate ****************d*g**/
- public function rewind(): void
+ /** @return \Generator */
+ public function getIterator(): \Generator
{
$this->execute();
- $this->keys = array_keys($this->data);
- reset($this->keys);
- }
-
-
- /** @return T|false */
- public function current(): ActiveRow|false
- {
- return ($key = current($this->keys)) !== false
- ? $this->data[$key]
- : false;
- }
-
-
- public function key(): string|int
- {
- return current($this->keys);
- }
-
-
- public function next(): void
- {
- do {
- next($this->keys);
- } while (($key = current($this->keys)) !== false && !isset($this->data[$key]));
- }
-
-
- public function valid(): bool
- {
- return current($this->keys) !== false;
+ foreach ($this->data as $key => $value) {
+ if (isset($this->data[$key])) { // may be unset by offsetUnset
+ yield $key => $value;
+ }
+ }
}
diff --git a/src/Database/Table/SqlBuilder.php b/src/Database/Table/SqlBuilder.php
index 4db2d3f09..29c0182b6 100644
--- a/src/Database/Table/SqlBuilder.php
+++ b/src/Database/Table/SqlBuilder.php
@@ -11,10 +11,10 @@
use Nette;
use Nette\Database\Conventions;
-use Nette\Database\Driver;
+use Nette\Database\Drivers\Engine;
use Nette\Database\Explorer;
-use Nette\Database\IStructure;
use Nette\Database\SqlLiteral;
+use Nette\Database\Structure;
/**
@@ -46,8 +46,8 @@ class SqlBuilder
protected array $reservedTableNames = [];
protected array $aliases = [];
protected string $currentAlias = '';
- private readonly Driver $driver;
- private readonly IStructure $structure;
+ private readonly Engine $engine;
+ private readonly Structure $structure;
private array $cacheTableList = [];
private array $expandingJoins = [];
@@ -55,11 +55,11 @@ class SqlBuilder
public function __construct(string $tableName, Explorer $explorer)
{
$this->tableName = $tableName;
- $this->driver = $explorer->getConnection()->getDriver();
+ $this->engine = $explorer->getDatabaseEngine();
$this->conventions = $explorer->getConventions();
$this->structure = $explorer->getStructure();
$tableNameParts = explode('.', $tableName);
- $this->delimitedTable = implode('.', array_map($this->driver->delimite(...), $tableNameParts));
+ $this->delimitedTable = implode('.', array_map($this->engine->delimit(...), $tableNameParts));
$this->checkUniqueTableName(end($tableNameParts), $tableName);
}
@@ -78,14 +78,14 @@ public function buildInsertQuery(): string
public function buildUpdateQuery(): string
{
- $query = "UPDATE {$this->delimitedTable} SET ?set" . $this->tryDelimite($this->buildConditions());
+ $query = "UPDATE {$this->delimitedTable} SET ?set" . $this->tryDelimit($this->buildConditions());
if ($this->order !== []) {
$query .= ' ORDER BY ' . implode(', ', $this->order);
}
if ($this->limit !== null || $this->offset) {
- $this->driver->applyLimit($query, $this->limit, $this->offset);
+ $query = $this->engine->applyLimit($query, $this->limit, $this->offset);
}
return $query;
@@ -94,9 +94,9 @@ public function buildUpdateQuery(): string
public function buildDeleteQuery(): string
{
- $query = "DELETE FROM {$this->delimitedTable}" . $this->tryDelimite($this->buildConditions());
+ $query = "DELETE FROM {$this->delimitedTable}" . $this->tryDelimit($this->buildConditions());
if ($this->limit !== null || $this->offset) {
- $this->driver->applyLimit($query, $this->limit, $this->offset);
+ $query = $this->engine->applyLimit($query, $this->limit, $this->offset);
}
return $query;
@@ -119,7 +119,7 @@ public function getSelectQueryHash(?array $columns = null): string
$parts[] = $this->select;
} elseif ($columns) {
$parts[] = [$this->delimitedTable, $columns];
- } elseif ($this->group && !$this->driver->isSupported(Driver::SupportSelectUngroupedColumns)) {
+ } elseif ($this->group && !$this->engine->isSupported(Engine::SupportSelectUngroupedColumns)) {
$parts[] = [$this->group];
} else {
$parts[] = "{$this->delimitedTable}.*";
@@ -171,7 +171,7 @@ public function buildSelectQuery(?array $columns = null): string
$querySelect = $this->buildSelect($cols);
- } elseif ($this->group && !$this->driver->isSupported(Driver::SupportSelectUngroupedColumns)) {
+ } elseif ($this->group && !$this->engine->isSupported(Engine::SupportSelectUngroupedColumns)) {
$querySelect = $this->buildSelect([$this->group]);
$this->parseJoins($joins, $querySelect);
@@ -183,9 +183,9 @@ public function buildSelectQuery(?array $columns = null): string
$queryJoins = $this->buildQueryJoins($joins, $finalJoinConditions);
$query = "{$querySelect} FROM {$this->delimitedTable}{$queryJoins}{$queryCondition}{$queryEnd}";
- $this->driver->applyLimit($query, $this->limit, $this->offset);
+ $query = $this->engine->applyLimit($query, $this->limit, $this->offset);
- return $this->tryDelimite($query);
+ return $this->tryDelimit($query);
}
@@ -343,7 +343,7 @@ protected function addCondition(
}
}
- if ($this->driver->isSupported(Driver::SupportSubselect)) {
+ if ($this->engine->isSupported(Engine::SupportSubselect)) {
$arg = null;
$subSelectPlaceholderCount = substr_count($clone->getSql(), '?');
$replace = $match[2][0] . '(' . $clone->getSql() . (!$subSelectPlaceholderCount && count($clone->getSqlBuilder()->getParameters()) === 1 ? ' ?' : '') . ')';
@@ -634,7 +634,7 @@ public function parseJoinsCb(array &$joins, array $match): string
$parentAlias = preg_replace('#^(.*\.)?(.*)$#', '$2', $this->tableName);
// join schema keyMatch and table keyMatch to schema.table keyMatch
- if ($this->driver->isSupported(Driver::SupportSchema) && count($keyMatches) > 1) {
+ if ($this->engine->isSupported(Engine::SupportSchema) && count($keyMatches) > 1) {
$tables = $this->getCachedTableList();
if (
!isset($tables[$keyMatches[0]['key']])
@@ -789,13 +789,13 @@ protected function buildQueryEnd(): string
}
- protected function tryDelimite(string $s): string
+ protected function tryDelimit(string $s): string
{
return preg_replace_callback(
'#(?<=[^\w`"\[?:]|^)[a-z_][a-z0-9_]*(?=[^\w`"(\]]|$)#Di',
fn(array $m): string => strtoupper($m[0]) === $m[0]
? $m[0]
- : $this->driver->delimite($m[0]),
+ : $this->engine->delimit($m[0]),
$s,
);
}
@@ -808,7 +808,7 @@ protected function addConditionComposition(
array &$conditionsParameters,
): bool
{
- if ($this->driver->isSupported(Driver::SupportMultiColumnAsOrCond)) {
+ if ($this->engine->isSupported(Engine::SupportMultiColumnAsOrCondition)) {
$conditionFragment = '(' . implode(' = ? AND ', $columns) . ' = ?) OR ';
$condition = substr(str_repeat($conditionFragment, count($parameters)), 0, -4);
return $this->addCondition($condition, [Nette\Utils\Arrays::flatten($parameters)], $conditions, $conditionsParameters);
diff --git a/src/Database/TypeConverter.php b/src/Database/TypeConverter.php
new file mode 100644
index 000000000..78d5edc2c
--- /dev/null
+++ b/src/Database/TypeConverter.php
@@ -0,0 +1,119 @@
+ self::Text, // PostgreSQL arrays
+ '(TINY|SMALL|SHORT|MEDIUM|BIG|LONG)(INT)?|INT(EGER|\d+| IDENTITY| UNSIGNED)?|(SMALL|BIG|)SERIAL\d*|COUNTER|YEAR|BYTE|LONGLONG|UNSIGNED BIG INT' => self::Integer,
+ '(NEW)?DEC(IMAL)?(\(.*)?|NUMERIC|(SMALL)?MONEY|CURRENCY|NUMBER' => self::Decimal,
+ 'REAL|DOUBLE( PRECISION)?|FLOAT\d*' => self::Float,
+ 'BOOL(EAN)?' => self::Boolean,
+ 'TIME' => self::Time,
+ 'DATE' => self::Date,
+ '(SMALL)?DATETIME(OFFSET)?\d*|TIME(STAMP.*)?' => self::DateTime,
+ 'BYTEA|(TINY|MEDIUM|LONG|)BLOB|(LONG )?(VAR)?BINARY|IMAGE' => self::Binary,
+ ];
+
+ public bool $convertBoolean = true;
+ public bool $convertDateTime = true;
+ public bool $convertDecimal = true;
+ public bool $newDateTime = true;
+
+
+ /**
+ * Heuristic column type detection.
+ */
+ private function detectType(string $nativeType): int
+ {
+ static $cache;
+ if (!isset($cache[$nativeType])) {
+ $cache[$nativeType] = self::Text;
+ foreach (self::Patterns as $s => $val) {
+ if (preg_match("#^($s)$#i", $nativeType)) {
+ return $cache[$nativeType] = $val;
+ }
+ }
+ }
+
+ return $cache[$nativeType];
+ }
+
+
+ public function convertToPhp(mixed $value, array $meta): mixed
+ {
+ return match ($this->detectType($meta['nativeType'] ?? '')) {
+ self::Integer => $this->toInt($value),
+ self::Float => $this->toFloat($value),
+ self::Decimal => $this->convertDecimal
+ ? ($meta['scale'] === 0 ? $this->toInt($value) : $this->toFloat($value))
+ : $value,
+ self::Boolean => $this->convertBoolean ? $this->toBool($value) : $value,
+ self::DateTime, self::Date => $this->convertDateTime ? $this->toDateTime($value) : $value,
+ self::Time => $this->convertDateTime ? $this->toTime($value) : $value,
+ self::Interval => $this->convertDateTime ? self::toInterval($value) : $value,
+ default => $value,
+ };
+ }
+
+
+ public function toInt(int|float|string $value): int|float|string
+ {
+ return is_float($tmp = $value * 1) ? $value : $tmp;
+ }
+
+
+ public function toFloat(float|string $value): float
+ {
+ return (float) $value;
+ }
+
+
+ public function toBool(bool|int|string $value): bool
+ {
+ return (bool) $value;
+ }
+
+
+ public function toDateTime(string $value): \DateTimeInterface
+ {
+ return $this->newDateTime ? new DateTime($value) : new \Nette\Utils\DateTime($value);
+ }
+
+
+ public function toTime(string $value): \DateTimeInterface
+ {
+ return $this->toDateTime($value)->setDate(1, 1, 1);
+ }
+
+
+ public function toInterval(string $value): \DateInterval
+ {
+ preg_match('#^(-?)(\d+)\D(\d+)\D(\d+)(\.\d+)?$#D', $value, $m);
+ $interval = new \DateInterval("PT$m[2]H$m[3]M$m[4]S");
+ $interval->f = isset($m[5]) ? (float) $m[5] : 0.0;
+ $interval->invert = (int) (bool) $m[1];
+ return $interval;
+ }
+}
diff --git a/src/compatibility-intf.php b/src/compatibility-intf.php
deleted file mode 100644
index fe3ab8558..000000000
--- a/src/compatibility-intf.php
+++ /dev/null
@@ -1,28 +0,0 @@
-initialize();
- $connection = $container->getService('database.default');
- Assert::type(Nette\Database\Connection::class, $connection);
- Assert::same('sqlite::memory:', $connection->getDsn());
-
- $explorer = $container->getService('database.default.explorer');
+ $explorer = $container->getService('database.default');
Assert::type(Nette\Database\Explorer::class, $explorer);
- Assert::same($connection, $explorer->getConnection());
- Assert::same($container->getService('database.default.context'), $explorer);
-
- Assert::type(Nette\Database\Structure::class, $explorer->getStructure());
- Assert::type(Nette\Database\Conventions\DiscoveredConventions::class, $explorer->getConventions());
+ Assert::type(Nette\Caching\Cache::class, $explorer->getCache());
// aliases
- Assert::same($connection, $container->getService('nette.database.default'));
+ Assert::same($explorer, $container->getService('database.default.explorer'));
+ Assert::same($explorer, $container->getService('nette.database.default'));
Assert::same($explorer, $container->getService('nette.database.default.context'));
});
diff --git a/tests/Database.DI/DatabaseExtension.multiple.phpt b/tests/Database.DI/DatabaseExtension.multiple.phpt
index 463349587..e808b5337 100644
--- a/tests/Database.DI/DatabaseExtension.multiple.phpt
+++ b/tests/Database.DI/DatabaseExtension.multiple.phpt
@@ -23,16 +23,12 @@ test('', function () {
user: name
password: secret
debugger: no
- options:
- lazy: yes
second:
dsn: "sqlite::memory:"
user: name
password: secret
debugger: no
- options:
- lazy: yes
services:
cache: Nette\Caching\Storages\DevNullStorage
@@ -45,23 +41,13 @@ test('', function () {
$container = new Container1;
$container->initialize();
- $connection = $container->getService('database.first');
- Assert::type(Nette\Database\Connection::class, $connection);
- Assert::same($connection, $container->getByType(Nette\Database\Connection::class));
- Assert::same('sqlite::memory:', $connection->getDsn());
-
- $explorer = $container->getService('database.first.explorer');
+ $explorer = $container->getService('database.first');
Assert::type(Nette\Database\Explorer::class, $explorer);
Assert::same($explorer, $container->getByType(Nette\Database\Explorer::class));
- Assert::same($connection, $explorer->getConnection());
- Assert::same($container->getService('database.first.context'), $explorer);
-
- Assert::type(Nette\Database\Structure::class, $explorer->getStructure());
- Assert::same($explorer->getStructure(), $container->getByType(Nette\Database\IStructure::class));
- Assert::type(Nette\Database\Conventions\DiscoveredConventions::class, $explorer->getConventions());
- Assert::same($explorer->getConventions(), $container->getByType(Nette\Database\Conventions::class));
+ Assert::type(Nette\Caching\Cache::class, $explorer->getCache());
// aliases
- Assert::same($connection, $container->getService('nette.database.first'));
+ Assert::same($explorer, $container->getService('database.first.explorer'));
+ Assert::same($explorer, $container->getService('nette.database.first'));
Assert::same($explorer, $container->getService('nette.database.first.context'));
});
diff --git a/tests/Database.Tracy/ConnectionPanel.phpt b/tests/Database.Tracy/ConnectionPanel.phpt
index 4dba1b30c..42374a537 100644
--- a/tests/Database.Tracy/ConnectionPanel.phpt
+++ b/tests/Database.Tracy/ConnectionPanel.phpt
@@ -15,7 +15,7 @@ require __DIR__ . '/../bootstrap.php';
test('Tracy Bar', function () {
$connection = new Connection('sqlite::memory:');
- $panel = ConnectionPanel::initialize($connection, addBarPanel: true, name: 'foo');
+ $panel = ConnectionPanel::initialize($connection, name: 'foo');
$connection->beginTransaction();
$connection->query('SELECT 1');
@@ -47,7 +47,7 @@ test('Bluescreen Panel', function () {
test('deprecated initialization', function () {
$connection = new Connection('sqlite::memory:');
- $panel = Nette\Database\Helpers::initializeTracy($connection, addBarPanel: true, name: 'foo');
+ $panel = @Nette\Database\Helpers::initializeTracy($connection, addBarPanel: true, name: 'foo'); // deprecated
$connection->beginTransaction();
$connection->query('SELECT 1');
diff --git a/tests/Database.Tracy/panel.html b/tests/Database.Tracy/panel.html
index 1ec032563..3722349a9 100644
--- a/tests/Database.Tracy/panel.html
+++ b/tests/Database.Tracy/panel.html
@@ -1,26 +1,26 @@
%A%
-Queries: 4, time: %a% ms, foo
+Queries: 4, time: %a% ms, foo
diff --git a/tests/Database/Connection.exceptions.mysql.phpt b/tests/Database/Connection.exceptions.mysql.phpt
index 1d60d5adc..8d8346638 100644
--- a/tests/Database/Connection.exceptions.mysql.phpt
+++ b/tests/Database/Connection.exceptions.mysql.phpt
@@ -11,20 +11,18 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
test('Exception thrown for invalid database credentials', function () {
$options = Tester\Environment::loadData();
$e = Assert::exception(
- fn() => new Nette\Database\Connection($options['dsn'], 'unknown', 'unknown'),
+ fn() => (new Nette\Database\Explorer($options['dsn'], 'unknown', 'unknown'))->connect(),
Nette\Database\ConnectionException::class,
'%a% Access denied for user %a%',
+ 1045,
);
-
- Assert::same(1045, $e->getDriverCode());
Assert::contains($e->getSqlState(), ['HY000', '28000']);
- Assert::same($e->getCode(), $e->getSqlState());
});
@@ -35,7 +33,7 @@ test('Exception thrown when calling rollback with no active transaction', functi
'There is no active transaction',
0,
);
- Assert::same(null, $e->getDriverCode());
+ Assert::null($e->getSqlState());
});
@@ -44,11 +42,9 @@ test('Exception thrown for syntax error in SQL query', function () use ($connect
fn() => $connection->query('SELECT'),
Nette\Database\DriverException::class,
'%a% Syntax error %a%',
- '42000',
+ 1064,
);
-
- Assert::same(1064, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('42000', $e->getSqlState());
});
@@ -57,11 +53,9 @@ test('Exception thrown for unique constraint violation', function () use ($conne
fn() => $connection->query('INSERT INTO author (id, name, web, born) VALUES (11, "", "", NULL)'),
Nette\Database\UniqueConstraintViolationException::class,
'%a% Integrity constraint violation: %a%',
- '23000',
+ 1062,
);
-
- Assert::same(1062, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('23000', $e->getSqlState());
});
@@ -70,11 +64,9 @@ test('Exception thrown for not null constraint violation', function () use ($con
fn() => $connection->query('INSERT INTO author (name, web, born) VALUES (NULL, "", NULL)'),
Nette\Database\NotNullConstraintViolationException::class,
'%a% Integrity constraint violation: %a%',
- '23000',
+ 1048,
);
-
- Assert::same(1048, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('23000', $e->getSqlState());
});
@@ -83,9 +75,7 @@ test('Exception thrown for foreign key constraint violation', function () use ($
fn() => $connection->query('INSERT INTO book (author_id, translator_id, title) VALUES (999, 12, "")'),
Nette\Database\ForeignKeyConstraintViolationException::class,
'%a% a foreign key constraint fails %a%',
- '23000',
+ 1452,
);
-
- Assert::same(1452, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('23000', $e->getSqlState());
});
diff --git a/tests/Database/Connection.exceptions.phpt b/tests/Database/Connection.exceptions.phpt
deleted file mode 100644
index 8efbc2871..000000000
--- a/tests/Database/Connection.exceptions.phpt
+++ /dev/null
@@ -1,22 +0,0 @@
- new Nette\Database\Connection('unknown'),
- Nette\Database\ConnectionException::class,
- '%a%valid data source %a%',
- 0,
-);
-
-Assert::same(null, $e->getDriverCode());
-Assert::same(null, $e->getSqlState());
diff --git a/tests/Database/Connection.exceptions.postgre.phpt b/tests/Database/Connection.exceptions.postgre.phpt
index 717245d38..8fe0f5a05 100644
--- a/tests/Database/Connection.exceptions.postgre.phpt
+++ b/tests/Database/Connection.exceptions.postgre.phpt
@@ -11,21 +11,19 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
test('Exception thrown for invalid database credentials', function () {
$options = Tester\Environment::loadData();
$e = Assert::exception(
- fn() => new Nette\Database\Connection($options['dsn'], 'unknown', 'unknown'),
+ fn() => (new Nette\Database\Explorer($options['dsn'], 'unknown', 'unknown'))->connect(),
Nette\Database\ConnectionException::class,
null,
- '08006',
+ 7,
);
-
- Assert::same(7, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('08006', $e->getSqlState());
});
@@ -36,8 +34,7 @@ test('Exception thrown when calling rollback with no active transaction', functi
'There is no active transaction',
0,
);
-
- Assert::same(null, $e->getDriverCode());
+ Assert::null($e->getSqlState());
});
@@ -46,11 +43,9 @@ test('Exception thrown for syntax error in SQL query', function () use ($connect
fn() => $connection->query('SELECT INTO'),
Nette\Database\DriverException::class,
'%a% syntax error %A%',
- '42601',
+ 7,
);
-
- Assert::same(7, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('42601', $e->getSqlState());
});
@@ -59,11 +54,9 @@ test('Exception thrown for unique constraint violation', function () use ($conne
fn() => $connection->query("INSERT INTO author (id, name, web, born) VALUES (11, '', '', NULL)"),
Nette\Database\UniqueConstraintViolationException::class,
'%a% Unique violation: %A%',
- '23505',
+ 7,
);
-
- Assert::same(7, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('23505', $e->getSqlState());
});
@@ -72,11 +65,9 @@ test('Exception thrown for not null constraint violation', function () use ($con
fn() => $connection->query("INSERT INTO author (name, web, born) VALUES (NULL, '', NULL)"),
Nette\Database\NotNullConstraintViolationException::class,
'%a% Not null violation: %A%',
- '23502',
+ 7,
);
-
- Assert::same(7, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('23502', $e->getSqlState());
});
@@ -85,9 +76,7 @@ test('Exception thrown for foreign key constraint violation', function () use ($
fn() => $connection->query("INSERT INTO book (author_id, translator_id, title) VALUES (999, 12, '')"),
Nette\Database\ForeignKeyConstraintViolationException::class,
'%a% Foreign key violation: %A%',
- '23503',
+ 7,
);
-
- Assert::same(7, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('23503', $e->getSqlState());
});
diff --git a/tests/Database/Connection.exceptions.sqlite.phpt b/tests/Database/Connection.exceptions.sqlite.phpt
index dbd66d5cb..12d41bbc5 100644
--- a/tests/Database/Connection.exceptions.sqlite.phpt
+++ b/tests/Database/Connection.exceptions.sqlite.phpt
@@ -11,20 +11,18 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
test('Exception thrown for unable to open database file', function () {
$e = Assert::exception(
- fn() => new Nette\Database\Connection('sqlite:.'),
+ fn() => (new Nette\Database\Explorer('sqlite:.'))->connect(),
Nette\Database\ConnectionException::class,
'SQLSTATE[HY000] [14] unable to open database file',
- 'HY000',
+ 14,
);
-
- Assert::same(14, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('HY000', $e->getSqlState());
});
@@ -35,8 +33,7 @@ test('Exception thrown when calling rollback with no active transaction', functi
'There is no active transaction',
0,
);
-
- Assert::same(null, $e->getDriverCode());
+ Assert::null($e->getSqlState());
});
@@ -45,11 +42,9 @@ test('Exception thrown for error in SQL query', function () use ($connection) {
fn() => $connection->query('SELECT'),
Nette\Database\DriverException::class,
'%a% error%a%',
- 'HY000',
+ 1,
);
-
- Assert::same(1, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('HY000', $e->getSqlState());
});
@@ -58,11 +53,9 @@ test('Exception thrown for unique constraint violation', function () use ($conne
fn() => $connection->query('INSERT INTO author (id, name, web, born) VALUES (11, "", "", NULL)'),
Nette\Database\UniqueConstraintViolationException::class,
'%a% Integrity constraint violation: %a%',
- '23000',
+ 19,
);
-
- Assert::same(19, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('23000', $e->getSqlState());
});
@@ -71,11 +64,9 @@ test('Exception thrown for not null constraint violation', function () use ($con
fn() => $connection->query('INSERT INTO author (name, web, born) VALUES (NULL, "", NULL)'),
Nette\Database\NotNullConstraintViolationException::class,
'%a% Integrity constraint violation: %a%',
- '23000',
+ 19,
);
-
- Assert::same(19, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ Assert::same('23000', $e->getSqlState());
});
@@ -83,8 +74,6 @@ test('Exception thrown for foreign key constraint violation', function () use ($
$e = Assert::exception(function () use ($connection) {
$connection->query('PRAGMA foreign_keys=true');
$connection->query('INSERT INTO book (author_id, translator_id, title) VALUES (999, 12, "")');
- }, Nette\Database\ForeignKeyConstraintViolationException::class, '%a% Integrity constraint violation: %a%', '23000');
-
- Assert::same(19, $e->getDriverCode());
- Assert::same($e->getCode(), $e->getSqlState());
+ }, Nette\Database\ForeignKeyConstraintViolationException::class, '%a% Integrity constraint violation: %a%', 19);
+ Assert::same('23000', $e->getSqlState());
});
diff --git a/tests/Database/Connection.fetch.phpt b/tests/Database/Connection.fetch.phpt
index 745d76c80..0d1bffaf6 100644
--- a/tests/Database/Connection.fetch.phpt
+++ b/tests/Database/Connection.fetch.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
@@ -39,8 +39,8 @@ test('fetchField', function () use ($connection) {
});
-test('fetchFields', function () use ($connection) {
- Assert::same([11, 'Jakub Vrana'], $connection->fetchFields('SELECT id, name FROM author ORDER BY id'));
+test('fetchList', function () use ($connection) {
+ Assert::same([11, 'Jakub Vrana'], $connection->fetchList('SELECT id, name FROM author ORDER BY id'));
});
diff --git a/tests/Database/Connection.getInsertId().mysql.phpt b/tests/Database/Connection.getInsertId().mysql.phpt
index 020ef596c..ffd7a71ff 100644
--- a/tests/Database/Connection.getInsertId().mysql.phpt
+++ b/tests/Database/Connection.getInsertId().mysql.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
$connection->query('
CREATE TEMPORARY TABLE noprimarykey (
@@ -19,11 +19,11 @@ $connection->query('
) ENGINE=InnoDB
');
-$connection->query('INSERT INTO noprimarykey (col) VALUES (NULL)');
-Assert::same('0', $connection->getInsertId());
-
$connection->query('INSERT INTO noprimarykey (col) VALUES (3)');
-Assert::same('0', $connection->getInsertId());
+Assert::exception(
+ fn() => $connection->getInsertId(),
+ Nette\Database\DriverException::class,
+);
$connection->query('
@@ -34,10 +34,10 @@ $connection->query('
');
$connection->query('INSERT INTO primarykey (prim) VALUES (5)');
-Assert::same('0', $connection->getInsertId());
-
-$connection->query('INSERT INTO primarykey (prim) VALUES (6)');
-Assert::same('0', $connection->getInsertId());
+Assert::exception(
+ fn() => $connection->getInsertId(),
+ Nette\Database\DriverException::class,
+);
$connection->query('
@@ -49,13 +49,13 @@ $connection->query('
');
$connection->query('INSERT INTO autoprimarykey (col) VALUES (NULL)');
-Assert::same('1', $connection->getInsertId());
+Assert::same(1, $connection->getInsertId());
$connection->query('INSERT INTO autoprimarykey (col) VALUES (NULL)');
-Assert::same('2', $connection->getInsertId());
+Assert::same(2, $connection->getInsertId());
$connection->query('INSERT INTO autoprimarykey (prim, col) VALUES (10, NULL)');
-Assert::same('10', $connection->getInsertId());
+Assert::same(10, $connection->getInsertId());
$connection->query('
@@ -67,10 +67,10 @@ $connection->query('
');
$connection->query('INSERT INTO multiautoprimarykey (prim2) VALUES (3)');
-Assert::same('1', $connection->getInsertId());
+Assert::same(1, $connection->getInsertId());
$connection->query('INSERT INTO multiautoprimarykey (prim2) VALUES (3)');
-Assert::same('2', $connection->getInsertId());
+Assert::same(2, $connection->getInsertId());
$connection->query('INSERT INTO multiautoprimarykey (prim1, prim2) VALUES (10, 3)');
-Assert::same('10', $connection->getInsertId());
+Assert::same(10, $connection->getInsertId());
diff --git a/tests/Database/Connection.getInsertId().postgre.phpt b/tests/Database/Connection.getInsertId().postgre.phpt
index 5c0a65c1c..41e2f10d5 100644
--- a/tests/Database/Connection.getInsertId().postgre.phpt
+++ b/tests/Database/Connection.getInsertId().postgre.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
$connection->query('
CREATE TEMPORARY TABLE "primarykey" (
@@ -36,13 +36,13 @@ $connection->query('
');
$connection->query('INSERT INTO autoprimarykey (col) VALUES (NULL)');
-Assert::same('1', $connection->getInsertId('autoprimarykey_prim_seq'));
+Assert::same(1, $connection->getInsertId('autoprimarykey_prim_seq'));
$connection->query('INSERT INTO autoprimarykey (col) VALUES (NULL)');
-Assert::same('2', $connection->getInsertId('autoprimarykey_prim_seq'));
+Assert::same(2, $connection->getInsertId('autoprimarykey_prim_seq'));
$connection->query('INSERT INTO autoprimarykey (prim, col) VALUES (10, NULL)');
-Assert::same('2', $connection->getInsertId('autoprimarykey_prim_seq'));
+Assert::same(2, $connection->getInsertId('autoprimarykey_prim_seq'));
$connection->query('
@@ -54,10 +54,10 @@ $connection->query('
');
$connection->query('INSERT INTO multiautoprimarykey (prim2) VALUES (3)');
-Assert::same('1', $connection->getInsertId('multiautoprimarykey_prim1_seq'));
+Assert::same(1, $connection->getInsertId('multiautoprimarykey_prim1_seq'));
$connection->query('INSERT INTO multiautoprimarykey (prim2) VALUES (3)');
-Assert::same('2', $connection->getInsertId('multiautoprimarykey_prim1_seq'));
+Assert::same(2, $connection->getInsertId('multiautoprimarykey_prim1_seq'));
$connection->query('INSERT INTO multiautoprimarykey (prim1, prim2) VALUES (10, 3)');
-Assert::same('2', $connection->getInsertId('multiautoprimarykey_prim1_seq'));
+Assert::same(2, $connection->getInsertId('multiautoprimarykey_prim1_seq'));
diff --git a/tests/Database/Connection.getInsertId().sqlite.phpt b/tests/Database/Connection.getInsertId().sqlite.phpt
index 26f57ac46..131431fca 100644
--- a/tests/Database/Connection.getInsertId().sqlite.phpt
+++ b/tests/Database/Connection.getInsertId().sqlite.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
$connection->query('
CREATE TABLE [noprimarykey] (
@@ -20,10 +20,10 @@ $connection->query('
');
$connection->query('INSERT INTO noprimarykey (col) VALUES (NULL)');
-Assert::same('1', $connection->getInsertId());
+Assert::same(1, $connection->getInsertId());
$connection->query('INSERT INTO noprimarykey (col) VALUES (3)');
-Assert::same('2', $connection->getInsertId());
+Assert::same(2, $connection->getInsertId());
$connection->query('
@@ -33,10 +33,10 @@ $connection->query('
');
$connection->query('INSERT INTO primarykey (prim) VALUES (5)');
-Assert::same('5', $connection->getInsertId());
+Assert::same(5, $connection->getInsertId());
$connection->query('INSERT INTO primarykey (prim) VALUES (6)');
-Assert::same('6', $connection->getInsertId());
+Assert::same(6, $connection->getInsertId());
$connection->query('
@@ -47,10 +47,10 @@ $connection->query('
');
$connection->query('INSERT INTO autoprimarykey (col) VALUES (NULL)');
-Assert::same('1', $connection->getInsertId());
+Assert::same(1, $connection->getInsertId());
$connection->query('INSERT INTO autoprimarykey (col) VALUES (NULL)');
-Assert::same('2', $connection->getInsertId());
+Assert::same(2, $connection->getInsertId());
$connection->query('INSERT INTO autoprimarykey (prim, col) VALUES (10, NULL)');
-Assert::same('10', $connection->getInsertId());
+Assert::same(10, $connection->getInsertId());
diff --git a/tests/Database/Connection.getInsertId().sqlsrv.phpt b/tests/Database/Connection.getInsertId().sqlsrv.phpt
index e971245c7..627fa45d0 100644
--- a/tests/Database/Connection.getInsertId().sqlsrv.phpt
+++ b/tests/Database/Connection.getInsertId().sqlsrv.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
$connection->query("IF OBJECT_ID('noprimarykey', 'U') IS NOT NULL DROP TABLE noprimarykey");
$connection->query('
@@ -21,10 +21,10 @@ $connection->query('
');
$connection->query('INSERT INTO noprimarykey (col) VALUES (NULL)');
-Assert::same('', $connection->getInsertId());
-
-$connection->query('INSERT INTO noprimarykey (col) VALUES (NULL)');
-Assert::same('', $connection->getInsertId());
+Assert::exception(
+ fn() => $connection->getInsertId(),
+ Nette\Database\DriverException::class,
+);
$connection->query("IF OBJECT_ID('primarykey', 'U') IS NOT NULL DROP TABLE primarykey");
@@ -36,10 +36,10 @@ $connection->query('
');
$connection->query('INSERT INTO primarykey (prim) VALUES (5)');
-Assert::same('', $connection->getInsertId());
-
-$connection->query('INSERT INTO primarykey (prim) VALUES (6)');
-Assert::same('', $connection->getInsertId());
+Assert::exception(
+ fn() => $connection->getInsertId(),
+ Nette\Database\DriverException::class,
+);
$connection->query("IF OBJECT_ID('autoprimarykey', 'U') IS NOT NULL DROP TABLE autoprimarykey");
@@ -52,13 +52,13 @@ $connection->query('
');
$connection->query('INSERT INTO autoprimarykey (col) VALUES (NULL)');
-Assert::same('1', $connection->getInsertId());
+Assert::same(1, $connection->getInsertId());
$connection->query('INSERT INTO autoprimarykey (col) VALUES (NULL)');
-Assert::same('2', $connection->getInsertId());
+Assert::same(2, $connection->getInsertId());
$connection->query('SET IDENTITY_INSERT autoprimarykey ON; INSERT INTO autoprimarykey (prim, col) VALUES (10, NULL)');
-Assert::same('10', $connection->getInsertId());
+Assert::same(10, $connection->getInsertId());
$connection->query("IF OBJECT_ID('multiautoprimarykey', 'U') IS NOT NULL DROP TABLE multiautoprimarykey");
@@ -71,10 +71,10 @@ $connection->query('
');
$connection->query('INSERT INTO multiautoprimarykey (prim2) VALUES (3)');
-Assert::same('1', $connection->getInsertId());
+Assert::same(1, $connection->getInsertId());
$connection->query('INSERT INTO multiautoprimarykey (prim2) VALUES (3)');
-Assert::same('2', $connection->getInsertId());
+Assert::same(2, $connection->getInsertId());
$connection->query('SET IDENTITY_INSERT multiautoprimarykey ON; INSERT INTO multiautoprimarykey (prim1, prim2) VALUES (10, 3)');
-Assert::same('10', $connection->getInsertId());
+Assert::same(10, $connection->getInsertId());
diff --git a/tests/Database/Connection.preprocess.phpt b/tests/Database/Connection.preprocess.phpt
index 5f8cd5547..1a59e3f80 100644
--- a/tests/Database/Connection.preprocess.phpt
+++ b/tests/Database/Connection.preprocess.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Assert::same(['SELECT name FROM author', []], $connection->preprocess('SELECT name FROM author'));
diff --git a/tests/Database/Connection.query.phpt b/tests/Database/Connection.query.phpt
index 1a1d60ce0..7e4633b61 100644
--- a/tests/Database/Connection.query.phpt
+++ b/tests/Database/Connection.query.phpt
@@ -11,28 +11,28 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
test('', function () use ($connection) {
$res = $connection->query('SELECT id FROM author WHERE id = ?', 11);
- Assert::type(Nette\Database\ResultSet::class, $res);
- Assert::same('SELECT id FROM author WHERE id = ?', $res->getQueryString());
- Assert::same([11], $res->getParameters());
- Assert::same('SELECT id FROM author WHERE id = ?', $connection->getLastQueryString());
+ Assert::type(Nette\Database\Result::class, $res);
+ Assert::same('SELECT id FROM author WHERE id = ?', $res->getQuery()->getSql());
+ Assert::same([11], $res->getQuery()->getParameters());
+ Assert::same('SELECT id FROM author WHERE id = ?', $connection->getLastQuery()->getSql());
});
test('', function () use ($connection) {
$res = $connection->query('SELECT id FROM author WHERE id = ? OR id = ?', 11, 12);
- Assert::same('SELECT id FROM author WHERE id = ? OR id = ?', $res->getQueryString());
- Assert::same([11, 12], $res->getParameters());
+ Assert::same('SELECT id FROM author WHERE id = ? OR id = ?', $res->getQuery()->getSql());
+ Assert::same([11, 12], $res->getQuery()->getParameters());
});
test('', function () use ($connection) {
- $res = $connection->queryArgs('SELECT id FROM author WHERE id = ? OR id = ?', [11, 12]);
- Assert::same('SELECT id FROM author WHERE id = ? OR id = ?', $res->getQueryString());
- Assert::same([11, 12], $res->getParameters());
+ $res = @$connection->queryArgs('SELECT id FROM author WHERE id = ? OR id = ?', [11, 12]); // is deprecated
+ Assert::same('SELECT id FROM author WHERE id = ? OR id = ?', $res->getQuery()->getSql());
+ Assert::same([11, 12], $res->getQuery()->getParameters());
});
diff --git a/tests/Database/Connection.transaction.phpt b/tests/Database/Connection.transaction.phpt
index 91d6f6fdc..26a3fc9bc 100644
--- a/tests/Database/Connection.transaction.phpt
+++ b/tests/Database/Connection.transaction.phpt
@@ -7,12 +7,12 @@
declare(strict_types=1);
-use Nette\Database\Connection;
+use Nette\Database\Explorer;
use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
@@ -27,7 +27,7 @@ test('', function () use ($connection) {
test('', function () use ($connection) {
Assert::exception(
- fn() => $connection->transaction(function (Connection $connection) {
+ fn() => $connection->transaction(function (Explorer $connection) {
$connection->query('DELETE FROM book');
throw new Exception('my exception');
}),
@@ -52,13 +52,13 @@ test('nested transaction() call fail', function () use ($connection) {
$base = (int) $connection->query('SELECT COUNT(*) AS cnt FROM author')->fetchField();
Assert::exception(
- fn() => $connection->transaction(function (Connection $connection) {
+ fn() => $connection->transaction(function (Explorer $connection) {
$connection->query('INSERT INTO author', [
'name' => 'A',
'web' => '',
]);
- $connection->transaction(function (Connection $connection2) {
+ $connection->transaction(function (Explorer $connection2) {
$connection2->query('INSERT INTO author', [
'name' => 'B',
'web' => '',
@@ -77,7 +77,7 @@ test('nested transaction() call fail', function () use ($connection) {
test('nested transaction() call success', function () use ($connection) {
$base = (int) $connection->query('SELECT COUNT(*) AS cnt FROM author')->fetchField();
- $connection->transaction(function (Connection $connection) {
+ $connection->transaction(function (Explorer $connection) {
$connection->query('INSERT INTO author', [
'name' => 'A',
'web' => '',
@@ -97,18 +97,18 @@ test('beginTransaction(), commit() & rollBack() calls are forbidden in transacti
Assert::exception(
fn() => $connection->transaction(fn() => $connection->beginTransaction()),
LogicException::class,
- Connection::class . '::beginTransaction() call is forbidden inside a transaction() callback',
+ Explorer::class . '::beginTransaction() call is forbidden inside a transaction() callback',
);
Assert::exception(
fn() => $connection->transaction(fn() => $connection->commit()),
LogicException::class,
- Connection::class . '::commit() call is forbidden inside a transaction() callback',
+ Explorer::class . '::commit() call is forbidden inside a transaction() callback',
);
Assert::exception(
fn() => $connection->transaction(fn() => $connection->rollBack()),
LogicException::class,
- Connection::class . '::rollBack() call is forbidden inside a transaction() callback',
+ Explorer::class . '::rollBack() call is forbidden inside a transaction() callback',
);
});
diff --git a/tests/Database/Conventions/DiscoveredConventions.getBelongsToReference().phpt b/tests/Database/Conventions/DiscoveredConventions.getBelongsToReference().phpt
index 7234910f3..5b3ec9430 100644
--- a/tests/Database/Conventions/DiscoveredConventions.getBelongsToReference().phpt
+++ b/tests/Database/Conventions/DiscoveredConventions.getBelongsToReference().phpt
@@ -13,7 +13,7 @@ require __DIR__ . '/../../bootstrap.php';
test('basic test', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('getBelongsToReference')->with('books')->andReturn([
'author_id' => 'authors',
'translator_id' => 'authors',
@@ -26,7 +26,7 @@ test('basic test', function () {
});
test('basic test', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('getBelongsToReference')->with('public.books')->andReturn([
'author_id' => 'public.authors',
'translator_id' => 'public.authors',
@@ -39,7 +39,7 @@ test('basic test', function () {
});
test('tests order of table columns with foreign keys', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('getBelongsToReference')->with('books')->andReturn([
'translator_id' => 'authors',
'author_id' => 'authors',
@@ -52,7 +52,7 @@ test('tests order of table columns with foreign keys', function () {
test('tests case insensivity', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('getBelongsToReference')->with('books')->andReturn([
'author_id' => 'authors',
'translator_id' => 'authors',
@@ -65,7 +65,7 @@ test('tests case insensivity', function () {
test('tests case insensivity and prefixes', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('getBelongsToReference')->with('nBooks')->andReturn([
'authorId' => 'nAuthors',
'translatorId' => 'nAuthors',
@@ -79,7 +79,7 @@ test('tests case insensivity and prefixes', function () {
test('tests rebuilt', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('isRebuilt')->andReturn(false);
$structure->shouldReceive('rebuild');
$structure->shouldReceive('getBelongsToReference')->andReturn([])->once();
@@ -96,7 +96,7 @@ test('tests rebuilt', function () {
test('tests already rebuilt structure', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('isRebuilt')->andReturn(true);
$structure->shouldReceive('getBelongsToReference')->with('books')->andReturn([])->once();
diff --git a/tests/Database/Conventions/DiscoveredConventions.getHasManyReference().phpt b/tests/Database/Conventions/DiscoveredConventions.getHasManyReference().phpt
index a7dc0255d..ed14a18ab 100644
--- a/tests/Database/Conventions/DiscoveredConventions.getHasManyReference().phpt
+++ b/tests/Database/Conventions/DiscoveredConventions.getHasManyReference().phpt
@@ -13,7 +13,7 @@ require __DIR__ . '/../../bootstrap.php';
test('basic test singular', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('getHasManyReference')->with('author')->andReturn([
'book' => ['author_id', 'translator_id'],
'book_topics' => ['author_id'],
@@ -43,7 +43,7 @@ test('basic test singular', function () {
test('basic test singular with schema', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('getHasManyReference')->with('public.author')->andReturn([
'public.book' => ['author_id', 'translator_id'],
'public.book_topics' => ['author_id'],
@@ -88,7 +88,7 @@ test('basic test singular with schema', function () {
test('basic test plural', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('getHasManyReference')->with('authors')->andReturn([
'books' => ['author_id', 'translator_id'],
])->once();
@@ -112,7 +112,7 @@ test('basic test plural', function () {
test('tests column match with source table', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('getHasManyReference')->with('author')->andReturn([
'book' => ['author_id', 'tran_id'],
])->once();
@@ -139,7 +139,7 @@ test('tests column match with source table', function () {
test('tests case insensivity and prefixes', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('getHasManyReference')->with('nAuthors')->andReturn([
'nBooks' => ['authorId', 'translatorId'],
])->once();
@@ -151,7 +151,7 @@ test('tests case insensivity and prefixes', function () {
test('tests rebuilt', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('isRebuilt')->andReturn(false);
$structure->shouldReceive('rebuild');
$structure->shouldReceive('getHasManyReference')->with('author')->andReturn([])->once();
@@ -165,7 +165,7 @@ test('tests rebuilt', function () {
test('tests already rebuilt structure', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('isRebuilt')->andReturn(true);
$structure->shouldReceive('getHasManyReference')->with('author')->andReturn([])->once();
diff --git a/tests/Database/Conventions/DiscoveredConventions.getPrimary().phpt b/tests/Database/Conventions/DiscoveredConventions.getPrimary().phpt
index 196c4e0e6..f68b38f5c 100644
--- a/tests/Database/Conventions/DiscoveredConventions.getPrimary().phpt
+++ b/tests/Database/Conventions/DiscoveredConventions.getPrimary().phpt
@@ -13,7 +13,7 @@ require __DIR__ . '/../../bootstrap.php';
test('', function () {
- $structure = Mockery::mock(Nette\Database\IStructure::class);
+ $structure = Mockery::mock(Nette\Database\Structure::class);
$structure->shouldReceive('getPrimaryKey')->with('books_x_tags')->andReturn(['book_id', 'tag_id']);
$conventions = new DiscoveredConventions($structure);
diff --git a/tests/Database/Drivers/MsSqlDriver.applyLimit.phpt b/tests/Database/Drivers/MsSqlDriver.applyLimit.phpt
deleted file mode 100644
index 636142214..000000000
--- a/tests/Database/Drivers/MsSqlDriver.applyLimit.phpt
+++ /dev/null
@@ -1,60 +0,0 @@
-applyLimit($query, 10, 20);
-}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, 0, 20);
-}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, 0);
-Assert::same('SELECT TOP 10 1 FROM t', $query);
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, null, 20);
-}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, null);
-Assert::same('SELECT TOP 10 1 FROM t', $query);
-
-$query = ' select distinct 1 FROM t';
-$driver->applyLimit($query, 10, null);
-Assert::same(' select distinct TOP 10 1 FROM t', $query);
-
-$query = 'UPDATE t SET';
-$driver->applyLimit($query, 10, null);
-Assert::same('UPDATE TOP 10 t SET', $query);
-
-$query = 'DELETE FROM t SET';
-$driver->applyLimit($query, 10, null);
-Assert::same('DELETE TOP 10 FROM t SET', $query);
-
-Assert::exception(function () use ($driver) {
- $query = 'SET FROM t';
- $driver->applyLimit($query, 10, null);
-}, Nette\InvalidArgumentException::class, 'SQL query must begin with SELECT, UPDATE or DELETE command.');
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, -1, null);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, null, -1);
-}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
diff --git a/tests/Database/Drivers/MySqlDriver.applyLimit.phpt b/tests/Database/Drivers/MySqlDriver.applyLimit.phpt
deleted file mode 100644
index 8434fe2f5..000000000
--- a/tests/Database/Drivers/MySqlDriver.applyLimit.phpt
+++ /dev/null
@@ -1,44 +0,0 @@
-getConnection();
-$driver = $connection->getDriver();
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, 20);
-Assert::same('SELECT 1 FROM t LIMIT 10 OFFSET 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 0, 20);
-Assert::same('SELECT 1 FROM t LIMIT 0 OFFSET 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, 0);
-Assert::same('SELECT 1 FROM t LIMIT 10', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, null, 20);
-Assert::same('SELECT 1 FROM t LIMIT 18446744073709551615 OFFSET 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, null);
-Assert::same('SELECT 1 FROM t LIMIT 10', $query);
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, -1, null);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, null, -1);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
diff --git a/tests/Database/Drivers/MySqlDriver.formatLike.phpt b/tests/Database/Drivers/MySqlDriver.formatLike.phpt
deleted file mode 100644
index 45d7fa032..000000000
--- a/tests/Database/Drivers/MySqlDriver.formatLike.phpt
+++ /dev/null
@@ -1,32 +0,0 @@
-getConnection();
-$driver = $connection->getDriver();
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A_B', 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA_BB' LIKE", $connection::literal($driver->formatLike('A_B', 0)))->fetchField());
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A%B', 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA%BB' LIKE", $connection::literal($driver->formatLike('A%B', 0)))->fetchField());
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike("A'B", 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA''BB' LIKE", $connection::literal($driver->formatLike("A'B", 0)))->fetchField());
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A"B', 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA\"BB' LIKE", $connection::literal($driver->formatLike('A"B', 0)))->fetchField());
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A\B', 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA\\\\BB' LIKE", $connection::literal($driver->formatLike('A\B', 0)))->fetchField());
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A\%B', 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA\\\\%BB' LIKE", $connection::literal($driver->formatLike('A\%B', 0)))->fetchField());
diff --git a/tests/Database/Drivers/OciDriver.applyLimit.phpt b/tests/Database/Drivers/OciDriver.applyLimit.phpt
deleted file mode 100644
index c446108f5..000000000
--- a/tests/Database/Drivers/OciDriver.applyLimit.phpt
+++ /dev/null
@@ -1,40 +0,0 @@
-applyLimit($query, 10, 20);
-Assert::same('SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (SELECT 1 FROM t) t WHERE ROWNUM <= 30) WHERE "__rnum" > 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 0, 20);
-Assert::same('SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (SELECT 1 FROM t) t WHERE ROWNUM <= 20) WHERE "__rnum" > 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, 0);
-Assert::same('SELECT * FROM (SELECT 1 FROM t) WHERE ROWNUM <= 10', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, null, 20);
-Assert::same('SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (SELECT 1 FROM t) t ) WHERE "__rnum" > 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, null);
-Assert::same('SELECT * FROM (SELECT 1 FROM t) WHERE ROWNUM <= 10', $query);
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, -1, null);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, null, -1);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
diff --git a/tests/Database/Drivers/OdbcDriver.applyLimit.phpt b/tests/Database/Drivers/OdbcDriver.applyLimit.phpt
deleted file mode 100644
index b40e3f03e..000000000
--- a/tests/Database/Drivers/OdbcDriver.applyLimit.phpt
+++ /dev/null
@@ -1,60 +0,0 @@
-applyLimit($query, 10, 20);
-}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, 0, 20);
-}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, 0);
-Assert::same('SELECT TOP 10 1 FROM t', $query);
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, null, 20);
-}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, null);
-Assert::same('SELECT TOP 10 1 FROM t', $query);
-
-$query = ' select distinct 1 FROM t';
-$driver->applyLimit($query, 10, null);
-Assert::same(' select distinct TOP 10 1 FROM t', $query);
-
-$query = 'UPDATE t SET';
-$driver->applyLimit($query, 10, null);
-Assert::same('UPDATE TOP 10 t SET', $query);
-
-$query = 'DELETE FROM t SET';
-$driver->applyLimit($query, 10, null);
-Assert::same('DELETE TOP 10 FROM t SET', $query);
-
-Assert::exception(function () use ($driver) {
- $query = 'SET FROM t';
- $driver->applyLimit($query, 10, null);
-}, Nette\InvalidArgumentException::class, 'SQL query must begin with SELECT, UPDATE or DELETE command.');
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, -1, null);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, null, -1);
-}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
diff --git a/tests/Database/Drivers/PgSqlDriver.applyLimit.phpt b/tests/Database/Drivers/PgSqlDriver.applyLimit.phpt
deleted file mode 100644
index 6516e93d6..000000000
--- a/tests/Database/Drivers/PgSqlDriver.applyLimit.phpt
+++ /dev/null
@@ -1,40 +0,0 @@
-applyLimit($query, 10, 20);
-Assert::same('SELECT 1 FROM t LIMIT 10 OFFSET 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 0, 20);
-Assert::same('SELECT 1 FROM t LIMIT 0 OFFSET 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, 0);
-Assert::same('SELECT 1 FROM t LIMIT 10', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, null, 20);
-Assert::same('SELECT 1 FROM t OFFSET 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, null);
-Assert::same('SELECT 1 FROM t LIMIT 10', $query);
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, -1, null);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, null, -1);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
diff --git a/tests/Database/Drivers/PgSqlDriver.formatLike.phpt b/tests/Database/Drivers/PgSqlDriver.formatLike.phpt
deleted file mode 100644
index 2e85ec7bb..000000000
--- a/tests/Database/Drivers/PgSqlDriver.formatLike.phpt
+++ /dev/null
@@ -1,42 +0,0 @@
-getConnection();
-
-$tests = function ($connection) {
- $driver = $connection->getDriver();
-
- Assert::false($connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A_B', 0)))->fetchField());
- Assert::true($connection->query("SELECT 'AA_BB' LIKE", $connection::literal($driver->formatLike('A_B', 0)))->fetchField());
-
- Assert::false($connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A%B', 0)))->fetchField());
- Assert::true($connection->query("SELECT 'AA%BB' LIKE", $connection::literal($driver->formatLike('A%B', 0)))->fetchField());
-
- Assert::false($connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike("A'B", 0)))->fetchField());
- Assert::true($connection->query("SELECT 'AA''BB' LIKE", $connection::literal($driver->formatLike("A'B", 0)))->fetchField());
-
- Assert::false($connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A"B', 0)))->fetchField());
- Assert::true($connection->query("SELECT 'AA\"BB' LIKE", $connection::literal($driver->formatLike('A"B', 0)))->fetchField());
-};
-
-$driver = $connection->getDriver();
-$connection->query('SET escape_string_warning TO off'); // do not log warnings
-
-$connection->query('SET standard_conforming_strings TO on');
-$tests($connection);
-Assert::false($connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A\\B', 0)))->fetchField());
-Assert::true($connection->query("SELECT 'AA\\BB' LIKE", $connection::literal($driver->formatLike('A\\B', 0)))->fetchField());
-
-$connection->query('SET standard_conforming_strings TO off');
-$tests($connection);
-Assert::false($connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A\\B', 0)))->fetchField());
-Assert::true($connection->query("SELECT 'AA\\\\BB' LIKE", $connection::literal($driver->formatLike('A\\B', 0)))->fetchField());
diff --git a/tests/Database/Drivers/SqliteDriver.applyLimit.phpt b/tests/Database/Drivers/SqliteDriver.applyLimit.phpt
deleted file mode 100644
index 662cb5d76..000000000
--- a/tests/Database/Drivers/SqliteDriver.applyLimit.phpt
+++ /dev/null
@@ -1,40 +0,0 @@
-applyLimit($query, 10, 20);
-Assert::same('SELECT 1 FROM t LIMIT 10 OFFSET 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 0, 20);
-Assert::same('SELECT 1 FROM t LIMIT 0 OFFSET 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, 0);
-Assert::same('SELECT 1 FROM t LIMIT 10', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, null, 20);
-Assert::same('SELECT 1 FROM t LIMIT -1 OFFSET 20', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, null);
-Assert::same('SELECT 1 FROM t LIMIT 10', $query);
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, -1, null);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, null, -1);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
diff --git a/tests/Database/Drivers/SqliteDriver.formatLike.phpt b/tests/Database/Drivers/SqliteDriver.formatLike.phpt
deleted file mode 100644
index 2b2443957..000000000
--- a/tests/Database/Drivers/SqliteDriver.formatLike.phpt
+++ /dev/null
@@ -1,32 +0,0 @@
-getConnection();
-$driver = $connection->getDriver();
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A_B', 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA_BB' LIKE", $connection::literal($driver->formatLike('A_B', 0)))->fetchField());
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A%B', 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA%BB' LIKE", $connection::literal($driver->formatLike('A%B', 0)))->fetchField());
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike("A'B", 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA''BB' LIKE", $connection::literal($driver->formatLike("A'B", 0)))->fetchField());
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A"B', 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA\"BB' LIKE", $connection::literal($driver->formatLike('A"B', 0)))->fetchField());
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A\B', 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA\\BB' LIKE", $connection::literal($driver->formatLike('A\B', 0)))->fetchField());
-
-Assert::same(0, $connection->query("SELECT 'AAxBB' LIKE", $connection::literal($driver->formatLike('A\%B', 0)))->fetchField());
-Assert::same(1, $connection->query("SELECT 'AA\\%BB' LIKE", $connection::literal($driver->formatLike('A\%B', 0)))->fetchField());
diff --git a/tests/Database/Drivers/SqlsrvDriver.applyLimit.phpt b/tests/Database/Drivers/SqlsrvDriver.applyLimit.phpt
deleted file mode 100644
index 3a06219af..000000000
--- a/tests/Database/Drivers/SqlsrvDriver.applyLimit.phpt
+++ /dev/null
@@ -1,42 +0,0 @@
-applyLimit($query, 10, 20);
-Assert::same('SELECT 1 FROM t OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 0, 20);
-Assert::same('SELECT 1 FROM t OFFSET 20 ROWS FETCH NEXT 0 ROWS ONLY', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, 0);
-Assert::same('SELECT 1 FROM t OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, null, 20);
-Assert::same('SELECT 1 FROM t OFFSET 20 ROWS FETCH NEXT 0 ROWS ONLY', $query);
-
-$query = 'SELECT 1 FROM t';
-$driver->applyLimit($query, 10, null);
-Assert::same('SELECT 1 FROM t OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $query);
-
-
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, -1, null);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
-
-Assert::exception(function () use ($driver) {
- $query = 'SELECT 1 FROM t';
- $driver->applyLimit($query, null, -1);
-}, Nette\InvalidArgumentException::class, 'Negative offset or limit.');
diff --git a/tests/Database/Drivers/SqlsrvDriver.formatLike.phpt b/tests/Database/Drivers/SqlsrvDriver.formatLike.phpt
deleted file mode 100644
index cd5ccc3f1..000000000
--- a/tests/Database/Drivers/SqlsrvDriver.formatLike.phpt
+++ /dev/null
@@ -1,35 +0,0 @@
-getConnection();
-$driver = $connection->getDriver();
-
-Assert::same(0, $connection->query("SELECT CASE WHEN 'AAxBB' LIKE", $connection::literal($driver->formatLike('A_B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-Assert::same(1, $connection->query("SELECT CASE WHEN 'AA_BB' LIKE", $connection::literal($driver->formatLike('A_B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-
-Assert::same(0, $connection->query("SELECT CASE WHEN 'AAxBB' LIKE", $connection::literal($driver->formatLike('A%B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-Assert::same(1, $connection->query("SELECT CASE WHEN 'AA%BB' LIKE", $connection::literal($driver->formatLike('A%B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-
-Assert::same(0, $connection->query("SELECT CASE WHEN 'AAxBB' LIKE", $connection::literal($driver->formatLike("A'B", 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-Assert::same(1, $connection->query("SELECT CASE WHEN 'AA''BB' LIKE", $connection::literal($driver->formatLike("A'B", 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-
-Assert::same(0, $connection->query("SELECT CASE WHEN 'AAxBB' LIKE", $connection::literal($driver->formatLike('A"B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-Assert::same(1, $connection->query("SELECT CASE WHEN 'AA\"BB' LIKE", $connection::literal($driver->formatLike('A"B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-
-Assert::same(0, $connection->query("SELECT CASE WHEN 'AAxBB' LIKE", $connection::literal($driver->formatLike('A\B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-Assert::same(1, $connection->query("SELECT CASE WHEN 'AA\\BB' LIKE", $connection::literal($driver->formatLike('A\B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-
-Assert::same(0, $connection->query("SELECT CASE WHEN 'AAxBB' LIKE", $connection::literal($driver->formatLike('A\%B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-Assert::same(1, $connection->query("SELECT CASE WHEN 'AA\\%BB' LIKE", $connection::literal($driver->formatLike('A\%B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-
-Assert::same(0, $connection->query("SELECT CASE WHEN 'AAxBB' LIKE", $connection::literal($driver->formatLike('A[a-z]B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
-Assert::same(1, $connection->query("SELECT CASE WHEN 'AA[a-z]BB' LIKE", $connection::literal($driver->formatLike('A[a-z]B', 0)), 'THEN 1 ELSE 0 END AS col')->fetchField());
diff --git a/tests/Database/Reflection.postgre.10.phpt b/tests/Database/Engine.postgre.10.phpt
similarity index 76%
rename from tests/Database/Reflection.postgre.10.phpt
rename to tests/Database/Engine.postgre.10.phpt
index 2b6191da0..c6e64379e 100644
--- a/tests/Database/Reflection.postgre.10.phpt
+++ b/tests/Database/Engine.postgre.10.phpt
@@ -12,7 +12,7 @@ use Tester\Environment;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
$ver = $connection->query('SHOW server_version')->fetchField();
if (version_compare($ver, '10') < 0) {
@@ -24,13 +24,13 @@ function shortInfo(array $columns): array
{
return array_map(fn(array $col): array => [
'name' => $col['name'],
- 'autoincrement' => $col['autoincrement'],
+ 'autoIncrement' => $col['autoIncrement'],
'sequence' => $col['vendor']['sequence'],
], $columns);
}
-test('SERIAL and IDENTITY imply autoincrement on primary keys', function () use ($connection) {
+test('SERIAL and IDENTITY imply autoIncrement on primary keys', function () use ($connection) {
Nette\Database\Helpers::loadFromFile($connection, Tester\FileMock::create('
DROP SCHEMA IF EXISTS "reflection_10" CASCADE;
CREATE SCHEMA "reflection_10";
@@ -45,53 +45,53 @@ test('SERIAL and IDENTITY imply autoincrement on primary keys', function () use
CREATE TABLE "reflection_10"."identity_by_default_pk" ("id" INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY);
'));
- $driver = $connection->getDriver();
+ $engine = $connection->getDatabaseEngine();
$connection->query('SET search_path TO reflection_10');
$columns = [
- 'serial' => shortInfo($driver->getColumns('serial')),
- 'serial_pk' => shortInfo($driver->getColumns('serial_pk')),
- 'identity_always' => shortInfo($driver->getColumns('identity_always')),
- 'identity_always_pk' => shortInfo($driver->getColumns('identity_always_pk')),
- 'identity_by_default' => shortInfo($driver->getColumns('identity_by_default')),
- 'identity_by_default_pk' => shortInfo($driver->getColumns('identity_by_default_pk')),
+ 'serial' => shortInfo($engine->getColumns('serial')),
+ 'serial_pk' => shortInfo($engine->getColumns('serial_pk')),
+ 'identity_always' => shortInfo($engine->getColumns('identity_always')),
+ 'identity_always_pk' => shortInfo($engine->getColumns('identity_always_pk')),
+ 'identity_by_default' => shortInfo($engine->getColumns('identity_by_default')),
+ 'identity_by_default_pk' => shortInfo($engine->getColumns('identity_by_default_pk')),
];
Assert::same([
'serial' => [[
'name' => 'id',
- 'autoincrement' => false,
+ 'autoIncrement' => false,
'sequence' => 'serial_id_seq',
]],
'serial_pk' => [[
'name' => 'id',
- 'autoincrement' => true,
+ 'autoIncrement' => true,
'sequence' => 'serial_pk_id_seq',
]],
'identity_always' => [[
'name' => 'id',
- 'autoincrement' => false,
+ 'autoIncrement' => false,
'sequence' => 'identity_always_id_seq',
]],
'identity_always_pk' => [[
'name' => 'id',
- 'autoincrement' => true,
+ 'autoIncrement' => true,
'sequence' => 'identity_always_pk_id_seq',
]],
'identity_by_default' => [[
'name' => 'id',
- 'autoincrement' => false,
+ 'autoIncrement' => false,
'sequence' => 'identity_by_default_id_seq',
]],
'identity_by_default_pk' => [[
'name' => 'id',
- 'autoincrement' => true,
+ 'autoIncrement' => true,
'sequence' => 'identity_by_default_pk_id_seq',
]],
], $columns);
@@ -111,18 +111,18 @@ test('Materialized view columns', function () use ($connection) {
CREATE MATERIALIZED VIEW "reflection_10"."source_mt" AS SELECT "name", "id" FROM "reflection_10"."source";
'));
- $driver = $connection->getDriver();
+ $engine = $connection->getDatabaseEngine();
$connection->query('SET search_path TO reflection_10');
Assert::same([
['name' => 'source', 'view' => false, 'fullName' => 'reflection_10.source'],
['name' => 'source_mt', 'view' => true, 'fullName' => 'reflection_10.source_mt'],
- ], $driver->getTables());
+ ], $engine->getTables());
Assert::same(
['name', 'id'],
- array_column($driver->getColumns('source_mt'), 'name'),
+ array_column($engine->getColumns('source_mt'), 'name'),
);
});
@@ -140,22 +140,22 @@ test('Partitioned table', function () use ($connection) {
CREATE TABLE "reflection_10"."part_1" PARTITION OF "reflection_10"."parted" FOR VALUES FROM (1) TO (10);
'));
- $driver = $connection->getDriver();
+ $engine = $connection->getDatabaseEngine();
$connection->query('SET search_path TO reflection_10');
Assert::same([
['name' => 'part_1', 'view' => false, 'fullName' => 'reflection_10.part_1'],
['name' => 'parted', 'view' => false, 'fullName' => 'reflection_10.parted'],
- ], $driver->getTables());
+ ], $engine->getTables());
- Assert::same(['id', 'value'], array_column($driver->getColumns('parted'), 'name'));
- Assert::same(['id', 'value'], array_column($driver->getColumns('part_1'), 'name'));
+ Assert::same(['id', 'value'], array_column($engine->getColumns('parted'), 'name'));
+ Assert::same(['id', 'value'], array_column($engine->getColumns('part_1'), 'name'));
Assert::same([[
'name' => 'parted_pkey',
'unique' => true,
'primary' => true,
'columns' => ['id'],
- ]], $driver->getIndexes('parted'));
+ ]], $engine->getIndexes('parted'));
});
diff --git a/tests/Database/Reflection.postgre.phpt b/tests/Database/Engine.postgre.phpt
similarity index 66%
rename from tests/Database/Reflection.postgre.phpt
rename to tests/Database/Engine.postgre.phpt
index 53393629a..89fc5dd90 100644
--- a/tests/Database/Reflection.postgre.phpt
+++ b/tests/Database/Engine.postgre.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
function names($columns): array
@@ -43,38 +43,38 @@ test('Tables in schema', function () use ($connection) {
ALTER TABLE "two"."slave" ADD CONSTRAINT "two_slave_fk" FOREIGN KEY ("two_id") REFERENCES "two"."master"("two_id");
'));
- $driver = $connection->getDriver();
+ $engine = $connection->getDatabaseEngine();
// Reflection for tables with the same name but different schema
$connection->query('SET search_path TO one, two');
- Assert::same(['master', 'slave'], names($driver->getTables()));
- Assert::same(['one_id'], names($driver->getColumns('master')));
- Assert::same(['one_master_pkey'], names($driver->getIndexes('master')));
- Assert::same(['one_slave_fk'], names($driver->getForeignKeys('slave')));
+ Assert::same(['master', 'slave'], names($engine->getTables()));
+ Assert::same(['one_id'], names($engine->getColumns('master')));
+ Assert::same(['one_master_pkey'], names($engine->getIndexes('master')));
+ Assert::same(['one_slave_fk'], names($engine->getForeignKeys('slave')));
$connection->query('SET search_path TO two, one');
- Assert::same(['master', 'slave'], names($driver->getTables()));
- Assert::same(['two_id'], names($driver->getColumns('master')));
- Assert::same(['two_master_pkey'], names($driver->getIndexes('master')));
- Assert::same(['two_slave_fk'], names($driver->getForeignKeys('slave')));
+ Assert::same(['master', 'slave'], names($engine->getTables()));
+ Assert::same(['two_id'], names($engine->getColumns('master')));
+ Assert::same(['two_master_pkey'], names($engine->getIndexes('master')));
+ Assert::same(['two_slave_fk'], names($engine->getForeignKeys('slave')));
// Reflection for FQN
- Assert::same(['one_id'], names($driver->getColumns('one.master')));
- Assert::same(['one_master_pkey'], names($driver->getIndexes('one.master')));
- $foreign = $driver->getForeignKeys('one.slave');
+ Assert::same(['one_id'], names($engine->getColumns('one.master')));
+ Assert::same(['one_master_pkey'], names($engine->getIndexes('one.master')));
+ $foreign = $engine->getForeignKeys('one.slave');
Assert::same([
'name' => 'one_slave_fk',
- 'local' => 'one_id',
+ 'local' => ['one_id'],
'table' => 'one.master',
- 'foreign' => 'one_id',
+ 'foreign' => ['one_id'],
], (array) $foreign[0]);
// Limit foreign keys for current schemas only
$connection->query('ALTER TABLE "one"."slave" ADD CONSTRAINT "one_two_fk" FOREIGN KEY ("one_id") REFERENCES "two"."master"("two_id")');
$connection->query('SET search_path TO one');
- Assert::same(['one_slave_fk'], names($driver->getForeignKeys('slave')));
+ Assert::same(['one_slave_fk'], names($engine->getForeignKeys('slave')));
$connection->query('SET search_path TO one, two');
- Assert::same(['one_slave_fk', 'one_two_fk'], names($driver->getForeignKeys('slave')));
+ Assert::same(['one_slave_fk', 'one_two_fk'], names($engine->getForeignKeys('slave')));
});
diff --git a/tests/Database/Reflection.driver.phpt b/tests/Database/Engine.reflection.phpt
similarity index 79%
rename from tests/Database/Reflection.driver.phpt
rename to tests/Database/Engine.reflection.phpt
index 04c676bf8..43d0449ed 100644
--- a/tests/Database/Reflection.driver.phpt
+++ b/tests/Database/Engine.reflection.phpt
@@ -7,23 +7,22 @@
declare(strict_types=1);
-use Nette\Database\Driver;
+use Nette\Database\Drivers\Engine;
use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/files/{$driverName}-nette_test1.sql");
-$driver = $connection->getDriver();
-$tables = $driver->getTables();
+$engine = $explorer->getDatabaseEngine();
+$tables = $engine->getTables();
$tables = array_filter($tables, fn($t) => in_array($t['name'], ['author', 'book', 'book_tag', 'tag'], true));
usort($tables, fn($a, $b) => strcmp($a['name'], $b['name']));
-if ($driver->isSupported(Driver::SupportSchema)) {
+if ($engine->isSupported(Engine::SupportSchema)) {
Assert::same(
[
['name' => 'author', 'view' => false, 'fullName' => 'public.author'],
@@ -43,7 +42,7 @@ if ($driver->isSupported(Driver::SupportSchema)) {
}
-$columns = $driver->getColumns('author');
+$columns = $engine->getColumns('author');
array_walk($columns, function (&$item) {
Assert::type('array', $item['vendor']);
unset($item['vendor']);
@@ -53,64 +52,68 @@ $expectedColumns = [
[
'name' => 'id',
'table' => 'author',
- 'nativetype' => 'INT',
+ 'nativeType' => 'INT',
'size' => 11,
+ 'scale' => null,
'nullable' => false,
'default' => null,
- 'autoincrement' => true,
+ 'autoIncrement' => true,
'primary' => true,
],
[
'name' => 'name',
'table' => 'author',
- 'nativetype' => 'VARCHAR',
+ 'nativeType' => 'VARCHAR',
'size' => 30,
+ 'scale' => null,
'nullable' => false,
'default' => null,
- 'autoincrement' => false,
+ 'autoIncrement' => false,
'primary' => false,
],
[
'name' => 'web',
'table' => 'author',
- 'nativetype' => 'VARCHAR',
+ 'nativeType' => 'VARCHAR',
'size' => 100,
+ 'scale' => null,
'nullable' => false,
'default' => null,
- 'autoincrement' => false,
+ 'autoIncrement' => false,
'primary' => false,
],
[
'name' => 'born',
'table' => 'author',
- 'nativetype' => 'DATE',
+ 'nativeType' => 'DATE',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
- 'autoincrement' => false,
+ 'autoIncrement' => false,
'primary' => false,
],
];
switch ($driverName) {
case 'mysql':
- $version = $connection->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION);
+ $version = $explorer->getServerVersion();
if (version_compare($version, '8.0', '>=')) {
$expectedColumns[0]['size'] = null;
}
break;
case 'pgsql':
- $expectedColumns[0]['nativetype'] = 'INT4';
+ $expectedColumns[0]['nativeType'] = 'INT4';
$expectedColumns[0]['default'] = "nextval('author_id_seq'::regclass)";
$expectedColumns[0]['size'] = 4;
$expectedColumns[3]['size'] = 4;
break;
case 'sqlite':
- $expectedColumns[0]['nativetype'] = 'INTEGER';
+ $expectedColumns[0]['nativeType'] = 'INTEGER';
$expectedColumns[0]['size'] = null;
- $expectedColumns[1]['nativetype'] = 'TEXT';
+ $expectedColumns[1]['nativeType'] = 'TEXT';
$expectedColumns[1]['size'] = null;
- $expectedColumns[2]['nativetype'] = 'TEXT';
+ $expectedColumns[2]['nativeType'] = 'TEXT';
$expectedColumns[2]['size'] = null;
break;
case 'sqlsrv':
@@ -124,7 +127,7 @@ switch ($driverName) {
Assert::same($expectedColumns, $columns);
-$indexes = $driver->getIndexes('book_tag');
+$indexes = $engine->getIndexes('book_tag');
switch ($driverName) {
case 'pgsql':
Assert::same([
diff --git a/tests/Database/Engines/MSSQLEngine.applyLimit.phpt b/tests/Database/Engines/MSSQLEngine.applyLimit.phpt
new file mode 100644
index 000000000..35cfb9159
--- /dev/null
+++ b/tests/Database/Engines/MSSQLEngine.applyLimit.phpt
@@ -0,0 +1,71 @@
+ $engine->applyLimit('SELECT 1 FROM t', 10, 20),
+ Nette\NotSupportedException::class,
+ 'Offset is not supported by this database.',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', 0, 20),
+ Nette\NotSupportedException::class,
+ 'Offset is not supported by this database.',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, 0),
+ 'SELECT TOP 10 1 FROM t',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', null, 20),
+ Nette\NotSupportedException::class,
+ 'Offset is not supported by this database.',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, null),
+ 'SELECT TOP 10 1 FROM t',
+);
+
+Assert::same(
+ $engine->applyLimit(' select distinct 1 FROM t', 10, null),
+ ' select distinct TOP 10 1 FROM t',
+);
+
+Assert::same(
+ $engine->applyLimit('UPDATE t SET', 10, null),
+ 'UPDATE TOP 10 t SET',
+);
+
+Assert::same(
+ $engine->applyLimit('DELETE FROM t SET', 10, null),
+ 'DELETE TOP 10 FROM t SET',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SET FROM t', 10, null),
+ Nette\InvalidArgumentException::class,
+ 'SQL query must begin with SELECT, UPDATE or DELETE command.',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', -1, null),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', null, -1),
+ Nette\NotSupportedException::class,
+ 'Offset is not supported by this database.',
+);
diff --git a/tests/Database/Engines/MySQLEngine.applyLimit.phpt b/tests/Database/Engines/MySQLEngine.applyLimit.phpt
new file mode 100644
index 000000000..59f67b995
--- /dev/null
+++ b/tests/Database/Engines/MySQLEngine.applyLimit.phpt
@@ -0,0 +1,47 @@
+applyLimit('SELECT 1 FROM t', 10, 20),
+ 'SELECT 1 FROM t LIMIT 10 OFFSET 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 0, 20),
+ 'SELECT 1 FROM t LIMIT 0 OFFSET 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, 0),
+ 'SELECT 1 FROM t LIMIT 10',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', null, 20),
+ 'SELECT 1 FROM t LIMIT 18446744073709551615 OFFSET 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, null),
+ 'SELECT 1 FROM t LIMIT 10',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', -1, null),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', null, -1),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
diff --git a/tests/Database/Engines/ODBCEngine.applyLimit.phpt b/tests/Database/Engines/ODBCEngine.applyLimit.phpt
new file mode 100644
index 000000000..ea38594c2
--- /dev/null
+++ b/tests/Database/Engines/ODBCEngine.applyLimit.phpt
@@ -0,0 +1,71 @@
+ $engine->applyLimit('SELECT 1 FROM t', 10, 20),
+ Nette\NotSupportedException::class,
+ 'Offset is not supported by this database.',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', 0, 20),
+ Nette\NotSupportedException::class,
+ 'Offset is not supported by this database.',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, 0),
+ 'SELECT TOP 10 1 FROM t',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', null, 20),
+ Nette\NotSupportedException::class,
+ 'Offset is not supported by this database.',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, null),
+ 'SELECT TOP 10 1 FROM t',
+);
+
+Assert::same(
+ $engine->applyLimit(' select distinct 1 FROM t', 10, null),
+ ' select distinct TOP 10 1 FROM t',
+);
+
+Assert::same(
+ $engine->applyLimit('UPDATE t SET', 10, null),
+ 'UPDATE TOP 10 t SET',
+);
+
+Assert::same(
+ $engine->applyLimit('DELETE FROM t SET', 10, null),
+ 'DELETE TOP 10 FROM t SET',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SET FROM t', 10, null),
+ Nette\InvalidArgumentException::class,
+ 'SQL query must begin with SELECT, UPDATE or DELETE command.',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', -1, null),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', null, -1),
+ Nette\NotSupportedException::class,
+ 'Offset is not supported by this database.',
+);
diff --git a/tests/Database/Engines/OracleEngine.applyLimit.phpt b/tests/Database/Engines/OracleEngine.applyLimit.phpt
new file mode 100644
index 000000000..a2ed1d618
--- /dev/null
+++ b/tests/Database/Engines/OracleEngine.applyLimit.phpt
@@ -0,0 +1,47 @@
+applyLimit('SELECT 1 FROM t', 10, 20),
+ 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (SELECT 1 FROM t) t WHERE ROWNUM <= 30) WHERE "__rnum" > 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 0, 20),
+ 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (SELECT 1 FROM t) t WHERE ROWNUM <= 20) WHERE "__rnum" > 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, 0),
+ 'SELECT * FROM (SELECT 1 FROM t) WHERE ROWNUM <= 10',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', null, 20),
+ 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (SELECT 1 FROM t) t ) WHERE "__rnum" > 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, null),
+ 'SELECT * FROM (SELECT 1 FROM t) WHERE ROWNUM <= 10',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', -1, null),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', null, -1),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
diff --git a/tests/Database/Engines/PostgreSQLEngine.applyLimit.phpt b/tests/Database/Engines/PostgreSQLEngine.applyLimit.phpt
new file mode 100644
index 000000000..b77321e76
--- /dev/null
+++ b/tests/Database/Engines/PostgreSQLEngine.applyLimit.phpt
@@ -0,0 +1,47 @@
+applyLimit('SELECT 1 FROM t', 10, 20),
+ 'SELECT 1 FROM t LIMIT 10 OFFSET 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 0, 20),
+ 'SELECT 1 FROM t LIMIT 0 OFFSET 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, 0),
+ 'SELECT 1 FROM t LIMIT 10',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', null, 20),
+ 'SELECT 1 FROM t OFFSET 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, null),
+ 'SELECT 1 FROM t LIMIT 10',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', -1, null),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', null, -1),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
diff --git a/tests/Database/Engines/SQLServerEngine.applyLimit.phpt b/tests/Database/Engines/SQLServerEngine.applyLimit.phpt
new file mode 100644
index 000000000..0bdc50957
--- /dev/null
+++ b/tests/Database/Engines/SQLServerEngine.applyLimit.phpt
@@ -0,0 +1,47 @@
+applyLimit('SELECT 1 FROM t', 10, 20),
+ 'SELECT 1 FROM t OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 0, 20),
+ 'SELECT 1 FROM t OFFSET 20 ROWS FETCH NEXT 0 ROWS ONLY',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, 0),
+ 'SELECT 1 FROM t OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', null, 20),
+ 'SELECT 1 FROM t OFFSET 20 ROWS FETCH NEXT 0 ROWS ONLY',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, null),
+ 'SELECT 1 FROM t OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', -1, null),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', null, -1),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
diff --git a/tests/Database/Engines/SQLiteEngine.applyLimit.phpt b/tests/Database/Engines/SQLiteEngine.applyLimit.phpt
new file mode 100644
index 000000000..4258393e7
--- /dev/null
+++ b/tests/Database/Engines/SQLiteEngine.applyLimit.phpt
@@ -0,0 +1,47 @@
+applyLimit('SELECT 1 FROM t', 10, 20),
+ 'SELECT 1 FROM t LIMIT 10 OFFSET 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 0, 20),
+ 'SELECT 1 FROM t LIMIT 0 OFFSET 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, 0),
+ 'SELECT 1 FROM t LIMIT 10',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', null, 20),
+ 'SELECT 1 FROM t LIMIT -1 OFFSET 20',
+);
+
+Assert::same(
+ $engine->applyLimit('SELECT 1 FROM t', 10, null),
+ 'SELECT 1 FROM t LIMIT 10',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', -1, null),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
+
+Assert::exception(
+ fn() => $engine->applyLimit('SELECT 1 FROM t', null, -1),
+ Nette\InvalidArgumentException::class,
+ 'Negative offset or limit.',
+);
diff --git a/tests/Database/Explorer.fetch.phpt b/tests/Database/Explorer.fetch.phpt
index bc1024032..0a6fe9a8b 100644
--- a/tests/Database/Explorer.fetch.phpt
+++ b/tests/Database/Explorer.fetch.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/files/{$driverName}-nette_test1.sql");
test('fetch', function () use ($explorer) {
@@ -41,8 +40,8 @@ test('fetchField', function () use ($explorer) {
});
-test('fetchFields', function () use ($explorer) {
- Assert::same([11, 'Jakub Vrana'], $explorer->fetchFields('SELECT id, name FROM author ORDER BY id'));
+test('fetchList', function () use ($explorer) {
+ Assert::same([11, 'Jakub Vrana'], $explorer->fetchList('SELECT id, name FROM author ORDER BY id'));
});
diff --git a/tests/Database/Explorer.query.phpt b/tests/Database/Explorer.query.phpt
index 254a38c7d..e36c76148 100644
--- a/tests/Database/Explorer.query.phpt
+++ b/tests/Database/Explorer.query.phpt
@@ -12,28 +12,27 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
$res = $explorer->query('SELECT id FROM author WHERE id = ?', 11);
- Assert::type(Nette\Database\ResultSet::class, $res);
- Assert::same('SELECT id FROM author WHERE id = ?', $res->getQueryString());
- Assert::same([11], $res->getParameters());
+ Assert::type(Nette\Database\Result::class, $res);
+ Assert::same('SELECT id FROM author WHERE id = ?', $res->getQuery()->getSql());
+ Assert::same([11], $res->getQuery()->getParameters());
});
test('', function () use ($explorer) {
$res = $explorer->query('SELECT id FROM author WHERE id = ? OR id = ?', 11, 12);
- Assert::same('SELECT id FROM author WHERE id = ? OR id = ?', $res->getQueryString());
- Assert::same([11, 12], $res->getParameters());
+ Assert::same('SELECT id FROM author WHERE id = ? OR id = ?', $res->getQuery()->getSql());
+ Assert::same([11, 12], $res->getQuery()->getParameters());
});
test('', function () use ($explorer) {
- $res = $explorer->queryArgs('SELECT id FROM author WHERE id = ? OR id = ?', [11, 12]);
- Assert::same('SELECT id FROM author WHERE id = ? OR id = ?', $res->getQueryString());
- Assert::same([11, 12], $res->getParameters());
+ $res = @$explorer->queryArgs('SELECT id FROM author WHERE id = ? OR id = ?', [11, 12]); // is deprecated
+ Assert::same('SELECT id FROM author WHERE id = ? OR id = ?', $res->getQuery()->getSql());
+ Assert::same([11, 12], $res->getQuery()->getParameters());
});
diff --git a/tests/Database/Explorer.transaction.phpt b/tests/Database/Explorer.transaction.phpt
index adbf31b1d..7dddcc567 100644
--- a/tests/Database/Explorer.transaction.phpt
+++ b/tests/Database/Explorer.transaction.phpt
@@ -13,9 +13,8 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/ActiveRow.__toString().phpt b/tests/Database/Explorer/ActiveRow.__toString().phpt
index f3a29d9d7..ce25195b6 100644
--- a/tests/Database/Explorer/ActiveRow.__toString().phpt
+++ b/tests/Database/Explorer/ActiveRow.__toString().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Explorer.aggregation.phpt b/tests/Database/Explorer/Explorer.aggregation.phpt
index e04fea142..79d31bdee 100644
--- a/tests/Database/Explorer/Explorer.aggregation.phpt
+++ b/tests/Database/Explorer/Explorer.aggregation.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Explorer.backjoin.phpt b/tests/Database/Explorer/Explorer.backjoin.phpt
index a466b3404..7fdcf7f61 100644
--- a/tests/Database/Explorer/Explorer.backjoin.phpt
+++ b/tests/Database/Explorer/Explorer.backjoin.phpt
@@ -7,16 +7,15 @@
declare(strict_types=1);
-use Nette\Database\Driver;
+use Nette\Database\Drivers\Engine;
use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
-$driver = $connection->getDriver();
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+$engine = $explorer->getDatabaseEngine();
test('', function () use ($explorer) {
@@ -39,10 +38,10 @@ test('', function () use ($explorer) {
});
-test('', function () use ($explorer, $driver) {
+test('', function () use ($explorer, $engine) {
$authorsSelection = $explorer->table('author')->where(':book.translator_id IS NOT NULL')->wherePrimary(12);
- if ($driver->isSupported(Driver::SupportSchema)) {
+ if ($engine->isSupported(Engine::SupportSchema)) {
Assert::same(
reformat('SELECT [author].* FROM [author] LEFT JOIN [public].[book] [book] ON [author].[id] = [book].[author_id] WHERE ([book].[translator_id] IS NOT NULL) AND ([author].[id] = ?)'),
$authorsSelection->getSql(),
diff --git a/tests/Database/Explorer/Explorer.basic.camelCase.phpt b/tests/Database/Explorer/Explorer.basic.camelCase.phpt
index 6fe3432fc..4f3a072b6 100644
--- a/tests/Database/Explorer/Explorer.basic.camelCase.phpt
+++ b/tests/Database/Explorer/Explorer.basic.camelCase.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test2.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test2.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Explorer.basic.phpt b/tests/Database/Explorer/Explorer.basic.phpt
index 4a1d833be..c109645fc 100644
--- a/tests/Database/Explorer/Explorer.basic.phpt
+++ b/tests/Database/Explorer/Explorer.basic.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Explorer.cache.observer.phpt b/tests/Database/Explorer/Explorer.cache.observer.phpt
index 1c52c4296..931a926a8 100644
--- a/tests/Database/Explorer/Explorer.cache.observer.phpt
+++ b/tests/Database/Explorer/Explorer.cache.observer.phpt
@@ -7,27 +7,30 @@
declare(strict_types=1);
-use Nette\Database\ResultSet;
+use Nette\Database\Result;
use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
-$cacheStorage = Mockery::mock(Nette\Caching\Istorage::class);
-$cacheStorage->shouldReceive('read')->withAnyArgs()->once()->andReturn(['id' => true]);
-$cacheStorage->shouldReceive('read')->withAnyArgs()->times(4)->andReturn(['id' => true, 'author_id' => true]);
-$cacheStorage->shouldReceive('write')->with(Mockery::any(), ['id' => true, 'author_id' => true, 'title' => true], []);
-
-$explorer = new Nette\Database\Explorer($connection, $explorer->getStructure(), $explorer->getConventions(), $cacheStorage);
+$cache = Mockery::mock(Nette\Caching\Cache::class);
+$cache->shouldReceive('load')->withAnyArgs()->once()->andReturn([]);
+$cache->shouldReceive('load')->withAnyArgs()->once()->andReturn(['id' => true]);
+$cache->shouldReceive('load')->withAnyArgs()->times(4)->andReturn(['id' => true, 'author_id' => true]);
+$cache->shouldReceive('save')->with('structure', Mockery::any());
+$cache->shouldReceive('save')->with(Mockery::any(), ['id' => true, 'author_id' => true, 'title' => true]);
+$explorer->setCache($cache);
$queries = 0;
-$connection->onQuery[] = function ($dao, ResultSet $result) use (&$queries) {
- if (!preg_match('#SHOW|CONSTRAINT_NAME|pg_catalog|sys\.|SET|PRAGMA|FROM sqlite_#i', $result->getQueryString())) {
+$explorer->onQuery[] = function ($explorer, $result) use (&$queries) {
+ if (
+ $result instanceof Result
+ && !preg_match('#SHOW|CONSTRAINT_NAME|pg_catalog|sys\.|SET|PRAGMA|FROM sqlite_#i', $result->getQuery()->getSql())
+ ) {
$queries++;
}
};
diff --git a/tests/Database/Explorer/Explorer.cache.observer2.phpt b/tests/Database/Explorer/Explorer.cache.observer2.phpt
index 5eff0cf66..0e7ce2ea1 100644
--- a/tests/Database/Explorer/Explorer.cache.observer2.phpt
+++ b/tests/Database/Explorer/Explorer.cache.observer2.phpt
@@ -7,31 +7,31 @@
declare(strict_types=1);
+use Nette\Caching\Cache;
use Nette\Caching\Storages\MemoryStorage;
use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
-class CacheMock extends MemoryStorage
+class CacheMock extends Cache
{
public int $writes = 0;
- public function write(string $key, $data, array $dependencies): void
+ public function save(mixed $key, mixed $data, ?array $dependencies = null): mixed
{
$this->writes++;
- parent::write($key, $data, $dependencies);
+ return parent::save($key, $data, $dependencies);
}
}
-$cacheStorage = new CacheMock;
-$explorer = new Nette\Database\Explorer($connection, $explorer->getStructure(), $explorer->getConventions(), $cacheStorage);
+$cache = new CacheMock(new MemoryStorage);
+$explorer->setCache($cache);
for ($i = 0; $i < 2; ++$i) {
$authors = $explorer->table('author');
@@ -52,4 +52,4 @@ for ($i = 0; $i < 2; ++$i) {
}
Assert::same(reformat('SELECT [id], [name] FROM [author]'), $sql);
-Assert::same(2, $cacheStorage->writes);
+Assert::same(3, $cache->writes); // Structure + 2x Selection
diff --git a/tests/Database/Explorer/Explorer.cache.phpt b/tests/Database/Explorer/Explorer.cache.phpt
index 20e94bad9..9ec981e47 100644
--- a/tests/Database/Explorer/Explorer.cache.phpt
+++ b/tests/Database/Explorer/Explorer.cache.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('Testing Selection caching', function () use ($explorer) {
@@ -198,7 +197,7 @@ test('Test saving the union of needed cols, the second call is not subset', func
test('Test multiple use of same selection', function () use ($explorer) {
$sql = [];
- $explorer->getConnection()->onQuery[] = function ($_, $result) use (&$sql) {
+ $explorer->onQuery[] = function ($_, $result) use (&$sql) {
$sql[] = $result->getQueryString();
};
diff --git a/tests/Database/Explorer/Explorer.cache.rows.phpt b/tests/Database/Explorer/Explorer.cache.rows.phpt
index 78761af63..19ba71027 100644
--- a/tests/Database/Explorer/Explorer.cache.rows.phpt
+++ b/tests/Database/Explorer/Explorer.cache.rows.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
$selections = [];
diff --git a/tests/Database/Explorer/Explorer.cache2.phpt b/tests/Database/Explorer/Explorer.cache2.phpt
index c174b7779..5f6202526 100644
--- a/tests/Database/Explorer/Explorer.cache2.phpt
+++ b/tests/Database/Explorer/Explorer.cache2.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
$res = [];
diff --git a/tests/Database/Explorer/Explorer.columnRefetch.phpt b/tests/Database/Explorer/Explorer.columnRefetch.phpt
index 4ff46a398..e49d7917e 100644
--- a/tests/Database/Explorer/Explorer.columnRefetch.phpt
+++ b/tests/Database/Explorer/Explorer.columnRefetch.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
$books = $explorer->table('book')->order('id DESC')->limit(2);
diff --git a/tests/Database/Explorer/Explorer.discoveredReflection.phpt b/tests/Database/Explorer/Explorer.discoveredReflection.phpt
index eed582dab..f427a8e5c 100644
--- a/tests/Database/Explorer/Explorer.discoveredReflection.phpt
+++ b/tests/Database/Explorer/Explorer.discoveredReflection.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
@@ -90,10 +89,10 @@ test('', function () use ($explorer) {
});
-test('', function () use ($connection, $explorer, $driverName) {
+test('', function () use ($explorer, $driverName) {
if (
$driverName === 'mysql' &&
- ($lowerCase = $connection->query('SHOW VARIABLES LIKE "lower_case_table_names"')->fetch()) &&
+ ($lowerCase = $explorer->query('SHOW VARIABLES LIKE "lower_case_table_names"')->fetch()) &&
$lowerCase->Value != 0
) {
// tests case-insensitive reflection
diff --git a/tests/Database/Explorer/Explorer.join-condition.phpt b/tests/Database/Explorer/Explorer.join-condition.phpt
index 34af228b9..9b22801ac 100644
--- a/tests/Database/Explorer/Explorer.join-condition.phpt
+++ b/tests/Database/Explorer/Explorer.join-condition.phpt
@@ -7,18 +7,18 @@
declare(strict_types=1);
-use Nette\Database\Driver;
+use Nette\Database\Drivers\Engine;
use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
-$driver = $connection->getDriver();
-test('', function () use ($explorer, $driver) {
- $schema = $driver->isSupported(Driver::SupportSchema)
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+$engine = $explorer->getDatabaseEngine();
+
+test('', function () use ($explorer, $engine) {
+ $schema = $engine->isSupported(Engine::SupportSchema)
? '[public].'
: '';
$sql = $explorer->table('book')->joinWhere('translator', 'translator.name', 'Geek')->select('book.*')->getSql();
@@ -29,7 +29,7 @@ test('', function () use ($explorer, $driver) {
), $sql);
});
-test('', function () use ($explorer, $driver) {
+test('', function () use ($explorer, $engine) {
$sql = $explorer->table('tag')
->select('tag.name, COUNT(:book_tag.book.id) AS count_of_next_volume_written_by_younger_author')
->joinWhere(':book_tag.book.author', ':book_tag.book.author.born < next_volume_author.born')
@@ -37,7 +37,7 @@ test('', function () use ($explorer, $driver) {
->where('tag.name', 'PHP')
->group('tag.name')
->getSql();
- if ($driver->isSupported(Driver::SupportSchema)) {
+ if ($engine->isSupported(Engine::SupportSchema)) {
Assert::same(
reformat(
'SELECT [tag].[name], COUNT([book].[id]) AS [count_of_next_volume_written_by_younger_author] FROM [tag] ' .
diff --git a/tests/Database/Explorer/Explorer.join.phpt b/tests/Database/Explorer/Explorer.join.phpt
index 897975fb7..39f63fa64 100644
--- a/tests/Database/Explorer/Explorer.join.phpt
+++ b/tests/Database/Explorer/Explorer.join.phpt
@@ -7,16 +7,15 @@
declare(strict_types=1);
-use Nette\Database\Driver;
+use Nette\Database\Drivers\Engine;
use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
-$driver = $connection->getDriver();
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+$engine = $explorer->getDatabaseEngine();
test('', function () use ($explorer) {
@@ -34,10 +33,10 @@ test('', function () use ($explorer) {
});
-test('', function () use ($explorer, $driver) {
+test('', function () use ($explorer, $engine) {
$joinSql = $explorer->table('book_tag')->where('book_id', 1)->select('tag.*')->getSql();
- if ($driver->isSupported(Driver::SupportSchema)) {
+ if ($engine->isSupported(Engine::SupportSchema)) {
Assert::same(
reformat('SELECT [tag].* FROM [book_tag] LEFT JOIN [public].[tag] [tag] ON [book_tag].[tag_id] = [tag].[id] WHERE ([book_id] = ?)'),
$joinSql,
@@ -51,10 +50,10 @@ test('', function () use ($explorer, $driver) {
});
-test('', function () use ($explorer, $driver) {
+test('', function () use ($explorer, $engine) {
$joinSql = $explorer->table('book_tag')->where('book_id', 1)->select('Tag.id')->getSql();
- if ($driver->isSupported(Driver::SupportSchema)) {
+ if ($engine->isSupported(Engine::SupportSchema)) {
Assert::same(
reformat('SELECT [Tag].[id] FROM [book_tag] LEFT JOIN [public].[tag] [Tag] ON [book_tag].[tag_id] = [Tag].[id] WHERE ([book_id] = ?)'),
$joinSql,
diff --git a/tests/Database/Explorer/Explorer.limit.phpt b/tests/Database/Explorer/Explorer.limit.phpt
index ccf1bec6a..95b733982 100644
--- a/tests/Database/Explorer/Explorer.limit.phpt
+++ b/tests/Database/Explorer/Explorer.limit.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
Assert::same(
diff --git a/tests/Database/Explorer/Explorer.limit.sqlsrv.phpt b/tests/Database/Explorer/Explorer.limit.sqlsrv.phpt
index e5218ff98..a803010e6 100644
--- a/tests/Database/Explorer/Explorer.limit.sqlsrv.phpt
+++ b/tests/Database/Explorer/Explorer.limit.sqlsrv.phpt
@@ -12,11 +12,10 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
-$version2008 = $connection->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION) < 11;
+$version2008 = $explorer->getServerVersion() < 11;
Assert::same(
$version2008
diff --git a/tests/Database/Explorer/Explorer.multi-primary-key.phpt b/tests/Database/Explorer/Explorer.multi-primary-key.phpt
index d914c028a..decc738f8 100644
--- a/tests/Database/Explorer/Explorer.multi-primary-key.phpt
+++ b/tests/Database/Explorer/Explorer.multi-primary-key.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Explorer.placeholders.phpt b/tests/Database/Explorer/Explorer.placeholders.phpt
index 52ce83415..858c6dd55 100644
--- a/tests/Database/Explorer/Explorer.placeholders.phpt
+++ b/tests/Database/Explorer/Explorer.placeholders.phpt
@@ -13,9 +13,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('Leave literals lower-cased, also not-delimiting them is tested.', function () use ($explorer, $driverName) {
diff --git a/tests/Database/Explorer/Explorer.ref().phpt b/tests/Database/Explorer/Explorer.ref().phpt
index a8a017087..e2cfdd36a 100644
--- a/tests/Database/Explorer/Explorer.ref().phpt
+++ b/tests/Database/Explorer/Explorer.ref().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
Assert::same('Jakub Vrana', $explorer->table('book')->get(1)->ref('author')->name);
@@ -36,10 +35,10 @@ test('', function () use ($explorer) {
Assert::null($explorer->table('book')->get(2)->ref('author', 'translator_id'));
});
-test('', function () use ($explorer, $connection) {
+test('', function () use ($explorer) {
$counter = 0;
- $connection->onQuery[] = function ($connection, $result) use (&$counter) {
+ $explorer->onQuery[] = function ($explorer, $result) use (&$counter) {
$counter++;
};
diff --git a/tests/Database/Explorer/Explorer.related().caching.phpt b/tests/Database/Explorer/Explorer.related().caching.phpt
index d6995923d..f1322ca3b 100644
--- a/tests/Database/Explorer/Explorer.related().caching.phpt
+++ b/tests/Database/Explorer/Explorer.related().caching.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Explorer.related().phpt b/tests/Database/Explorer/Explorer.related().phpt
index 84455a402..daf9c3462 100644
--- a/tests/Database/Explorer/Explorer.related().phpt
+++ b/tests/Database/Explorer/Explorer.related().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Explorer.self-reference.phpt b/tests/Database/Explorer/Explorer.self-reference.phpt
index 345043024..6d13a2710 100644
--- a/tests/Database/Explorer/Explorer.self-reference.phpt
+++ b/tests/Database/Explorer/Explorer.self-reference.phpt
@@ -12,15 +12,14 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
$explorer->query('UPDATE book SET next_volume = 3 WHERE id IN (2,4)');
-test('', function () use ($connection, $explorer) {
+test('', function () use ($explorer) {
$book = $explorer->table('book')->get(4);
Assert::same('Nette', $book->volume->title);
Assert::same('Nette', $book->ref('book', 'next_volume')->title);
diff --git a/tests/Database/Explorer/Explorer.subquery.phpt b/tests/Database/Explorer/Explorer.subquery.phpt
index 314188f0d..744a5ecc6 100644
--- a/tests/Database/Explorer/Explorer.subquery.phpt
+++ b/tests/Database/Explorer/Explorer.subquery.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Explorer.update().phpt b/tests/Database/Explorer/Explorer.update().phpt
index 11ffd1a81..0c966779f 100644
--- a/tests/Database/Explorer/Explorer.update().phpt
+++ b/tests/Database/Explorer/Explorer.update().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
$author = $explorer->table('author')->get(12); // SELECT * FROM `author` WHERE (`id` = ?)
@@ -79,7 +78,7 @@ $tag2 = $explorer->table('tag')->insert([
'name' => 'PS4 Game',
]); // INSERT INTO `tag` (`name`) VALUES ('PS4 Game')
-// SQL Server throw PDOException because does not allow to update identity column
+// SQL Server throw exception because does not allow to update identity column
if ($driverName !== 'sqlsrv') {
$tag2->update([
'id' => 1,
diff --git a/tests/Database/Explorer/GroupedSelection.insert().phpt b/tests/Database/Explorer/GroupedSelection.insert().phpt
index 60c239637..b24d7b307 100644
--- a/tests/Database/Explorer/GroupedSelection.insert().phpt
+++ b/tests/Database/Explorer/GroupedSelection.insert().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Selection.delete().phpt b/tests/Database/Explorer/Selection.delete().phpt
index f5292bb95..f3ba7f959 100644
--- a/tests/Database/Explorer/Selection.delete().phpt
+++ b/tests/Database/Explorer/Selection.delete().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Selection.fetch().phpt b/tests/Database/Explorer/Selection.fetch().phpt
index ec71f3887..594debe55 100644
--- a/tests/Database/Explorer/Selection.fetch().phpt
+++ b/tests/Database/Explorer/Selection.fetch().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Selection.fetchAssoc().phpt b/tests/Database/Explorer/Selection.fetchAssoc().phpt
index 6280b9cb6..63e66b7b9 100644
--- a/tests/Database/Explorer/Selection.fetchAssoc().phpt
+++ b/tests/Database/Explorer/Selection.fetchAssoc().phpt
@@ -13,9 +13,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Selection.fetchField().phpt b/tests/Database/Explorer/Selection.fetchField().phpt
index 5eb29cc3b..ff35ca756 100644
--- a/tests/Database/Explorer/Selection.fetchField().phpt
+++ b/tests/Database/Explorer/Selection.fetchField().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Selection.fetchPairs().phpt b/tests/Database/Explorer/Selection.fetchPairs().phpt
index 89fc97028..832ed2e3f 100644
--- a/tests/Database/Explorer/Selection.fetchPairs().phpt
+++ b/tests/Database/Explorer/Selection.fetchPairs().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Selection.get().phpt b/tests/Database/Explorer/Selection.get().phpt
index 138afd97e..b153cc479 100644
--- a/tests/Database/Explorer/Selection.get().phpt
+++ b/tests/Database/Explorer/Selection.get().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Selection.group().phpt b/tests/Database/Explorer/Selection.group().phpt
index ec51d7da7..68cb0ef2b 100644
--- a/tests/Database/Explorer/Selection.group().phpt
+++ b/tests/Database/Explorer/Selection.group().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Selection.insert().multi.phpt b/tests/Database/Explorer/Selection.insert().multi.phpt
index 99dbcdcb7..0a032e008 100644
--- a/tests/Database/Explorer/Selection.insert().multi.phpt
+++ b/tests/Database/Explorer/Selection.insert().multi.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Selection.insert().phpt b/tests/Database/Explorer/Selection.insert().phpt
index f96e6f88c..4f5599278 100644
--- a/tests/Database/Explorer/Selection.insert().phpt
+++ b/tests/Database/Explorer/Selection.insert().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
$book = $explorer->table('author')->insert([
@@ -41,7 +40,7 @@ $book2 = $books->insert([
Assert::same('eddard stark', $book2->author->name); // SELECT * FROM `author` WHERE (`author`.`id` IN (11, 15))
-// SQL Server throw PDOException because does not allow insert explicit value for IDENTITY column.
+// SQL Server throw exception because does not allow insert explicit value for IDENTITY column.
// This exception is about primary key violation.
if ($driverName !== 'sqlsrv') {
Assert::exception(
@@ -50,7 +49,7 @@ if ($driverName !== 'sqlsrv') {
'name' => 'Jon Snow',
'web' => 'http://example.com',
]),
- PDOException::class,
+ Nette\Database\UniqueConstraintViolationException::class,
);
}
diff --git a/tests/Database/Explorer/Selection.insert().primaryKeys.phpt b/tests/Database/Explorer/Selection.insert().primaryKeys.phpt
index 885a89e37..0562d6af7 100644
--- a/tests/Database/Explorer/Selection.insert().primaryKeys.phpt
+++ b/tests/Database/Explorer/Selection.insert().primaryKeys.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test4.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test4.sql");
test('Insert into table with simple primary index (autoincrement)', function () use ($explorer) {
$simplePkAutoincrementResult = $explorer->table('simple_pk_autoincrement')->insert([
diff --git a/tests/Database/Explorer/Selection.order().phpt b/tests/Database/Explorer/Selection.order().phpt
index f264baa84..5633bbfb7 100644
--- a/tests/Database/Explorer/Selection.order().phpt
+++ b/tests/Database/Explorer/Selection.order().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/Selection.page().phpt b/tests/Database/Explorer/Selection.page().phpt
index ea05cad0a..b4cce1ccb 100644
--- a/tests/Database/Explorer/Selection.page().phpt
+++ b/tests/Database/Explorer/Selection.page().phpt
@@ -12,13 +12,12 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-if ($driverName === 'sqlsrv' && $connection->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION) < 11) {
+if ($driverName === 'sqlsrv' && $explorer->getServerVersion() < 11) {
Tester\Environment::skip('Offset is supported since SQL Server 2012');
}
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
//public function page($page, $itemsPerPage, &$numOfPages = null)
diff --git a/tests/Database/Explorer/Selection.whereOr().phpt b/tests/Database/Explorer/Selection.whereOr().phpt
index 9cc8b1058..2279db58a 100644
--- a/tests/Database/Explorer/Selection.whereOr().phpt
+++ b/tests/Database/Explorer/Selection.whereOr().phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('without question mark', function () use ($explorer) {
$count = $explorer->table('book')->whereOr([
diff --git a/tests/Database/Explorer/SqlBuilder.addAlias().phpt b/tests/Database/Explorer/SqlBuilder.addAlias().phpt
index f3fbd4a06..adb9a41d3 100644
--- a/tests/Database/Explorer/SqlBuilder.addAlias().phpt
+++ b/tests/Database/Explorer/SqlBuilder.addAlias().phpt
@@ -7,16 +7,15 @@
declare(strict_types=1);
-use Nette\Database\Driver;
+use Nette\Database\Drivers\Engine;
use Nette\Database\Table\SqlBuilder;
use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
class SqlBuilderMock extends SqlBuilder
{
@@ -32,11 +31,11 @@ class SqlBuilderMock extends SqlBuilder
}
}
-$driver = $connection->getDriver();
+$engine = $explorer->getDatabaseEngine();
-test('test duplicated table names throw exception', function () use ($explorer, $driver) {
- $authorTable = ($driver->isSupported(Driver::SupportSchema) ? 'public.' : '') . 'author';
+test('test duplicated table names throw exception', function () use ($explorer, $engine) {
+ $authorTable = ($engine->isSupported(Engine::SupportSchema) ? 'public.' : '') . 'author';
$sqlBuilder = new SqlBuilderMock($authorTable, $explorer);
$sqlBuilder->addAlias(':book(translator)', 'book1');
$sqlBuilder->addAlias(':book:book_tag', 'book2');
@@ -73,7 +72,7 @@ test('test duplicated table names throw exception', function () use ($explorer,
});
-test('test same table chain with another alias', function () use ($explorer, $driver) {
+test('test same table chain with another alias', function () use ($explorer, $engine) {
$sqlBuilder = new SqlBuilderMock('author', $explorer);
$sqlBuilder->addAlias(':book(translator)', 'translated_book');
$sqlBuilder->addAlias(':book(translator)', 'translated_book2');
@@ -90,8 +89,8 @@ test('test same table chain with another alias', function () use ($explorer, $dr
});
-test('test nested alias', function () use ($explorer, $driver) {
- $sqlBuilder = $driver->isSupported(Driver::SupportSchema)
+test('test nested alias', function () use ($explorer, $engine) {
+ $sqlBuilder = $engine->isSupported(Engine::SupportSchema)
? new SqlBuilderMock('public.author', $explorer)
: new SqlBuilderMock('author', $explorer);
$sqlBuilder->addAlias(':book(translator)', 'translated_book');
@@ -100,7 +99,7 @@ test('test nested alias', function () use ($explorer, $driver) {
$joins = [];
$sqlBuilder->parseJoins($joins, $query);
$join = $sqlBuilder->buildQueryJoins($joins);
- if ($driver->isSupported(Driver::SupportSchema)) {
+ if ($engine->isSupported(Engine::SupportSchema)) {
Assert::same(
'LEFT JOIN book translated_book ON author.id = translated_book.translator_id ' .
'LEFT JOIN public.book next ON translated_book.next_volume = next.id',
diff --git a/tests/Database/Explorer/SqlBuilder.addWhere().phpt b/tests/Database/Explorer/SqlBuilder.addWhere().phpt
index 12e81c04b..92b43343e 100644
--- a/tests/Database/Explorer/SqlBuilder.addWhere().phpt
+++ b/tests/Database/Explorer/SqlBuilder.addWhere().phpt
@@ -7,7 +7,7 @@
declare(strict_types=1);
-use Nette\Database\Driver;
+use Nette\Database\Drivers\Engine;
use Nette\Database\SqlLiteral;
use Nette\Database\Table\SqlBuilder;
use Tester\Assert;
@@ -15,9 +15,8 @@ use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
test('test paramateres with null', function () use ($explorer) {
@@ -82,7 +81,7 @@ test('test more ActiveRow as a parameter', function () use ($explorer) {
test('test Selection with parameters as a parameter', function () use ($explorer) {
$sqlBuilder = new SqlBuilder('book', $explorer);
$sqlBuilder->addWhere('id', $explorer->table('book')->having('COUNT(:book_tag.tag_id) >', 1));
- $schemaSupported = $explorer->getConnection()->getDriver()->isSupported(Driver::SupportSchema);
+ $schemaSupported = $explorer->getDatabaseEngine()->isSupported(Engine::SupportSchema);
Assert::same(reformat([
'mysql' => 'SELECT * FROM `book` WHERE (`id` IN (?))',
'SELECT * FROM [book] WHERE ([id] IN (SELECT [id] FROM [book] LEFT JOIN ' . ($schemaSupported ? '[public].[book_tag] ' : '') . '[book_tag] ON [book].[id] = [book_tag].[book_id] HAVING COUNT([book_tag].[tag_id]) > ?))',
@@ -243,7 +242,7 @@ Assert::exception(function () use ($explorer) {
}, Nette\InvalidArgumentException::class, 'Column operator does not accept array argument.');
-test('', function () use ($driverName, $explorer, $connection) {
+test('', function () use ($driverName, $explorer) {
$structure = $explorer->getStructure();
switch ($driverName) {
case 'mysql':
diff --git a/tests/Database/Explorer/SqlBuilder.parseJoinConditions().phpt b/tests/Database/Explorer/SqlBuilder.parseJoinConditions().phpt
index cb0d83ff0..b1c6f9f5f 100644
--- a/tests/Database/Explorer/SqlBuilder.parseJoinConditions().phpt
+++ b/tests/Database/Explorer/SqlBuilder.parseJoinConditions().phpt
@@ -7,16 +7,15 @@
declare(strict_types=1);
-use Nette\Database\Driver;
+use Nette\Database\Drivers\Engine;
use Nette\Database\Table\SqlBuilder;
use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
class SqlBuilderMock extends SqlBuilder
{
@@ -44,7 +43,7 @@ class SqlBuilderMock extends SqlBuilder
}
}
-$driver = $connection->getDriver();
+$engine = $explorer->getDatabaseEngine();
test('test circular reference', function () use ($explorer) {
$sqlBuilder = new SqlBuilderMock('author', $explorer);
@@ -75,7 +74,7 @@ test('test circular reference', function () use ($explorer) {
);
});
-test('', function () use ($explorer, $driver) {
+test('', function () use ($explorer, $engine) {
$sqlBuilder = new SqlBuilderMock('author', $explorer);
$sqlBuilder->addJoinCondition(':book(translator)', ':book(translator).id > ?', 2);
$sqlBuilder->addJoinCondition(':book(translator):book_tag_alt', ':book(translator):book_tag_alt.state ?', 'private');
@@ -83,7 +82,7 @@ test('', function () use ($explorer, $driver) {
$leftJoinConditions = $sqlBuilder->parseJoinConditions($joins, $sqlBuilder->buildJoinConditions());
$join = $sqlBuilder->buildQueryJoins($joins, $leftJoinConditions);
- if ($driver->isSupported(Driver::SupportSchema)) {
+ if ($engine->isSupported(Engine::SupportSchema)) {
Assert::same(
'LEFT JOIN book ON author.id = book.translator_id AND (book.id > ?) ' .
'LEFT JOIN public.book_tag_alt book_tag_alt ON book.id = book_tag_alt.book_id AND (book_tag_alt.state = ?)',
diff --git a/tests/Database/Explorer/SqlBuilder.parseJoins().phpt b/tests/Database/Explorer/SqlBuilder.parseJoins().phpt
index 847f32ec4..3fabed91b 100644
--- a/tests/Database/Explorer/SqlBuilder.parseJoins().phpt
+++ b/tests/Database/Explorer/SqlBuilder.parseJoins().phpt
@@ -8,16 +8,15 @@
declare(strict_types=1);
use Nette\Database\Conventions\DiscoveredConventions;
-use Nette\Database\Driver;
+use Nette\Database\Drivers\Engine;
use Nette\Database\Table\SqlBuilder;
use Tester\Assert;
require __DIR__ . '/../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test2.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test2.sql");
class SqlBuilderMock extends SqlBuilder
@@ -37,7 +36,7 @@ class SqlBuilderMock extends SqlBuilder
$structure = $explorer->getStructure();
$conventions = new DiscoveredConventions($structure);
$sqlBuilder = new SqlBuilderMock('nUsers', $explorer);
-$driver = $connection->getDriver();
+$engine = $explorer->getDatabaseEngine();
$joins = [];
@@ -46,9 +45,9 @@ $sqlBuilder->parseJoins($joins, $query);
$join = $sqlBuilder->buildQueryJoins($joins);
Assert::same('WHERE priorit.id IS NULL', $query);
-$tables = $connection->getDriver()->getTables();
+$tables = $explorer->getDatabaseEngine()->getTables();
if (!in_array($tables[0]['name'], ['npriorities', 'ntopics', 'nusers', 'nusers_ntopics', 'nusers_ntopics_alt'], true)) {
- if ($driver->isSupported(Driver::SupportSchema)) {
+ if ($engine->isSupported(Engine::SupportSchema)) {
Assert::same(
'LEFT JOIN public.nUsers_nTopics nusers_ntopics ON nUsers.nUserId = nusers_ntopics.nUserId ' .
'LEFT JOIN public.nTopics topic ON nusers_ntopics.nTopicId = topic.nTopicId ' .
@@ -75,7 +74,7 @@ if (!in_array($tables[0]['name'], ['npriorities', 'ntopics', 'nusers', 'nusers_n
}
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../files/{$driverName}-nette_test1.sql");
$structure->rebuild();
$sqlBuilder = new SqlBuilderMock('author', $explorer);
@@ -91,7 +90,7 @@ Assert::same(
);
-$sqlBuilder = $driver->isSupported(Driver::SupportSchema)
+$sqlBuilder = $engine->isSupported(Engine::SupportSchema)
? new SqlBuilderMock('public.book', $explorer)
: new SqlBuilderMock('book', $explorer);
@@ -101,7 +100,7 @@ $sqlBuilder->parseJoins($joins, $query);
$join = $sqlBuilder->buildQueryJoins($joins);
Assert::same('WHERE book_ref.translator_id IS NULL AND book_ref_ref.translator_id IS NULL', $query);
-if ($driver->isSupported(Driver::SupportSchema)) {
+if ($engine->isSupported(Engine::SupportSchema)) {
Assert::same(
'LEFT JOIN public.book book_ref ON book.id = book_ref.next_volume ' .
'LEFT JOIN public.book book_ref_ref ON book_ref.id = book_ref_ref.next_volume',
diff --git a/tests/Database/Explorer/SqlBuilder.tryDelimit().phpt b/tests/Database/Explorer/SqlBuilder.tryDelimit().phpt
new file mode 100644
index 000000000..a2930edf2
--- /dev/null
+++ b/tests/Database/Explorer/SqlBuilder.tryDelimit().phpt
@@ -0,0 +1,29 @@
+getMethod('tryDelimit');
+$tryDelimit->setAccessible(true);
+
+Assert::same(reformat('[hello]'), $tryDelimit->invoke($sqlBuilder, 'hello'));
+Assert::same(reformat(' [hello] '), $tryDelimit->invoke($sqlBuilder, ' hello '));
+Assert::same(reformat('HELLO'), $tryDelimit->invoke($sqlBuilder, 'HELLO'));
+Assert::same(reformat('[HellO]'), $tryDelimit->invoke($sqlBuilder, 'HellO'));
+Assert::same(reformat('[hello].[world]'), $tryDelimit->invoke($sqlBuilder, 'hello.world'));
+Assert::same(reformat('[hello] [world]'), $tryDelimit->invoke($sqlBuilder, 'hello world'));
+Assert::same(reformat('HELLO([world])'), $tryDelimit->invoke($sqlBuilder, 'HELLO(world)'));
+Assert::same(reformat('hello([world])'), $tryDelimit->invoke($sqlBuilder, 'hello(world)'));
+Assert::same('[hello]', $tryDelimit->invoke($sqlBuilder, '[hello]'));
+Assert::same(reformat('::int'), $tryDelimit->invoke($sqlBuilder, '::int'));
diff --git a/tests/Database/Explorer/SqlBuilder.tryDelimite().phpt b/tests/Database/Explorer/SqlBuilder.tryDelimite().phpt
deleted file mode 100644
index 5aa8aaf31..000000000
--- a/tests/Database/Explorer/SqlBuilder.tryDelimite().phpt
+++ /dev/null
@@ -1,29 +0,0 @@
-getMethod('tryDelimite');
-$tryDelimite->setAccessible(true);
-
-Assert::same(reformat('[hello]'), $tryDelimite->invoke($sqlBuilder, 'hello'));
-Assert::same(reformat(' [hello] '), $tryDelimite->invoke($sqlBuilder, ' hello '));
-Assert::same(reformat('HELLO'), $tryDelimite->invoke($sqlBuilder, 'HELLO'));
-Assert::same(reformat('[HellO]'), $tryDelimite->invoke($sqlBuilder, 'HellO'));
-Assert::same(reformat('[hello].[world]'), $tryDelimite->invoke($sqlBuilder, 'hello.world'));
-Assert::same(reformat('[hello] [world]'), $tryDelimite->invoke($sqlBuilder, 'hello world'));
-Assert::same(reformat('HELLO([world])'), $tryDelimite->invoke($sqlBuilder, 'HELLO(world)'));
-Assert::same(reformat('hello([world])'), $tryDelimite->invoke($sqlBuilder, 'hello(world)'));
-Assert::same('[hello]', $tryDelimite->invoke($sqlBuilder, '[hello]'));
-Assert::same(reformat('::int'), $tryDelimite->invoke($sqlBuilder, '::int'));
diff --git a/tests/Database/Explorer/bugs/ActiveRow.__isset().phpt b/tests/Database/Explorer/bugs/ActiveRow.__isset().phpt
index bac634f6a..a26087efd 100644
--- a/tests/Database/Explorer/bugs/ActiveRow.__isset().phpt
+++ b/tests/Database/Explorer/bugs/ActiveRow.__isset().phpt
@@ -11,9 +11,8 @@ use Tester\Assert;
require __DIR__ . '/../../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/bugs/Selection.emptyResultSet.phpt b/tests/Database/Explorer/bugs/Selection.emptyResultSet.phpt
index e0b42ed08..ff3974cee 100644
--- a/tests/Database/Explorer/bugs/Selection.emptyResultSet.phpt
+++ b/tests/Database/Explorer/bugs/Selection.emptyResultSet.phpt
@@ -11,9 +11,8 @@ use Tester\Assert;
require __DIR__ . '/../../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/bugs/Selection.getReferencingTable.pkTypes.phpt b/tests/Database/Explorer/bugs/Selection.getReferencingTable.pkTypes.phpt
index cc4621b7b..fe38a5be9 100644
--- a/tests/Database/Explorer/bugs/Selection.getReferencingTable.pkTypes.phpt
+++ b/tests/Database/Explorer/bugs/Selection.getReferencingTable.pkTypes.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../../files/{$driverName}-nette_test5.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../../files/{$driverName}-nette_test5.sql");
test('referencing table with integer primary key', function () use ($explorer) {
diff --git a/tests/Database/Explorer/bugs/bug1356.phpt b/tests/Database/Explorer/bugs/bug1356.phpt
index 479b5ae32..9e26a2eda 100644
--- a/tests/Database/Explorer/bugs/bug1356.phpt
+++ b/tests/Database/Explorer/bugs/bug1356.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
$books = $explorer->table('book')->limit(1);
@@ -31,7 +30,7 @@ foreach ($books as $book) {
}
Assert::same(reformat([
- 'sqlsrv' => $connection->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION) < 11
+ 'sqlsrv' => $explorer->getServerVersion() < 11
? 'SELECT TOP 1 * FROM [book] ORDER BY [book].[id]'
: 'SELECT * FROM [book] ORDER BY [book].[id] OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY',
'SELECT * FROM [book] ORDER BY [book].[id] LIMIT 1',
diff --git a/tests/Database/Explorer/bugs/bug170.phpt b/tests/Database/Explorer/bugs/bug170.phpt
index 53c020d17..098400e78 100644
--- a/tests/Database/Explorer/bugs/bug170.phpt
+++ b/tests/Database/Explorer/bugs/bug170.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../../files/{$driverName}-bug170.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../../files/{$driverName}-bug170.sql");
Assert::noError(function () use ($explorer) {
// this bug is about picking the right foreign key to specified table regardless FKs definition order
diff --git a/tests/Database/Explorer/bugs/bug187.phpt b/tests/Database/Explorer/bugs/bug187.phpt
index a5210b55a..e1a44fd41 100644
--- a/tests/Database/Explorer/bugs/bug187.phpt
+++ b/tests/Database/Explorer/bugs/bug187.phpt
@@ -13,9 +13,8 @@ use Tester\Assert;
require __DIR__ . '/../../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../../files/{$driverName}-bug187.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../../files/{$driverName}-bug187.sql");
foreach ([true, false] as $published) {
$where = $published
diff --git a/tests/Database/Explorer/bugs/bug216.phpt b/tests/Database/Explorer/bugs/bug216.phpt
index 23db5de1e..8f085c919 100644
--- a/tests/Database/Explorer/bugs/bug216.phpt
+++ b/tests/Database/Explorer/bugs/bug216.phpt
@@ -12,9 +12,8 @@ use Tester\Assert;
require __DIR__ . '/../../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
$book = $explorer->table('author')->insert([
'name' => $explorer->literal('LOWER(?)', 'Eddard Stark'),
diff --git a/tests/Database/Explorer/bugs/deleteCacheBug.phpt b/tests/Database/Explorer/bugs/deleteCacheBug.phpt
index fd1912a48..227f9c4a2 100644
--- a/tests/Database/Explorer/bugs/deleteCacheBug.phpt
+++ b/tests/Database/Explorer/bugs/deleteCacheBug.phpt
@@ -11,9 +11,8 @@ use Tester\Assert;
require __DIR__ . '/../../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
for ($i = 0; $i < 2; $i++) {
diff --git a/tests/Database/Explorer/bugs/query.count.phpt b/tests/Database/Explorer/bugs/query.count.phpt
index 52dd15ce5..d26c4339b 100644
--- a/tests/Database/Explorer/bugs/query.count.phpt
+++ b/tests/Database/Explorer/bugs/query.count.phpt
@@ -11,20 +11,19 @@ use Tester\Assert;
require __DIR__ . '/../../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
// add additional tags (not relevant to other tests)
$explorer->query("INSERT INTO book_tag_alt (book_id, tag_id, state) VALUES (1, 24, 'private');");
$explorer->query("INSERT INTO book_tag_alt (book_id, tag_id, state) VALUES (2, 24, 'private');");
$explorer->query("INSERT INTO book_tag_alt (book_id, tag_id, state) VALUES (2, 22, 'private');");
-test('', function () use ($connection, $explorer) {
+test('', function () use ($explorer) {
$explorer->table('author')->get(11); // have to build cache first
$count = 0;
- $connection->onQuery[] = function () use (&$count) {
+ $explorer->onQuery[] = function () use (&$count) {
$count++;
};
diff --git a/tests/Database/Explorer/bugs/staticReflection.undeclaredColumn.phpt b/tests/Database/Explorer/bugs/staticReflection.undeclaredColumn.phpt
index 4780a937c..2f3ca74c2 100644
--- a/tests/Database/Explorer/bugs/staticReflection.undeclaredColumn.phpt
+++ b/tests/Database/Explorer/bugs/staticReflection.undeclaredColumn.phpt
@@ -12,13 +12,10 @@ use Tester\Assert;
require __DIR__ . '/../../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-$conventions = new Nette\Database\Conventions\StaticConventions;
-$cacheStorage = new Nette\Caching\Storages\MemoryStorage;
-$explorer = new Nette\Database\Explorer($explorer->getConnection(), $explorer->getStructure(), $conventions, $cacheStorage);
+$explorer->setConventions(new Nette\Database\Conventions\StaticConventions);
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
test('', function () use ($explorer) {
diff --git a/tests/Database/Explorer/bugs/view.bug.phpt b/tests/Database/Explorer/bugs/view.bug.phpt
index 0a555757b..32cd165b4 100644
--- a/tests/Database/Explorer/bugs/view.bug.phpt
+++ b/tests/Database/Explorer/bugs/view.bug.phpt
@@ -11,9 +11,8 @@ use Tester\Assert;
require __DIR__ . '/../../../bootstrap.php';
$explorer = connectToDB();
-$connection = $explorer->getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
+Nette\Database\Helpers::loadFromFile($explorer, __DIR__ . "/../../files/{$driverName}-nette_test1.sql");
$explorer->query('CREATE VIEW books_view AS SELECT * FROM book');
@@ -22,9 +21,9 @@ test('', function () use ($explorer) {
Assert::same(1, $selection->count());
});
-test('', function () use ($connection) {
- $driver = $connection->getDriver();
- $columns = $driver->getColumns('books_view');
+test('', function () use ($explorer) {
+ $engine = $explorer->getDatabaseEngine();
+ $columns = $engine->getColumns('books_view');
$columnsNames = array_map(fn($item) => $item['name'], $columns);
Assert::same(['id', 'author_id', 'translator_id', 'title', 'next_volume'], $columnsNames);
});
diff --git a/tests/Database/Helpers.dumpSql.phpt b/tests/Database/Helpers.dumpSql.phpt
index 907a870b5..360961b2d 100644
--- a/tests/Database/Helpers.dumpSql.phpt
+++ b/tests/Database/Helpers.dumpSql.phpt
@@ -7,58 +7,62 @@
declare(strict_types=1);
+use Nette\Database\SqlLiteral;
use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
test('int check', function () use ($connection) {
Assert::same(
" SELECT id \nFROM author \nWHERE id = 10 OR id = 11 \n",
- Nette\Database\Helpers::dumpSql('SELECT id FROM author WHERE id = ? OR id = ?', [10, 11], $connection),
+ Nette\Database\Helpers::dumpSql(new SqlLiteral('SELECT id FROM author WHERE id = ? OR id = ?', [10, 11]), $connection),
);
});
test('bool check', function () use ($connection) {
Assert::same(
" SELECT id \nFROM author \nWHERE deleted = 0 \n",
- Nette\Database\Helpers::dumpSql('SELECT id FROM author WHERE deleted = ?', [false], $connection),
+ Nette\Database\Helpers::dumpSql(new SqlLiteral('SELECT id FROM author WHERE deleted = ?', [false]), $connection),
);
});
test('string check', function () use ($connection) {
Assert::same(
" SELECT id \nFROM author \nWHERE name = 'Alexej Chruščev' \n",
- Nette\Database\Helpers::dumpSql('SELECT id FROM author WHERE name = ?', ['Alexej Chruščev'], $connection),
+ Nette\Database\Helpers::dumpSql(new SqlLiteral('SELECT id FROM author WHERE name = ?', ['Alexej Chruščev']), $connection),
);
});
test('string check with \'', function () use ($connection) {
Assert::same(
" SELECT id \nFROM author \nWHERE name = 'Alexej Ch\\'ruščev' \n",
- Nette\Database\Helpers::dumpSql('SELECT id FROM author WHERE name = ?', ["Alexej Ch'ruščev"], $connection),
+ Nette\Database\Helpers::dumpSql(new SqlLiteral('SELECT id FROM author WHERE name = ?', ["Alexej Ch'ruščev"]), $connection),
);
});
test('string check without connection', function () {
Assert::same(
" SELECT id \nFROM author \nWHERE name = 'Alexej Ch'ruščev' \n",
- Nette\Database\Helpers::dumpSql('SELECT id FROM author WHERE name = ?', ["Alexej Ch'ruščev"]),
+ Nette\Database\Helpers::dumpSql(new SqlLiteral('SELECT id FROM author WHERE name = ?', ["Alexej Ch'ruščev"])),
);
});
test('string compare with $connection vs without', function () use ($connection) {
- Assert::notSame(Nette\Database\Helpers::dumpSql('SELECT id FROM author WHERE name = ?', ["Alexej Ch'ruščev"], $connection), Nette\Database\Helpers::dumpSql('SELECT id FROM author WHERE name = ?', ["Alexej Ch'ruščev"]));
+ Assert::notSame(
+ Nette\Database\Helpers::dumpSql(new SqlLiteral('SELECT id FROM author WHERE name = ?', ["Alexej Ch'ruščev"]), $connection),
+ Nette\Database\Helpers::dumpSql(new SqlLiteral('SELECT id FROM author WHERE name = ?', ["Alexej Ch'ruščev"])),
+ );
});
test('string check with \'', function () use ($connection) {
Nette\Database\Helpers::$maxLength = 10;
Assert::same(
" SELECT id \nFROM author \nWHERE name = 'Alexej Ch…' \n",
- Nette\Database\Helpers::dumpSql('SELECT id FROM author WHERE name = ?', ["Alexej Ch'ruščev"], $connection),
+ Nette\Database\Helpers::dumpSql(new SqlLiteral('SELECT id FROM author WHERE name = ?', ["Alexej Ch'ruščev"]), $connection),
);
});
diff --git a/tests/Database/Helpers.loadFromFile.phpt b/tests/Database/Helpers.loadFromFile.phpt
index 1f6c616cc..d0cc8ba43 100644
--- a/tests/Database/Helpers.loadFromFile.phpt
+++ b/tests/Database/Helpers.loadFromFile.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-delimiter.sql');
$arr = $connection->query('SELECT name, id FROM author ORDER BY id')->fetchAll();
diff --git a/tests/Database/Helpers.parseColumnType.phpt b/tests/Database/Helpers.parseColumnType.phpt
index fe665d92e..a8bca9003 100644
--- a/tests/Database/Helpers.parseColumnType.phpt
+++ b/tests/Database/Helpers.parseColumnType.phpt
@@ -15,16 +15,16 @@ require __DIR__ . '/../bootstrap.php';
// Test basic type
$result = Helpers::parseColumnType('UNSIGNED INT');
-Assert::same(['type' => 'UNSIGNED INT', 'length' => null, 'scale' => null, 'parameters' => null], $result);
+Assert::same(['type' => 'UNSIGNED INT', 'size' => null, 'scale' => null, 'parameters' => null], $result);
// Test type with length
$result = Helpers::parseColumnType('VARCHAR(255)');
-Assert::same(['type' => 'VARCHAR', 'length' => 255, 'scale' => null, 'parameters' => null], $result);
+Assert::same(['type' => 'VARCHAR', 'size' => 255, 'scale' => null, 'parameters' => null], $result);
// Test type with precision and scale
$result = Helpers::parseColumnType('DECIMAL(10,2)');
-Assert::same(['type' => 'DECIMAL', 'length' => 10, 'scale' => 2, 'parameters' => null], $result);
+Assert::same(['type' => 'DECIMAL', 'size' => 10, 'scale' => 2, 'parameters' => null], $result);
// Test type with additional parameters
$result = Helpers::parseColumnType("ENUM('value1','value2')");
-Assert::same(['type' => 'ENUM', 'length' => null, 'scale' => null, 'parameters' => "'value1','value2'"], $result);
+Assert::same(['type' => 'ENUM', 'size' => null, 'scale' => null, 'parameters' => "'value1','value2'"], $result);
diff --git a/tests/Database/Reflection.columns.mysql.phpt b/tests/Database/Reflection.columns.mysql.phpt
index 14d913162..07ab45e8b 100644
--- a/tests/Database/Reflection.columns.mysql.phpt
+++ b/tests/Database/Reflection.columns.mysql.phpt
@@ -11,11 +11,11 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-nette_test3.sql');
-$version80 = version_compare($connection->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION), '8.0', '>=');
+$version80 = version_compare($connection->getServerVersion(), '8.0', '>=');
$reflection = $connection->getReflection();
$columns = $reflection->getTable('types')->columns;
@@ -25,6 +25,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => $version80 ? 'INT UNSIGNED' : 'INT',
'size' => $version80 ? null : 11,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -35,6 +36,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'INT',
'size' => $version80 ? null : 11,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -45,6 +47,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'SMALLINT',
'size' => $version80 ? null : 6,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -55,6 +58,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TINYINT',
'size' => $version80 ? null : 4,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -65,6 +69,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'MEDIUMINT',
'size' => $version80 ? null : 9,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -75,6 +80,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BIGINT',
'size' => $version80 ? null : 20,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -85,6 +91,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TINYINT',
'size' => 1,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -95,6 +102,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BIT',
'size' => 1,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -105,6 +113,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DECIMAL',
'size' => 10,
+ 'scale' => 0,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -115,6 +124,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DECIMAL',
'size' => 10,
+ 'scale' => 2,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -125,6 +135,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'FLOAT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -135,6 +146,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DOUBLE',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -145,6 +157,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DATE',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -155,6 +168,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TIME',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -165,6 +179,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DATETIME',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -175,6 +190,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TIMESTAMP',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -185,6 +201,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'YEAR',
'size' => $version80 ? null : 4,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -195,6 +212,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'CHAR',
'size' => 1,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -205,6 +223,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'VARCHAR',
'size' => 30,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -215,6 +234,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BINARY',
'size' => 1,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -225,6 +245,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'VARBINARY',
'size' => 30,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -235,6 +256,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BLOB',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -245,6 +267,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TINYBLOB',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -255,6 +278,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'MEDIUMBLOB',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -265,6 +289,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'LONGBLOB',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -275,6 +300,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TEXT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -285,6 +311,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TINYTEXT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -295,6 +322,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'MEDIUMTEXT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -305,6 +333,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'LONGTEXT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -315,6 +344,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'ENUM',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -325,6 +355,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'SET',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -339,6 +370,7 @@ Assert::same(
'table' => $c->table->name,
'nativeType' => $c->nativeType,
'size' => $c->size,
+ 'scale' => $c->scale,
'nullable' => $c->nullable,
'default' => $c->default,
'autoIncrement' => $c->autoIncrement,
diff --git a/tests/Database/Reflection.columns.postgre.phpt b/tests/Database/Reflection.columns.postgre.phpt
index b404de843..81c219838 100644
--- a/tests/Database/Reflection.columns.postgre.phpt
+++ b/tests/Database/Reflection.columns.postgre.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/pgsql-nette_test3.sql');
@@ -24,6 +24,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'INT2',
'size' => 2,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -34,6 +35,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'INT4',
'size' => 4,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -44,6 +46,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'INT8',
'size' => 8,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -54,6 +57,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'NUMERIC',
'size' => 3,
+ 'scale' => 2,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -64,6 +68,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'FLOAT4',
'size' => 4,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -74,6 +79,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'FLOAT8',
'size' => 8,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -84,6 +90,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'MONEY',
'size' => 8,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -94,6 +101,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BOOL',
'size' => 1,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -104,6 +112,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DATE',
'size' => 4,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -114,6 +123,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TIME',
'size' => 8,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -124,6 +134,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TIMESTAMP',
'size' => 8,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -134,6 +145,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TIMESTAMPTZ',
'size' => 8,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -144,6 +156,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'INTERVAL',
'size' => 16,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -154,6 +167,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BPCHAR',
'size' => 30,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -164,6 +178,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'VARCHAR',
'size' => 30,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -174,6 +189,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TEXT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -184,6 +200,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TSQUERY',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -194,6 +211,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TSVECTOR',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -204,6 +222,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'UUID',
'size' => 16,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -214,6 +233,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'XML',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -224,6 +244,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'CIDR',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -234,6 +255,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'INET',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -244,6 +266,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'MACADDR',
'size' => 6,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -254,6 +277,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BIT',
'size' => -3,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -264,6 +288,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'VARBIT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -274,6 +299,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BYTEA',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -284,6 +310,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BOX',
'size' => 32,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -294,6 +321,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'CIRCLE',
'size' => 24,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -304,6 +332,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'LSEG',
'size' => 32,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -314,6 +343,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'PATH',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -324,6 +354,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'POINT',
'size' => 16,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -334,6 +365,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'POLYGON',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -348,6 +380,7 @@ Assert::same(
'table' => $c->table->name,
'nativeType' => $c->nativeType,
'size' => $c->size,
+ 'scale' => $c->scale,
'nullable' => $c->nullable,
'default' => $c->default,
'autoIncrement' => $c->autoIncrement,
diff --git a/tests/Database/Reflection.columns.sqlite.phpt b/tests/Database/Reflection.columns.sqlite.phpt
index 4f32b02a5..c2b7e8855 100644
--- a/tests/Database/Reflection.columns.sqlite.phpt
+++ b/tests/Database/Reflection.columns.sqlite.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlite-nette_test3.sql');
@@ -24,6 +24,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'INT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -34,6 +35,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'INTEGER',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -44,6 +46,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TINYINT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -54,6 +57,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'SMALLINT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -64,6 +68,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'MEDIUMINT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -74,6 +79,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BIGINT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -84,6 +90,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'UNSIGNED BIG INT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -94,6 +101,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'INT2',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -104,6 +112,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'INT8',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -114,6 +123,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'CHARACTER',
'size' => 20,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -124,6 +134,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'VARCHAR',
'size' => 255,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -134,6 +145,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'VARYING CHARACTER',
'size' => 255,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -144,6 +156,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'NCHAR',
'size' => 55,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -154,6 +167,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'NATIVE CHARACTER',
'size' => 70,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -164,6 +178,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'NVARCHAR',
'size' => 100,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -174,6 +189,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TEXT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -184,6 +200,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'CLOB',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -194,6 +211,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BLOB',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -204,6 +222,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'REAL',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -214,6 +233,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DOUBLE',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -224,6 +244,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DOUBLE PRECISION',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -234,6 +255,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'FLOAT',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -244,6 +266,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'NUMERIC',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -254,6 +277,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DECIMAL',
'size' => 10,
+ 'scale' => 5,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -264,6 +288,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BOOLEAN',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -274,6 +299,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DATE',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -284,6 +310,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DATETIME',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -298,6 +325,7 @@ Assert::same(
'table' => $c->table->name,
'nativeType' => $c->nativeType,
'size' => $c->size,
+ 'scale' => $c->scale,
'nullable' => $c->nullable,
'default' => $c->default,
'autoIncrement' => $c->autoIncrement,
diff --git a/tests/Database/Reflection.columns.sqlsrv.phpt b/tests/Database/Reflection.columns.sqlsrv.phpt
index 57109e4aa..1d7ce8952 100644
--- a/tests/Database/Reflection.columns.sqlsrv.phpt
+++ b/tests/Database/Reflection.columns.sqlsrv.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-nette_test3.sql');
@@ -24,6 +24,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BIGINT',
'size' => 19,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -34,6 +35,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BINARY',
'size' => 3,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -44,6 +46,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'BIT',
'size' => 1,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -54,6 +57,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'CHAR',
'size' => 5,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -64,6 +68,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DATE',
'size' => 10,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -74,6 +79,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DATETIME',
'size' => 23,
+ 'scale' => 3,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -84,6 +90,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DATETIME2',
'size' => 27,
+ 'scale' => 7,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -94,6 +101,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'DECIMAL',
'size' => 18,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -104,6 +112,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'FLOAT',
'size' => 53,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -114,6 +123,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'GEOGRAPHY',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -124,6 +134,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'GEOMETRY',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -134,6 +145,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'HIERARCHYID',
'size' => 892,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -144,6 +156,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'INT',
'size' => 10,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -154,6 +167,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'MONEY',
'size' => 19,
+ 'scale' => 4,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -164,6 +178,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'NCHAR',
'size' => 2,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -174,6 +189,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'NTEXT',
'size' => 16,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -184,6 +200,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'NUMERIC',
'size' => 10,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -194,6 +211,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'NUMERIC',
'size' => 10,
+ 'scale' => 2,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -204,6 +222,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'NVARCHAR',
'size' => 2,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -214,6 +233,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'REAL',
'size' => 24,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -224,6 +244,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'SMALLDATETIME',
'size' => 16,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -234,6 +255,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'SMALLINT',
'size' => 5,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -244,6 +266,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'SMALLMONEY',
'size' => 10,
+ 'scale' => 4,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -254,6 +277,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TEXT',
'size' => 16,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -264,6 +288,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TIME',
'size' => 16,
+ 'scale' => 7,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -274,6 +299,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'TINYINT',
'size' => 3,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -284,6 +310,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'UNIQUEIDENTIFIER',
'size' => 16,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -294,6 +321,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'VARBINARY',
'size' => 1,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -304,6 +332,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'VARCHAR',
'size' => 1,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -314,6 +343,7 @@ $expectedColumns = [
'table' => 'types',
'nativeType' => 'XML',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -328,6 +358,7 @@ Assert::same(
'table' => $c->table->name,
'nativeType' => $c->nativeType,
'size' => $c->size,
+ 'scale' => $c->scale,
'nullable' => $c->nullable,
'default' => $c->default,
'autoIncrement' => $c->autoIncrement,
diff --git a/tests/Database/Reflection.phpt b/tests/Database/Reflection.phpt
index ebbc1f9c6..9afcd4116 100644
--- a/tests/Database/Reflection.phpt
+++ b/tests/Database/Reflection.phpt
@@ -7,17 +7,17 @@
declare(strict_types=1);
-use Nette\Database\Driver;
+use Nette\Database\Drivers\Engine;
use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
$reflection = $connection->getReflection();
-$schemaSupported = $connection->getDriver()->isSupported(Driver::SupportSchema);
+$schemaSupported = $connection->getDatabaseEngine()->isSupported(Engine::SupportSchema);
// table names
$tableNames = array_keys($reflection->tables);
@@ -75,6 +75,7 @@ $expectedColumns = [
'table' => 'author',
'nativeType' => 'INT',
'size' => 11,
+ 'scale' => null,
'nullable' => false,
'default' => null,
'autoIncrement' => true,
@@ -85,6 +86,7 @@ $expectedColumns = [
'table' => 'author',
'nativeType' => 'VARCHAR',
'size' => 30,
+ 'scale' => null,
'nullable' => false,
'default' => null,
'autoIncrement' => false,
@@ -95,6 +97,7 @@ $expectedColumns = [
'table' => 'author',
'nativeType' => 'VARCHAR',
'size' => 100,
+ 'scale' => null,
'nullable' => false,
'default' => null,
'autoIncrement' => false,
@@ -105,6 +108,7 @@ $expectedColumns = [
'table' => 'author',
'nativeType' => 'DATE',
'size' => null,
+ 'scale' => null,
'nullable' => true,
'default' => null,
'autoIncrement' => false,
@@ -114,7 +118,7 @@ $expectedColumns = [
switch ($driverName) {
case 'mysql':
- $version = $connection->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION);
+ $version = $connection->getServerVersion();
if (version_compare($version, '8.0', '>=')) {
$expectedColumns['id']['size'] = null;
}
@@ -149,6 +153,7 @@ Assert::same(
'table' => $c->table->name,
'nativeType' => $c->nativeType,
'size' => $c->size,
+ 'scale' => $c->scale,
'nullable' => $c->nullable,
'default' => $c->default,
'autoIncrement' => $c->autoIncrement,
diff --git a/tests/Database/ResultSet.fetch().phpt b/tests/Database/Result.fetch().phpt
similarity index 86%
rename from tests/Database/ResultSet.fetch().phpt
rename to tests/Database/Result.fetch().phpt
index 376bcb085..a62214044 100644
--- a/tests/Database/ResultSet.fetch().phpt
+++ b/tests/Database/Result.fetch().phpt
@@ -1,7 +1,7 @@
getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
test('', function () use ($connection, $driverName) {
$res = $connection->query('SELECT name, name FROM author');
$message = match ($driverName) {
- 'mysql' => "Found duplicate columns in database result set: 'name' (from author).",
+ 'mysql' => "Found duplicate columns in database result set: 'name'.",
'pgsql' => "Found duplicate columns in database result set: 'name'%a%",
- 'sqlite' => "Found duplicate columns in database result set: 'name' (from author).",
+ 'sqlite' => "Found duplicate columns in database result set: 'name'.",
'sqlsrv' => "Found duplicate columns in database result set: 'name'.",
default => Assert::fail("Unsupported driver $driverName"),
};
@@ -38,7 +38,7 @@ test('', function () use ($connection, $driverName) {
test('tests closeCursor()', function () use ($connection, $driverName) {
if ($driverName === 'mysql') {
$connection->query('CREATE DEFINER = CURRENT_USER PROCEDURE `testProc`(IN param int(10) unsigned) BEGIN SELECT * FROM book WHERE id != param; END;;');
- $connection->getPdo()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+ $connection->getConnection()->getNativeConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$res = $connection->query('CALL testProc(1)');
foreach ($res as $row) {
@@ -54,9 +54,9 @@ test('tests closeCursor()', function () use ($connection, $driverName) {
test('', function () use ($connection, $driverName) {
$res = $connection->query('SELECT book.id, author.id, author.name, translator.name FROM book JOIN author ON (author.id = book.author_id) JOIN author translator ON (translator.id = book.translator_id)');
$message = match ($driverName) {
- 'mysql' => "Found duplicate columns in database result set: 'id' (from book, author), 'name' (from author, translator).",
+ 'mysql' => "Found duplicate columns in database result set: 'id', 'name'.",
'pgsql' => "Found duplicate columns in database result set: 'id'%a% 'name'%a%",
- 'sqlite' => "Found duplicate columns in database result set: 'id' (from book, author), 'name' (from author).",
+ 'sqlite' => "Found duplicate columns in database result set: 'id', 'name'.",
'sqlsrv' => "Found duplicate columns in database result set: 'id', 'name'.",
default => Assert::fail("Unsupported driver $driverName"),
};
diff --git a/tests/Database/ResultSet.fetchAll().phpt b/tests/Database/Result.fetchAll().phpt
similarity index 87%
rename from tests/Database/ResultSet.fetchAll().phpt
rename to tests/Database/Result.fetchAll().phpt
index 8d7ade31d..0609c94cf 100644
--- a/tests/Database/ResultSet.fetchAll().phpt
+++ b/tests/Database/Result.fetchAll().phpt
@@ -1,7 +1,7 @@
getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
@@ -24,7 +24,7 @@ match ($driverName) {
};
Assert::same(1, $res->getColumnCount());
-Assert::same('SELECT id FROM book ORDER BY id', $res->getQueryString());
+Assert::same('SELECT id FROM book ORDER BY id', $res->getQuery()->getSql());
Assert::equal([
Nette\Database\Row::from(['id' => 1]),
diff --git a/tests/Database/ResultSet.fetchAssoc().phpt b/tests/Database/Result.fetchAssoc().phpt
similarity index 93%
rename from tests/Database/ResultSet.fetchAssoc().phpt
rename to tests/Database/Result.fetchAssoc().phpt
index 01bd04391..2b33f8287 100644
--- a/tests/Database/ResultSet.fetchAssoc().phpt
+++ b/tests/Database/Result.fetchAssoc().phpt
@@ -1,7 +1,7 @@
getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
diff --git a/tests/Database/ResultSet.fetchField().phpt b/tests/Database/Result.fetchField().phpt
similarity index 85%
rename from tests/Database/ResultSet.fetchField().phpt
rename to tests/Database/Result.fetchField().phpt
index 065c3820a..f54d3b6cb 100644
--- a/tests/Database/ResultSet.fetchField().phpt
+++ b/tests/Database/Result.fetchField().phpt
@@ -1,7 +1,7 @@
getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
diff --git a/tests/Database/ResultSet.fetchFields().phpt b/tests/Database/Result.fetchList().phpt
similarity index 71%
rename from tests/Database/ResultSet.fetchFields().phpt
rename to tests/Database/Result.fetchList().phpt
index 92457b389..3885b942b 100644
--- a/tests/Database/ResultSet.fetchFields().phpt
+++ b/tests/Database/Result.fetchList().phpt
@@ -1,7 +1,7 @@
getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
test('', function () use ($connection) {
$res = $connection->query('SELECT name, id FROM author ORDER BY id');
- Assert::same(['Jakub Vrana', 11], $res->fetchFields());
+ Assert::same(['Jakub Vrana', 11], $res->fetchList());
});
test('', function () use ($connection) {
$res = $connection->query('SELECT id FROM author WHERE id = ?', 666);
- Assert::null($res->fetchFields());
+ Assert::null($res->fetchList());
});
diff --git a/tests/Database/ResultSet.fetchPairs().phpt b/tests/Database/Result.fetchPairs().phpt
similarity index 97%
rename from tests/Database/ResultSet.fetchPairs().phpt
rename to tests/Database/Result.fetchPairs().phpt
index a0fc0ca8f..6927dfb8a 100644
--- a/tests/Database/ResultSet.fetchPairs().phpt
+++ b/tests/Database/Result.fetchPairs().phpt
@@ -1,7 +1,7 @@
getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
diff --git a/tests/Database/ResultSet.customNormalizer.phpt b/tests/Database/ResultSet.customNormalizer.phpt
deleted file mode 100644
index 4da4189ae..000000000
--- a/tests/Database/ResultSet.customNormalizer.phpt
+++ /dev/null
@@ -1,53 +0,0 @@
-getConnection();
-Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql");
-
-$connection->query('UPDATE author SET born=?', new DateTime('2022-01-23'));
-
-
-test('disabled normalization', function () use ($connection) {
- $driverName = $GLOBALS['driverName'];
-
- $connection->setRowNormalizer(null);
- $res = $connection->query('SELECT * FROM author');
- $asInt = $driverName === 'pgsql' || ($driverName !== 'sqlsrv' && PHP_VERSION_ID >= 80100);
- Assert::same([
- 'id' => $asInt ? 11 : '11',
- 'name' => 'Jakub Vrana',
- 'web' => 'http://www.vrana.cz/',
- 'born' => $driverName === 'sqlite' ? ($asInt ? 1_642_892_400 : '1642892400') : '2022-01-23',
- ], (array) $res->fetch());
-});
-
-
-test('custom normalization', function () use ($connection) {
- $driverName = $GLOBALS['driverName'];
-
- $connection->setRowNormalizer(function (array $row, Nette\Database\ResultSet $resultSet) {
- foreach ($row as $key => $value) {
- unset($row[$key]);
- $row['_' . $key . '_'] = (string) $value;
- }
-
- return $row;
- });
-
- $res = $connection->query('SELECT * FROM author');
- Assert::same([
- '_id_' => '11',
- '_name_' => 'Jakub Vrana',
- '_web_' => 'http://www.vrana.cz/',
- '_born_' => $driverName === 'sqlite' ? '1642892400' : '2022-01-23',
- ], (array) $res->fetch());
-});
diff --git a/tests/Database/ResultSet.normalizeRow.mysql.phpt b/tests/Database/ResultSet.normalizeRow.mysql.phpt
index f78e86154..e078dfbf6 100644
--- a/tests/Database/ResultSet.normalizeRow.mysql.phpt
+++ b/tests/Database/ResultSet.normalizeRow.mysql.phpt
@@ -12,7 +12,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-nette_test3.sql');
@@ -151,7 +151,7 @@ Assert::same(
);
-$connection->getPdo()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
+$connection->getConnection()->getNativeConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$res = $connection->query('SELECT `int`, `decimal`, `decimal2`, `float`, `double` FROM types');
Assert::same([
'int' => 1,
diff --git a/tests/Database/ResultSet.normalizeRow.postgre.phpt b/tests/Database/ResultSet.normalizeRow.postgre.phpt
index fd24a2315..eac4f0e84 100644
--- a/tests/Database/ResultSet.normalizeRow.postgre.phpt
+++ b/tests/Database/ResultSet.normalizeRow.postgre.phpt
@@ -12,7 +12,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/pgsql-nette_test3.sql');
diff --git a/tests/Database/ResultSet.normalizeRow.sqlite.phpt b/tests/Database/ResultSet.normalizeRow.sqlite.phpt
index 347cf977b..5e92fcd3a 100644
--- a/tests/Database/ResultSet.normalizeRow.sqlite.phpt
+++ b/tests/Database/ResultSet.normalizeRow.sqlite.phpt
@@ -12,7 +12,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlite-nette_test3.sql');
diff --git a/tests/Database/ResultSet.normalizeRow.sqlsrv.phpt b/tests/Database/ResultSet.normalizeRow.sqlsrv.phpt
index 09ea94fe7..4ff795da7 100644
--- a/tests/Database/ResultSet.normalizeRow.sqlsrv.phpt
+++ b/tests/Database/ResultSet.normalizeRow.sqlsrv.phpt
@@ -12,7 +12,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-nette_test3.sql');
@@ -21,12 +21,12 @@ $res = $connection->query('SELECT * FROM types');
Assert::equal([
'bigint' => 1,
'binary_3' => "\x00\x00\xFF",
- 'bit' => '1',
+ 'bit' => true,
'char_5' => 'a ',
'date' => new DateTime('2012-10-13 00:00:00'),
'datetime' => new DateTime('2012-10-13 10:10:10'),
'datetime2' => new DateTime('2012-10-13 10:10:10'),
- 'decimal' => 1.0,
+ 'decimal' => 1,
'float' => 1.1,
'geography' => "\xe6\x10\x00\x00\x01\x14\x87\x16\xd9\xce\xf7\xd3G@\xd7\xa3p=\n\x97^\xc0\x87\x16\xd9\xce\xf7\xd3G@\xcb\xa1E\xb6\xf3\x95^\xc0",
'geometry' => "\x00\x00\x00\x00\x01\x04\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00Y@\x00\x00\x00\x00\x00\x00Y@\x00\x00\x00\x00\x00\x004@\x00\x00\x00\x00\x00\x80f@\x00\x00\x00\x00\x00\x80f@\x00\x00\x00\x00\x00\x80f@\x01\x00\x00\x00\x01\x00\x00\x00\x00\x01\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x02",
@@ -35,7 +35,7 @@ Assert::equal([
'money' => 1111.1,
'nchar' => 'a',
'ntext' => 'a',
- 'numeric_10_0' => 1.0,
+ 'numeric_10_0' => 1,
'numeric_10_2' => 1.1,
'nvarchar' => 'a',
'real' => 1.1,
@@ -54,12 +54,12 @@ Assert::equal([
Assert::equal([
'bigint' => 0,
'binary_3' => "\x00\x00\x00",
- 'bit' => '0',
+ 'bit' => false,
'char_5' => ' ',
'date' => new DateTime('0001-01-01 00:00:00'),
'datetime' => new DateTime('1753-01-01 00:00:00'),
'datetime2' => new DateTime('0001-01-01 00:00:00'),
- 'decimal' => 0.0,
+ 'decimal' => 0,
'float' => 0.5,
'geography' => null,
'geometry' => null,
@@ -68,7 +68,7 @@ Assert::equal([
'money' => 0.0,
'nchar' => ' ',
'ntext' => '',
- 'numeric_10_0' => 0.0,
+ 'numeric_10_0' => 0,
'numeric_10_2' => 0.5,
'nvarchar' => '',
'real' => 0.0,
diff --git a/tests/Database/Row.phpt b/tests/Database/Row.phpt
index 9dfc65170..04631da86 100644
--- a/tests/Database/Row.phpt
+++ b/tests/Database/Row.phpt
@@ -11,10 +11,10 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
test('numeric field', function () use ($connection) {
- $row = $connection->fetch("SELECT 123 AS {$connection->getDriver()->delimite('123')}, NULL as nullcol");
+ $row = $connection->fetch("SELECT 123 AS {$connection->getDatabaseEngine()->delimit('123')}, NULL as nullcol");
Assert::same(123, $row->{123});
Assert::same(123, $row->{'123'});
Assert::true(isset($row->{123}));
diff --git a/tests/Database/SqlPreprocessor.enum.phpt b/tests/Database/SqlPreprocessor.enum.phpt
index 91c787cff..0dc4cc250 100644
--- a/tests/Database/SqlPreprocessor.enum.phpt
+++ b/tests/Database/SqlPreprocessor.enum.phpt
@@ -11,7 +11,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
enum EnumInt: int
{
diff --git a/tests/Database/SqlPreprocessor.phpt b/tests/Database/SqlPreprocessor.phpt
index f51d5ef02..ee8daccc2 100644
--- a/tests/Database/SqlPreprocessor.phpt
+++ b/tests/Database/SqlPreprocessor.phpt
@@ -12,7 +12,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
-$connection = connectToDB()->getConnection();
+$connection = connectToDB();
$preprocessor = new Nette\Database\SqlPreprocessor($connection);
test('basic', function () use ($preprocessor) {
diff --git a/tests/Database/Structure.phpt b/tests/Database/Structure.phpt
index 434908402..61afde090 100644
--- a/tests/Database/Structure.phpt
+++ b/tests/Database/Structure.phpt
@@ -6,6 +6,7 @@
declare(strict_types=1);
+use Mockery\MockInterface;
use Nette\Database\Structure;
use Tester\Assert;
use Tester\TestCase;
@@ -29,61 +30,56 @@ class StructureMock extends Structure
*/
class StructureTestCase extends TestCase
{
- private Nette\Database\Connection $connection;
- private Nette\Database\Driver $driver;
- private Nette\Caching\Storage $storage;
- private Structure $structure;
+ private Nette\Database\Drivers\Engine|MockInterface $engine;
+ private Nette\Caching\Cache|MockInterface $cache;
+ private Structure|MockInterface $structure;
protected function setUp()
{
parent::setUp();
- $this->driver = Mockery::mock(Nette\Database\Driver::class);
- $this->connection = Mockery::mock(Nette\Database\Connection::class);
- $this->storage = Mockery::mock(Nette\Caching\Storage::class);
+ $this->engine = Mockery::mock(Nette\Database\Drivers\Engine::class);
+ $this->cache = Mockery::mock(Nette\Caching\Cache::class);
- $this->connection->shouldReceive('getDsn')->once()->andReturn('');
- $this->connection->shouldReceive('getDriver')->once()->andReturn($this->driver);
- $this->driver->shouldReceive('getTables')->once()->andReturn([
+ $this->engine->shouldReceive('getTables')->once()->andReturn([
['name' => 'authors', 'view' => false],
['name' => 'Books', 'view' => false],
['name' => 'tags', 'view' => false],
['name' => 'books_x_tags', 'view' => false],
['name' => 'books_view', 'view' => true],
]);
- $this->driver->shouldReceive('getColumns')->with('authors')->once()->andReturn([
- ['name' => 'id', 'primary' => true, 'autoincrement' => true, 'vendor' => ['sequence' => '"public"."authors_id_seq"']],
- ['name' => 'name', 'primary' => false, 'autoincrement' => false, 'vendor' => []],
+ $this->engine->shouldReceive('getColumns')->with('authors')->once()->andReturn([
+ ['name' => 'id', 'primary' => true, 'autoIncrement' => true, 'vendor' => ['sequence' => '"public"."authors_id_seq"']],
+ ['name' => 'name', 'primary' => false, 'autoIncrement' => false, 'vendor' => []],
]);
- $this->driver->shouldReceive('getColumns')->with('Books')->once()->andReturn([
- ['name' => 'id', 'primary' => true, 'autoincrement' => true, 'vendor' => ['sequence' => '"public"."Books_id_seq"']],
- ['name' => 'title', 'primary' => false, 'autoincrement' => false, 'vendor' => []],
+ $this->engine->shouldReceive('getColumns')->with('Books')->once()->andReturn([
+ ['name' => 'id', 'primary' => true, 'autoIncrement' => true, 'vendor' => ['sequence' => '"public"."Books_id_seq"']],
+ ['name' => 'title', 'primary' => false, 'autoIncrement' => false, 'vendor' => []],
]);
- $this->driver->shouldReceive('getColumns')->with('tags')->once()->andReturn([
- ['name' => 'id', 'primary' => true, 'autoincrement' => false, 'vendor' => []],
- ['name' => 'name', 'primary' => false, 'autoincrement' => false, 'vendor' => []],
+ $this->engine->shouldReceive('getColumns')->with('tags')->once()->andReturn([
+ ['name' => 'id', 'primary' => true, 'autoIncrement' => false, 'vendor' => []],
+ ['name' => 'name', 'primary' => false, 'autoIncrement' => false, 'vendor' => []],
]);
- $this->driver->shouldReceive('getColumns')->with('books_x_tags')->once()->andReturn([
- ['name' => 'book_id', 'primary' => true, 'autoincrement' => false, 'vendor' => []],
- ['name' => 'tag_id', 'primary' => true, 'autoincrement' => false, 'vendor' => []],
+ $this->engine->shouldReceive('getColumns')->with('books_x_tags')->once()->andReturn([
+ ['name' => 'book_id', 'primary' => true, 'autoIncrement' => false, 'vendor' => []],
+ ['name' => 'tag_id', 'primary' => true, 'autoIncrement' => false, 'vendor' => []],
]);
- $this->driver->shouldReceive('getColumns')->with('books_view')->once()->andReturn([
- ['name' => 'id', 'primary' => false, 'autoincrement' => false, 'vendor' => []],
- ['name' => 'title', 'primary' => false, 'autoincrement' => false, 'vendor' => []],
+ $this->engine->shouldReceive('getColumns')->with('books_view')->once()->andReturn([
+ ['name' => 'id', 'primary' => false, 'autoIncrement' => false, 'vendor' => []],
+ ['name' => 'title', 'primary' => false, 'autoIncrement' => false, 'vendor' => []],
]);
- $this->connection->shouldReceive('getDriver')->times(4)->andReturn($this->driver);
- $this->driver->shouldReceive('getForeignKeys')->with('authors')->once()->andReturn([]);
- $this->driver->shouldReceive('getForeignKeys')->with('Books')->once()->andReturn([
- ['local' => 'author_id', 'table' => 'authors', 'foreign' => 'id', 'name' => 'authors_fk1'],
- ['local' => 'translator_id', 'table' => 'authors', 'foreign' => 'id', 'name' => 'authors_fk2'],
+ $this->engine->shouldReceive('getForeignKeys')->with('authors')->once()->andReturn([]);
+ $this->engine->shouldReceive('getForeignKeys')->with('Books')->once()->andReturn([
+ ['local' => ['author_id'], 'table' => 'authors', 'foreign' => ['id'], 'name' => 'authors_fk1'],
+ ['local' => ['translator_id'], 'table' => 'authors', 'foreign' => ['id'], 'name' => 'authors_fk2'],
]);
- $this->driver->shouldReceive('getForeignKeys')->with('tags')->once()->andReturn([]);
- $this->driver->shouldReceive('getForeignKeys')->with('books_x_tags')->once()->andReturn([
- ['local' => 'book_id', 'table' => 'Books', 'foreign' => 'id', 'name' => 'books_x_tags_fk1'],
- ['local' => 'tag_id', 'table' => 'tags', 'foreign' => 'id', 'name' => 'books_x_tags_fk2'],
+ $this->engine->shouldReceive('getForeignKeys')->with('tags')->once()->andReturn([]);
+ $this->engine->shouldReceive('getForeignKeys')->with('books_x_tags')->once()->andReturn([
+ ['local' => ['book_id'], 'table' => 'Books', 'foreign' => ['id'], 'name' => 'books_x_tags_fk1'],
+ ['local' => ['tag_id'], 'table' => 'tags', 'foreign' => ['id'], 'name' => 'books_x_tags_fk2'],
]);
- $this->structure = new StructureMock($this->connection, $this->storage);
+ $this->structure = new StructureMock($this->engine, $this->cache);
}
@@ -102,8 +98,8 @@ class StructureTestCase extends TestCase
public function testGetColumns()
{
$columns = [
- ['name' => 'id', 'primary' => true, 'autoincrement' => false, 'vendor' => []],
- ['name' => 'name', 'primary' => false, 'autoincrement' => false, 'vendor' => []],
+ ['name' => 'id', 'primary' => true, 'autoIncrement' => false, 'vendor' => []],
+ ['name' => 'name', 'primary' => false, 'autoIncrement' => false, 'vendor' => []],
];
Assert::same($columns, $this->structure->getColumns('tags'));
@@ -132,9 +128,8 @@ class StructureTestCase extends TestCase
public function testGetPrimaryKeySequence()
{
- $this->connection->shouldReceive('getDriver')->times(4)->andReturn($this->driver);
- $this->driver->shouldReceive('isSupported')->with('sequence')->once()->andReturn(false);
- $this->driver->shouldReceive('isSupported')->with('sequence')->times(3)->andReturn(true);
+ $this->engine->shouldReceive('isSupported')->with('sequence')->once()->andReturn(false);
+ $this->engine->shouldReceive('isSupported')->with('sequence')->times(3)->andReturn(true);
Assert::null($this->structure->getPrimaryKeySequence('Authors'));
Assert::same('"public"."authors_id_seq"', $this->structure->getPrimaryKeySequence('Authors'));
diff --git a/tests/Database/Structure.schemas.phpt b/tests/Database/Structure.schemas.phpt
index 0a145a56c..e92d333b5 100644
--- a/tests/Database/Structure.schemas.phpt
+++ b/tests/Database/Structure.schemas.phpt
@@ -6,6 +6,7 @@
declare(strict_types=1);
+use Mockery\MockInterface;
use Nette\Database\Structure;
use Tester\Assert;
use Tester\TestCase;
@@ -29,42 +30,37 @@ class StructureMock extends Structure
*/
class StructureSchemasTestCase extends TestCase
{
- private Nette\Database\Connection $connection;
- private Nette\Database\Driver $driver;
- private Nette\Caching\Storage $storage;
- private Structure $structure;
+ private Nette\Database\Drivers\Engine|MockInterface $engine;
+ private Nette\Caching\Cache|MockInterface $cache;
+ private Structure|MockInterface $structure;
protected function setUp()
{
parent::setUp();
- $this->driver = Mockery::mock(Nette\Database\Driver::class);
- $this->connection = Mockery::mock(Nette\Database\Connection::class);
- $this->storage = Mockery::mock(Nette\Caching\Storage::class);
+ $this->engine = Mockery::mock(Nette\Database\Drivers\Engine::class);
+ $this->cache = Mockery::mock(Nette\Caching\Cache::class);
- $this->connection->shouldReceive('getDsn')->once()->andReturn('');
- $this->connection->shouldReceive('getDriver')->once()->andReturn($this->driver);
- $this->driver->shouldReceive('getTables')->once()->andReturn([
+ $this->engine->shouldReceive('getTables')->once()->andReturn([
['name' => 'authors', 'view' => false, 'fullName' => 'authors.authors'],
['name' => 'books', 'view' => false, 'fullName' => 'books.books'],
]);
- $this->driver->shouldReceive('getColumns')->with('authors.authors')->once()->andReturn([
+ $this->engine->shouldReceive('getColumns')->with('authors.authors')->once()->andReturn([
['name' => 'id', 'primary' => true, 'vendor' => ['sequence' => '"authors"."authors_id_seq"']],
['name' => 'name', 'primary' => false, 'vendor' => []],
]);
- $this->driver->shouldReceive('getColumns')->with('books.books')->once()->andReturn([
+ $this->engine->shouldReceive('getColumns')->with('books.books')->once()->andReturn([
['name' => 'id', 'primary' => true, 'vendor' => ['sequence' => '"books"."books_id_seq"']],
['name' => 'title', 'primary' => false, 'vendor' => []],
]);
- $this->connection->shouldReceive('getDriver')->times(2)->andReturn($this->driver);
- $this->driver->shouldReceive('getForeignKeys')->with('authors.authors')->once()->andReturn([]);
- $this->driver->shouldReceive('getForeignKeys')->with('books.books')->once()->andReturn([
- ['local' => 'author_id', 'table' => 'authors.authors', 'foreign' => 'id', 'name' => 'authors_authors_fk1'],
- ['local' => 'translator_id', 'table' => 'authors.authors', 'foreign' => 'id', 'name' => 'authors_authors_fk2'],
+ $this->engine->shouldReceive('getForeignKeys')->with('authors.authors')->once()->andReturn([]);
+ $this->engine->shouldReceive('getForeignKeys')->with('books.books')->once()->andReturn([
+ ['local' => ['author_id'], 'table' => 'authors.authors', 'foreign' => ['id'], 'name' => 'authors_authors_fk1'],
+ ['local' => ['translator_id'], 'table' => 'authors.authors', 'foreign' => ['id'], 'name' => 'authors_authors_fk2'],
]);
- $this->structure = new StructureMock($this->connection, $this->storage);
+ $this->structure = new StructureMock($this->engine, $this->cache);
}
diff --git a/tests/Database/connection.disconnect.phpt b/tests/Database/connection.disconnect.phpt
new file mode 100644
index 000000000..b2b06ed8e
--- /dev/null
+++ b/tests/Database/connection.disconnect.phpt
@@ -0,0 +1,55 @@
+ null, 'password' => null];
+ $connections = 1;
+
+ $connection = new Nette\Database\Explorer($options['dsn'], $options['username'], $options['password']);
+ try {
+ $connection->connect();
+ } catch (Nette\Database\DriverException $e) {
+ Tester\Environment::skip("Connection to '$options[dsn]' failed. Reason: " . $e->getMessage());
+ }
+
+ $connection->onConnect[] = function () use (&$connections) {
+ $connections++;
+ };
+
+ // first connection
+ $native = $connection->getConnection()->getNativeConnection();
+ $driver = $connection->getConnection();
+ Assert::same(1, $connections);
+
+ // still first connection
+ $connection->connect();
+ Assert::same($native, $connection->getConnection()->getNativeConnection());
+ Assert::same($driver, $connection->getConnection());
+ Assert::same(1, $connections);
+
+ // second connection
+ $connection->reconnect();
+ $native2 = $connection->getConnection()->getNativeConnection();
+ $driver2 = $connection->getConnection();
+
+ Assert::notSame($native, $native2);
+ Assert::notSame($driver, $driver2);
+ Assert::same(2, $connections);
+
+ // third connection
+ $connection->disconnect();
+ Assert::notSame($native2, $connection->getConnection()->getNativeConnection());
+ Assert::notSame($driver2, $connection->getConnection());
+ Assert::same(3, $connections);
+});
diff --git a/tests/Database/connection.option.lazy.phpt b/tests/Database/connection.option.lazy.phpt
deleted file mode 100644
index 1561dc39f..000000000
--- a/tests/Database/connection.option.lazy.phpt
+++ /dev/null
@@ -1,86 +0,0 @@
- new Nette\Database\Connection('dsn', 'user', 'password'),
- Nette\Database\DriverException::class,
- '%a%valid data source %a%',
- );
-});
-
-
-test('lazy', function () {
- $connection = new Nette\Database\Connection('dsn', 'user', 'password', ['lazy' => true]);
- $explorer = new Nette\Database\Explorer($connection, new Structure($connection, new DevNullStorage));
- Assert::exception(
- fn() => $explorer->query('SELECT ?', 10),
- Nette\Database\DriverException::class,
- '%a%valid data source %a%',
- );
-});
-
-
-test('', function () {
- $connection = new Nette\Database\Connection('dsn', 'user', 'password', ['lazy' => true]);
- Assert::exception(
- fn() => $connection->quote('x'),
- Nette\Database\DriverException::class,
- '%a%valid data source %a%',
- );
-});
-
-
-test('connect & disconnect', function () {
- $options = Tester\Environment::loadData() + ['username' => null, 'password' => null];
- $connections = 1;
-
- try {
- $connection = new Nette\Database\Connection($options['dsn'], $options['username'], $options['password']);
- } catch (PDOException $e) {
- Tester\Environment::skip("Connection to '$options[dsn]' failed. Reason: " . $e->getMessage());
- }
-
- $connection->onConnect[] = function () use (&$connections) {
- $connections++;
- };
-
- // first connection
- $pdo = $connection->getPdo();
- $driver = $connection->getDriver();
- Assert::same(1, $connections);
-
- // still first connection
- $connection->connect();
- Assert::same($pdo, $connection->getPdo());
- Assert::same($driver, $connection->getDriver());
- Assert::same(1, $connections);
-
- // second connection
- $connection->reconnect();
- $pdo2 = $connection->getPdo();
- $driver2 = $connection->getDriver();
-
- Assert::notSame($pdo, $pdo2);
- Assert::notSame($driver, $driver2);
- Assert::same(2, $connections);
-
- // third connection
- $connection->disconnect();
- Assert::notSame($pdo2, $connection->getPdo());
- Assert::notSame($driver2, $connection->getDriver());
- Assert::same(3, $connections);
-});
diff --git a/tests/Database/connection.options.mysql.phpt b/tests/Database/connection.options.mysql.phpt
index f95c202c7..9e20c290d 100644
--- a/tests/Database/connection.options.mysql.phpt
+++ b/tests/Database/connection.options.mysql.phpt
@@ -13,13 +13,13 @@ require __DIR__ . '/../bootstrap.php';
test('default charset', function () {
- $connection = connectToDB(['charset' => null])->getConnection();
+ $connection = connectToDB(['charset' => null]);
$row = $connection->fetch("SHOW VARIABLES LIKE 'character_set_client'");
Assert::same('utf8mb4', $row->Value);
});
test('custom charset', function () {
- $connection = connectToDB(['charset' => 'latin2'])->getConnection();
+ $connection = connectToDB(['charset' => 'latin2']);
$row = $connection->fetch("SHOW VARIABLES LIKE 'character_set_client'");
Assert::same('latin2', $row->Value);
});
@@ -27,28 +27,28 @@ test('custom charset', function () {
test('custom sqlmode', function () {
$desiredMode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';
- $connection = connectToDB(['sqlmode' => $desiredMode])->getConnection();
+ $connection = connectToDB(['sqlmode' => $desiredMode]);
$field = $connection->fetchField('SELECT @@sql_mode');
Assert::same($desiredMode, $field);
});
test('default convertBoolean', function () {
- $connection = connectToDB(['convertBoolean' => null])->getConnection();
+ $connection = connectToDB(['convertBoolean' => null]);
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-nette_test3.sql');
$row = $connection->fetch('SELECT * FROM types');
- Assert::same(1, $row->bool);
+ Assert::same(true, $row->bool);
});
test('convertBoolean = true', function () {
- $connection = connectToDB(['convertBoolean' => true])->getConnection();
+ $connection = connectToDB(['convertBoolean' => true]);
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-nette_test3.sql');
$row = $connection->fetch('SELECT * FROM types');
Assert::same(true, $row->bool);
});
test('convertBoolean = false', function () {
- $connection = connectToDB(['convertBoolean' => false])->getConnection();
+ $connection = connectToDB(['convertBoolean' => false]);
Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-nette_test3.sql');
$row = $connection->fetch('SELECT * FROM types');
Assert::same(1, $row->bool);
@@ -56,19 +56,72 @@ test('convertBoolean = false', function () {
test('default newDateTime', function () {
- $connection = connectToDB(['newDateTime' => null])->getConnection();
+ $connection = connectToDB(['newDateTime' => null]);
$field = $connection->fetchField('SELECT NOW()');
- Assert::type(Nette\Utils\DateTime::class, $field);
+ Assert::type(Nette\Database\DateTime::class, $field);
});
test('newDateTime = false', function () {
- $connection = connectToDB(['newDateTime' => false])->getConnection();
+ $connection = connectToDB(['newDateTime' => false]);
$field = $connection->fetchField('SELECT NOW()');
Assert::type(Nette\Utils\DateTime::class, $field);
});
test('newDateTime = true', function () {
- $connection = connectToDB(['newDateTime' => true])->getConnection();
+ $connection = connectToDB(['newDateTime' => true]);
+ $field = $connection->fetchField('SELECT NOW()');
+ Assert::type(Nette\Database\DateTime::class, $field);
+});
+
+
+test('default convertDateTime', function () {
+ $connection = connectToDB(['convertDateTime' => null]);
+ $field = $connection->fetchField('SELECT NOW()');
+ Assert::type(Nette\Database\DateTime::class, $field);
+});
+
+test('convertDateTime = false', function () {
+ $connection = connectToDB(['convertDateTime' => false]);
+ $field = $connection->fetchField('SELECT NOW()');
+ Assert::type('string', $field);
+});
+
+test('convertDateTime = true', function () {
+ $connection = connectToDB(['convertDateTime' => true]);
$field = $connection->fetchField('SELECT NOW()');
Assert::type(Nette\Database\DateTime::class, $field);
});
+
+
+test('default convertDecimal', function () {
+ $connection = connectToDB(['convertDecimal' => null]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::same(1, $row->decimal);
+ Assert::same(1.1, $row->decimal2);
+
+ $fields = $connection->fetchFields('SELECT 10, 10.5');
+ Assert::same([10, 10.5], $fields);
+});
+
+test('convertDecimal = false', function () {
+ $connection = connectToDB(['convertDecimal' => false]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::same('1', $row->decimal);
+ Assert::same('1.10', $row->decimal2);
+
+ $fields = $connection->fetchFields('SELECT 10, 10.5');
+ Assert::same([10, '10.5'], $fields);
+});
+
+test('convertDecimal = true', function () {
+ $connection = connectToDB(['convertDecimal' => true]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::same(1, $row->decimal);
+ Assert::same(1.1, $row->decimal2);
+
+ $fields = $connection->fetchFields('SELECT 10, 10.5');
+ Assert::same([10, 10.5], $fields);
+});
diff --git a/tests/Database/connection.options.sqlite.phpt b/tests/Database/connection.options.sqlite.phpt
index 63b8536d4..352803206 100644
--- a/tests/Database/connection.options.sqlite.phpt
+++ b/tests/Database/connection.options.sqlite.phpt
@@ -13,13 +13,37 @@ require __DIR__ . '/../bootstrap.php';
test('formatDateTime', function () {
- $connection = connectToDB(['formatDateTime' => 'U'])->getConnection();
- $driver = $connection->getDriver();
- Assert::same('254358000', $driver->formatDateTime(new DateTime('1978-01-23 00:00:00')));
+ $connection = connectToDB(['formatDateTime' => 'U']);
+ $engine = $connection->getDatabaseEngine();
+ Assert::same('254358000', $engine->formatDateTime(new DateTime('1978-01-23 00:00:00')));
});
test('formatDateTime', function () {
- $connection = connectToDB(['formatDateTime' => 'Y-m-d'])->getConnection();
- $driver = $connection->getDriver();
- Assert::same('1978-01-23', $driver->formatDateTime(new DateTime('1978-01-23 00:00:00')));
+ $connection = connectToDB(['formatDateTime' => 'Y-m-d']);
+ $engine = $connection->getDatabaseEngine();
+ Assert::same('1978-01-23', $engine->formatDateTime(new DateTime('1978-01-23 00:00:00')));
+});
+
+
+test('default convertDateTime', function () {
+ $connection = connectToDB(['convertDateTime' => null]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlite-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::type(Nette\Database\DateTime::class, $row->date);
+ Assert::type(Nette\Database\DateTime::class, $row->datetime);
+});
+
+test('convertDateTime = false', function () {
+ $connection = connectToDB(['convertDateTime' => false]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlite-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::type('int', $row->date);
+ Assert::type('int', $row->datetime);
+});
+
+test('convertDateTime = true', function () {
+ $connection = connectToDB(['convertDateTime' => true]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlite-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::type(Nette\Database\DateTime::class, $row->date);
});
diff --git a/tests/Database/connection.options.sqlsrv.phpt b/tests/Database/connection.options.sqlsrv.phpt
new file mode 100644
index 000000000..39369c69a
--- /dev/null
+++ b/tests/Database/connection.options.sqlsrv.phpt
@@ -0,0 +1,62 @@
+ null]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::same(1, $row->decimal);
+ Assert::same(1, $row->numeric_10_0);
+ Assert::same(1.1, $row->numeric_10_2);
+});
+
+test('convertDecimal = true', function () {
+ $connection = connectToDB(['convertDecimal' => true]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::same(1, $row->decimal);
+ Assert::same(1, $row->numeric_10_0);
+ Assert::same(1.1, $row->numeric_10_2);
+});
+
+test('convertDecimal = false', function () {
+ $connection = connectToDB(['convertDecimal' => false]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::same('1', $row->decimal);
+ Assert::same('1', $row->numeric_10_0);
+ Assert::same('1.10', $row->numeric_10_2);
+});
+
+
+test('default convertBoolean', function () {
+ $connection = connectToDB(['convertBoolean' => null]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::equal(true, $row->bit);
+});
+
+test('convertBoolean = true', function () {
+ $connection = connectToDB(['convertBoolean' => true]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::equal(true, $row->bit);
+});
+
+test('convertBoolean = false', function () {
+ $connection = connectToDB(['convertBoolean' => false]);
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-nette_test3.sql');
+ $row = $connection->fetch('SELECT * FROM types');
+ Assert::equal(1, $row->bit);
+});
diff --git a/tests/Database/files/sqlsrv-loadFromFile.sql b/tests/Database/files/sqlsrv-loadFromFile.sql
new file mode 100644
index 000000000..d4336c2a0
--- /dev/null
+++ b/tests/Database/files/sqlsrv-loadFromFile.sql
@@ -0,0 +1,13 @@
+IF OBJECT_ID('products', 'U') IS NOT NULL DROP TABLE products;
+
+CREATE TABLE products (
+ product_id int NOT NULL IDENTITY(11,1),
+ title varchar(50) NOT NULL,
+ PRIMARY KEY(product_id)
+);
+
+SET IDENTITY_INSERT products ON;
+INSERT INTO products (product_id, title) VALUES (1, 'Chair');
+INSERT INTO products (product_id, title) VALUES (2, 'Table');
+INSERT INTO products (product_id, title) VALUES (3, 'Computer');
+SET IDENTITY_INSERT products OFF;
diff --git a/tests/Database/sqlsrv-loadFromFile.phpt b/tests/Database/sqlsrv-loadFromFile.phpt
new file mode 100644
index 000000000..2289d6fd5
--- /dev/null
+++ b/tests/Database/sqlsrv-loadFromFile.phpt
@@ -0,0 +1,18 @@
+ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-loadFromFile.sql')
+);
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index f112e33ce..73bb24e86 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -16,6 +16,10 @@
Tester\Environment::setupFunctions();
date_default_timezone_set('Europe/Prague');
+if (PHP_VERSION_ID >= 80400) {
+ error_reporting(E_ALL & ~E_DEPRECATED);
+}
+
function getTempDir(): string
{
@@ -34,18 +38,16 @@ function connectToDB(array $options = []): Nette\Database\Explorer
Tester\Environment::lock($args['dsn'], getTempDir());
}
+ $explorer = new Nette\Database\Explorer($args['dsn'], $args['username'], $args['password'], $args['options']);
+
try {
- $connection = new Nette\Database\Connection($args['dsn'], $args['username'], $args['password'], $args['options']);
- } catch (PDOException $e) {
+ $explorer->connect();
+ } catch (Nette\Database\ConnectionException $e) {
Tester\Environment::skip("Connection to '$args[dsn]' failed. Reason: " . $e->getMessage());
}
- $driverName = $connection->getPdo()->getAttribute(PDO::ATTR_DRIVER_NAME);
- $cacheMemoryStorage = new Nette\Caching\Storages\MemoryStorage;
-
- $structure = new Nette\Database\Structure($connection, $cacheMemoryStorage);
- $conventions = new Nette\Database\Conventions\DiscoveredConventions($structure);
- $explorer = new Nette\Database\Explorer($connection, $structure, $conventions, $cacheMemoryStorage);
+ $driverName = $explorer->getConnection()->getNativeConnection()->getAttribute(PDO::ATTR_DRIVER_NAME);
+ $explorer->setCache(new Nette\Caching\Cache(new Nette\Caching\Storages\MemoryStorage));
echo "Driver: $driverName\n";
$GLOBALS['driverName'] = $driverName;
diff --git a/tests/databases.github.ini b/tests/databases.github.ini
index d00f44271..1c722a84c 100644
--- a/tests/databases.github.ini
+++ b/tests/databases.github.ini
@@ -2,34 +2,26 @@
dsn = "mysql:host=127.0.0.1;port=3306;dbname=nette_test"
username = root
password = root
-options[convertBoolean] = yes
-options[newDateTime] = yes
[mysql 8.0]
dsn = "mysql:host=127.0.0.1;port=3307;dbname=nette_test"
username = root
password = root
-options[convertBoolean] = yes
-options[newDateTime] = yes
[postgresql 9.6]
dsn = "pgsql:host=127.0.0.1;port=5432;dbname=nette_test"
username = postgres
password = postgres
-options[newDateTime] = yes
[postgresql 13]
dsn = "pgsql:host=127.0.0.1;port=5433;dbname=nette_test"
username = postgres
password = postgres
-options[newDateTime] = yes
[sqlsrv]
dsn = "sqlsrv:Server=localhost,1433;Database=nette_test"
username = SA
password = "YourStrong!Passw0rd"
-options[newDateTime] = yes
[sqlite]
dsn = "sqlite::memory:"
-options[newDateTime] = yes
diff --git a/tests/databases.sqlite.ini b/tests/databases.sqlite.ini
index 2e076f7e8..2d89c58ce 100644
--- a/tests/databases.sqlite.ini
+++ b/tests/databases.sqlite.ini
@@ -1,3 +1,2 @@
[sqlite]
dsn = "sqlite::memory:"
-options[newDateTime] = yes
|