Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 29 additions & 25 deletions cmd/dump/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,28 @@ import (
)

var (
host string
port int
db string
user string
password string
schema string
multiFile bool
file string
host string
port int
db string
user string
password string
schema string
multiFile bool
file string
noComments bool
)

// DumpConfig holds configuration for dump execution
type DumpConfig struct {
Host string
Port int
DB string
User string
Password string
Schema string
MultiFile bool
File string
Host string
Port int
DB string
User string
Password string
Schema string
MultiFile bool
File string
NoComments bool
}

var DumpCmd = &cobra.Command{
Expand All @@ -52,6 +54,7 @@ func init() {
DumpCmd.Flags().StringVar(&schema, "schema", "public", "Schema name to dump (default: public)")
DumpCmd.Flags().BoolVar(&multiFile, "multi-file", false, "Output schema to multiple files organized by object type")
DumpCmd.Flags().StringVar(&file, "file", "", "Output file path (required when --multi-file is used)")
DumpCmd.Flags().BoolVar(&noComments, "no-comments", false, "Do not output object comment headers")
}

// ExecuteDump executes the dump operation with the given configuration
Expand Down Expand Up @@ -82,7 +85,7 @@ func ExecuteDump(config *DumpConfig) (string, error) {
diffs := diff.GenerateMigration(emptyIR, schemaIR, config.Schema)

// Create dump formatter
formatter := dump.NewDumpFormatter(schemaIR.Metadata.DatabaseVersion, config.Schema)
formatter := dump.NewDumpFormatter(schemaIR.Metadata.DatabaseVersion, config.Schema, config.NoComments)

if config.MultiFile {
// Multi-file mode - output to files
Expand All @@ -109,14 +112,15 @@ func runDump(cmd *cobra.Command, args []string) error {

// Create config from command-line flags
config := &DumpConfig{
Host: host,
Port: port,
DB: db,
User: user,
Password: finalPassword,
Schema: schema,
MultiFile: multiFile,
File: file,
Host: host,
Port: port,
DB: db,
User: user,
Password: finalPassword,
Schema: schema,
MultiFile: multiFile,
File: file,
NoComments: noComments,
}

// Execute dump
Expand Down
102 changes: 102 additions & 0 deletions cmd/dump/dump_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package dump

import (
"os"
"strings"
"testing"

"github.com/pgschema/pgschema/cmd/util"
"github.com/pgschema/pgschema/internal/diff"
"github.com/pgschema/pgschema/internal/dump"
"github.com/pgschema/pgschema/ir"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -288,3 +292,101 @@ func TestDumpCommand_PgpassFile(t *testing.T) {
t.Error("Expected error with unreachable database, but got nil")
}
}

func TestDumpCommand_NoCommentsFlag(t *testing.T) {
// Test that the --no-comments flag is defined
flags := DumpCmd.Flags()
noCommentsFlag := flags.Lookup("no-comments")
if noCommentsFlag == nil {
t.Error("Expected --no-comments flag to be defined")
}

// Verify default value is false
if noCommentsFlag.DefValue != "false" {
t.Errorf("Expected --no-comments default to be 'false', got '%s'", noCommentsFlag.DefValue)
}
}

func TestNoComments_SingleFile(t *testing.T) {
// Create test diffs
diffs := []diff.Diff{
{
Statements: []diff.SQLStatement{
{
SQL: "CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT NOT NULL);",
CanRunInTransaction: true,
},
},
Type: diff.DiffTypeTable,
Operation: diff.DiffOperationCreate,
Path: "public.users",
Source: &ir.Table{
Name: "users",
},
},
{
Statements: []diff.SQLStatement{
{
SQL: "COMMENT ON TABLE users IS 'User accounts';",
CanRunInTransaction: true,
},
},
Type: diff.DiffTypeComment,
Operation: diff.DiffOperationCreate,
Path: "public.users",
Source: &ir.Table{
Name: "users",
},
},
}

t.Run("WithComments", func(t *testing.T) {
formatter := dump.NewDumpFormatter("PostgreSQL 17.0", "public", false)
output := formatter.FormatSingleFile(diffs)

// Should contain dump header
if !strings.Contains(output, "-- pgschema database dump") {
t.Error("Expected output to contain dump header")
}

// Should contain object comment header
if !strings.Contains(output, "-- Name: users; Type: TABLE") {
t.Error("Expected output to contain object comment header")
}

// Should contain DDL
if !strings.Contains(output, "CREATE TABLE users") {
t.Error("Expected output to contain DDL")
}

// Should contain COMMENT ON statement (this is schema content, not commentary)
if !strings.Contains(output, "COMMENT ON TABLE users") {
t.Error("Expected output to contain COMMENT ON statement")
}
})

t.Run("NoComments", func(t *testing.T) {
formatter := dump.NewDumpFormatter("PostgreSQL 17.0", "public", true)
output := formatter.FormatSingleFile(diffs)

// Should still contain dump header (retained per design)
if !strings.Contains(output, "-- pgschema database dump") {
t.Error("Expected output to contain dump header even with --no-comments")
}

// Should NOT contain object comment header
if strings.Contains(output, "-- Name: users; Type: TABLE") {
t.Error("Expected output to NOT contain object comment header with --no-comments")
}

// Should still contain DDL
if !strings.Contains(output, "CREATE TABLE users") {
t.Error("Expected output to contain DDL")
}

// Should still contain COMMENT ON statement (this is schema content)
if !strings.Contains(output, "COMMENT ON TABLE users") {
t.Error("Expected output to contain COMMENT ON statement")
}
})
}
4 changes: 2 additions & 2 deletions cmd/dump/multifile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func TestCreateMultiFileOutput(t *testing.T) {
}

// Test the FormatMultiFile function
formatter := dump.NewDumpFormatter("PostgreSQL 17.0", "public")
formatter := dump.NewDumpFormatter("PostgreSQL 17.0", "public", false)
err := formatter.FormatMultiFile(diffs, outputPath)
if err != nil {
t.Fatalf("FormatMultiFile failed: %v", err)
Expand Down Expand Up @@ -154,7 +154,7 @@ func TestCreateMultiFileOutput(t *testing.T) {

func TestDumpFormatterHelpers(t *testing.T) {
// Create a formatter instance for testing helper methods
formatter := dump.NewDumpFormatter("PostgreSQL 17.0", "public")
formatter := dump.NewDumpFormatter("PostgreSQL 17.0", "public", false)

// Test getObjectDirectory through the formatter
testObjectDirectories := []struct {
Expand Down
8 changes: 7 additions & 1 deletion docs/cli/dump.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,17 @@ pgschema apply --host staging-host --db myapp --user postgres --file current.sql

<ParamField path="--file" type="string">
Output file path (required when --multi-file is used)

For single-file mode, this is optional (defaults to stdout).
For multi-file mode, this specifies the main file path.
</ParamField>

<ParamField path="--no-comments" type="boolean" default="false">
Do not output object comment headers (e.g., `-- Name: users; Type: TABLE; Schema: -; Owner: -`).

The dump header with pgschema version information is retained. This option is useful when you need pure DDL output without per-object commentary.
</ParamField>

## Ignoring Objects

You can exclude specific database objects from dumps using a `.pgschemaignore` file. See [Ignore (.pgschemaignore)](/cli/ignore) for complete documentation.
Expand Down
18 changes: 13 additions & 5 deletions internal/dump/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ import (
type DumpFormatter struct {
dbVersion string
targetSchema string
noComments bool
}

// NewDumpFormatter creates a new DumpFormatter
func NewDumpFormatter(dbVersion string, targetSchema string) *DumpFormatter {
func NewDumpFormatter(dbVersion string, targetSchema string, noComments bool) *DumpFormatter {
return &DumpFormatter{
dbVersion: dbVersion,
targetSchema: targetSchema,
noComments: noComments,
}
}

Expand All @@ -46,8 +48,12 @@ func (f *DumpFormatter) FormatSingleFile(diffs []diff.Diff) string {
output.WriteString("\n")
}
} else {
// Add object comment header
output.WriteString(f.formatObjectCommentHeader(step))
// Add object comment header (unless --no-comments is set)
if !f.noComments {
output.WriteString(f.formatObjectCommentHeader(step))
} else if i > 0 {
output.WriteString("\n") // Add separator between statements
}

// Add the SQL statements
for _, stmt := range step.Statements {
Expand Down Expand Up @@ -195,8 +201,10 @@ func (f *DumpFormatter) writeObjectFile(filePath string, diffs []diff.Diff) erro
}
}

// Add object comment header
file.WriteString(f.formatObjectCommentHeader(step))
// Add object comment header (unless --no-comments is set)
if !f.noComments {
file.WriteString(f.formatObjectCommentHeader(step))
}

// Print the SQL statements
for _, stmt := range step.Statements {
Expand Down