mirror of
https://github.com/databasus/databasus.git
synced 2026-04-06 00:32:03 +02:00
feat(postgresus): Add schema filter for pg_dump and pg_restore (#131)
Add optional "Schemas" field to PostgreSQL database settings allowing users to specify which schemas to include in backups (comma-separated). This solves permission issues when backing up some of databases that have restricted internal schemas (auth, storage, realtime). Changes: - Add schemas column to postgresql_databases table (migration) - Update PostgresqlDatabase model with Schemas field - Modify buildPgDumpArgs() to append --schema flags for each schema - Modify pg_restore args to support --schema filtering on restore - Add Schemas input field to frontend edit form with tooltip - Display schemas in read-only database view Example usage: Setting schemas to "public,drizzle" generates: pg_dump ... --schema public --schema drizzle pg_restore ... --schema public --schema drizzle
This commit is contained in:
@@ -334,6 +334,17 @@ func (uc *CreatePostgresqlBackupUsecase) buildPgDumpArgs(pg *pgtypes.PostgresqlD
|
||||
"--verbose",
|
||||
}
|
||||
|
||||
// Add schema filters if specified
|
||||
if pg.Schemas != nil && *pg.Schemas != "" {
|
||||
schemas := strings.Split(*pg.Schemas, ",")
|
||||
for _, schema := range schemas {
|
||||
schema = strings.TrimSpace(schema)
|
||||
if schema != "" {
|
||||
args = append(args, "--schema", schema)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compressionArgs := uc.getCompressionArgs(pg.Version)
|
||||
return append(args, compressionArgs...)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ type PostgresqlDatabase struct {
|
||||
Password string `json:"password" gorm:"type:text;not null"`
|
||||
Database *string `json:"database" gorm:"type:text"`
|
||||
IsHttps bool `json:"isHttps" gorm:"type:boolean;default:false"`
|
||||
Schemas *string `json:"schemas" gorm:"type:text"`
|
||||
}
|
||||
|
||||
func (p *PostgresqlDatabase) TableName() string {
|
||||
@@ -85,6 +86,7 @@ func (p *PostgresqlDatabase) Update(incoming *PostgresqlDatabase) {
|
||||
p.Username = incoming.Username
|
||||
p.Database = incoming.Database
|
||||
p.IsHttps = incoming.IsHttps
|
||||
p.Schemas = incoming.Schemas
|
||||
|
||||
if incoming.Password != "" {
|
||||
p.Password = incoming.Password
|
||||
|
||||
@@ -83,6 +83,17 @@ func (uc *RestorePostgresqlBackupUsecase) Execute(
|
||||
"--no-acl", // Skip restoring access privileges (GRANT/REVOKE commands)
|
||||
}
|
||||
|
||||
// Add schema filters if specified
|
||||
if pg.Schemas != nil && *pg.Schemas != "" {
|
||||
schemas := strings.Split(*pg.Schemas, ",")
|
||||
for _, schema := range schemas {
|
||||
schema = strings.TrimSpace(schema)
|
||||
if schema != "" {
|
||||
args = append(args, "--schema", schema)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uc.restoreFromStorage(
|
||||
originalDB,
|
||||
tools.GetPostgresqlExecutable(
|
||||
|
||||
15
backend/migrations/20251210053223_add_schemas_column.sql
Normal file
15
backend/migrations/20251210053223_add_schemas_column.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
ALTER TABLE postgresql_databases
|
||||
ADD COLUMN schemas TEXT;
|
||||
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
|
||||
ALTER TABLE postgresql_databases
|
||||
DROP COLUMN IF EXISTS schemas;
|
||||
|
||||
-- +goose StatementEnd
|
||||
@@ -11,4 +11,5 @@ export interface PostgresqlDatabase {
|
||||
password: string;
|
||||
database?: string;
|
||||
isHttps: boolean;
|
||||
schemas?: string;
|
||||
}
|
||||
|
||||
@@ -649,7 +649,7 @@ export const BackupsComponent = ({ database, isCanManageDBs, scrollContainerRef
|
||||
|
||||
{showingRestoresBackupId && (
|
||||
<Modal
|
||||
width={400}
|
||||
width={420}
|
||||
open={!!showingRestoresBackupId}
|
||||
onCancel={() => setShowingRestoresBackupId(undefined)}
|
||||
title="Restore from backup"
|
||||
|
||||
@@ -275,6 +275,32 @@ export const EditDatabaseSpecificDataComponent = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-1 flex w-full items-center">
|
||||
<div className="min-w-[150px]">Schemas</div>
|
||||
<Input
|
||||
value={editingDatabase.postgresql?.schemas}
|
||||
onChange={(e) => {
|
||||
if (!editingDatabase.postgresql) return;
|
||||
|
||||
setEditingDatabase({
|
||||
...editingDatabase,
|
||||
postgresql: { ...editingDatabase.postgresql, schemas: e.target.value.trim() },
|
||||
});
|
||||
setIsConnectionTested(false);
|
||||
}}
|
||||
size="small"
|
||||
className="max-w-[200px] grow"
|
||||
placeholder="public,myschema (optional)"
|
||||
/>
|
||||
|
||||
<Tooltip
|
||||
className="cursor-pointer"
|
||||
title="Comma-separated list of schemas to include. Leave empty for all schemas."
|
||||
>
|
||||
<InfoCircleOutlined className="ml-2" style={{ color: 'gray' }} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<div className="mb-3 flex w-full items-center">
|
||||
<div className="min-w-[150px]">Use HTTPS</div>
|
||||
<Switch
|
||||
|
||||
@@ -53,6 +53,11 @@ export const ShowDatabaseSpecificDataComponent = ({ database }: Props) => {
|
||||
<div>{database.postgresql?.database || ''}</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-1 flex w-full items-center">
|
||||
<div className="min-w-[150px]">Schemas</div>
|
||||
<div>{database.postgresql?.schemas || 'All (full backup)'}</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-1 flex w-full items-center">
|
||||
<div className="min-w-[150px]">Use HTTPS</div>
|
||||
<div>{database.postgresql?.isHttps ? 'Yes' : 'No'}</div>
|
||||
|
||||
Reference in New Issue
Block a user