test and fix schema builder

This commit is contained in:
Dennis Eichhorn 2019-02-26 21:41:52 +01:00
parent 6e2bfebc60
commit 0bd6cb95f5
10 changed files with 236 additions and 58 deletions

View File

@ -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 .= '*, ';

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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(), ';');
}

View File

@ -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;
}

View File

@ -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.
*

View File

@ -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

View File

@ -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);
}
}

View File

@ -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"
}
}
}
}

View File

@ -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);
}
}