diff --git a/src/CockroachDbConnection.php b/src/CockroachDbConnection.php index 456dc83..f50e56b 100644 --- a/src/CockroachDbConnection.php +++ b/src/CockroachDbConnection.php @@ -4,10 +4,10 @@ use Illuminate\Database\ConnectionInterface; use Illuminate\Database\Grammar as BaseGrammar; -use Illuminate\Database\PDO\PostgresDriver; use Illuminate\Database\PostgresConnection; use Illuminate\Filesystem\Filesystem; use YlsIdeas\CockroachDb\Builder\CockroachDbBuilder as DbBuilder; +use YlsIdeas\CockroachDb\Driver\CockroachDbDriver; use YlsIdeas\CockroachDb\Processor\CockroachDbProcessor as DbProcessor; use YlsIdeas\CockroachDb\Query\CockroachGrammar as QueryGrammar; use YlsIdeas\CockroachDb\Schema\CockroachGrammar as SchemaGrammar; @@ -76,7 +76,7 @@ protected function getDefaultPostProcessor(): DbProcessor */ protected function getDoctrineDriver() { - return new PostgresDriver(); + return new CockroachDbDriver(); } /** diff --git a/src/Driver/CockroachDbDriver.php b/src/Driver/CockroachDbDriver.php new file mode 100644 index 0000000..019d959 --- /dev/null +++ b/src/Driver/CockroachDbDriver.php @@ -0,0 +1,17 @@ +wrapTable($blueprint)}@{$index} cascade"; } + + public function compileColumns($database, $schema, $table): string + { + return sprintf( + 'select a.attname as name, t.typname as type_name, format_type(a.atttypid, a.atttypmod) as type, ' + .'(select tc.collcollate from pg_catalog.pg_collation tc where tc.oid = a.attcollation) as collation, ' + .'not a.attnotnull as nullable, ' + .'(select pg_get_expr(adbin, adrelid) from pg_attrdef where c.oid = pg_attrdef.adrelid and pg_attrdef.adnum = a.attnum) as default, ' + .'col_description(c.oid, a.attnum) as comment ' + .'from pg_attribute a, pg_class c, pg_type t, pg_namespace n ' + .'where c.relname = %s and n.nspname = %s and a.attnum > 0 and a.attrelid = c.oid and a.atttypid = t.oid and n.oid = c.relnamespace and a.attisdropped = false ' + .'order by a.attnum', + $this->quoteString($table), + $this->quoteString($schema) + ); + } } diff --git a/src/Schema/CockroachSchemaManager.php b/src/Schema/CockroachSchemaManager.php new file mode 100644 index 0000000..3125747 --- /dev/null +++ b/src/Schema/CockroachSchemaManager.php @@ -0,0 +1,93 @@ + 0', + "c.relkind = 'r'", + 'd.refobjid IS NULL', + 'a.attisdropped = false', + ], $this->buildQueryConditions($tableName)); + + $sql .= ' WHERE ' . implode(' AND ', $conditions) . ' ORDER BY a.attnum'; + + return $this->_conn->executeQuery($sql); + } + + /** + * @param string|null $tableName + * + * @return list + */ + private function buildQueryConditions($tableName): array + { + $conditions = []; + + if ($tableName !== null) { + if (strpos($tableName, '.') !== false) { + [$schemaName, $tableName] = explode('.', $tableName); + $conditions[] = 'n.nspname = ' . $this->_platform->quoteStringLiteral($schemaName); + } else { + $conditions[] = 'n.nspname = ANY(current_schemas(false))'; + } + + $identifier = new Identifier($tableName); + $conditions[] = 'c.relname = ' . $this->_platform->quoteStringLiteral($identifier->getName()); + } + + $conditions[] = "n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')"; + + return $conditions; + } +} diff --git a/tests/Integration/Database/MigrationRenamingTest.php b/tests/Integration/Database/MigrationRenamingTest.php new file mode 100644 index 0000000..4fd8644 --- /dev/null +++ b/tests/Integration/Database/MigrationRenamingTest.php @@ -0,0 +1,67 @@ +id(); + $table->string('column_y'); + $table->string('column_x'); + }); + } + + public function test_rename_column_to_previously_deleted_one(): void + { + Schema::table(self::TEST_TABLE, function (Blueprint $table) { + $table->dropColumn('column_y'); + }); + + Schema::table(self::TEST_TABLE, function (Blueprint $table) { + $table->renameColumn('column_x', 'column_y'); + }); + + $tableColumns = Schema::getColumnListing(self::TEST_TABLE); + $this->assertCount(2, $tableColumns); + $this->assertEquals('id', $tableColumns[0]); + $this->assertEquals('column_y', $tableColumns[1]); + } + + public function test_rename_column_with_any_previously_deleted_one(): void + { + Schema::table(self::TEST_TABLE, function (Blueprint $table) { + $table->dropColumn('column_y'); + }); + + Schema::table(self::TEST_TABLE, function (Blueprint $table) { + $table->renameColumn('column_x', 'column_z'); + }); + + $tableColumns = Schema::getColumnListing(self::TEST_TABLE); + $this->assertCount(2, $tableColumns); + $this->assertEquals('id', $tableColumns[0]); + $this->assertEquals('column_z', $tableColumns[1]); + } + + public function test_rename_column_without_deleted_ones(): void + { + Schema::table(self::TEST_TABLE, function (Blueprint $table) { + $table->renameColumn('column_x', 'column_z'); + }); + + $tableColumns = Schema::getColumnListing(self::TEST_TABLE); + $this->assertCount(3, $tableColumns); + $this->assertEquals('id', $tableColumns[0]); + $this->assertEquals('column_y', $tableColumns[1]); + $this->assertEquals('column_z', $tableColumns[2]); + } +} diff --git a/tests/Integration/Database/SchemaGetColumnsTest.php b/tests/Integration/Database/SchemaGetColumnsTest.php new file mode 100644 index 0000000..9b724b6 --- /dev/null +++ b/tests/Integration/Database/SchemaGetColumnsTest.php @@ -0,0 +1,54 @@ +markTestSkipped("The Schema::getColumns() function is only available in a later Laravel version."); + } + } + + protected function setUp(): void + { + parent::setUp(); + + Schema::create(self::TEST_TABLE, function (Blueprint $table) { + $table->id(); + $table->string('column_y'); + $table->string('column_x'); + }); + } + + public function test_schema_get_columns_with_dropped_columns(): void + { + Schema::table(self::TEST_TABLE, function (Blueprint $table) { + $table->dropColumn('column_y'); + }); + + $tableColumns = Schema::getColumns(self::TEST_TABLE); + $this->assertCount(2, $tableColumns); + $this->assertSame('id', $tableColumns[0]['name']); + $this->assertSame('column_x', $tableColumns[1]['name']); + } + + public function test_schema_get_columns_without_dropped_columns(): void + { + $tableColumns = Schema::getColumns(self::TEST_TABLE); + $this->assertCount(3, $tableColumns); + $this->assertSame('id', $tableColumns[0]['name']); + $this->assertSame('column_y', $tableColumns[1]['name']); + $this->assertSame('column_x', $tableColumns[2]['name']); + } +}