Refactoring schema handling for SQLite and Postgres drivers. Non-primary key indexes are now created properly. Fixed testing bugs in db drivers.

git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@6922 3807eeeb-6ff5-0310-8944-8be069107fe0
This commit is contained in:
nate 2008-05-18 06:42:36 +00:00
parent e1fc6ad5fd
commit 6bed503b56
5 changed files with 166 additions and 35 deletions

View file

@ -597,28 +597,62 @@ class DboPostgres extends DboSource {
* Format indexes for create table
*
* @param array $indexes
* @param string $table
* @return string
*/
function buildIndex($indexes) {
function buildIndex($indexes, $table = null) {
$join = array();
foreach ($indexes as $name => $value) {
$out = '';
if ($name == 'PRIMARY') {
$out .= 'PRIMARY ';
$name = null;
$out = 'PRIMARY KEY (' . $this->name($value['column']) . ')';
} else {
$out = 'CREATE ';
if (!empty($value['unique'])) {
$name .= ' UNIQUE ';
}
$out .= 'UNIQUE ';
}
if (is_array($value['column'])) {
$out .= 'CONSTRAINT '. $name .' (' . join(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
$value['column'] = join(', ', array_map(array(&$this, 'name'), $value['column']));
} else {
$out .= 'KEY '. $name .' (' . $this->name($value['column']) . ')';
$value['column'] = $this->name($value['column']);
}
$out .= "INDEX {$name} ON {$table}({$value['column']});";
}
$join[] = $out;
}
return join(",\n\t", $join);
return $join;
}
/**
* Overrides DboSource::renderStatement to handle schema generation with Postgres-style indexes
*
* @param string $type
* @param array $data
* @return string
*/
function renderStatement($type, $data) {
switch (strtolower($type)) {
case 'schema':
extract($data);
foreach ($indexes as $i => $index) {
if (preg_match('/PRIMARY KEY/', $index)) {
unset($indexes[$i]);
$columns[] = $index;
break;
}
}
foreach (array('columns', 'indexes') as $var) {
if (is_array(${$var})) {
${$var} = "\t" . join(",\n\t", array_filter(${$var}));
}
}
return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}";
break;
default:
return parent::renderStatement($type, $data);
break;
}
}
}

View file

@ -93,6 +93,10 @@ class DboSqlite extends DboSource {
$config = $this->config;
$this->connection = $config['connect']($config['database']);
$this->connected = is_resource($this->connection);
if ($this->connected) {
$this->_execute('PRAGMA count_changes = 1');
}
return $this->connected;
}
/**
@ -485,6 +489,79 @@ class DboSqlite extends DboSource {
}
return $out;
}
/**
* Sets the database encoding
*
* @param string $enc Database encoding
*/
function setEncoding($enc) {
if (!in_array($enc, array("UTF-8", "UTF-16", "UTF-16le", "UTF-16be"))) {
return false;
}
return $this->_execute("PRAGMA encoding = \"{$enc}\"") !== false;
}
/**
* Gets the database encoding
*
* @return string The database encoding
*/
function getEncoding() {
return $this->fetchRow('PRAGMA encoding');
}
/**
* Removes redundant primary key indexes, as they are handled in the column def of the key.
*
* @param array $indexes
* @param string $table
* @return string
*/
function buildIndex($indexes, $table = null) {
$join = array();
foreach ($indexes as $name => $value) {
if ($name == 'PRIMARY') {
continue;
}
$out = 'CREATE ';
if (!empty($value['unique'])) {
$out .= 'UNIQUE ';
}
if (is_array($value['column'])) {
$value['column'] = join(', ', array_map(array(&$this, 'name'), $value['column']));
} else {
$value['column'] = $this->name($value['column']);
}
$out .= "INDEX {$name} ON {$table}({$value['column']});";
$join[] = $out;
}
return $join;
}
/**
* Overrides DboSource::renderStatement to handle schema generation with SQLite-style indexes
*
* @param string $type
* @param array $data
* @return string
*/
function renderStatement($type, $data) {
switch (strtolower($type)) {
case 'schema':
extract($data);
foreach (array('columns', 'indexes') as $var) {
if (is_array(${$var})) {
${$var} = "\t" . join(",\n\t", array_filter(${$var}));
}
}
return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}";
break;
default:
return parent::renderStatement($type, $data);
break;
}
}
}
?>

View file

