feat(migrate-db): SQLite <-> .dump conversion and Download Migration in Overview

Binary: extend the migrate-db subcommand with --dump and --restore so a
SQLite database can be exported to a portable SQL text dump and rebuilt from
one, alongside the existing --dsn PostgreSQL copy. Implemented in Go via the
bundled sqlite driver (new database/dump_sqlite.go); no external sqlite3 client
is required. Add ExportPostgresToSQLite (reverse of MigrateData) to build a
SQLite .db from live PostgreSQL data, reusing the shared copyAllModels helper.

Overview: add a "Download Migration" item to Backup & Restore plus a
getMigration endpoint/service that returns a .dump on SQLite or a .db on
PostgreSQL, so the data can seed a panel on the other backend. Document the
endpoint in api-docs and translate the three new strings across all locales.

Tests: cover the destination-side copy (AutoMigrate + copyTable into SQLite)
and the dump/restore round-trip including quoted values. Ignore *.dump.

The x-ui.sh helper that drives this from the CLI is in PR #4910.
This commit is contained in:
MHSanaei
2026-06-04 15:32:22 +02:00
parent 5c1d64b841
commit a07c7b7f4e
24 changed files with 599 additions and 22 deletions
+35
View File
@@ -1156,6 +1156,41 @@ func (s *ServerService) GetDb() ([]byte, error) {
return fileContents, nil
}
// GetMigration produces a cross-engine migration file plus its filename: on a
// SQLite panel it returns a portable .dump (SQL text), and on a PostgreSQL panel
// it returns a .db SQLite database built from the live data. Either output can
// then seed a panel running on the other backend.
func (s *ServerService) GetMigration() ([]byte, string, error) {
if database.IsPostgres() {
tmp, err := os.CreateTemp("", "x-ui-migration-*.db")
if err != nil {
return nil, "", err
}
tmpPath := tmp.Name()
tmp.Close()
defer os.Remove(tmpPath)
if err := database.ExportPostgresToSQLite(config.GetDBDSN(), tmpPath); err != nil {
return nil, "", err
}
data, err := os.ReadFile(tmpPath)
if err != nil {
return nil, "", err
}
return data, "x-ui.db", nil
}
// SQLite panel: checkpoint so the .db reflects the latest writes, then dump.
if err := database.Checkpoint(); err != nil {
return nil, "", err
}
data, err := database.DumpSQLiteToBytes(config.GetDBPath())
if err != nil {
return nil, "", err
}
return data, "x-ui.dump", nil
}
func (s *ServerService) ImportDB(file multipart.File) error {
if database.IsPostgres() {
return s.importPostgresDB(file)