mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-02-09 05:38:39 +00:00
test and fix schema builder
This commit is contained in:
parent
6e2bfebc60
commit
0bd6cb95f5
|
|
@ -205,10 +205,6 @@ abstract class GrammarAbstract
|
||||||
|
|
||||||
foreach ($elements as $key => $element) {
|
foreach ($elements as $key => $element) {
|
||||||
if (\is_string($element) && $element !== '*') {
|
if (\is_string($element) && $element !== '*') {
|
||||||
if (\strpos($element, '.') === false) {
|
|
||||||
$prefix = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$expression .= $this->compileSystem($element, $prefix) . ', ';
|
$expression .= $this->compileSystem($element, $prefix) . ', ';
|
||||||
} elseif (\is_string($element) && $element === '*') {
|
} elseif (\is_string($element) && $element === '*') {
|
||||||
$expression .= '*, ';
|
$expression .= '*, ';
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,13 @@ class Builder extends QueryBuilder
|
||||||
|
|
||||||
public $createFields = [];
|
public $createFields = [];
|
||||||
|
|
||||||
public $drop = [];
|
public $dropDatabase = '';
|
||||||
|
|
||||||
|
public $dropTable = '';
|
||||||
|
|
||||||
public $selectTables = ['*'];
|
public $selectTables = ['*'];
|
||||||
|
|
||||||
public $selectFields = [];
|
public $selectFields = '';
|
||||||
|
|
||||||
public $createTableSettings = true;
|
public $createTableSettings = true;
|
||||||
|
|
||||||
|
|
@ -43,20 +45,70 @@ class Builder extends QueryBuilder
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param ConnectionAbstract $connection Database connection
|
* @param ConnectionAbstract $connection Database connection
|
||||||
|
* @param bool $readOnly Query is read only
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @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->connection = $connection;
|
||||||
$this->grammar = $connection->getSchemaGrammar();
|
$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;
|
$builder = new self($connection);
|
||||||
$this->drop += $table;
|
$builder->prefix($connection->prefix);
|
||||||
$this->drop = \array_unique($this->drop);
|
$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;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
@ -70,8 +122,8 @@ class Builder extends QueryBuilder
|
||||||
|
|
||||||
public function selectFields(string $table) : self
|
public function selectFields(string $table) : self
|
||||||
{
|
{
|
||||||
$this->type = QueryType::FIELDS;
|
$this->type = QueryType::FIELDS;
|
||||||
$this->selectFields[0] = $table;
|
$this->selectFields = $table;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,18 @@ class Grammar extends QueryGrammar
|
||||||
* @var string[]
|
* @var string[]
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
protected $dropComponents = [
|
protected $dropDatabaseComponents = [
|
||||||
'drop',
|
'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
|
protected function getComponents(int $type) : array
|
||||||
{
|
{
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case QueryType::DROP:
|
case QueryType::DROP_DATABASE:
|
||||||
return $this->dropComponents;
|
return $this->dropDatabaseComponents;
|
||||||
case QueryType::TABLES:
|
case QueryType::TABLES:
|
||||||
return $this->tablesComponents;
|
return $this->tablesComponents;
|
||||||
case QueryType::FIELDS:
|
case QueryType::FIELDS:
|
||||||
return $this->fieldsComponents;
|
return $this->fieldsComponents;
|
||||||
case QueryType::CREATE_TABLE:
|
case QueryType::CREATE_TABLE:
|
||||||
return $this->createTablesComponents;
|
return $this->createTablesComponents;
|
||||||
|
case QueryType::DROP_TABLE:
|
||||||
|
return $this->dropTableComponents;
|
||||||
default:
|
default:
|
||||||
return parent::getComponents($type);
|
return parent::getComponents($type);
|
||||||
}
|
}
|
||||||
|
|
@ -123,15 +135,15 @@ class Grammar extends QueryGrammar
|
||||||
* Compile drop query.
|
* Compile drop query.
|
||||||
*
|
*
|
||||||
* @param BuilderAbstract $query Query
|
* @param BuilderAbstract $query Query
|
||||||
* @param array $tables Tables to drop
|
* @param string $table Tables to drop
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @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 === '') {
|
if ($expression === '') {
|
||||||
$expression = '*';
|
$expression = '*';
|
||||||
|
|
@ -139,4 +151,25 @@ class Grammar extends QueryGrammar
|
||||||
|
|
||||||
return 'DROP DATABASE ' . $expression;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,13 +65,13 @@ class MysqlGrammar extends Grammar
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @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 = new Builder($query->getConnection());
|
||||||
$builder->select('*')
|
$builder->select('*')
|
||||||
->from('information_schema.columns')
|
->from('information_schema.columns')
|
||||||
->where('table_schema', '=', $query->getConnection()->getDatabase())
|
->where('table_schema', '=', $query->getConnection()->getDatabase())
|
||||||
->andWhere('table_name', '=', 'test');
|
->andWhere('table_name', '=', $query->getPrefix() . $table);
|
||||||
|
|
||||||
return \rtrim($builder->toSql(), ';');
|
return \rtrim($builder->toSql(), ';');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,10 @@ use phpOMS\DataStorage\Database\Query\QueryType as DefaultQueryType;
|
||||||
*/
|
*/
|
||||||
abstract class QueryType extends DefaultQueryType
|
abstract class QueryType extends DefaultQueryType
|
||||||
{
|
{
|
||||||
public const DROP = 128;
|
public const DROP_DATABASE = 128;
|
||||||
public const ALTER = 129;
|
public const ALTER = 129;
|
||||||
public const TABLES = 130;
|
public const TABLES = 130;
|
||||||
public const FIELDS = 131;
|
public const FIELDS = 131;
|
||||||
public const CREATE_TABLE = 132;
|
public const CREATE_TABLE = 132;
|
||||||
|
public const DROP_TABLE = 133;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,37 +119,10 @@ abstract class InstallerAbstract
|
||||||
|
|
||||||
$definitions = \json_decode($content, true);
|
$definitions = \json_decode($content, true);
|
||||||
foreach ($definitions as $definition) {
|
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.
|
* Activate after install.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class BuilderTest extends \PHPUnit\Framework\TestCase
|
||||||
{
|
{
|
||||||
$query = new Builder($this->con);
|
$query = new Builder($this->con);
|
||||||
$sql = 'DROP DATABASE `test`;';
|
$sql = 'DROP DATABASE `test`;';
|
||||||
self::assertEquals($sql, $query->drop('test')->toSql());
|
self::assertEquals($sql, $query->dropDatabase('test')->toSql());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMysqlShowTables() : void
|
public function testMysqlShowTables() : void
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,55 @@
|
||||||
|
|
||||||
namespace phpOMS\tests\DataStorage\Database\Schema\Grammar;
|
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\DataStorage\Database\Schema\Grammar\MysqlGrammar;
|
||||||
|
use phpOMS\Utils\ArrayUtils;
|
||||||
use phpOMS\Utils\TestUtils;
|
use phpOMS\Utils\TestUtils;
|
||||||
|
|
||||||
class MysqlGrammarTest extends \PHPUnit\Framework\TestCase
|
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
|
public function testDefault() : void
|
||||||
{
|
{
|
||||||
self::assertInstanceOf('\phpOMS\DataStorage\Database\Schema\Grammar\Grammar', new MysqlGrammar());
|
self::assertInstanceOf('\phpOMS\DataStorage\Database\Schema\Grammar\Grammar', new MysqlGrammar());
|
||||||
self::assertEquals('`', TestUtils::getMember(new MysqlGrammar(), 'systemIdentifier'));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
81
tests/DataStorage/Database/Schema/Grammar/testSchema.json
Normal file
81
tests/DataStorage/Database/Schema/Grammar/testSchema.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,13 +19,14 @@ class QueryTypeTest extends \PHPUnit\Framework\TestCase
|
||||||
{
|
{
|
||||||
public function testEnums() : void
|
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(QueryType::getConstants(), array_unique(QueryType::getConstants()));
|
||||||
|
|
||||||
self::assertEquals(128, QueryType::DROP);
|
self::assertEquals(128, QueryType::DROP_DATABASE);
|
||||||
self::assertEquals(129, QueryType::ALTER);
|
self::assertEquals(129, QueryType::ALTER);
|
||||||
self::assertEquals(130, QueryType::TABLES);
|
self::assertEquals(130, QueryType::TABLES);
|
||||||
self::assertEquals(131, QueryType::FIELDS);
|
self::assertEquals(131, QueryType::FIELDS);
|
||||||
self::assertEquals(132, QueryType::CREATE_TABLE);
|
self::assertEquals(132, QueryType::CREATE_TABLE);
|
||||||
|
self::assertEquals(133, QueryType::DROP_TABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user