@ -1232,6 +1232,19 @@ class DboSource extends DataSource {
}
return "DELETE {$alias} FROM {$table} {$aliases}{$conditions}";
break;
case 'schema':
foreach (array('columns', 'indexes') as $var) {
if (is_array(${$var})) {
${$var} = "\t" . join(",\n\t", array_filter(${$var}));
}
}
if (trim($indexes) != '') {
$columns .= ',';
}
return "CREATE TABLE {$table} (\n{$columns}{$indexes});";
break;
case 'alter':
break;
}
}
/**
@ -2007,11 +2020,11 @@ class DboSource extends DataSource {
* Generate a database-native schema for the given Schema object
*
* @param object $schema An instance of a subclass of CakeSchema
* @param string $table Optional. If specified only the table name given will be generated.
* @param string $tableName Optional. If specified only the table name given will be generated.
* Otherwise, all tables defined in the schema are generated.
* @return string
*/
function createSchema($schema, $table = null) {
function createSchema($schema, $tableName = null) {
if (!is_a($schema, 'CakeSchema')) {
trigger_error(__('Invalid schema object', true), E_USER_WARNING);
return null;
@ -2019,10 +2032,11 @@ class DboSource extends DataSource {
$out = '';
foreach ($schema->tables as $curTable => $columns) {
if (!$table || $table == $curTable) {
$out .= 'CREATE TABLE ' . $this->fullTableName($curTable) . " (\n";
$cols = $colList = $index = array();
if (!$tableName || $tableName == $curTable) {
$cols = $colList = $indexes = array();
$primary = null;
$table = $this->fullTableName($curTable);
foreach ($columns as $name => $col) {
if (is_string($col)) {
$col = array('type' => $col);
@ -2037,14 +2051,15 @@ class DboSource extends DataSource {
}
$cols[] = $this->buildColumn($col);
} else {
$index[] = $this->buildIndex($col);
$indexes = array_merge($indexes, $this->buildIndex($col, $table));
}
}
if (empty($index) && !empty($primary)) {
if (empty($indexes) && !empty($primary)) {
$col = array('PRIMARY' => array('column' => $primary, 'unique' => 1));
$index[] = $this->buildIndex($col);
$indexes = array_merge($indexes, $this->buildIndex($col, $table));
}
$out .= "\t" . join(",\n\t", array_filter(array_merge($cols, $index))) . "\n);\n\n";
$columns = $cols;
$out .= $this->renderStatement('schema', compact('table', 'columns', 'indexes')) . "\n\n";
}
}
return $out;
@ -2135,9 +2150,10 @@ class DboSource extends DataSource {
* Format indexes for create table
*
* @param array $indexes
* @return string
* @param string $table
* @return array
*/
function buildIndex($indexes) {
function buildIndex($indexes, $table = null) {
$join = array();
foreach ($indexes as $name => $value) {
$out = '';
@ -2156,7 +2172,8 @@ class DboSource extends DataSource {
}
$join[] = $out;
}
return join(",\n\t", $join);
return $join;
}
}
?>

View file

@ -194,7 +194,9 @@ class DboMysqlTest extends CakeTestCase {
$this->db->cacheSources = $this->db->testing = false;
$this->db->query('CREATE TABLE ' . $this->db->fullTableName('tinyint') . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id));');
$this->model = new Model(array('name' => 'Tinyint', 'table' => $this->db->fullTableName('tinyint', false)));
$this->model = new CakeTestModel(array(
'name' => 'Tinyint', 'table' => $this->db->fullTableName('tinyint', false)
));
$result = $this->model->schema();
$this->assertEqual($result['bool']['type'], 'boolean');
$this->assertEqual($result['small_int']['type'], 'integer');

View file

@ -2484,12 +2484,13 @@ class ModelTest extends CakeTestCase {
$this->assertIdentical($model->Comment->find('count'), 0);
$result = $model->saveAll(array(
'Article' => array('title' => 'Post with Author', 'body' => 'This post will be saved without an author'),
'Comment' => array(
array('comment' => 'Only new comment'),
)
), array('validate' => 'first'));
$result = $model->saveAll(
array(
'Article' => array('title' => 'Post with Author', 'body' => 'This post will be saved with an author', 'user_id' => 2),
'Comment' => array(array('comment' => 'Only new comment', 'user_id' => 2))
),
array('validate' => 'first')
);
$this->assertIdentical($result, true);
$result = $model->Comment->find('all');