diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..f02a64bf
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,20 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 4
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.yml]
+indent_style = space
+indent_size = 2
+
+[*.json]
+indent_style = space
+indent_size = 4
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index ae75b7a0..04179573 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -73,7 +73,6 @@ jobs:
file: ./coverage.xml
sqlite:
- needs: lint
name: SQLite PHP ${{ matrix.php-versions }}
runs-on: ubuntu-latest
strategy:
diff --git a/.gitignore b/.gitignore
index d5e6a473..d89a76d9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,4 +10,4 @@ build/
clover.xml
clover.json
.php_cs.cache
-/.phpunit.result.cache
+.phpunit.result.cache
diff --git a/LICENSE b/LICENSE
index be7d3b94..586cdb02 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2020 Spiral Scout
+Copyright (c) 2021 Spiral Scout
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/composer.json b/composer.json
index a7a73ebd..95d5eba4 100644
--- a/composer.json
+++ b/composer.json
@@ -1,36 +1,60 @@
{
- "name": "cycle/database",
- "type": "library",
- "description": "DBAL, schema introspection, migration and pagination",
- "license": "MIT",
- "authors": [
- {
- "name": "Anton Titov / Wolfy-J",
- "email": "wolfy.jd@gmail.com"
- }
- ],
- "require": {
- "php": ">=8.0",
- "ext-pdo": "*",
- "spiral/core": "^2.7",
- "spiral/logger": "^2.7",
- "spiral/pagination": "^2.7"
- },
- "require-dev": {
- "phpunit/phpunit": "~8.0",
- "mockery/mockery": "^1.1",
- "spiral/dumper": "^2.7",
- "spiral/code-style": "^1.0",
- "spiral/tokenizer": "^2.7"
- },
- "autoload": {
- "psr-4": {
- "Cycle\\Database\\": "src/"
- }
- },
- "autoload-dev": {
- "psr-4": {
- "Cycle\\Database\\Tests\\": "tests/Database/"
- }
- }
+ "name": "cycle/database",
+ "type": "library",
+ "description": "DBAL, schema introspection, migration and pagination",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Anton Titov / Wolfy-J",
+ "email": "wolfy.jd@gmail.com"
+ }
+ ],
+ "replace": {
+ "spiral/database": "^2.0"
+ },
+ "require": {
+ "php": ">=8.0",
+ "ext-pdo": "*",
+ "spiral/core": "^2.8",
+ "spiral/logger": "^2.8",
+ "spiral/pagination": "^2.8"
+ },
+ "autoload": {
+ "files": [
+ "src/polyfill.php"
+ ],
+ "psr-4": {
+ "Cycle\\Database\\": "src"
+ }
+ },
+ "require-dev": {
+ "vimeo/psalm": "^4.10",
+ "phpunit/phpunit": "^8.5|^9.0",
+ "mockery/mockery": "^1.3",
+ "spiral/dumper": "^2.8",
+ "spiral/code-style": "^1.0",
+ "spiral/tokenizer": "^2.8"
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Cycle\\Database\\Tests\\": "tests/Database"
+ }
+ },
+ "scripts": {
+ "test": [
+ "phpcs --standard=phpcs.xml",
+ "psalm --no-cache",
+ "phpunit"
+ ]
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "config": {
+ "sort-packages": true
+ },
+ "minimum-stability": "dev",
+ "prefer-stable": true
}
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 00000000..a81e1731
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./src
+
diff --git a/phpunit.xml b/phpunit.xml
index 1d822c27..c7cd12cf 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -22,4 +22,4 @@
src/
-
\ No newline at end of file
+
diff --git a/psalm.xml b/psalm.xml
new file mode 100644
index 00000000..b82c72f3
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/.phpstorm.meta.php b/resources/.phpstorm.meta.php
new file mode 100644
index 00000000..55f0c22e
--- /dev/null
+++ b/resources/.phpstorm.meta.php
@@ -0,0 +1,754 @@
+select(), stupid bug.
- $columns = $columns[0];
+ $arguments = $arguments[0];
}
return $this->getDriver(self::READ)
->getQueryBuilder()
- ->selectQuery($this->prefix, [], $columns);
+ ->selectQuery($this->prefix, [], $arguments);
}
/**
diff --git a/src/DatabaseInterface.php b/src/DatabaseInterface.php
index 2789d768..42fcd9d6 100644
--- a/src/DatabaseInterface.php
+++ b/src/DatabaseInterface.php
@@ -1,10 +1,10 @@
config->getDefaultDatabase();
}
- //Spiral support ability to link multiple virtual databases together using aliases
+ // Cycle support ability to link multiple virtual databases together
+ // using aliases.
$database = $this->config->resolveAlias($database);
if (isset($this->databases[$database])) {
diff --git a/src/DatabaseProviderInterface.php b/src/DatabaseProviderInterface.php
index 2492d243..ada66cbc 100644
--- a/src/DatabaseProviderInterface.php
+++ b/src/DatabaseProviderInterface.php
@@ -1,10 +1,10 @@
true,
// disable schema modifications
- 'readonlySchema' => false
+ 'readonlySchema' => false,
+
+ // disable write expressions
+ 'readonly' => false,
];
/** @var PDO|null */
@@ -119,6 +124,41 @@ public function __construct(
if ($this->options['readonlySchema']) {
$this->schemaHandler = new ReadonlyHandler($this->schemaHandler);
}
+
+ // Actualize DSN
+ $this->updateDSN();
+ }
+
+ /**
+ * Updates an internal options
+ *
+ * @return void
+ */
+ private function updateDSN(): void
+ {
+ [$connection, $this->options['username'], $this->options['password']] = $this->parseDSN();
+
+ // Update connection. The DSN field can be located in one of the
+ // following keys of the configuration array.
+ switch (true) {
+ case \array_key_exists('dsn', $this->options):
+ $this->options['dsn'] = $connection;
+ break;
+ case \array_key_exists('addr', $this->options):
+ $this->options['addr'] = $connection;
+ break;
+ default:
+ $this->options['connection'] = $connection;
+ break;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function isReadonly(): bool
+ {
+ return (bool)($this->options['readonly'] ?? false);
}
/**
@@ -299,9 +339,14 @@ public function query(string $statement, array $parameters = []): StatementInter
* @return int
*
* @throws StatementException
+ * @throws ReadonlyConnectionException
*/
public function execute(string $query, array $parameters = []): int
{
+ if ($this->isReadonly()) {
+ throw ReadonlyConnectionException::onWriteStatementExecution();
+ }
+
return $this->statement($query, $parameters)->rowCount();
}
@@ -651,6 +696,42 @@ protected function rollbackSavepoint(int $level): void
$this->execute('ROLLBACK TO SAVEPOINT ' . $this->identifier("SVP{$level}"));
}
+ /**
+ * @return array{string, string, string}
+ */
+ private function parseDSN(): array
+ {
+ $dsn = $this->getDSN();
+
+ $user = (string)($this->options['username'] ?? '');
+ $pass = (string)($this->options['password'] ?? '');
+
+ if (\strpos($dsn, '://') > 0) {
+ $parts = \parse_url($dsn);
+
+ if (!isset($parts['scheme'])) {
+ throw new ConfigException('Configuration database scheme must be defined');
+ }
+
+ // Update username and password from DSN if not defined.
+ $user = $user ?: $parts['user'] ?? '';
+ $pass = $pass ?: $parts['pass'] ?? '';
+
+ // Build new DSN
+ $dsn = \sprintf('%s:host=%s', $parts['scheme'], $parts['host'] ?? 'localhost');
+
+ if (isset($parts['port'])) {
+ $dsn .= ';port=' . $parts['port'];
+ }
+
+ if (isset($parts['path']) && \trim($parts['path'], '/')) {
+ $dsn .= ';dbname=' . \trim($parts['path'], '/');
+ }
+ }
+
+ return [$dsn, $user, $pass];
+ }
+
/**
* Create instance of configured PDO class.
*
@@ -658,12 +739,9 @@ protected function rollbackSavepoint(int $level): void
*/
protected function createPDO(): PDO
{
- return new PDO(
- $this->getDSN(),
- $this->options['username'],
- $this->options['password'],
- $this->options['options']
- );
+ [$dsn, $user, $pass] = $this->parseDSN();
+
+ return new PDO($dsn, $user, $pass, $this->options['options']);
}
/**
diff --git a/src/Driver/DriverInterface.php b/src/Driver/DriverInterface.php
index a6bb9493..759e1f83 100644
--- a/src/Driver/DriverInterface.php
+++ b/src/Driver/DriverInterface.php
@@ -1,10 +1,10 @@
driver->query(
$query,
- [$this->driver->getSource(), $name]
+ [$this->driver->getSource(), $table]
)->fetchColumn();
}
diff --git a/src/Driver/MySQL/Schema/MySQLColumn.php b/src/Driver/MySQL/Schema/MySQLColumn.php
index a8f20884..596f38b8 100644
--- a/src/Driver/MySQL/Schema/MySQLColumn.php
+++ b/src/Driver/MySQL/Schema/MySQLColumn.php
@@ -1,10 +1,10 @@
exec("SET NAMES 'UTF-8'");
diff --git a/src/Driver/Postgres/PostgresHandler.php b/src/Driver/Postgres/PostgresHandler.php
index 58c93a59..b97548b8 100644
--- a/src/Driver/Postgres/PostgresHandler.php
+++ b/src/Driver/Postgres/PostgresHandler.php
@@ -1,10 +1,10 @@
sqlStatement($params);
+ if ($this->driver->isReadonly()) {
+ throw ReadonlyConnectionException::onWriteStatementExecution();
+ }
+
$result = $this->driver->query($queryString, $params->getParameters());
try {
diff --git a/src/Driver/Postgres/Query/PostgresSelectQuery.php b/src/Driver/Postgres/Query/PostgresSelectQuery.php
index 1227fac4..3cc4c7b7 100644
--- a/src/Driver/Postgres/Query/PostgresSelectQuery.php
+++ b/src/Driver/Postgres/Query/PostgresSelectQuery.php
@@ -1,10 +1,10 @@
type = $schema['typname'];
/**
- * Attention, this is not default spiral enum type emulated via CHECK. This is real
- * Postgres enum type.
+ * Attention, this is not default enum type emulated via CHECK.
+ * This is real Postgres enum type.
*/
self::resolveEnum($driver, $column);
}
diff --git a/src/Driver/Postgres/Schema/PostgresForeignKey.php b/src/Driver/Postgres/Schema/PostgresForeignKey.php
index 6ff46bab..9fd24f3a 100644
--- a/src/Driver/Postgres/Schema/PostgresForeignKey.php
+++ b/src/Driver/Postgres/Schema/PostgresForeignKey.php
@@ -1,10 +1,10 @@
bindParam(
$index,
$parameter,
diff --git a/src/Driver/SQLServer/SQLServerHandler.php b/src/Driver/SQLServer/SQLServerHandler.php
index e72820f3..ba7bed89 100644
--- a/src/Driver/SQLServer/SQLServerHandler.php
+++ b/src/Driver/SQLServer/SQLServerHandler.php
@@ -1,10 +1,10 @@
driver->query($query, [$name])->fetchColumn();
+ return (bool)$this->driver->query($query, [$table])->fetchColumn();
}
/**
diff --git a/src/Driver/SQLServer/Schema/SQLServerColumn.php b/src/Driver/SQLServer/Schema/SQLServerColumn.php
index 08112510..ecf86e0f 100644
--- a/src/Driver/SQLServer/Schema/SQLServerColumn.php
+++ b/src/Driver/SQLServer/Schema/SQLServerColumn.php
@@ -1,10 +1,10 @@
$schema) {
+ foreach ($indexes as $_ => $schema) {
//Once all columns are aggregated we can finally create an index
$result[] = SQLServerIndex::createInstance($this->getFullName(), $schema);
}
diff --git a/src/Driver/SQLite/SQLiteCompiler.php b/src/Driver/SQLite/SQLiteCompiler.php
index cf344969..882d3b80 100644
--- a/src/Driver/SQLite/SQLiteCompiler.php
+++ b/src/Driver/SQLite/SQLiteCompiler.php
@@ -1,10 +1,10 @@
fetchColumn();
/*
- * There is not really many ways to get extra information about column in SQLite, let's parse
- * table schema. As mention, spiral SQLite schema reader will support fully only tables created
- * by spiral as we expecting every column definition be on new line.
- */
+ * There is not really many ways to get extra information about column
+ * in SQLite, let's parse table schema. As mention, Cycle SQLite
+ * schema reader will support fully only tables created by Cycle as we
+ * expecting every column definition be on new line.
+ */
$definition = explode("\n", $definition);
$result = [];
diff --git a/src/Driver/Statement.php b/src/Driver/Statement.php
index a19c1acf..62e7159e 100644
--- a/src/Driver/Statement.php
+++ b/src/Driver/Statement.php
@@ -1,10 +1,10 @@
current->getIndexes() as $name => $index) {
+ foreach ($this->current->getIndexes() as $_ => $index) {
if (!$this->initial->hasIndex($index->getColumnsWithSort())) {
$difference[] = $index;
}
@@ -155,7 +155,7 @@ public function addedIndexes(): array
public function droppedIndexes(): array
{
$difference = [];
- foreach ($this->initial->getIndexes() as $name => $index) {
+ foreach ($this->initial->getIndexes() as $_ => $index) {
if (!$this->current->hasIndex($index->getColumnsWithSort())) {
$difference[] = $index;
}
@@ -173,7 +173,7 @@ public function alteredIndexes(): array
{
$difference = [];
- foreach ($this->current->getIndexes() as $name => $index) {
+ foreach ($this->current->getIndexes() as $_ => $index) {
if (!$this->initial->hasIndex($index->getColumnsWithSort())) {
//Added into schema
continue;
@@ -194,7 +194,7 @@ public function alteredIndexes(): array
public function addedForeignKeys(): array
{
$difference = [];
- foreach ($this->current->getForeignKeys() as $name => $foreignKey) {
+ foreach ($this->current->getForeignKeys() as $_ => $foreignKey) {
if (!$this->initial->hasForeignKey($foreignKey->getColumns())) {
$difference[] = $foreignKey;
}
@@ -209,7 +209,7 @@ public function addedForeignKeys(): array
public function droppedForeignKeys(): array
{
$difference = [];
- foreach ($this->initial->getForeignKeys() as $name => $foreignKey) {
+ foreach ($this->initial->getForeignKeys() as $_ => $foreignKey) {
if (!$this->current->hasForeignKey($foreignKey->getColumns())) {
$difference[] = $foreignKey;
}
@@ -227,7 +227,7 @@ public function alteredForeignKeys(): array
{
$difference = [];
- foreach ($this->current->getForeignKeys() as $name => $foreignKey) {
+ foreach ($this->current->getForeignKeys() as $_ => $foreignKey) {
if (!$this->initial->hasForeignKey($foreignKey->getColumns())) {
//Added into schema
continue;
diff --git a/src/Schema/ComparatorInterface.php b/src/Schema/ComparatorInterface.php
index e3be69ba..09e92f24 100644
--- a/src/Schema/ComparatorInterface.php
+++ b/src/Schema/ComparatorInterface.php
@@ -1,10 +1,10 @@
beginTransaction(null, false);
} else {
- /** @var DriverInterface $driver */
$driver->beginTransaction(null);
}
}
@@ -192,7 +191,6 @@ protected function beginTransaction(): void
protected function commitTransaction(): void
{
foreach ($this->drivers as $driver) {
- /** @var DriverInterface $driver */
$driver->commitTransaction();
}
}
@@ -203,7 +201,6 @@ protected function commitTransaction(): void
protected function rollbackTransaction(): void
{
foreach (array_reverse($this->drivers) as $driver) {
- /** @var DriverInterface $driver */
$driver->rollbackTransaction();
}
}
diff --git a/src/Schema/State.php b/src/Schema/State.php
index 1f760588..38067df3 100644
--- a/src/Schema/State.php
+++ b/src/Schema/State.php
@@ -1,10 +1,10 @@
driver)) {
$class = $config['driver'];
- $options = [
+ $options = \array_merge($options, [
'connection' => $config['conn'],
- 'username' => $config['user'],
- 'password' => $config['pass'],
+ 'username' => $config['user'] ?? '',
+ 'password' => $config['pass'] ?? '',
'options' => [],
'queryCache' => true
- ];
+ ]);
if (isset($config['schema'])) {
$options['schema'] = $config['schema'];
@@ -84,15 +86,15 @@ public function getDriver(): Driver
/**
* @param string $name
* @param string $prefix
- *
+ * @param array $config
* @return Database|null When non empty null will be given, for safety, for science.
*/
- protected function db(string $name = 'default', string $prefix = '')
+ protected function db(string $name = 'default', string $prefix = '', array $config = []): ?Database
{
if (isset(static::$driverCache[static::DRIVER])) {
$driver = static::$driverCache[static::DRIVER];
} else {
- static::$driverCache[static::DRIVER] = $driver = $this->getDriver();
+ static::$driverCache[static::DRIVER] = $driver = $this->getDriver($config);
}
return new Database($name, $prefix, $driver);
diff --git a/tests/Database/Driver/MySQL/ReadonlyTest.php b/tests/Database/Driver/MySQL/ReadonlyTest.php
new file mode 100644
index 00000000..faaa7528
--- /dev/null
+++ b/tests/Database/Driver/MySQL/ReadonlyTest.php
@@ -0,0 +1,21 @@
+database = new Database('default', '', $this->getDriver(['readonly' => true]));
+
+ $this->allowWrite(function () {
+ $table = $this->database->table($this->table);
+ $schema = $table->getSchema();
+ $schema->primary('id');
+ $schema->string('value')->nullable();
+ $schema->save();
+ });
+ }
+
+ private function allowWrite(\Closure $then): void
+ {
+ /** @var Driver $driver */
+ $driver = $this->database->getDriver();
+
+ (function (\Closure $then): void {
+ $this->options['readonly'] = false;
+ try {
+ $then();
+ } finally {
+ $this->options['readonly'] = true;
+ }
+ })->call($driver, $then);
+ }
+
+ public function tearDown(): void
+ {
+ $this->allowWrite(function () {
+ $schema = $this->database->table($this->table)
+ ->getSchema();
+
+ $schema->declareDropped();
+ $schema->save();
+ });
+ }
+
+ protected function table(): Table
+ {
+ return $this->database->table($this->table);
+ }
+
+ public function testTableAllowSelection(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->table()
+ ->select()
+ ->run()
+ ;
+ }
+
+ public function testTableAllowCount(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->table()
+ ->count()
+ ;
+ }
+
+ public function testTableAllowExists(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->table()
+ ->exists()
+ ;
+ }
+
+ public function testTableAllowGetPrimaryKeys(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->table()
+ ->getPrimaryKeys()
+ ;
+ }
+
+ public function testTableAllowHasColumn(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->table()
+ ->hasColumn('column')
+ ;
+ }
+
+ public function testTableAllowGetColumns(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->table()
+ ->getColumns()
+ ;
+ }
+
+ public function testTableAllowHasIndex(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->table()
+ ->hasIndex(['column'])
+ ;
+ }
+
+ public function testTableAllowGetIndexes(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->table()
+ ->getIndexes()
+ ;
+ }
+
+ public function testTableAllowHasForeignKey(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->table()
+ ->hasForeignKey(['column'])
+ ;
+ }
+
+ public function testTableAllowGetForeignKeys(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->table()
+ ->getForeignKeys()
+ ;
+ }
+
+ public function testTableAllowGetDependencies(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->table()
+ ->getDependencies()
+ ;
+ }
+
+ public function testTableRejectInsertOne(): void
+ {
+ $this->expectException(ReadonlyConnectionException::class);
+
+ $this->table()
+ ->insertOne(['value' => 'example'])
+ ;
+ }
+
+ public function testTableRejectInsertMultiple(): void
+ {
+ $this->expectException(ReadonlyConnectionException::class);
+
+ $this->table()
+ ->insertMultiple(['value'], ['example'])
+ ;
+ }
+
+ public function testTableRejectInsert(): void
+ {
+ $this->expectException(ReadonlyConnectionException::class);
+
+ $this->table()
+ ->insert()
+ ->columns('value')
+ ->values('example')
+ ->run();
+ }
+
+ public function testTableRejectUpdate(): void
+ {
+ $this->expectException(ReadonlyConnectionException::class);
+
+ $this->table()
+ ->update(['value' => 'updated'])
+ ->run()
+ ;
+ }
+
+ public function testTableRejectDelete(): void
+ {
+ $this->expectException(ReadonlyConnectionException::class);
+
+ $this->table()
+ ->delete()
+ ->run()
+ ;
+ }
+
+ public function testTableRejectEraseData(): void
+ {
+ $this->expectException(ReadonlyConnectionException::class);
+
+ $this->table()
+ ->eraseData()
+ ;
+ }
+
+ public function testSchemaRejectSaving(): void
+ {
+ $this->expectException(ReadonlyConnectionException::class);
+
+ $table = $this->database
+ ->table('not_allowed_to_creation');
+
+ $schema = $table->getSchema();
+ $schema->primary('id');
+ $schema->string('value')->nullable();
+ $schema->save();
+ }
+
+ public function testDatabaseAllowSelection(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->database->select()
+ ->from($this->table)
+ ->run()
+ ;
+ }
+
+ public function testDatabaseRejectUpdate(): void
+ {
+ $this->expectException(ReadonlyConnectionException::class);
+
+ $this->database->update($this->table, ['value' => 'example'])
+ ->run()
+ ;
+ }
+
+ public function testDatabaseRejectInsert(): void
+ {
+ $this->expectException(ReadonlyConnectionException::class);
+
+ $this->database->insert($this->table)
+ ->columns('value')
+ ->values('example')
+ ->run()
+ ;
+ }
+
+ public function testDatabaseRejectDelete(): void
+ {
+ $this->expectException(ReadonlyConnectionException::class);
+
+ $this->database->delete($this->table)
+ ->run()
+ ;
+ }
+
+ public function testDatabaseAllowRawQuery(): void
+ {
+ $this->expectNotToPerformAssertions();
+
+ $this->database->query('SELECT 1');
+ }
+
+ public function testDatabaseRejectRawExecution(): void
+ {
+ $this->expectException(ReadonlyConnectionException::class);
+
+ $this->database->execute("DROP TABLE {$this->table}");
+ }
+}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 0c96ea3e..ec5fd432 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -30,9 +30,7 @@
],
'mysql' => [
'driver' => Database\Driver\MySQL\MySQLDriver::class,
- 'conn' => 'mysql:host=127.0.0.1:13306;dbname=spiral',
- 'user' => 'root',
- 'pass' => 'root',
+ 'conn' => 'mysql://root:root@127.0.0.1:13306/spiral',
'queryCache' => 100
],
'postgres' => [
@@ -53,9 +51,8 @@
$db = getenv('DB') ?: null;
Database\Tests\BaseTest::$config = [
- 'debug' => false,
- ] + (
- $db === null
+ 'debug' => getenv('DB_DEBUG') ?: false,
+ ] + ($db === null
? $drivers
: array_intersect_key($drivers, array_flip((array)$db))
);