Navigation Menu

Skip to content

Commit

Permalink
Implement index/constraint reflection for postgres.
Browse files Browse the repository at this point in the history
Implement index reflection for postgres.
  • Loading branch information
markstory committed Jun 2, 2013
1 parent 24b88c0 commit be529eb
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 12 deletions.
57 changes: 48 additions & 9 deletions lib/Cake/Database/Schema/PostgresSchema.php
Expand Up @@ -168,13 +168,9 @@ public function convertFieldDescription(Table $table, $row, $fieldParams = []) {
$field += [
'null' => $row['null'] === 'YES' ? true : false,
'default' => $row['default'],
'comment' => $row['comment']
];
$field['length'] = $row['char_length'] ?: $field['length'];
foreach ($fieldParams as $key => $metadata) {
if (!empty($row[$metadata['column']])) {
$field[$key] = $row[$metadata['column']];
}
}
$table->addColumn($row['name'], $field);
if (!empty($row['pk'])) {
$table->addConstraint('primary', [
Expand All @@ -188,11 +184,34 @@ public function convertFieldDescription(Table $table, $row, $fieldParams = []) {
* Get the SQL to describe the indexes in a table.
*
* @param string $table The table name to get information on.
* @param array $config The configuration containing the schema name.
* @return array An array of (sql, params) to execute.
*/
public function describeIndexSql($table) {
$sql = '';
return [$sql, []];
public function describeIndexSql($table, $config) {
$sql = "SELECT
c2.relname,
i.indisprimary,
i.indisunique,
i.indisvalid,
pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) AS statement
FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i
WHERE c.oid = (
SELECT c.oid
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = ?
AND pg_catalog.pg_table_is_visible(c.oid)
AND n.nspname = ?
)
AND c.oid = i.indrelid
AND i.indexrelid = c2.oid
ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname";

$schema = 'public';
if (!empty($config['schema'])) {
$schema = $config['schema'];
}
return [$sql, [$table, $schema]];
}

/**
Expand All @@ -204,6 +223,27 @@ public function describeIndexSql($table) {
* @return void
*/
public function convertIndexDescription(Table $table, $row) {
$type = Table::INDEX_INDEX;
$name = $row['relname'];
if ($row['indisprimary']) {
$name = $type = Table::CONSTRAINT_PRIMARY;
}
if ($row['indisunique'] && $type === Table::INDEX_INDEX) {
$type = Table::CONSTRAINT_UNIQUE;
}
preg_match('/\(([^\)]+)\)/', $row['statement'], $matches);
$columns = explode(', ', $matches[1]);
if ($type === Table::CONSTRAINT_PRIMARY || $type === Table::CONSTRAINT_UNIQUE) {
$table->addConstraint($name, [
'type' => $type,
'columns' => $columns
]);
} else {
$table->addIndex($name, [
'type' => $type,
'columns' => $columns
]);
}
}


Expand Down Expand Up @@ -373,7 +413,6 @@ public function dropTableSql(Table $table) {
*/
public function truncateTableSql(Table $table) {
$name = $this->_driver->quoteIdentifier($table->name());

return [
sprintf("TRUNCATE %s RESTART IDENTITY", $name)
];
Expand Down
45 changes: 42 additions & 3 deletions lib/Cake/Test/TestCase/Database/Schema/PostgresSchemaTest.php
Expand Up @@ -67,11 +67,13 @@ protected function _createTables($connection) {
author_id INTEGER NOT NULL,
published BOOLEAN DEFAULT false,
views SMALLINT DEFAULT 0,
created TIMESTAMP
created TIMESTAMP,
CONSTRAINT "content_idx" UNIQUE ("title", "body")
)
SQL;
$connection->execute($table);
$connection->execute('COMMENT ON COLUMN "articles"."title" IS \'a title\'');
$connection->execute('CREATE INDEX "author_idx" ON "articles" ("author_id")');
}

/**
Expand Down Expand Up @@ -282,7 +284,7 @@ public function testDescribeTable() {
'length' => null,
'precision' => null,
'fixed' => null,
'collate' => null,
'comment' => null,
],
];
$this->assertEquals(['id'], $result->primaryKey());
Expand All @@ -291,6 +293,43 @@ public function testDescribeTable() {
}
}

/**
* Test describing a table with indexes
*
* @return void
*/
public function testDescribeTableIndexes() {
$connection = new Connection(Configure::read('Datasource.test'));
$this->_createTables($connection);

$schema = new SchemaCollection($connection);
$result = $schema->describe('articles');
$this->assertInstanceOf('Cake\Database\Schema\Table', $result);
$expected = [
'primary' => [
'type' => 'primary',
'columns' => ['id'],
'length' => []
],
'content_idx' => [
'type' => 'unique',
'columns' => ['title', 'body'],
'length' => []
]
];
$this->assertCount(2, $result->constraints());
$this->assertEquals($expected['primary'], $result->constraint('primary'));
$this->assertEquals($expected['content_idx'], $result->constraint('content_idx'));

$this->assertCount(1, $result->indexes());
$expected = [
'type' => 'index',
'columns' => ['author_id'],
'length' => []
];
$this->assertEquals($expected, $result->index('author_idx'));
}

/**
* Column provider for creating column sql
*
Expand Down Expand Up @@ -473,7 +512,7 @@ public static function constraintSqlProvider() {
}

/**
* Test the indexSql method.
* Test the constraintSql method.
*
* @dataProvider constraintSqlProvider
*/
Expand Down

0 comments on commit be529eb

Please sign in to comment.