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

dropAllTables #161

Merged
merged 47 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
eee602b
add json and medium/long text column type
matthewjumpsoffbuildings Dec 12, 2023
2c57408
Update src/Schema/Grammar.php
matthewjumpsoffbuildings Dec 12, 2023
b7e5282
Update src/Schema/Grammar.php
matthewjumpsoffbuildings Dec 12, 2023
f57a184
Update src/Schema/Grammar.php
matthewjumpsoffbuildings Dec 12, 2023
468cb19
add unit tests
matthewjumpsoffbuildings Dec 12, 2023
e56b6b5
Update tests/Schema/BlueprintTest.php
taka-oyama Dec 12, 2023
ea81865
Merge branch 'master' into json-column
matthewjumpsoffbuildings Dec 12, 2023
2797836
add typeChar
matthewjumpsoffbuildings Dec 12, 2023
5e0c321
add/alter columns should be separate statements
matthewjumpsoffbuildings Dec 12, 2023
3621299
type hint compileAdd properly
matthewjumpsoffbuildings Dec 12, 2023
3742664
dropAllTables - just delete and recreate the database
matthewjumpsoffbuildings Dec 12, 2023
8eccb28
phpdoc
matthewjumpsoffbuildings Dec 12, 2023
513a5b1
only drop if db exists
matthewjumpsoffbuildings Dec 13, 2023
0cbb9f5
add dropForeign compilation
matthewjumpsoffbuildings Dec 13, 2023
c3a5ae2
fix dropColumn as well
matthewjumpsoffbuildings Dec 13, 2023
8d9328a
fix type hint
matthewjumpsoffbuildings Dec 13, 2023
d83137e
changelog
matthewjumpsoffbuildings Dec 14, 2023
d42b1af
Update CHANGELOG.md
taka-oyama Dec 14, 2023
35f2d26
changelog
matthewjumpsoffbuildings Dec 14, 2023
b79f8a0
Update CHANGELOG.md
taka-oyama Dec 14, 2023
c042d03
added test and changelog
matthewjumpsoffbuildings Dec 14, 2023
b98dbea
Merge remote-tracking branch 'upstream/master' into drop-foreign
matthewjumpsoffbuildings Dec 14, 2023
54736f4
Merge remote-tracking branch 'upstream/master' into drop-all
matthewjumpsoffbuildings Dec 14, 2023
ea9dc3d
instead of dropping db, move towards proper drop sequence
matthewjumpsoffbuildings Dec 14, 2023
717f35b
Merge branch 'drop-foreign' into drop-all
matthewjumpsoffbuildings Dec 14, 2023
8a6e4eb
proper drop sequence with testss
matthewjumpsoffbuildings Dec 14, 2023
bf2bc5d
changelog
matthewjumpsoffbuildings Dec 14, 2023
6bac86d
oh man phpstan
matthewjumpsoffbuildings Dec 14, 2023
bbd6ec1
Allow for some tests to be run last
matthewjumpsoffbuildings Dec 14, 2023
4dab33f
ugh dd
matthewjumpsoffbuildings Dec 14, 2023
a153e04
Update src/Schema/Builder.php
matthewjumpsoffbuildings Dec 14, 2023
74fe12c
compileForeignListing > compileForeignKeys
matthewjumpsoffbuildings Dec 14, 2023
4ede3de
Merge remote-tracking branch 'upstream/master' into drop-all
matthewjumpsoffbuildings Dec 14, 2023
13c7b95
tidy up dropAllTables
matthewjumpsoffbuildings Dec 14, 2023
8f79961
getForeignKeyListing > getForeignKeys
matthewjumpsoffbuildings Dec 14, 2023
558f847
remove unneeded override of getForeignKeys
matthewjumpsoffbuildings Dec 14, 2023
c6ba2b4
composer laravel dependency
matthewjumpsoffbuildings Dec 14, 2023
f0f2744
getTables inheritDoc
matthewjumpsoffbuildings Dec 14, 2023
3da8fe2
fix getForeignKey and getIndexListing > getIndexes
matthewjumpsoffbuildings Dec 14, 2023
01ecae0
changelog
matthewjumpsoffbuildings Dec 14, 2023
ae93adf
Merge branch 'json-column' into drop-all
matthewjumpsoffbuildings Dec 14, 2023
c3fe095
Merge branch 'json-column' into alter-table
matthewjumpsoffbuildings Dec 14, 2023
c37862b
Merge branch 'json-column' into drop-foreign
matthewjumpsoffbuildings Dec 14, 2023
f1387f4
Merge branch 'drop-foreign' into drop-all
matthewjumpsoffbuildings Dec 14, 2023
3529d60
Merge branch 'alter-table' into drop-all
matthewjumpsoffbuildings Dec 14, 2023
c5b51ea
dup changelog
matthewjumpsoffbuildings Dec 14, 2023
7d520af
deprecate instead of delete index listing methods
matthewjumpsoffbuildings Dec 14, 2023
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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# v6.2.0 (Not Released Yet)

