Skip to content

Commit 5944d7c

Browse files
authored
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
1 parent 1f5c9d3 commit 5944d7c

File tree

8 files changed

+72
-1
lines changed

8 files changed

+72
-1
lines changed

backend/internal/features/backups/backups/usecases/postgresql/create_backup_uc.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,17 @@ func (uc *CreatePostgresqlBackupUsecase) buildPgDumpArgs(pg *pgtypes.PostgresqlD
334334
"--verbose",
335335
}
336336

337+
// Add schema filters if specified
338+
if pg.Schemas != nil && *pg.Schemas != "" {
339+
schemas := strings.Split(*pg.Schemas, ",")
340+
for _, schema := range schemas {
341+
schema = strings.TrimSpace(schema)
342+
if schema != "" {
343+
args = append(args, "--schema", schema)
344+
}
345+
}
346+
}
347+
337348
compressionArgs := uc.getCompressionArgs(pg.Version)
338349
return append(args, compressionArgs...)
339350
}

backend/internal/features/databases/databases/postgresql/model.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type PostgresqlDatabase struct {
2929
Password string `json:"password" gorm:"type:text;not null"`
3030
Database *string `json:"database" gorm:"type:text"`
3131
IsHttps bool `json:"isHttps" gorm:"type:boolean;default:false"`
32+
Schemas *string `json:"schemas" gorm:"type:text"`
3233
}
3334

3435
func (p *PostgresqlDatabase) TableName() string {
@@ -85,6 +86,7 @@ func (p *PostgresqlDatabase) Update(incoming *PostgresqlDatabase) {
8586
p.Username = incoming.Username
8687
p.Database = incoming.Database
8788
p.IsHttps = incoming.IsHttps
89+
p.Schemas = incoming.Schemas
8890

8991
if incoming.Password != "" {
9092
p.Password = incoming.Password

backend/internal/features/restores/usecases/postgresql/restore_backup_uc.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,17 @@ func (uc *RestorePostgresqlBackupUsecase) Execute(
8383
"--no-acl", // Skip restoring access privileges (GRANT/REVOKE commands)
8484
}
8585

86+
// Add schema filters if specified
87+
if pg.Schemas != nil && *pg.Schemas != "" {
88+
schemas := strings.Split(*pg.Schemas, ",")
89+
for _, schema := range schemas {
90+
schema = strings.TrimSpace(schema)
91+
if schema != "" {
92+
args = append(args, "--schema", schema)
93+
}
94+
}
95+
}
96+
8697
return uc.restoreFromStorage(
8798
originalDB,
8899
tools.GetPostgresqlExecutable(
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-- +goose Up
2+
-- +goose StatementBegin
3+
4+
ALTER TABLE postgresql_databases
5+
ADD COLUMN schemas TEXT;
6+
7+
-- +goose StatementEnd
8+
9+
-- +goose Down
10+
-- +goose StatementBegin
11+
12+
ALTER TABLE postgresql_databases
13+
DROP COLUMN IF EXISTS schemas;
14+
15+
-- +goose StatementEnd

frontend/src/entity/databases/model/postgresql/PostgresqlDatabase.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ export interface PostgresqlDatabase {
1111
password: string;
1212
database?: string;
1313
isHttps: boolean;
14+
schemas?: string;
1415
}

frontend/src/features/backups/ui/BackupsComponent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ export const BackupsComponent = ({ database, isCanManageDBs, scrollContainerRef
649649

650650
{showingRestoresBackupId && (
651651
<Modal
652-
width={400}
652+
width={420}
653653
open={!!showingRestoresBackupId}
654654
onCancel={() => setShowingRestoresBackupId(undefined)}
655655
title="Restore from backup"

frontend/src/features/databases/ui/edit/EditDatabaseSpecificDataComponent.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,32 @@ export const EditDatabaseSpecificDataComponent = ({
275275
</div>
276276
)}
277277

278+
<div className="mb-1 flex w-full items-center">
279+
<div className="min-w-[150px]">Schemas</div>
280+
<Input
281+
value={editingDatabase.postgresql?.schemas}
282+
onChange={(e) => {
283+
if (!editingDatabase.postgresql) return;
284+
285+
setEditingDatabase({
286+
...editingDatabase,
287+
postgresql: { ...editingDatabase.postgresql, schemas: e.target.value.trim() },
288+
});
289+
setIsConnectionTested(false);
290+
}}
291+
size="small"
292+
className="max-w-[200px] grow"
293+
placeholder="public,myschema (optional)"
294+
/>
295+
296+
<Tooltip
297+
className="cursor-pointer"
298+
title="Comma-separated list of schemas to include. Leave empty for all schemas."
299+
>
300+
<InfoCircleOutlined className="ml-2" style={{ color: 'gray' }} />
301+
</Tooltip>
302+
</div>
303+
278304
<div className="mb-3 flex w-full items-center">
279305
<div className="min-w-[150px]">Use HTTPS</div>
280306
<Switch

frontend/src/features/databases/ui/show/ShowDatabaseSpecificDataComponent.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ export const ShowDatabaseSpecificDataComponent = ({ database }: Props) => {
5353
<div>{database.postgresql?.database || ''}</div>
5454
</div>
5555

56+
<div className="mb-1 flex w-full items-center">
57+
<div className="min-w-[150px]">Schemas</div>
58+
<div>{database.postgresql?.schemas || 'All (full backup)'}</div>
59+
</div>
60+
5661
<div className="mb-1 flex w-full items-center">
5762
<div className="min-w-[150px]">Use HTTPS</div>
5863
<div>{database.postgresql?.isHttps ? 'Yes' : 'No'}</div>

0 commit comments

Comments
 (0)