Jeroen De Dauw has submitted this change and it was merged.
Change subject: Implement MysqlDefinitionreader
......................................................................
Implement MysqlDefinitionreader
Change-Id: I94cee1121e631175ac784a8f8af8b228a4d98b1f
---
M src/MediaWiki/MediaWikiQueryInterface.php
M src/MySQL/MySqlTableDefinitionReader.php
M src/QueryInterface/QueryInterface.php
A tests/phpunit/MySQL/MySQLTableDefinitionReaderTest.php
4 files changed, 240 insertions(+), 6 deletions(-)
Approvals:
Jeroen De Dauw: Looks good to me, approved
jenkins-bot: Verified
diff --git a/src/MediaWiki/MediaWikiQueryInterface.php
b/src/MediaWiki/MediaWikiQueryInterface.php
index e4fc903..bea4790 100644
--- a/src/MediaWiki/MediaWikiQueryInterface.php
+++ b/src/MediaWiki/MediaWikiQueryInterface.php
@@ -142,16 +142,18 @@
* @param string $tableName
* @param array $fields
* @param array $conditions
+ * @param array $options
*
* @return ResultIterator
* @throws SelectFailedException
*/
- public function select( $tableName, array $fields, array $conditions ) {
+ public function select( $tableName, array $fields, array $conditions,
array $options = array() ) {
$selectionResult = $this->getDB()->select(
$tableName,
$fields,
$conditions,
- __METHOD__
+ __METHOD__,
+ $options
);
if ( $selectionResult instanceof \ResultWrapper ) {
diff --git a/src/MySQL/MySqlTableDefinitionReader.php
b/src/MySQL/MySqlTableDefinitionReader.php
index 43d251d..adcca72 100644
--- a/src/MySQL/MySqlTableDefinitionReader.php
+++ b/src/MySQL/MySqlTableDefinitionReader.php
@@ -3,6 +3,9 @@
namespace Wikibase\Database\MySQL;
use Wikibase\Database\QueryInterface\QueryInterface;
+use Wikibase\Database\QueryInterface\QueryInterfaceException;
+use Wikibase\Database\Schema\Definitions\FieldDefinition;
+use Wikibase\Database\Schema\Definitions\IndexDefinition;
use Wikibase\Database\Schema\Definitions\TableDefinition;
use Wikibase\Database\Schema\TableDefinitionReader;
@@ -10,11 +13,15 @@
* @since 0.1
* @licence GNU GPL v2+
* @author Jeroen De Dauw < [email protected] >
+ * @author Adam Shorland
*/
class MySqlTableDefinitionReader implements TableDefinitionReader {
protected $queryInterface;
+ /**
+ * @param QueryInterface $queryInterface
+ */
public function __construct( QueryInterface $queryInterface ) {
$this->queryInterface = $queryInterface;
}
@@ -24,10 +31,133 @@
*
* @param string $tableName
*
+ * @throws QueryInterfaceException
* @return TableDefinition
*/
public function readDefinition( $tableName ) {
- // TODO
+ if( !$this->queryInterface->tableExists( $tableName ) ){
+ throw new QueryInterfaceException( "Unknown table
{$tableName}" );
+ }
+
+ $fields = $this->getFields( $tableName );
+ $indexes = $this->getIndexes( $tableName );
+ return new TableDefinition( $tableName, $fields, $indexes );
+ }
+
+ /**
+ * @param $tableName string
+ * @return FieldDefinition[]
+ */
+ private function getFields( $tableName ) {
+ $results = $this->queryInterface->select(
+ 'information_schema.COLUMNS',
+ array(
+ 'name' => 'COLUMN_NAME',
+ 'cannull' => 'IS_NULLABLE',
+ 'type' => 'DATA_TYPE',
+ 'default' => 'COLUMN_DEFAULT' ),
+ array( 'TABLE_SCHEMA' => $tableName )
+ );
+
+ $fields = array();
+ foreach( $results as $field ){
+
+ $fields[] = new FieldDefinition(
+ $field['name'],
+ $this->getDataType( $field['type'] ),
+ $this->getNullable( $field['cannull'] ),
+ $field['default'] );
+ }
+
+ return $fields;
+ }
+
+ /**
+ * @param $tableName string
+ * @throws QueryInterfaceException
+ * @return IndexDefinition[]
+ */
+ private function getIndexes( $tableName ) {
+ //TODO we currently don't notice FULLTEXT or SPATIAL indexes
+ $indexes = array();
+
+ $constraintsResult = $this->queryInterface->select(
+ 'information_schema.table_constraints',
+ array(
+ 'name' => 'CONSTRAINT_NAME',
+ 'type' => 'CONSTRAINT_TYPE',
+ ),
+ array( 'TABLE_NAME' => $tableName )
+ );
+
+ foreach( $constraintsResult as $constraint ) {
+ if( $constraint['type'] === 'PRIMARY KEY' ) {
+ $type = IndexDefinition::TYPE_PRIMARY;
+ } else if( $constraint['type'] === 'UNIQUE' ) {
+ $type = IndexDefinition::TYPE_UNIQUE;
+ } else {
+ throw new QueryInterfaceException(
+ 'Unknown Constraint when reading
definition ' .
+ $constraint['name'] . ', ' .
$constraint['type'] );
+ }
+ $indexes[] = new IndexDefinition( $constraint['name'] ,
$constraint['columns'] , $type );
+ }
+
+ $indexesResult = $this->queryInterface->select(
+ 'information_schema.statistics',
+ array(
+ 'name' => 'index_name',
+ 'columns' => 'GROUP_CONCAT(column_name ORDER BY
seq_in_index)' ),
+ array( 'TABLE_NAME' => $tableName ),
+ array( 'GROUP BY' => '1,2' )
+ );
+
+ foreach( $indexesResult as $index ){
+ //ignore any indexes we already have (primary and
unique)
+ foreach( $constraintsResult as $constraint ){
+ if( $constraint['name'] === $index['name'] ){
+ continue 2;
+ }
+ }
+ $cols = array();
+ foreach( explode( ',', $index['columns'] ) as $col ){
+ $cols[ $col ] = 0;
+ }
+ $indexes[] = new IndexDefinition( $index['name'], $cols
, IndexDefinition::TYPE_INDEX );
+ }
+
+ return $indexes;
+ }
+
+ /**
+ * Simplifies the datatype and returns something a FieldDefinition can
expect
+ * @param $dataType string
+ * @return string
+ */
+ private function getDataType( $dataType ) {
+ if( stristr( $dataType, 'blob' ) ){
+ return FieldDefinition::TYPE_TEXT;
+ } else if ( stristr( $dataType, 'tinyint' ) ){
+ return FieldDefinition::TYPE_INTEGER;
+ } else if ( stristr( $dataType, 'int' ) ){
+ return FieldDefinition::TYPE_INTEGER;
+ } else if ( stristr( $dataType, 'float' ) ){
+ return FieldDefinition::TYPE_FLOAT;
+ } else {
+ return $dataType;
+ }
+ }
+
+ /**
+ * @param $nullable string
+ * @return bool
+ */
+ private function getNullable( $nullable ) {
+ if( $nullable === 'YES' ){
+ return true;
+ } else {
+ return false;
+ }
}
}
diff --git a/src/QueryInterface/QueryInterface.php
b/src/QueryInterface/QueryInterface.php
index 9556b41..2621e5f 100644
--- a/src/QueryInterface/QueryInterface.php
+++ b/src/QueryInterface/QueryInterface.php
@@ -67,18 +67,23 @@
/**
* Selects the specified fields from the rows that match the provided
conditions.
- * The conditions are provided as an associative array in
- * which the keys are the field names.
+ *
+ * The conditions are provided as an associative array in which the
keys are the field names.
+ *
+ * The optional options are provided as an array.
+ * Options are specified by using the key as the options and the value
as the value
+ * Boolean options are specified by including them in the array as a
string value with a numeric key.
*
* @since 0.1
*
* @param string $tableName
* @param array $fields
* @param array $conditions
+ * @param array $options
*
* @return ResultIterator
* @throws SelectFailedException
*/
- public function select( $tableName, array $fields, array $conditions );
+ public function select( $tableName, array $fields, array $conditions,
array $options = array() );
}
diff --git a/tests/phpunit/MySQL/MySQLTableDefinitionReaderTest.php
b/tests/phpunit/MySQL/MySQLTableDefinitionReaderTest.php
new file mode 100644
index 0000000..9c2a991
--- /dev/null
+++ b/tests/phpunit/MySQL/MySQLTableDefinitionReaderTest.php
@@ -0,0 +1,97 @@
+<?php
+
+namespace Wikibase\Database\Tests;
+
+use Wikibase\Database\MySQL\MySqlTableDefinitionReader;
+use Wikibase\Database\QueryInterface\ResultIterator;
+use Wikibase\Database\Schema\Definitions\FieldDefinition;
+use Wikibase\Database\Schema\Definitions\IndexDefinition;
+use Wikibase\Database\Schema\Definitions\TableDefinition;
+
+/**
+ * @since 0.1
+ * @licence GNU GPL v2+
+ * @author Adam Shorland
+ */
+class MySQLTableDefinitionReaderTest extends \PHPUnit_Framework_TestCase {
+
+ public function testCanConstruct() {
+ $this->newInstance();
+ $this->assertTrue( true );
+ }
+
+ protected function newInstance( $results = array() ) {
+ $mockQueryInterface = $this
+ ->getMockBuilder(
'Wikibase\Database\MediaWiki\MediaWikiQueryInterface' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $mockQueryInterface->expects( $this->any() )
+ ->method( 'tableExists' )
+ ->will( $this->returnValue( true ) );
+
+ foreach( $results as $key => $result ){
+ $mockQueryInterface->expects( $this->at( $key + 1 ) )
+ ->method( 'select' )
+ ->will( $this->returnValue( new ResultIterator(
$result ) ) );
+ }
+
+ return new MySqlTableDefinitionReader( $mockQueryInterface );
+ }
+
+ /**
+ * @dataProvider sqlAndDefinitionProvider
+ */
+ public function testReadDefinition( $results, TableDefinition
$expectedDefinition ) {
+ $reader = $this->newInstance( $results );
+ $definition = $reader->readDefinition( 'dbNametableName' );
+ $this->assertEquals( $definition, $expectedDefinition );
+ }
+
+ public function sqlAndDefinitionProvider() {
+ $argLists = array();
+
+ $argLists[] = array(
+ array(
+ array(
+ array( 'name' => 'primaryField', 'type'
=> 'INT', 'cannull' => 'NO', 'default' => null ),
+ array( 'name' => 'textField', 'type' =>
'BLOB', 'cannull' => 'YES', 'default' => null ),
+ array( 'name' => 'intField', 'type' =>
'INT', 'cannull' => 'NO', 'default' => 42 ),
+ ),
+ //TODO test UNIQUE and PRIMARY keys
+ array( array( ) ),
+ array( array( 'name' => 'indexName', 'columns'
=> 'intField,textField' ) )
+ ),
+ new TableDefinition(
+ 'dbNametableName',
+ array(
+ new FieldDefinition(
+ 'primaryField',
+ FieldDefinition::TYPE_INTEGER,
+ FieldDefinition::NOT_NULL,
+ FieldDefinition::NO_DEFAULT
+ ),
+ new FieldDefinition(
+ 'textField',
+ FieldDefinition::TYPE_TEXT
+ ),
+ new FieldDefinition(
+ 'intField',
+ FieldDefinition::TYPE_INTEGER,
+ FieldDefinition::NOT_NULL, 42
+ ),
+ ),
+ array(
+ new IndexDefinition(
+ 'indexName',
+ array( 'intField' => 0,
'textField' => 0 ),
+ IndexDefinition::TYPE_INDEX
+ ),
+ )
+ )
+ );
+
+ return $argLists;
+ }
+
+}
\ No newline at end of file
--
To view, visit https://gerrit.wikimedia.org/r/84317
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I94cee1121e631175ac784a8f8af8b228a4d98b1f
Gerrit-PatchSet: 5
Gerrit-Project: mediawiki/extensions/WikibaseDatabase
Gerrit-Branch: master
Gerrit-Owner: Addshore <[email protected]>
Gerrit-Reviewer: Jeroen De Dauw <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits