From 355a886887301c3131b1a38e707382d10d89ef9a Mon Sep 17 00:00:00 2001 From: Adam Mustafa Date: Thu, 27 Nov 2025 14:53:48 -0500 Subject: [PATCH] Create a public Golang API --- api_doc.md | 105 ++++++++++++++ convenience.go | 79 +++++++++++ examples_test.go | 347 +++++++++++++++++++++++++++++++++++++++++++++++ pgschema.go | 297 ++++++++++++++++++++++++++++++++++++++++ types.go | 74 ++++++++++ 5 files changed, 902 insertions(+) create mode 100644 api_doc.md create mode 100644 convenience.go create mode 100644 examples_test.go create mode 100644 pgschema.go create mode 100644 types.go diff --git a/api_doc.md b/api_doc.md new file mode 100644 index 00000000..3c859afc --- /dev/null +++ b/api_doc.md @@ -0,0 +1,105 @@ +# pgschema Public API + +This package provides a programmatic API for pgschema's PostgreSQL schema management functionality. It offers Terraform-style declarative schema migration workflows with dump/plan/apply operations that can be used directly from Go code. + +## Quick Start + +```go +package main + +import ( + "context" + "log" + + "github.com/pgschema/pgschema/pgschema" +) + +func main() { + ctx := context.Background() + + dbConfig := pgschema.DatabaseConfig{ + Host: "localhost", + Port: 5432, + Database: "myapp", + User: "postgres", + Password: "password", + Schema: "public", + } + + // Dump current schema + schema, err := pgschema.DumpSchema(ctx, dbConfig) + if err != nil { + log.Fatal(err) + } + + // Generate migration plan + plan, err := pgschema.GeneratePlan(ctx, dbConfig, "desired_schema.sql") + if err != nil { + log.Fatal(err) + } + + // Apply migration + err = pgschema.ApplyPlan(ctx, dbConfig, plan, true) + if err != nil { + log.Fatal(err) + } +} +``` + +## Core Operations + +### Dump + +Extract current database schema as SQL: + +```go +// Simple dump to string +schema, err := pgschema.DumpSchema(ctx, dbConfig) + +// Dump to file +err := pgschema.DumpSchemaToFile(ctx, dbConfig, "schema.sql") + +// Dump to multiple files organized by object type +err := pgschema.DumpSchemaMultiFile(ctx, dbConfig, "schemas/") +``` + +### Plan + +Generate migration plans by comparing current and desired states: + +```go +// Generate plan from desired state file +plan, err := pgschema.GeneratePlan(ctx, dbConfig, "desired_schema.sql") + +// Generate plan with custom options +client := pgschema.NewClient(dbConfig) +plan, err := client.Plan(ctx, pgschema.PlanOptions{ + File: "desired_schema.sql", + ApplicationName: "my-migration-tool", +}) +``` + +### Apply + +Apply migration plans to update database schema: + +```go +// Apply schema file directly +err := pgschema.ApplySchemaFile(ctx, dbConfig, "desired_schema.sql", false) + +// Apply with auto-approval (no prompts) +err := pgschema.ApplySchemaFile(ctx, dbConfig, "desired_schema.sql", true) + +// Apply silently (no output) +err := pgschema.QuietApplySchemaFile(ctx, dbConfig, "desired_schema.sql") +``` + +## Relationship to CLI + +This API provides programmatic access to the same functionality available through the pgschema CLI commands: + +- `pgschema dump` → `pgschema.DumpSchema()` / `Client.Dump()` +- `pgschema plan` → `pgschema.GeneratePlan()` / `Client.Plan()` +- `pgschema apply` → `pgschema.ApplySchemaFile()` / `Client.Apply()` + +The CLI commands and public API are independent - using the API doesn't affect CLI behavior. \ No newline at end of file diff --git a/convenience.go b/convenience.go new file mode 100644 index 00000000..8e5e2bee --- /dev/null +++ b/convenience.go @@ -0,0 +1,79 @@ +package pgschema + +import ( + "context" + + "github.com/pgschema/pgschema/internal/plan" +) + +// DumpSchema is a convenience function to dump a database schema as a single SQL string. +func DumpSchema(ctx context.Context, dbConfig DatabaseConfig) (string, error) { + client := NewClient(dbConfig) + return client.Dump(ctx, DumpOptions{}) +} + +// DumpSchemaToFile is a convenience function to dump a database schema to a single file. +func DumpSchemaToFile(ctx context.Context, dbConfig DatabaseConfig, filePath string) error { + client := NewClient(dbConfig) + _, err := client.Dump(ctx, DumpOptions{ + File: filePath, + }) + return err +} + +// DumpSchemaMultiFile is a convenience function to dump a database schema to multiple files. +func DumpSchemaMultiFile(ctx context.Context, dbConfig DatabaseConfig, basePath string) error { + client := NewClient(dbConfig) + _, err := client.Dump(ctx, DumpOptions{ + MultiFile: true, + File: basePath, + }) + return err +} + +// GeneratePlan is a convenience function to generate a migration plan from a desired state file. +func GeneratePlan(ctx context.Context, dbConfig DatabaseConfig, desiredStateFile string) (*plan.Plan, error) { + client := NewClient(dbConfig) + return client.Plan(ctx, PlanOptions{ + File: desiredStateFile, + }) +} + +// ApplySchemaFile is a convenience function to apply a desired state schema file directly. +// This generates a plan and applies it in one operation. +func ApplySchemaFile(ctx context.Context, dbConfig DatabaseConfig, desiredStateFile string, autoApprove bool) error { + client := NewClient(dbConfig) + return client.Apply(ctx, ApplyOptions{ + File: desiredStateFile, + AutoApprove: autoApprove, + }) +} + +// ApplyPlan is a convenience function to apply a pre-generated migration plan. +func ApplyPlan(ctx context.Context, dbConfig DatabaseConfig, migrationPlan *plan.Plan, autoApprove bool) error { + client := NewClient(dbConfig) + return client.Apply(ctx, ApplyOptions{ + Plan: migrationPlan, + AutoApprove: autoApprove, + }) +} + +// QuietApplySchemaFile is like ApplySchemaFile but suppresses all output except errors. +func QuietApplySchemaFile(ctx context.Context, dbConfig DatabaseConfig, desiredStateFile string) error { + client := NewClient(dbConfig) + return client.Apply(ctx, ApplyOptions{ + File: desiredStateFile, + AutoApprove: true, + Quiet: true, + }) +} + +// QuietApplyPlan is like ApplyPlan but suppresses all output except errors. +func QuietApplyPlan(ctx context.Context, dbConfig DatabaseConfig, migrationPlan *plan.Plan) error { + client := NewClient(dbConfig) + return client.Apply(ctx, ApplyOptions{ + Plan: migrationPlan, + AutoApprove: true, + Quiet: true, + }) +} \ No newline at end of file diff --git a/examples_test.go b/examples_test.go new file mode 100644 index 00000000..9a7f2854 --- /dev/null +++ b/examples_test.go @@ -0,0 +1,347 @@ +package pgschema_test + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/pgschema/pgschema/pgschema" +) + +// ExampleDumpSchema demonstrates how to dump a database schema as a SQL string. +func ExampleDumpSchema() { + ctx := context.Background() + + dbConfig := pgschema.DatabaseConfig{ + Host: "localhost", + Port: 5432, + Database: "myapp", + User: "postgres", + Password: "password", + Schema: "public", + } + + schema, err := pgschema.DumpSchema(ctx, dbConfig) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Schema dump:") + fmt.Println(schema) +} + +// ExampleDumpSchemaToFile demonstrates how to dump a database schema to a file. +func ExampleDumpSchemaToFile() { + ctx := context.Background() + + dbConfig := pgschema.DatabaseConfig{ + Host: "localhost", + Port: 5432, + Database: "myapp", + User: "postgres", + Password: "password", + Schema: "public", + } + + err := pgschema.DumpSchemaToFile(ctx, dbConfig, "schema.sql") + if err != nil { + log.Fatal(err) + } + + fmt.Println("Schema dumped to schema.sql") +} + +// ExampleGeneratePlan demonstrates how to generate a migration plan. +func ExampleGeneratePlan() { + ctx := context.Background() + + dbConfig := pgschema.DatabaseConfig{ + Host: "localhost", + Port: 5432, + Database: "myapp", + User: "postgres", + Password: "password", + Schema: "public", + } + + plan, err := pgschema.GeneratePlan(ctx, dbConfig, "desired_schema.sql") + if err != nil { + log.Fatal(err) + } + + // Display the plan in human-readable format + fmt.Println("Migration plan:") + fmt.Println(plan.HumanColored(true)) + + // You can also get JSON representation + jsonPlan, err := plan.ToJSONWithDebug(false) + if err != nil { + log.Fatal(err) + } + fmt.Println("JSON plan:", jsonPlan) +} + +// ExampleApplySchemaFile demonstrates how to apply a schema file directly. +func ExampleApplySchemaFile() { + ctx := context.Background() + + dbConfig := pgschema.DatabaseConfig{ + Host: "localhost", + Port: 5432, + Database: "myapp", + User: "postgres", + Password: "password", + Schema: "public", + } + + // Apply with user confirmation + err := pgschema.ApplySchemaFile(ctx, dbConfig, "desired_schema.sql", false) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Schema applied successfully") +} + +// ExampleApplySchemaFileAutoApprove demonstrates how to apply a schema file without confirmation. +func ExampleApplySchemaFileAutoApprove() { + ctx := context.Background() + + dbConfig := pgschema.DatabaseConfig{ + Host: "localhost", + Port: 5432, + Database: "myapp", + User: "postgres", + Password: "password", + Schema: "public", + } + + // Apply automatically without user confirmation + err := pgschema.ApplySchemaFile(ctx, dbConfig, "desired_schema.sql", true) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Schema applied successfully") +} + +// ExampleQuietApplySchemaFile demonstrates how to apply a schema file silently. +func ExampleQuietApplySchemaFile() { + ctx := context.Background() + + dbConfig := pgschema.DatabaseConfig{ + Host: "localhost", + Port: 5432, + Database: "myapp", + User: "postgres", + Password: "password", + Schema: "public", + } + + // Apply silently without any output + err := pgschema.QuietApplySchemaFile(ctx, dbConfig, "desired_schema.sql") + if err != nil { + log.Fatal(err) + } + + // No output - useful for automation +} + +// ExampleClient demonstrates using the Client API for more control. +func ExampleClient() { + ctx := context.Background() + + dbConfig := pgschema.DatabaseConfig{ + Host: "localhost", + Port: 5432, + Database: "myapp", + User: "postgres", + Password: "password", + Schema: "public", + } + + client := pgschema.NewClient(dbConfig) + + // Dump schema with custom options + schema, err := client.Dump(ctx, pgschema.DumpOptions{ + MultiFile: true, + File: "schemas/", + }) + if err != nil { + log.Fatal(err) + } + + // Generate plan with custom application name + plan, err := client.Plan(ctx, pgschema.PlanOptions{ + File: "desired_schema.sql", + ApplicationName: "my-migration-tool", + }) + if err != nil { + log.Fatal(err) + } + + // Apply with custom settings + err = client.Apply(ctx, pgschema.ApplyOptions{ + Plan: plan, + AutoApprove: true, + LockTimeout: "30s", + NoColor: true, + }) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Migration completed") + _ = schema // Silence unused variable +} + +// ExampleExternalPlanDatabase demonstrates using an external database for plan generation. +func ExampleExternalPlanDatabase() { + ctx := context.Background() + + dbConfig := pgschema.DatabaseConfig{ + Host: "localhost", + Port: 5432, + Database: "myapp", + User: "postgres", + Password: "password", + Schema: "public", + } + + planDBConfig := pgschema.PlanDatabaseConfig{ + Host: "plan-db-host", + Port: 5432, + Database: "plan_validation_db", + User: "plan_user", + Password: "plan_password", + } + + client := pgschema.NewClient(dbConfig) + + // Generate plan using external database instead of embedded PostgreSQL + plan, err := client.Plan(ctx, pgschema.PlanOptions{ + File: "desired_schema.sql", + PlanDatabase: &planDBConfig, + }) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Generated plan using external database:") + fmt.Println(plan.HumanColored(true)) +} + +// ExampleCreateProviders demonstrates how to create and manage providers manually. +func ExampleCreateProviders() { + ctx := context.Background() + + dbConfig := pgschema.DatabaseConfig{ + Host: "localhost", + Port: 5432, + Database: "myapp", + User: "postgres", + Password: "password", + Schema: "public", + } + + // Detect PostgreSQL version + pgVersion, err := pgschema.DetectPostgresVersion(ctx, dbConfig) + if err != nil { + log.Fatal(err) + } + + // Create embedded provider manually + provider, err := pgschema.CreateEmbeddedProvider(ctx, dbConfig, pgVersion) + if err != nil { + log.Fatal(err) + } + defer provider.Stop() // Important: always stop the provider + + // Use the provider for plan generation + client := pgschema.NewClient(dbConfig) + plan, err := client.Plan(ctx, pgschema.PlanOptions{ + File: "desired_schema.sql", + DesiredStateProvider: provider, + }) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Plan generated with manually managed provider:") + fmt.Println(plan.HumanColored(true)) +} + +// ExampleEnvironmentConfiguration demonstrates using environment variables for configuration. +func ExampleEnvironmentConfiguration() { + ctx := context.Background() + + // Set environment variables + os.Setenv("PGHOST", "localhost") + os.Setenv("PGPORT", "5432") + os.Setenv("PGDATABASE", "myapp") + os.Setenv("PGUSER", "postgres") + os.Setenv("PGPASSWORD", "password") + + // Configuration can be minimal when using environment variables + dbConfig := pgschema.DatabaseConfig{ + Host: os.Getenv("PGHOST"), + Port: 5432, // Could also parse PGPORT + Database: os.Getenv("PGDATABASE"), + User: os.Getenv("PGUSER"), + Password: os.Getenv("PGPASSWORD"), + Schema: "public", + } + + // Or use the convenience functions directly + schema, err := pgschema.DumpSchema(ctx, dbConfig) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Dumped %d characters of schema\n", len(schema)) +} + +// ExampleWorkflowComplete demonstrates a complete dump/edit/plan/apply workflow. +func ExampleWorkflowComplete() { + ctx := context.Background() + + dbConfig := pgschema.DatabaseConfig{ + Host: "localhost", + Port: 5432, + Database: "myapp", + User: "postgres", + Password: "password", + Schema: "public", + } + + // Step 1: Dump current schema + fmt.Println("Step 1: Dumping current schema...") + err := pgschema.DumpSchemaToFile(ctx, dbConfig, "current_schema.sql") + if err != nil { + log.Fatal(err) + } + + // Step 2: Edit the schema file (this would be done manually) + // For this example, we'll assume the file is edited and saved as "desired_schema.sql" + + // Step 3: Generate migration plan + fmt.Println("Step 3: Generating migration plan...") + plan, err := pgschema.GeneratePlan(ctx, dbConfig, "desired_schema.sql") + if err != nil { + log.Fatal(err) + } + + // Display the plan + fmt.Println("Migration plan:") + fmt.Println(plan.HumanColored(true)) + + // Step 4: Apply the migration (in this example, we'll use auto-approve for simplicity) + fmt.Println("Step 4: Applying migration...") + err = pgschema.ApplyPlan(ctx, dbConfig, plan, true) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Migration workflow completed successfully!") +} \ No newline at end of file diff --git a/pgschema.go b/pgschema.go new file mode 100644 index 00000000..56326866 --- /dev/null +++ b/pgschema.go @@ -0,0 +1,297 @@ +// Package pgschema provides a programmatic API for PostgreSQL schema management. +// It offers Terraform-style declarative schema migration workflows with dump/plan/apply operations. +package pgschema + +import ( + "context" + "fmt" + + "github.com/pgschema/pgschema/cmd/apply" + "github.com/pgschema/pgschema/cmd/dump" + planCmd "github.com/pgschema/pgschema/cmd/plan" + "github.com/pgschema/pgschema/internal/plan" + "github.com/pgschema/pgschema/internal/postgres" +) + +// DatabaseConfig holds connection details for a PostgreSQL database. +type DatabaseConfig struct { + Host string // Database server host + Port int // Database server port + Database string // Database name + User string // Database user + Password string // Database password (optional) + Schema string // Target schema name (default: "public") +} + +// PlanDatabaseConfig holds optional configuration for using an external database +// for plan generation instead of embedded PostgreSQL. +type PlanDatabaseConfig struct { + Host string // Plan database server host + Port int // Plan database server port + Database string // Plan database name + User string // Plan database user + Password string // Plan database password (optional) +} + +// DumpOptions configures how schema dumping is performed. +type DumpOptions struct { + DatabaseConfig + MultiFile bool // Output to multiple files organized by object type + File string // Output file path (required when MultiFile is true) +} + +// PlanOptions configures how migration planning is performed. +type PlanOptions struct { + DatabaseConfig + File string // Path to desired state SQL schema file + ApplicationName string // Application name for database connection (default: "pgschema") + PlanDatabase *PlanDatabaseConfig // Optional external database for plan generation + DesiredStateProvider postgres.DesiredStateProvider // Optional pre-created provider +} + +// ApplyOptions configures how migration application is performed. +type ApplyOptions struct { + DatabaseConfig + File string // Path to desired state SQL schema file (alternative to Plan) + Plan *plan.Plan // Pre-generated plan (alternative to File) + AutoApprove bool // Apply changes without prompting for approval + NoColor bool // Disable colored output + Quiet bool // Suppress plan display and progress messages + LockTimeout string // Maximum time to wait for database locks (e.g., "30s", "5m", "1h") + ApplicationName string // Application name for database connection (default: "pgschema") + PlanDatabase *PlanDatabaseConfig // Optional external database for plan generation (only used with File) + DesiredStateProvider postgres.DesiredStateProvider // Optional pre-created provider (only used with File) +} + +// Client provides the main interface for pgschema operations. +type Client struct { + // Default configuration that can be overridden by individual operations + defaultDB DatabaseConfig + defaultApp string +} + +// NewClient creates a new pgschema client with default database configuration. +func NewClient(dbConfig DatabaseConfig) *Client { + // Set default schema if not provided + if dbConfig.Schema == "" { + dbConfig.Schema = "public" + } + + return &Client{ + defaultDB: dbConfig, + defaultApp: "pgschema", + } +} + +// Dump extracts the current database schema and returns it as a SQL string. +// If opts.MultiFile is true, files are written to disk and an empty string is returned. +func (c *Client) Dump(ctx context.Context, opts DumpOptions) (string, error) { + // Apply defaults + if opts.Host == "" { + opts.DatabaseConfig = c.defaultDB + } + if opts.Schema == "" { + opts.Schema = "public" + } + + // Convert to internal config + config := &dump.DumpConfig{ + Host: opts.Host, + Port: opts.Port, + DB: opts.Database, + User: opts.User, + Password: opts.Password, + Schema: opts.Schema, + MultiFile: opts.MultiFile, + File: opts.File, + } + + return dump.ExecuteDump(config) +} + +// Plan generates a migration plan by comparing the current database state with a desired state. +// The desired state is defined by SQL files that will be applied to a temporary database +// (embedded PostgreSQL or external database) for validation. +func (c *Client) Plan(ctx context.Context, opts PlanOptions) (*plan.Plan, error) { + // Apply defaults + if opts.Host == "" { + opts.DatabaseConfig = c.defaultDB + } + if opts.Schema == "" { + opts.Schema = "public" + } + if opts.ApplicationName == "" { + opts.ApplicationName = c.defaultApp + } + + // Convert to internal config + config := &planCmd.PlanConfig{ + Host: opts.Host, + Port: opts.Port, + DB: opts.Database, + User: opts.User, + Password: opts.Password, + Schema: opts.Schema, + File: opts.File, + ApplicationName: opts.ApplicationName, + } + + // Add plan database config if provided + if opts.PlanDatabase != nil { + config.PlanDBHost = opts.PlanDatabase.Host + config.PlanDBPort = opts.PlanDatabase.Port + config.PlanDBDatabase = opts.PlanDatabase.Database + config.PlanDBUser = opts.PlanDatabase.User + config.PlanDBPassword = opts.PlanDatabase.Password + } + + // Use provided provider or create a new one + var provider postgres.DesiredStateProvider + var err error + + if opts.DesiredStateProvider != nil { + provider = opts.DesiredStateProvider + } else { + provider, err = planCmd.CreateDesiredStateProvider(config) + if err != nil { + return nil, fmt.Errorf("failed to create desired state provider: %w", err) + } + defer provider.Stop() + } + + return planCmd.GeneratePlan(config, provider) +} + +// Apply executes a migration plan to update the database schema. +// You can either provide a pre-generated plan (opts.Plan) or a desired state file (opts.File). +func (c *Client) Apply(ctx context.Context, opts ApplyOptions) error { + // Validate that either File or Plan is provided + if opts.File == "" && opts.Plan == nil { + return fmt.Errorf("either File or Plan must be provided") + } + + // Apply defaults + if opts.Host == "" { + opts.DatabaseConfig = c.defaultDB + } + if opts.Schema == "" { + opts.Schema = "public" + } + if opts.ApplicationName == "" { + opts.ApplicationName = c.defaultApp + } + + // Convert to internal config + config := &apply.ApplyConfig{ + Host: opts.Host, + Port: opts.Port, + DB: opts.Database, + User: opts.User, + Password: opts.Password, + Schema: opts.Schema, + File: opts.File, + Plan: opts.Plan, + AutoApprove: opts.AutoApprove, + NoColor: opts.NoColor, + Quiet: opts.Quiet, + LockTimeout: opts.LockTimeout, + ApplicationName: opts.ApplicationName, + } + + // Handle desired state provider for File mode + var provider postgres.DesiredStateProvider + var err error + + if opts.File != "" && opts.DesiredStateProvider == nil { + // Need to create a provider for File mode + planConfig := &planCmd.PlanConfig{ + Host: opts.Host, + Port: opts.Port, + DB: opts.Database, + User: opts.User, + Password: opts.Password, + Schema: opts.Schema, + File: opts.File, + ApplicationName: opts.ApplicationName, + } + + // Add plan database config if provided + if opts.PlanDatabase != nil { + planConfig.PlanDBHost = opts.PlanDatabase.Host + planConfig.PlanDBPort = opts.PlanDatabase.Port + planConfig.PlanDBDatabase = opts.PlanDatabase.Database + planConfig.PlanDBUser = opts.PlanDatabase.User + planConfig.PlanDBPassword = opts.PlanDatabase.Password + } + + provider, err = planCmd.CreateDesiredStateProvider(planConfig) + if err != nil { + return fmt.Errorf("failed to create desired state provider: %w", err) + } + defer provider.Stop() + } else if opts.File != "" { + provider = opts.DesiredStateProvider + } + + return apply.ApplyMigration(config, provider) +} + +// CreateEmbeddedProvider creates an embedded PostgreSQL provider for plan generation. +// The provider must be stopped by calling Stop() when done. +func CreateEmbeddedProvider(ctx context.Context, targetDB DatabaseConfig, pgVersion postgres.PostgresVersion) (*postgres.EmbeddedPostgres, error) { + config := &planCmd.PlanConfig{ + Host: targetDB.Host, + Port: targetDB.Port, + DB: targetDB.Database, + User: targetDB.User, + Password: targetDB.Password, + Schema: targetDB.Schema, + } + + return planCmd.CreateEmbeddedPostgresForPlan(config, pgVersion) +} + +// CreateExternalProvider creates an external database provider for plan generation. +// The provider must be stopped by calling Stop() when done. +func CreateExternalProvider(ctx context.Context, targetDB DatabaseConfig, planDB PlanDatabaseConfig) (postgres.DesiredStateProvider, error) { + // Detect target database version + pgVersion, err := postgres.DetectPostgresVersionFromDB( + targetDB.Host, + targetDB.Port, + targetDB.Database, + targetDB.User, + targetDB.Password, + ) + if err != nil { + return nil, fmt.Errorf("failed to detect PostgreSQL version: %w", err) + } + + // Extract major version + var targetMajorVersion int + _, err = fmt.Sscanf(string(pgVersion), "%d.", &targetMajorVersion) + if err != nil { + return nil, fmt.Errorf("failed to parse PostgreSQL version %s: %w", pgVersion, err) + } + + externalConfig := &postgres.ExternalDatabaseConfig{ + Host: planDB.Host, + Port: planDB.Port, + Database: planDB.Database, + Username: planDB.User, + Password: planDB.Password, + TargetMajorVersion: targetMajorVersion, + } + + return postgres.NewExternalDatabase(externalConfig) +} + +// DetectPostgresVersion detects the PostgreSQL version of a database. +func DetectPostgresVersion(ctx context.Context, dbConfig DatabaseConfig) (postgres.PostgresVersion, error) { + return postgres.DetectPostgresVersionFromDB( + dbConfig.Host, + dbConfig.Port, + dbConfig.Database, + dbConfig.User, + dbConfig.Password, + ) +} \ No newline at end of file diff --git a/types.go b/types.go new file mode 100644 index 00000000..45f33b35 --- /dev/null +++ b/types.go @@ -0,0 +1,74 @@ +package pgschema + +import ( + "github.com/pgschema/pgschema/internal/plan" + "github.com/pgschema/pgschema/internal/postgres" + "github.com/pgschema/pgschema/ir" +) + +// Re-export important types for external consumption + +// Plan represents a migration plan that can be applied to a database. +type Plan = plan.Plan + +// DesiredStateProvider abstracts the desired state database provider. +// It can be implemented by either embedded PostgreSQL or an external database connection. +type DesiredStateProvider = postgres.DesiredStateProvider + +// EmbeddedPostgres represents an embedded PostgreSQL instance for plan generation. +type EmbeddedPostgres = postgres.EmbeddedPostgres + +// PostgresVersion represents a PostgreSQL version string. +type PostgresVersion = postgres.PostgresVersion + +// ExternalDatabaseConfig holds configuration for using an external database for plan generation. +type ExternalDatabaseConfig = postgres.ExternalDatabaseConfig + +// EmbeddedPostgresConfig holds configuration for starting embedded PostgreSQL. +type EmbeddedPostgresConfig = postgres.EmbeddedPostgresConfig + +// IR represents the intermediate representation of a database schema. +type IR = ir.IR + +// Schema represents a database schema with all its objects. +type Schema = ir.Schema + +// Table represents a database table with its columns, constraints, indexes, etc. +type Table = ir.Table + +// Column represents a table column. +type Column = ir.Column + +// Constraint represents a table constraint (primary key, foreign key, etc.). +type Constraint = ir.Constraint + +// Index represents a database index. +type Index = ir.Index + +// View represents a database view (regular or materialized). +type View = ir.View + +// Function represents a database function. +type Function = ir.Function + +// Procedure represents a database procedure. +type Procedure = ir.Procedure + +// Sequence represents a database sequence. +type Sequence = ir.Sequence + +// Type represents a custom database type (enum, composite, domain). +type Type = ir.Type + +// Trigger represents a database trigger. +type Trigger = ir.Trigger + +// RLSPolicy represents a row-level security policy. +type RLSPolicy = ir.RLSPolicy + +// Aggregate represents a custom aggregate function. +type Aggregate = ir.Aggregate + +// IgnoreConfig represents configuration for ignoring objects during operations. +type IgnoreConfig = ir.IgnoreConfig +