From 0bd6cb95f5b0d0e536d30ba5f172d04ec093d579 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Tue, 26 Feb 2019 21:41:52 +0100 Subject: [PATCH] test and fix schema builder --- DataStorage/Database/GrammarAbstract.php | 4 - DataStorage/Database/Schema/Builder.php | 70 +++++++++++++--- .../Database/Schema/Grammar/Grammar.php | 47 +++++++++-- .../Database/Schema/Grammar/MysqlGrammar.php | 4 +- DataStorage/Database/Schema/QueryType.php | 11 +-- Module/InstallerAbstract.php | 29 +------ .../Database/Schema/BuilderTest.php | 2 +- .../Schema/Grammar/MysqlGrammarTest.php | 41 ++++++++++ .../Database/Schema/Grammar/testSchema.json | 81 +++++++++++++++++++ .../Database/Schema/QueryTypeTest.php | 5 +- 10 files changed, 236 insertions(+), 58 deletions(-) create mode 100644 tests/DataStorage/Database/Schema/Grammar/testSchema.json diff --git a/DataStorage/Database/GrammarAbstract.php b/DataStorage/Database/GrammarAbstract.php index 62e3bcd42..7278d3934 100644 --- a/DataStorage/Database/GrammarAbstract.php +++ b/DataStorage/Database/GrammarAbstract.php @@ -205,10 +205,6 @@ abstract class GrammarAbstract foreach ($elements as $key => $element) { if (\is_string($element) && $element !== '*') { - if (\strpos($element, '.') === false) { - $prefix = ''; - } - $expression .= $this->compileSystem($element, $prefix) . ', '; } elseif (\is_string($element) && $element === '*') { $expression .= '*, '; diff --git a/DataStorage/Database/Schema/Builder.php b/DataStorage/Database/Schema/Builder.php index 12e86b14c..28c3045cb 100644 --- a/DataStorage/Database/Schema/Builder.php +++ b/DataStorage/Database/Schema/Builder.php @@ -31,11 +31,13 @@ class Builder extends QueryBuilder public $createFields = []; - public $drop = []; + public $dropDatabase = ''; + + public $dropTable = ''; public $selectTables = ['*']; - public $selectFields = []; + public $selectFields = ''; public $createTableSettings = true; @@ -43,20 +45,70 @@ class Builder extends QueryBuilder * Constructor. * * @param ConnectionAbstract $connection Database connection + * @param bool $readOnly Query is read only * * @since 1.0.0 */ - public function __construct(ConnectionAbstract $connection) + public function __construct(ConnectionAbstract $connection, bool $readOnly = false) + { + $this->isReadOnly = $readOnly; + $this->setConnection($connection); + } + + /** + * Set connection for grammar. + * + * @param ConnectionAbstract $connection Database connection + * + * @return void + * + * @since 1.0.0 + */ + public function setConnection(ConnectionAbstract $connection) : void { $this->connection = $connection; $this->grammar = $connection->getSchemaGrammar(); } - public function drop(...$table) : self + /** + * Create schema builder from schema definition. + * + * @param array $definition Database schema definition + * @param ConnectionAbstract $connection Database connection + * + * @return self + * + * @since 1.0.0 + */ + public static function createFromSchema(array $definition, ConnectionAbstract $connection) : self { - $this->type = QueryType::DROP; - $this->drop += $table; - $this->drop = \array_unique($this->drop); + $builder = new self($connection); + $builder->prefix($connection->prefix); + $builder->createTable($definition['name'] ?? ''); + + foreach ($definition['fields'] as $name => $def) { + $builder->field( + $name, $def['type'], $def['default'] ?? null, + $def['null'] ?? true, $def['primary'] ?? false, $def['autoincrement'] ?? false, + $def['foreignTable'] ?? null, $def['foreignKey'] ?? null + ); + } + + return $builder; + } + + public function dropDatabase(string $database) : self + { + $this->type = QueryType::DROP_DATABASE; + $this->dropDatabase = $database; + + return $this; + } + + public function dropTable(string $table) : self + { + $this->type = QueryType::DROP_TABLE; + $this->dropTable = $table; return $this; } @@ -70,8 +122,8 @@ class Builder extends QueryBuilder public function selectFields(string $table) : self { - $this->type = QueryType::FIELDS; - $this->selectFields[0] = $table; + $this->type = QueryType::FIELDS; + $this->selectFields = $table; return $this; } diff --git a/DataStorage/Database/Schema/Grammar/Grammar.php b/DataStorage/Database/Schema/Grammar/Grammar.php index f422de118..70ff08083 100644 --- a/DataStorage/Database/Schema/Grammar/Grammar.php +++ b/DataStorage/Database/Schema/Grammar/Grammar.php @@ -34,8 +34,18 @@ class Grammar extends QueryGrammar * @var string[] * @since 1.0.0 */ - protected $dropComponents = [ - 'drop', + protected $dropDatabaseComponents = [ + 'dropDatabase', + ]; + + /** + * Drop components. + * + * @var string[] + * @since 1.0.0 + */ + protected $dropTableComponents = [ + 'dropTable', ]; /** @@ -76,14 +86,16 @@ class Grammar extends QueryGrammar protected function getComponents(int $type) : array { switch ($type) { - case QueryType::DROP: - return $this->dropComponents; + case QueryType::DROP_DATABASE: + return $this->dropDatabaseComponents; case QueryType::TABLES: return $this->tablesComponents; case QueryType::FIELDS: return $this->fieldsComponents; case QueryType::CREATE_TABLE: return $this->createTablesComponents; + case QueryType::DROP_TABLE: + return $this->dropTableComponents; default: return parent::getComponents($type); } @@ -123,15 +135,15 @@ class Grammar extends QueryGrammar * Compile drop query. * * @param BuilderAbstract $query Query - * @param array $tables Tables to drop + * @param string $table Tables to drop * * @return string * * @since 1.0.0 */ - protected function compileDrop(BuilderAbstract $query, array $tables) : string + protected function compileDropDatabase(BuilderAbstract $query, string $table) : string { - $expression = $this->expressionizeTableColumn($tables, $query->getPrefix()); + $expression = $this->expressionizeTableColumn([$table], $query->getPrefix()); if ($expression === '') { $expression = '*'; @@ -139,4 +151,25 @@ class Grammar extends QueryGrammar return 'DROP DATABASE ' . $expression; } + + /** + * Compile drop query. + * + * @param BuilderAbstract $query Query + * @param string $table Tables to drop + * + * @return string + * + * @since 1.0.0 + */ + protected function compileDropTable(BuilderAbstract $query, string $table) : string + { + $expression = $this->expressionizeTableColumn([$table], $query->getPrefix()); + + if ($expression === '') { + $expression = '*'; + } + + return 'DROP TABLE ' . $expression; + } } diff --git a/DataStorage/Database/Schema/Grammar/MysqlGrammar.php b/DataStorage/Database/Schema/Grammar/MysqlGrammar.php index c9217c6b6..79b6abde7 100644 --- a/DataStorage/Database/Schema/Grammar/MysqlGrammar.php +++ b/DataStorage/Database/Schema/Grammar/MysqlGrammar.php @@ -65,13 +65,13 @@ class MysqlGrammar extends Grammar * * @since 1.0.0 */ - protected function compileSelectFields(Builder $query, array $table) : string + protected function compileSelectFields(Builder $query, string $table) : string { $builder = new Builder($query->getConnection()); $builder->select('*') ->from('information_schema.columns') ->where('table_schema', '=', $query->getConnection()->getDatabase()) - ->andWhere('table_name', '=', 'test'); + ->andWhere('table_name', '=', $query->getPrefix() . $table); return \rtrim($builder->toSql(), ';'); } diff --git a/DataStorage/Database/Schema/QueryType.php b/DataStorage/Database/Schema/QueryType.php index 45e308f21..68776f9ae 100644 --- a/DataStorage/Database/Schema/QueryType.php +++ b/DataStorage/Database/Schema/QueryType.php @@ -28,9 +28,10 @@ use phpOMS\DataStorage\Database\Query\QueryType as DefaultQueryType; */ abstract class QueryType extends DefaultQueryType { - public const DROP = 128; - public const ALTER = 129; - public const TABLES = 130; - public const FIELDS = 131; - public const CREATE_TABLE = 132; + public const DROP_DATABASE = 128; + public const ALTER = 129; + public const TABLES = 130; + public const FIELDS = 131; + public const CREATE_TABLE = 132; + public const DROP_TABLE = 133; } diff --git a/Module/InstallerAbstract.php b/Module/InstallerAbstract.php index f4774ddaf..a2c805242 100644 --- a/Module/InstallerAbstract.php +++ b/Module/InstallerAbstract.php @@ -119,37 +119,10 @@ abstract class InstallerAbstract $definitions = \json_decode($content, true); foreach ($definitions as $definition) { - self::createTable($definition, $dbPool); + SchemaBuilder::createFromSchema($definition, $dbPool->get('schema'))->execute(); } } - /** - * Create table module. - * - * @param array $definition Table definition - * @param DatabasePool $dbPool Database instance - * - * @return void - * - * @since 1.0.0 - */ - private static function createTable(array $definition, DatabasePool $dbPool) : void - { - $builder = new SchemaBuilder($dbPool->get('schema')); - $builder->prefix($dbPool->get('schema')->prefix); - $builder->createTable($definition['name'] ?? ''); - - foreach ($definition['fields'] as $name => $def) { - $builder->field( - $name, $def['type'], $def['default'] ?? null, - $def['null'] ?? true, $def['primary'] ?? false, $def['autoincrement'] ?? false, - $def['foreignTable'] ?? null, $def['foreignKey'] ?? null - ); - } - - $builder->execute(); - } - /** * Activate after install. * diff --git a/tests/DataStorage/Database/Schema/BuilderTest.php b/tests/DataStorage/Database/Schema/BuilderTest.php index e7d1d0683..c63027f0d 100644 --- a/tests/DataStorage/Database/Schema/BuilderTest.php +++ b/tests/DataStorage/Database/Schema/BuilderTest.php @@ -29,7 +29,7 @@ class BuilderTest extends \PHPUnit\Framework\TestCase { $query = new Builder($this->con); $sql = 'DROP DATABASE `test`;'; - self::assertEquals($sql, $query->drop('test')->toSql()); + self::assertEquals($sql, $query->dropDatabase('test')->toSql()); } public function testMysqlShowTables() : void diff --git a/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php b/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php index 573222411..9a3f44603 100644 --- a/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php +++ b/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php @@ -13,14 +13,55 @@ namespace phpOMS\tests\DataStorage\Database\Schema\Grammar; +use phpOMS\DataStorage\Database\Connection\MysqlConnection; +use phpOMS\DataStorage\Database\Schema\Builder as SchemaBuilder; use phpOMS\DataStorage\Database\Schema\Grammar\MysqlGrammar; +use phpOMS\Utils\ArrayUtils; use phpOMS\Utils\TestUtils; class MysqlGrammarTest extends \PHPUnit\Framework\TestCase { + protected $con = null; + + protected function setUp() : void + { + $this->con = new MysqlConnection($GLOBALS['CONFIG']['db']['core']['masters']['admin']); + } + public function testDefault() : void { self::assertInstanceOf('\phpOMS\DataStorage\Database\Schema\Grammar\Grammar', new MysqlGrammar()); self::assertEquals('`', TestUtils::getMember(new MysqlGrammar(), 'systemIdentifier')); } + + public function testSchemaCreateReadDelete() : void + { + $definitions = \json_decode(\file_get_contents(__DIR__ . '/testSchema.json'), true); + foreach ($definitions as $definition) { + SchemaBuilder::createFromSchema($definition, $this->con)->execute(); + } + + $table = new SchemaBuilder($this->con); + $tables = $table->prefix($this->con->prefix)->selectTables()->execute()->fetchAll(\PDO::FETCH_COLUMN); + self::assertContains($this->con->prefix . 'test', $tables); + self::assertContains($this->con->prefix . 'test_foreign', $tables); + + $field = new SchemaBuilder($this->con); + $fields = $field->prefix($this->con->prefix)->selectFields('test')->execute()->fetchAll(); + + foreach ($definitions['test']['fields'] as $key => $field) { + self::assertTrue( + ArrayUtils::inArrayRecursive($key, $fields), + 'Couldn\'t find "' . $key . '" in array' + ); + } + + $delete = new SchemaBuilder($this->con); + $delete->prefix($this->con->prefix)->dropTable('test')->execute(); + $delete->prefix($this->con->prefix)->dropTable('test_foreign')->execute(); + + $tables = $table->prefix($this->con->prefix)->selectTables()->execute()->fetchAll(); + self::assertNotContains($this->con->prefix . 'test', $tables); + self::assertNotContains($this->con->prefix . 'test_foreign', $tables); + } } diff --git a/tests/DataStorage/Database/Schema/Grammar/testSchema.json b/tests/DataStorage/Database/Schema/Grammar/testSchema.json new file mode 100644 index 000000000..3a13d7ffc --- /dev/null +++ b/tests/DataStorage/Database/Schema/Grammar/testSchema.json @@ -0,0 +1,81 @@ +{ + "test_foreign": { + "name": "test_foreign", + "fields": { + "test_foreign_id": { + "name": "test_foreign_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + } + } + }, + "test": { + "name": "test", + "fields": { + "test_id": { + "name": "test_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "test_varchar": { + "name": "test_varchar", + "type": "VARCHAR(255)", + "null": false + }, + "test_text": { + "name": "test_text", + "type": "TEXT", + "null": false + }, + "test_tinyint": { + "name": "test_tinyint", + "type": "TINYINT", + "null": false + }, + "test_smallint": { + "name": "test_smallint", + "type": "SMALLINT", + "null": false + }, + "test_int": { + "name": "test_int", + "type": "INT", + "null": false + }, + "test_bigint": { + "name": "test_bigint", + "type": "BIGINT", + "null": false + }, + "test_datetime": { + "name": "test_datetime", + "type": "DATETIME", + "null": false + }, + "test_null": { + "name": "test_null", + "type": "VARCHAR(2)", + "default": null, + "null": true + }, + "test_default": { + "name": "test_default", + "type": "VARCHAR(10)", + "default": "TeSt1", + "null": true + }, + "test_foreign": { + "name": "test_foreign", + "type": "INT", + "default": null, + "null": true, + "foreignTable": "test_foreign", + "foreignKey": "test_foreign_id" + } + } + } +} \ No newline at end of file diff --git a/tests/DataStorage/Database/Schema/QueryTypeTest.php b/tests/DataStorage/Database/Schema/QueryTypeTest.php index 05fcddc97..0876a46ad 100644 --- a/tests/DataStorage/Database/Schema/QueryTypeTest.php +++ b/tests/DataStorage/Database/Schema/QueryTypeTest.php @@ -19,13 +19,14 @@ class QueryTypeTest extends \PHPUnit\Framework\TestCase { public function testEnums() : void { - self::assertEquals(12, \count(QueryType::getConstants())); + self::assertEquals(13, \count(QueryType::getConstants())); self::assertEquals(QueryType::getConstants(), array_unique(QueryType::getConstants())); - self::assertEquals(128, QueryType::DROP); + self::assertEquals(128, QueryType::DROP_DATABASE); self::assertEquals(129, QueryType::ALTER); self::assertEquals(130, QueryType::TABLES); self::assertEquals(131, QueryType::FIELDS); self::assertEquals(132, QueryType::CREATE_TABLE); + self::assertEquals(133, QueryType::DROP_TABLE); } }