feat(backups): support restoring sqlite backups

This commit is contained in:
peaklabs-dev
2026-09-24 22:15:06 +02:00
parent 9998dccc0a
commit 46e53e1fb8
3 changed files with 21 additions and 1 deletions
@@ -14,6 +14,7 @@ use App\Models\StandaloneMariadb;
use App\Models\StandaloneMysql;
use App\Models\StandalonePostgresql;
use App\Models\StandaloneRedis;
use App\Models\StandaloneSqlite;
use App\Rules\SafeWebhookUrl;
use App\Support\DatabaseImport\DatabaseImportCommandBuilder;
use App\Support\DatabaseImport\DatabaseImportException;
@@ -176,6 +177,8 @@ class ImportForm extends Component
public string $mongodbRestoreCommand = 'mongorestore --authenticationDatabase=admin --username $MONGO_INITDB_ROOT_USERNAME --password $MONGO_INITDB_ROOT_PASSWORD --uri mongodb://localhost:27017 --gzip --archive=';
public string $sqliteRestoreCommand = '';
// S3 Restore properties
public array $availableS3Storages = [];
@@ -340,6 +343,9 @@ EOD;
// Store IDs for Livewire serialization
$this->resourceId = $resource->id;
$this->resourceType = get_class($resource);
if ($resource instanceof StandaloneSqlite) {
$this->sqliteRestoreCommand = $this->buildRestoreCommand('<temp_backup_file>');
}
// Store view-friendly properties
$this->resourceStatus = $resource->status ?? '';
@@ -22,10 +22,18 @@ class DatabaseImportCommandBuilder
? $this->mysqlDumpAll('mariadb', 'MARIADB', $path)
: '(gunzip -cf '.$path.' 2>/dev/null || cat '.$path.') | mariadb -u $MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE',
'mongodb' => 'mongorestore --authenticationDatabase=admin --username $MONGO_INITDB_ROOT_USERNAME --password $MONGO_INITDB_ROOT_PASSWORD --uri mongodb://localhost:27017 --gzip --archive='.$path,
'sqlite' => $this->sqliteRestore($resource->databaseFilePath(), $path),
default => throw new InvalidArgumentException('Database import is not supported for this database type.'),
};
}
private function sqliteRestore(string $file, string $path): string
{
$file = escapeshellarg($file);
return "backup={$path}; gunzip -c \"\$backup\" > \"\$backup.db\" && sqlite3 -bail {$file} '.timeout 10000' \".restore \$backup.db\"; status=\$?; rm -f \"\$backup.db\"; exit \$status";
}
public function buildPostgresRestoreScanScript(object $resource, string $path): ?string
{
if ($this->databaseType($resource) !== 'postgresql') {
@@ -82,7 +90,7 @@ SH;
public function supports(object $resource): bool
{
return in_array($this->databaseType($resource), ['postgresql', 'mysql', 'mariadb', 'mongodb'], true);
return in_array($this->databaseType($resource), ['postgresql', 'mysql', 'mariadb', 'mongodb', 'sqlite'], true);
}
public function databaseType(object $resource): string
@@ -97,6 +105,7 @@ SH;
str_contains($type, 'mariadb') => 'mariadb',
str_contains($type, 'mysql') => 'mysql',
str_contains($type, 'mongo') => 'mongodb',
str_contains($type, 'sqlite') => 'sqlite',
default => 'unsupported',
};
}
@@ -88,13 +88,18 @@
<x-forms.input label="Import command" wire:model="mariadbRestoreCommand"
canGate="update" :canResource="$this->resource" />
@endif
@elseif ($resourceDbType === 'standalone-sqlite')
<x-forms.input label="Import command" readonly wire:model="sqliteRestoreCommand"
canGate="update" :canResource="$this->resource" />
@endif
@if ($resourceDbType !== 'standalone-sqlite')
<div class="max-w-sm">
<x-forms.listbox id="dumpAll" label="Backup contents" live :options="[
['value' => true, 'label' => 'Backup contains all databases'],
['value' => false, 'label' => 'Backup contains one database'],
]" />
</div>
@endif
@if (in_array($resourceDbType, ['standalone-postgresql', 'postgresql'], true) && ! $dumpAll)
<div class="max-w-sm">
<x-forms.checkbox id="replaceExisting" label="Replace objects that already exist"