-
Notifications
You must be signed in to change notification settings - Fork 0
feat: ✨ [NEW FEATURE] Creation of specific schemas for each team #519
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
Open
vqlion
wants to merge
6
commits into
master/dev
Choose a base branch
from
feature/issue-517-_NEW_FEATURE_Creation_of_specific_schemas_for_each_team
base: master/dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
1efba6e
feat(schemas): schema creation command
vqlion 53b3a36
feat(schemas): schema migration command
vqlion b9f20c7
feat(schemas): create team-specific migration folder
vqlion 6c371b1
test(schemas): add tests
vqlion ace6224
feat(schemas): error handling
vqlion 015f7d9
Merge branch 'master/dev' into feature/issue-517-_NEW_FEATURE_Creatio…
lduf File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| <?php | ||
|
|
||
| namespace App\Console\Commands; | ||
|
|
||
| use App\Models\Crew; | ||
| use App\Models\Schema; | ||
| use Illuminate\Console\Command; | ||
| use Illuminate\Database\Schema\Builder; | ||
| use Illuminate\Support\Facades\Config; | ||
| use Illuminate\Support\Facades\DB; | ||
| use Illuminate\Support\Facades\File; | ||
|
|
||
| class MakeSchemaCommand extends Command | ||
| { | ||
| /** | ||
| * The name and signature of the console command. | ||
| * | ||
| * @var string | ||
| */ | ||
| protected $signature = 'make:schema {team_id}'; | ||
|
|
||
| /** | ||
| * The console command description. | ||
| * | ||
| * @var string | ||
| */ | ||
| protected $description = 'Generates a schema for a team in the database and creates the associated migration folder if the schema doesn\'t already exist'; | ||
|
|
||
| protected Builder $builder; | ||
|
|
||
| public function __construct( | ||
| Builder $builder, | ||
| ) | ||
| { | ||
| parent::__construct(); | ||
| $this->builder = DB::getSchemaBuilder(); | ||
| } | ||
|
|
||
| /** | ||
| * Execute the console command. | ||
| * | ||
| * @return int | ||
| */ | ||
| public function handle() | ||
| { | ||
| try { | ||
| $crew_id = $this->argument('team_id'); | ||
| $crew = Crew::find($crew_id); | ||
|
|
||
| if(!$crew) { | ||
| $this->warn("Team " . $this->argument('team_id') . " doesn't exist yet."); | ||
| $this->info("Create the team before creating its schema"); | ||
| return Command::FAILURE; | ||
| } | ||
|
|
||
| $migrationFolderPath = Config::get('database.migration_path'); | ||
| File::ensureDirectoryExists($migrationFolderPath . DIRECTORY_SEPARATOR . $crew_id); | ||
|
|
||
| $dbName = Schema::getSchemaName($crew_id); | ||
| $schema = Schema::where('name', $dbName)->first(); | ||
|
|
||
| if(!$schema) { | ||
| $schema['name'] = $dbName; | ||
| $schema['crew_id'] = $crew_id; | ||
| Schema::Create($schema); | ||
| $this->builder->createDatabase($dbName); | ||
| $this->info("Created database: " . $dbName); | ||
| } else { | ||
| $this->info("Database already exists for this team"); | ||
| } | ||
|
|
||
| return Command::SUCCESS; | ||
|
|
||
| } catch(\Exception $e) { | ||
| $this->error($e->getMessage()); | ||
| return Command::FAILURE; | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| <?php | ||
|
|
||
| namespace App\Console\Commands; | ||
|
|
||
| use App\Models\Crew; | ||
| use App\Models\Schema; | ||
| use Illuminate\Console\Command; | ||
|
|
||
| class MigrateCustomSchemaCommand extends Command | ||
| { | ||
| /** | ||
| * The name and signature of the console command. | ||
| * | ||
| * @var string | ||
| */ | ||
|
|
||
| protected $signature = 'migrate:custom {team_id} {--path=}'; | ||
|
|
||
| /** | ||
| * The console command description. | ||
| * | ||
| * @var string | ||
| */ | ||
| protected $description = 'Executes the migration for the database linked to the team id'; | ||
|
|
||
| /** | ||
| * Execute the console command. | ||
| * | ||
| * @return int | ||
| */ | ||
| public function handle() | ||
| { | ||
| $crew_id = $this->argument('team_id'); | ||
| $crew = Crew::find($crew_id); | ||
|
|
||
| if(!$crew) { | ||
| $this->warn("Team " . $this->argument('team_id') . " doesn't exist yet."); | ||
| $this->info("Create the team before migrating to its schema"); | ||
| return Command::FAILURE; | ||
| } | ||
|
|
||
| $dbName = Schema::getSchemaName($crew_id); | ||
| $schema = Schema::where("name", $dbName)->first(); | ||
| if(!$schema) { | ||
| $this->warn("No database found for " . $this->argument('team_id')); | ||
| $this->info("You can initiate a new schema with artisan make:schema {team_id}"); | ||
| return Command::FAILURE; | ||
| } | ||
|
|
||
| $schema->openDatabaseConnection(); | ||
| $path = $this->option('path') ?? config('database.migration_path'); | ||
|
|
||
| $migrationResult = $this->call('migrate', ['--database' => $dbName, '--path' => $path]); | ||
|
|
||
| if ($migrationResult !== Command::SUCCESS) { | ||
| $this->warn("Something went wrong during the migration. Aborting."); | ||
| return Command::FAILURE; | ||
| } | ||
| return Command::SUCCESS; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,55 @@ | ||||||
| <?php | ||||||
|
|
||||||
| namespace App\Models; | ||||||
|
|
||||||
| use App\Traits\Uuids; | ||||||
| use Illuminate\Database\Eloquent\Factories\HasFactory; | ||||||
| use Illuminate\Database\Eloquent\Model; | ||||||
| use Illuminate\Database\Eloquent\Relations\BelongsTo; | ||||||
| Use Illuminate\Database\Eloquent\SoftDeletes; | ||||||
|
||||||
| Use Illuminate\Database\Eloquent\SoftDeletes; | |
| use Illuminate\Database\Eloquent\SoftDeletes; |
34 changes: 34 additions & 0 deletions
34
src/database/migrations/2025_01_15_143802_create_schemas_table.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| <?php | ||
|
|
||
| use Illuminate\Database\Migrations\Migration; | ||
| use Illuminate\Database\Schema\Blueprint; | ||
| use Illuminate\Support\Facades\Schema; | ||
|
|
||
| return new class extends Migration | ||
| { | ||
| /** | ||
| * Run the migrations. | ||
| * | ||
| * @return void | ||
| */ | ||
| public function up() | ||
| { | ||
| Schema::create('schemas', function (Blueprint $table) { | ||
| $table->uuid("id")->primary(); | ||
| $table->string("name")->unique(); | ||
| $table->foreignUuid("crew_id"); | ||
| $table->timestamps(); | ||
| $table->softDeletes(); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Reverse the migrations. | ||
| * | ||
| * @return void | ||
| */ | ||
| public function down() | ||
| { | ||
| Schema::dropIfExists('schemas'); | ||
| } | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| <?php | ||
|
|
||
| namespace Tests\Feature; | ||
|
|
||
| use App\Models\Crew; | ||
| use App\Models\Schema; | ||
| use Illuminate\Support\Facades\Config; | ||
| use Illuminate\Support\Facades\DB; | ||
| use Illuminate\Support\Facades\File; | ||
| use Tests\TestCase; | ||
|
|
||
| class CustomSchemaTest extends TestCase | ||
| { | ||
| public function setUp(): void | ||
| { | ||
| parent::setUp(); | ||
| } | ||
|
|
||
| public function test_create_schema_for_existing_team() | ||
| { | ||
| $test_crew = Crew::factory()->create(); | ||
| $crew_id = $test_crew->id; | ||
| $db_name = Schema::getSchemaName($crew_id); | ||
|
|
||
| $this->artisan('make:schema ' . $crew_id) | ||
| ->assertSuccessful() | ||
| ->expectsOutput("Created database: " . $db_name); | ||
|
|
||
| $this->assertDatabaseHas('schemas', [ | ||
| 'crew_id' => $crew_id | ||
| ]); | ||
|
|
||
| $migrationFolderPath = Config::get('database.migration_path'); | ||
| $this->assertTrue(File::exists($migrationFolderPath . DIRECTORY_SEPARATOR . $crew_id)); | ||
|
|
||
| $dbConfig = Config::get('database.connections.mysql'); | ||
| $dbConfig['database'] = $db_name; | ||
| Config::set('database.connections.' . $db_name, $dbConfig); | ||
|
|
||
| $this->assertEquals($db_name, DB::connection($db_name)->getDatabaseName()); | ||
|
|
||
| } | ||
|
|
||
| public function test_recreate_schema_for_existing_team() | ||
| { | ||
| $test_crew = Crew::factory()->create(); | ||
| $this->artisan('make:schema ' . $test_crew->id) | ||
| ->assertSuccessful(); | ||
|
|
||
| $this->artisan('make:schema ' . $test_crew->id) | ||
| ->assertSuccessful() | ||
| ->expectsOutput('Database already exists for this team'); | ||
| } | ||
|
|
||
| public function test_create_schema_for_non_existing_team() | ||
| { | ||
| $this->artisan('make:schema ' . 'test') | ||
| ->assertFailed() | ||
| ->expectsOutput("Team test doesn't exist yet."); | ||
| } | ||
|
|
||
| public function test_migrate_to_non_existing_team() | ||
| { | ||
| $this->artisan('migrate:custom test') | ||
| ->assertFailed() | ||
| ->expectsOutput("Team test doesn't exist yet."); | ||
| } | ||
|
|
||
| public function test_migrate_to_existing_team_without_schema() | ||
| { | ||
| $crew = Crew::factory()->create(); | ||
|
|
||
| $this->artisan('migrate:custom ' . $crew->id) | ||
| ->assertFailed() | ||
| ->expectsOutput("No database found for " . $crew->id); | ||
| } | ||
|
|
||
| public function test_migrate_to_existing_team_with_schema() | ||
| { | ||
| $crew = Crew::factory()->create(); | ||
| $db_name = Schema::getSchemaName($crew->id); | ||
|
|
||
| $this->artisan('make:schema ' . $crew->id) | ||
| ->assertSuccessful(); | ||
|
|
||
| $this->artisan('migrate:custom ' . $crew->id) | ||
| ->assertSuccessful(); | ||
|
|
||
| $dbConfig = Config::get('database.connections.mysql'); | ||
| $dbConfig['database'] = $db_name; | ||
| Config::set('database.connections.' . $db_name, $dbConfig); | ||
|
|
||
| $schemaBuilder = \Illuminate\Support\Facades\Schema::connection($db_name); | ||
| $this->assertTrue($schemaBuilder->hasTable("migrations")); | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable
$schemais being used as an array but was previously assigned a model instance from the query. This will cause a runtime error. Should initialize as an empty array or useSchema::create()with lowercase 'c'.