Navigation Menu

Skip to content

Commit

Permalink
Add basic columnSql generation for Sqlite.
Browse files Browse the repository at this point in the history
  • Loading branch information
markstory committed May 12, 2013
1 parent d8f1d23 commit edc5b5c
Show file tree
Hide file tree
Showing 2 changed files with 255 additions and 0 deletions.
104 changes: 104 additions & 0 deletions lib/Cake/Database/Schema/SqliteSchema.php
Expand Up @@ -139,4 +139,108 @@ public function convertFieldDescription(Table $table, $row, $fieldParams = []) {
}
}

/**
* Generate the SQL fragment for a single column in Sqlite
*
* @param Cake\Database\Schema\Table $table The table object the column is in.
* @param string $name The name of the column.
* @return string SQL fragment.
*/
public function columnSql(Table $table, $name) {
$data = $table->column($name);
$typeMap = [
'string' => ' VARCHAR',
'integer' => ' INTEGER',
'biginteger' => ' BIGINT',
'boolean' => ' BOOLEAN',
'binary' => ' BLOB',
'float' => ' FLOAT',
'decimal' => ' DECIMAL',
'text' => ' TEXT',
'date' => ' DATE',
'time' => ' TIME',
'datetime' => ' DATETIME',
'timestamp' => ' TIMESTAMP',
];
if (!isset($typeMap[$data['type']])) {
throw new Error\Exception(__d('cake_dev', 'Unknown column type "%s"', $data['type']));
}

$out = $this->_driver->quoteIdentifier($name);
$out .= $typeMap[$data['type']];

$hasLength = ['integer', 'string'];
if (in_array($data['type'], $hasLength, true) && isset($data['length'])) {
$out .= '(' . (int)$data['length'] . ')';
}
$hasPrecision = ['float', 'decimal'];
if (
in_array($data['type'], $hasPrecision, true) &&
(isset($data['length']) || isset($data['precision']))
) {
$out .= '(' . (int)$data['length'] . ',' . (int)$data['precision'] . ')';
}
if (isset($data['null']) && $data['null'] === false) {
$out .= ' NOT NULL';
}
if (isset($data['null']) && $data['null'] === true) {
$out .= ' DEFAULT NULL';
unset($data['default']);
}
if (isset($data['default'])) {
$out .= ' DEFAULT ' . $this->_value($data['default']);
}
return $out;
}

/**
* Escapes values for use in schema definitions.
*
* @param mixed $value The value to escape.
* @return string String for use in schema definitions.
*/
protected function _value($value) {
if (is_null($value)) {
return 'NULL';
}
if ($value === false) {
return 'FALSE';
}
if ($value === true) {
return 'TRUE';
}
if (is_float($value)) {
return str_replace(',', '.', strval($value));
}
if ((is_int($value) || $value === '0') || (
is_numeric($value) && strpos($value, ',') === false &&
$value[0] != '0' && strpos($value, 'e') === false)
) {
return $value;
}
return $this->_driver->quote($value, \PDO::PARAM_STR);
}

/**
* Generate the SQL fragment for a single index in MySQL
*
* @param Cake\Database\Schema\Table $table The table object the column is in.
* @param string $name The name of the column.
* @return string SQL fragment.
*/
public function indexSql(Table $table, $name) {
$data = $table->index($name);
}

/**
* Generate the SQL to create a table.
*
* @param string $table The name of the table.
* @param array $lines The lines (columns + indexes) to go inside the table.
* @return string A complete CREATE TABLE statement
*/
public function createTableSql($table, $lines) {
$content = implode(",\n", $lines);
return sprintf("CREATE TABLE \"%s\" (\n%s\n);", $table, $content);
}
}
151 changes: 151 additions & 0 deletions lib/Cake/Test/TestCase/Database/Schema/SqliteSchemaTest.php
Expand Up @@ -20,6 +20,7 @@
use Cake\Database\Connection;
use Cake\Database\Schema\Collection as SchemaCollection;
use Cake\Database\Schema\SqliteSchema;
use Cake\Database\Schema\Table;
use Cake\TestSuite\TestCase;


Expand Down Expand Up @@ -247,4 +248,154 @@ public function testDescribeTable() {
}
}

/**
* Column provider for creating column sql
*
* @return array
*/
public static function columnSqlProvider() {
return [
// strings
[
'title',
['type' => 'string', 'length' => 25, 'null' => false],
'"title" VARCHAR(25) NOT NULL'
],
[
'title',
['type' => 'string', 'length' => 25, 'null' => true, 'default' => 'ignored'],
'"title" VARCHAR(25) DEFAULT NULL'
],
[
'id',
['type' => 'string', 'length' => 32, 'fixed' => true, 'null' => false],
'"id" VARCHAR(32) NOT NULL'
],
[
'role',
['type' => 'string', 'length' => 10, 'null' => false, 'default' => 'admin'],
'"role" VARCHAR(10) NOT NULL DEFAULT "admin"'
],
[
'title',
['type' => 'string'],
'"title" VARCHAR'
],
// Text
[
'body',
['type' => 'text', 'null' => false],
'"body" TEXT NOT NULL'
],
// Integers
[
'post_id',
['type' => 'integer', 'length' => 11],
'"post_id" INTEGER(11)'
],
[
'post_id',
['type' => 'biginteger', 'length' => 20],
'"post_id" BIGINT'
],
// Decimal
[
'value',
['type' => 'decimal'],
'"value" DECIMAL'
],
[
'value',
['type' => 'decimal', 'length' => 11],
'"value" DECIMAL(11,0)'
],
[
'value',
['type' => 'decimal', 'length' => 12, 'precision' => 5],
'"value" DECIMAL(12,5)'
],
// Float
[
'value',
['type' => 'float'],
'"value" FLOAT'
],
[
'value',
['type' => 'float', 'length' => 11, 'precision' => 3],
'"value" FLOAT(11,3)'
],
// Boolean
[
'checked',
['type' => 'boolean', 'default' => false],
'"checked" BOOLEAN DEFAULT FALSE'
],
[
'checked',
['type' => 'boolean', 'default' => true, 'null' => false],
'"checked" BOOLEAN NOT NULL DEFAULT TRUE'
],
// datetimes
[
'created',
['type' => 'datetime'],
'"created" DATETIME'
],
// Date & Time
[
'start_date',
['type' => 'date'],
'"start_date" DATE'
],
[
'start_time',
['type' => 'time'],
'"start_time" TIME'
],
// timestamps
[
'created',
['type' => 'timestamp', 'null' => true],
'"created" TIMESTAMP DEFAULT NULL'
],
];
}

/**
* Test generating column definitions
*
* @dataProvider columnSqlProvider
* @return void
*/
public function testColumnSql($name, $data, $expected) {
$driver = $this->_getMockedDriver();
$schema = new SqliteSchema($driver);

$table = (new Table('articles'))->addColumn($name, $data);
$this->assertEquals($expected, $schema->columnSql($table, $name));
}

/**
* Get a schema instance with a mocked driver/pdo instances
*
* @return MysqlSchema
*/
protected function _getMockedDriver() {
$driver = new \Cake\Database\Driver\Sqlite();
$mock = $this->getMock('FakePdo', ['quote', 'quoteIdentifier']);
$mock->expects($this->any())
->method('quote')
->will($this->returnCallback(function ($value) {
return '"' . $value . '"';
}));
$mock->expects($this->any())
->method('quoteIdentifier')
->will($this->returnCallback(function ($value) {
return '"' . $value . '"';
}));
$driver->connection($mock);
return $driver;
}

}

0 comments on commit edc5b5c

Please sign in to comment.