Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.7] Add support for identity columns in PostgreSQL 10+ #26096

Merged
merged 1 commit into from
Oct 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Illuminate/Database/Schema/ColumnDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
* @method ColumnDefinition unsigned() Set the INTEGER column as UNSIGNED (MySQL)
* @method ColumnDefinition useCurrent() Set the TIMESTAMP column to use CURRENT_TIMESTAMP as default value
* @method ColumnDefinition virtualAs(string $expression) Create a virtual generated column (MySQL)
* @method ColumnDefinition generatedAs($expression) Create a SQL compliant identity column (PostgreSQL)
* @method ColumnDefinition always() Used as a modifier for generatedAs() (PostgreSQL)
*/
class ColumnDefinition extends Fluent
{
Expand Down
44 changes: 38 additions & 6 deletions src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,38 @@ protected function typeLongText(Fluent $column)
return 'text';
}

private function generatableColumn($type, Fluent $column)
{
if (! $column->autoIncrement && $column->generatedAs === null) {
return $type;
}

if ($column->autoIncrement && $column->generatedAs === null) {
$serial = [
'integer' => 'serial',
'bigint' => 'bigserial',
'smallint' => 'smallserial',
];

return $serial[$type];
}

// Identity column but not a primary key
$always = $column->always ? 'always' : 'by default';
$options = '';

if (! is_bool($column->generatedAs) && ((string) $column->generatedAs !== '')) {
$options = sprintf(' (%s)', $column->generatedAs);
}

return sprintf(
'%s generated %s as identity%s',
$type,
$always,
$options
);
}

/**
* Create the column definition for an integer type.
*
Expand All @@ -445,7 +477,7 @@ protected function typeLongText(Fluent $column)
*/
protected function typeInteger(Fluent $column)
{
return $column->autoIncrement ? 'serial' : 'integer';
return $this->generatableColumn('integer', $column);
}

/**
Expand All @@ -456,7 +488,7 @@ protected function typeInteger(Fluent $column)
*/
protected function typeBigInteger(Fluent $column)
{
return $column->autoIncrement ? 'bigserial' : 'bigint';
return $this->generatableColumn('bigint', $column);
}

/**
Expand All @@ -467,7 +499,7 @@ protected function typeBigInteger(Fluent $column)
*/
protected function typeMediumInteger(Fluent $column)
{
return $column->autoIncrement ? 'serial' : 'integer';
return $this->generatableColumn('integer', $column);
}

/**
Expand All @@ -478,7 +510,7 @@ protected function typeMediumInteger(Fluent $column)
*/
protected function typeTinyInteger(Fluent $column)
{
return $column->autoIncrement ? 'smallserial' : 'smallint';
return $this->generatableColumn('smallint', $column);
}

/**
Expand All @@ -489,7 +521,7 @@ protected function typeTinyInteger(Fluent $column)
*/
protected function typeSmallInteger(Fluent $column)
{
return $column->autoIncrement ? 'smallserial' : 'smallint';
return $this->generatableColumn('smallint', $column);
}

/**
Expand Down Expand Up @@ -854,7 +886,7 @@ protected function modifyDefault(Blueprint $blueprint, Fluent $column)
*/
protected function modifyIncrement(Blueprint $blueprint, Fluent $column)
{
if (in_array($column->type, $this->serials) && $column->autoIncrement) {
if ((in_array($column->type, $this->serials) || ($column->generatedAs !== null)) && $column->autoIncrement) {
return ' primary key';
}
}
Expand Down
27 changes: 27 additions & 0 deletions tests/Database/DatabasePostgresSchemaGrammarTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,33 @@ public function testAddingUuid()
$this->assertEquals('alter table "users" add column "foo" uuid not null', $statements[0]);
}

public function testAddingGeneratedAs()
{
$blueprint = new Blueprint('users');
$blueprint->increments('foo')->generatedAs();
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertCount(1, $statements);
$this->assertEquals('alter table "users" add column "foo" integer generated by default as identity primary key not null', $statements[0]);
// With always modifier
$blueprint = new Blueprint('users');
$blueprint->increments('foo')->generatedAs()->always();
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertCount(1, $statements);
$this->assertEquals('alter table "users" add column "foo" integer generated always as identity primary key not null', $statements[0]);
// With sequence options
$blueprint = new Blueprint('users');
$blueprint->increments('foo')->generatedAs('increment by 10 start with 100');
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertCount(1, $statements);
$this->assertEquals('alter table "users" add column "foo" integer generated by default as identity (increment by 10 start with 100) primary key not null', $statements[0]);
// Not a primary key
$blueprint = new Blueprint('users');
$blueprint->integer('foo')->generatedAs();
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertCount(1, $statements);
$this->assertEquals('alter table "users" add column "foo" integer generated by default as identity not null', $statements[0]);
}

public function testAddingIpAddress()
{
$blueprint = new Blueprint('users');
Expand Down