Added
- `json` `mediumText` `longText` `char` support for `Schema\Builder` (#155) (#158)
- `json` `mediumText` `longText` support for `Schema\Builder` (#155)
- `Schema\Grammar::compileDropForeign` to allow dropping foreign key constraints (#163)
- `Schema\Builder::dropAllTables` works properly, dropping foreign keys, indexes, then tables in order of interleaving (#161)

Changed
- `Query\Builder::lock()` no longer throw an error and will be ignored instead (#156)
Expand Down
1 change: 1 addition & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
stopOnFailure="true">
<testsuite name="all">
<directory suffix="Test.php">./tests</directory>
<directory suffix="TestLast.php">./tests</directory>
</testsuite>
<php>
<env name="SPANNER_EMULATOR_HOST" value="emulator:9010"/>
Expand Down
103 changes: 103 additions & 0 deletions src/Schema/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@

use Closure;
use Colopl\Spanner\Query\Processor;
use Colopl\Spanner\Connection;
use Illuminate\Database\Schema\Builder as BaseBuilder;
use Illuminate\Support\Facades\DB;
matthewjumpsoffbuildings marked this conversation as resolved.
Show resolved Hide resolved
use Illuminate\Support\Fluent;

/**
* @property Grammar $grammar
Expand All @@ -46,6 +49,18 @@ public function getAllTables()
);
}

/**
* @inheritDoc
*
* @return list<array{ name: string, type: string, parent: string }>
*/
public function getTables()
taka-oyama marked this conversation as resolved.
Show resolved Hide resolved
{
return $this->connection->select(
$this->grammar->compileTables()
);
}

/**
* @param string $table
* @return string[]
Expand All @@ -64,6 +79,24 @@ public function getIndexListing($table)
return $processor->processIndexListing($results);
}

/**
* @param string $table
* @return string[]
*/
public function getForeignListing($table)
matthewjumpsoffbuildings marked this conversation as resolved.
Show resolved Hide resolved
{
$table = $this->connection->getTablePrefix().$table;

$results = $this->connection->select(
$this->grammar->compileForeignListing(), [$table]
);

/** @var Processor $processor */
$processor = $this->connection->getPostProcessor();

return $processor->processIndexListing($results);
}

/**
* @param string $table
* @param string $name
Expand Down Expand Up @@ -99,4 +132,74 @@ protected function createBlueprint($table, Closure $callback = null)
? ($this->resolver)($table, $callback)
: new Blueprint($table, $callback);
}

/**
* Drop all tables from the database.
*
* @return void
*/
public function dropAllTables()
{
/** @var Connection */
$connection = $this->connection;
$tables = self::getTables();
$sortedTables = [];

// get all tables
foreach ($tables as $table) {
$tableName = $table['name'];
$parentTableName = $table['parent'];

$sortedTables[$tableName] = [
'name' => $tableName,
'parent' => $parentTableName,
'parents' => 0
];
}

// loop through all tables and count how many parents they have
foreach ($sortedTables as $tableName => $tableData) {
if(!$tableData['parent']) continue;

$current = $tableData;
while($current['parent']) {
$tableData['parents'] += 1;
$current = $sortedTables[$current['parent']];
}
$sortedTables[$tableName] = $tableData;
}

// sort tables desc based on parent count
usort($sortedTables, fn($a, $b) => $b['parents'] <=> $a['parents']);

// drop foreign keys first (otherwise index queries will include them)
$queries = [];
foreach ($sortedTables as $tableData) {
$tableName = $tableData['name'];
$blueprint = new Blueprint($tableName);
$foreigns = self::getForeignListing($tableName);
foreach ($foreigns as $foreign) {
$column = new Fluent();
$column->index = $foreign;
$queries[] = $this->grammar->compileDropForeign($blueprint, $column);
}
}
$connection->runDdlBatch($queries);

// drop indexes and tables
$queries = [];
foreach ($sortedTables as $tableData) {
$tableName = $tableData['name'];
$blueprint = new Blueprint($tableName);
$indexes = self::getIndexListing($tableName);
foreach ($indexes as $index) {
if($index == 'PRIMARY_KEY') continue;
$column = new Fluent();
$column->index = $index;
$queries [] = $this->grammar->compileDropIndex($blueprint, $column);
}
$queries[] = $this->grammar->compileDrop($blueprint, new Fluent());
}
$connection->runDdlBatch($queries);
}
}
26 changes: 25 additions & 1 deletion src/Schema/Grammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function compileTableExists()
*/
public function compileTables()
{
return 'select `table_name` as name from information_schema.tables where table_schema = \'\' and table_type = \'BASE TABLE\'';
return 'select `table_name` as name, `table_type` as type, `parent_table_name` as parent from information_schema.tables where table_schema = \'\' and table_type = \'BASE TABLE\'';
}

/**
Expand Down Expand Up @@ -93,6 +93,16 @@ public function compileIndexListing()
return 'select index_name as `index_name` from information_schema.indexes where table_schema = \'\' and table_name = ?';
}

/**
* Compile the query to determine the list of foreign keys.
*
* @return string
*/
public function compileForeignListing()
taka-oyama marked this conversation as resolved.
Show resolved Hide resolved
{
return 'select constraint_name as `index_name` from information_schema.table_constraints where constraint_type = "FOREIGN KEY" and table_schema = \'\' and table_name = ?';
}

/**
* Compile the query to determine the columns.
*
Expand Down Expand Up @@ -344,6 +354,20 @@ public function compileDropUnique(Blueprint $blueprint, Fluent $command)
return $this->compileDropIndex($blueprint, $command);
}

/**
* Compile a drop foreign key command.
*
* @param Blueprint $blueprint
* @param \Illuminate\Support\Fluent<string, mixed> $command
* @return string
*/
public function compileDropForeign(Blueprint $blueprint, Fluent $command)
{
$index = $this->wrap($command->index);

return "alter table {$this->wrapTable($blueprint)} drop constraint {$index}";
}

/**
* Get the primary key syntax for a table creation statement.
*
Expand Down
17 changes: 17 additions & 0 deletions tests/Schema/BlueprintTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,23 @@ public function testDropIndex(): void
);
}

public function testDropForeign(): void
{
$conn = $this->getDefaultConnection();

$blueprint = new Blueprint('Test3', function (Blueprint $table) {
$table->dropForeign('fk_test3');
});

$queries = $blueprint->toSql($conn, new Grammar());
$this->assertEquals(
[
'alter table `Test3` drop constraint `fk_test3`',
],
$queries
);
}

public function test_no_primaryKey(): void
{
$this->expectException(LogicException::class);
Expand Down
46 changes: 44 additions & 2 deletions tests/Schema/BuilderTest.php → tests/Schema/BuilderTestLast.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

class BuilderTest extends TestCase
class BuilderTestLast extends TestCase
{
private const TABLE_NAME_CREATED = 'schema_builder_test_table';
private const TABLE_NAME_RELATION_PARENT = 'users';
Expand Down Expand Up @@ -243,11 +243,53 @@ public function test_getAllTables(): void

/** @var array{ name: string, type: string } $row */
$row = Arr::first(
$sb->getAllTables(),
$sb->getTables(),
static fn (array $row): bool => $row['name'] === $table,
);

$this->assertSame($table, $row['name']);
$this->assertSame('BASE TABLE', $row['type']);
}

public function test_dropAllTables(): void
{
$conn = $this->getDefaultConnection();
$sb = $conn->getSchemaBuilder();
$table1 = $this->generateTableName(class_basename(__CLASS__));
$sb->create($table1, function (Blueprint $table) {
$table->uuid('id')->primary();
$table->uuid('something');
$table->index('something');
});

$table2 = $this->generateTableName(class_basename(__CLASS__));
$sb->create($table2, function (Blueprint $table) use ($table1) {
$table->uuid('table2_id')->primary();
$table->uuid('other_id');
$table->index('other_id');
$table->foreign('other_id')->references('id')->on($table1);
});

$table3 = $this->generateTableName(class_basename(__CLASS__));
$sb->create($table3, function (Blueprint $table) use ($table2) {
$table->uuid('table2_id');
$table->uuid('table3_id');
$table->primary(['table2_id', 'table3_id']);
$table->interleaveInParent($table2);
});

$table4 = $this->generateTableName(class_basename(__CLASS__));
$sb->create($table4, function (Blueprint $table) use ($table3) {
$table->uuid('table2_id');
$table->uuid('table3_id');
$table->uuid('table4_id');
$table->primary(['table2_id', 'table3_id', 'table4_id']);
$table->interleaveInParent($table3);
});

$sb->dropAllTables();

$tables = $sb->getTables();
$this->assertEmpty($tables);
}
}