feat(database): record which sqlite database a connected volume comes from

This commit is contained in:
peaklabs-dev
2026-09-26 18:05:18 +02:00
parent b182654203
commit 09c5cbcbb0
5 changed files with 57 additions and 7 deletions
@@ -80,13 +80,15 @@ class ConnectApplication extends Component
throw new \Exception('Docker Compose applications are not supported: Coolify renames named volumes in compose files.');
}
if ($application->persistentStorages()->where('name', $this->volumeName)->exists()) {
if ($application->persistentStorages()->where('standalone_sqlite_id', $this->database->id)->exists()) {
throw new \Exception("{$application->name} already mounts this database volume.");
}
LocalPersistentVolume::create([
'name' => $this->volumeName,
'mount_path' => $this->mountPath,
'host_path' => null,
'standalone_sqlite_id' => $this->database->id,
'resource_id' => $application->id,
'resource_type' => $application->getMorphClass(),
'is_preview_suffix_enabled' => false,
+16 -5
View File
@@ -3,6 +3,7 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Str;
use Symfony\Component\Yaml\Yaml;
@@ -22,6 +23,7 @@ class LocalPersistentVolume extends BaseModel
'name',
'mount_path',
'host_path',
'standalone_sqlite_id',
'container_id',
'resource_type',
'resource_id',
@@ -57,6 +59,14 @@ class LocalPersistentVolume extends BaseModel
return $this->morphMany(ScheduledVolumeBackup::class, 'backupable');
}
/**
* The SQLite database this volume was connected from, if any.
*/
public function standaloneSqlite(): BelongsTo
{
return $this->belongsTo(StandaloneSqlite::class);
}
public function abortIfScheduledBackupsExist(): void
{
if ($this->scheduledBackups()->exists()) {
@@ -69,16 +79,17 @@ class LocalPersistentVolume extends BaseModel
*/
public function isSharedWithAnotherResource(): bool
{
if (filled($this->host_path)) {
if ($this->standalone_sqlite_id !== null) {
return true;
}
if ($this->resource_type !== StandaloneSqlite::class) {
return false;
}
return static::query()
->where('standalone_sqlite_id', $this->resource_id)
->where('name', $this->name)
->where(function ($query): void {
$query->where('resource_type', '!=', $this->resource_type)
->orWhere('resource_id', '!=', $this->resource_id);
})
->exists();
}
+8
View File
@@ -306,6 +306,14 @@ class StandaloneSqlite extends BaseModel
return $this->morphMany(LocalPersistentVolume::class, 'resource');
}
/**
* Volumes of other resources that mount this database's data volume.
*/
public function connectedVolumes()
{
return $this->hasMany(LocalPersistentVolume::class, 'standalone_sqlite_id');
}
public function scheduledBackups()
{
return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
@@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Records which SQLite database a volume was connected from, so the mount
* can be traced back to its database without matching volume names.
*/
public function up(): void
{
Schema::table('local_persistent_volumes', function (Blueprint $table) {
$table->foreignId('standalone_sqlite_id')->nullable()->after('host_path')->constrained('standalone_sqlites')->nullOnDelete();
});
}
public function down(): void
{
Schema::table('local_persistent_volumes', function (Blueprint $table) {
$table->dropConstrainedForeignId('standalone_sqlite_id');
});
}
};
@@ -96,7 +96,9 @@ it('mounts the data volume into the selected application and redirects to its st
expect($volume->name)->toBe('sqlite-data-'.$this->sqlite->uuid)
->and($volume->mount_path)->toBe('/app/database')
->and($volume->is_preview_suffix_enabled)->toBeFalse();
->and($volume->is_preview_suffix_enabled)->toBeFalse()
->and($volume->standalone_sqlite_id)->toBe($this->sqlite->id)
->and($this->sqlite->connectedVolumes()->sole()->resource->is($this->application))->toBeTrue();
});
it('refuses to mount the volume into compose applications', function () {
@@ -148,6 +150,7 @@ it('keeps a docker volume shared with another resource when the application volu
'name' => 'sqlite-data-'.$this->sqlite->uuid,
'mount_path' => StandaloneSqlite::DATA_DIRECTORY,
'host_path' => null,
'standalone_sqlite_id' => $this->sqlite->id,
'resource_id' => $this->application->id,
'resource_type' => $this->application->getMorphClass(),
'is_preview_suffix_enabled' => false,