validation

package
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package validation provides comprehensive schema validation and safety checking.

This package exposes validation functionality for external tools to validate migration squashing results and ensure schema equivalence.

Basic Usage

Validate squashed migrations against originals:

config := validation.DefaultConfig()
config.DockerApproach = validation.ApproachTwoDatabases
config.PostgreSQLVersion = "17"

validator, err := validation.NewValidator(config)
if err != nil {
    log.Fatal(err)
}

result, err := validator.ValidateWithDocker(ctx, originalDir, squashedDir)
if err != nil {
    log.Fatal(err)
}

if result.Success {
    fmt.Println("✓ Validation passed!")
} else {
    for _, err := range result.Errors {
        fmt.Printf("Error: %s\n", err.Message)
    }
}

Validation Approaches

Three Docker-based strategies:

ApproachTwoContainers  - Most accurate, separate containers
ApproachTwoDatabases   - Balanced, one container two databases (recommended)
ApproachSchemaDiff     - Fastest, sequential application

Extension Detection

Automatic detection and installation of PostgreSQL extensions:

config := validation.DefaultConfig()
config.EnableExtensionDetection = true
config.AutoInstallExtensions = true

validator, err := validation.NewValidator(config)
// Extensions like pgcrypto, uuid-ossp will be auto-detected and installed

Custom Validation

Validate specific aspects:

config := validation.DefaultConfig()
config.Level = validation.LevelThorough
config.ValidateConstraints = true
config.ValidateDependencies = true
config.ValidatePerformance = true

Index

Constants

View Source
const (
	RuleCodeBreakingDropColumn        = internal_validation.RuleCodeBreakingDropColumn
	RuleCodeBreakingDropTable         = internal_validation.RuleCodeBreakingDropTable
	RuleCodeBreakingRenameColumn      = internal_validation.RuleCodeBreakingRenameColumn
	RuleCodeBreakingRenameTable       = internal_validation.RuleCodeBreakingRenameTable
	RuleCodeBreakingTypeChange        = internal_validation.RuleCodeBreakingTypeChange
	RuleCodeSafetyConcurrentIndex     = internal_validation.RuleCodeSafetyConcurrentIndex
	RuleCodeSafetyMissingWhere        = internal_validation.RuleCodeSafetyMissingWhere
	RuleCodeSafetyConstraintNotValid  = internal_validation.RuleCodeSafetyConstraintNotValid
	RuleCodeSafetyConstraintFlow      = internal_validation.RuleCodeSafetyConstraintFlow
	RuleCodeHygienePreferText         = internal_validation.RuleCodeHygienePreferText
	RuleCodeHygienePreferBigInt       = internal_validation.RuleCodeHygienePreferBigInt
	RuleCodeMetaUnusedIgnoreDirective = internal_validation.RuleCodeMetaUnusedIgnoreDirective
)

Rule codes (stable cross-surface identifiers)

View Source
const CatalogSnapshotContractVersion = internal_validation.CatalogSnapshotContractVersion

Variables

This section is empty.

Functions

func IsReadOnlySQL

func IsReadOnlySQL(sql string) (bool, error)

IsReadOnlySQL reports whether every statement in the script is read-only. Empty scripts (no statements after comment stripping) report false so that gates never treat unparseable-or-empty input as safe. Parse errors are returned to the caller, which must fail closed.

func ListRuleCodes

func ListRuleCodes() []string

ListRuleCodes returns all registered static validation rule codes.

func ResolveEnabledRules

func ResolveEnabledRules(baseEnabled, enableRules, disableRules []string) ([]string, error)

ResolveEnabledRules resolves a final enabled rule set from base config values plus runtime enable/disable overrides.

Types

type CatalogSnapshot

type CatalogSnapshot = internal_validation.CatalogSnapshot

CatalogSnapshot is a portable schema signature captured from a caller-owned database.

type ClassifiedStatement

type ClassifiedStatement struct {
	// SQL is the exact statement text as it appeared in the input.
	SQL string `json:"sql"`
	// Class is the side-effect classification.
	Class StatementClass `json:"class"`
	// Reason explains why a non-read-only class was assigned.
	Reason string `json:"reason,omitempty"`
}

ClassifiedStatement is one statement extracted from a SQL script together with its classification.

func ClassifyStatements

func ClassifyStatements(sql string) ([]ClassifiedStatement, error)

ClassifyStatements parses a SQL script with the real PostgreSQL parser (pg_query) and classifies every top-level statement. Statement splitting is therefore correct in the presence of dollar-quoted bodies, string literals, and comments. A parse failure returns an error; callers implementing safety gates must fail closed on error.

func (ClassifiedStatement) IsReadOnly

func (c ClassifiedStatement) IsReadOnly() bool

IsReadOnly reports whether the statement is safe on a read-only connection.

type DockerValidationResult

type DockerValidationResult = internal_validation.DockerValidationResult

DockerValidationResult represents the result of Docker-based validation

type ExternalValidationOptions

type ExternalValidationOptions = internal_validation.ExternalValidationOptions

ExternalValidationOptions identifies platform-owned schemas allowed in an otherwise empty database.

type Fix

Fix represents a suggested code change

type SchemaComparisonResult

type SchemaComparisonResult = internal_validation.SchemaComparisonResult

SchemaComparisonResult represents a comparison between two database schemas

type SchemaDiff

type SchemaDiff = internal_validation.SchemaDiff

SchemaDiff represents differences between two schemas (normalized)

func CompareCatalogSnapshots

func CompareCatalogSnapshots(original, candidate *CatalogSnapshot) (*SchemaDiff, error)

CompareCatalogSnapshots compares portable catalog snapshots without a live database.

func ValidateSchemaDiff

func ValidateSchemaDiff(schema1, schema2 string) (*SchemaDiff, error)

ValidateSchemaDiff performs a direct schema difference comparison between two schema strings. It normalizes both schemas using the default normalizer and returns the differences.

This is useful for pre-flight checks where you have the raw SQL of two schemas (e.g. pg_dump output) and want to see if they are equivalent.

type SchemaDifference

type SchemaDifference = internal_validation.SchemaDifference

SchemaDifference represents a difference between schemas

type SchemaValidator

type SchemaValidator = internal_validation.SchemaValidator

SchemaValidator performs schema validation and safety checking

func NewValidator

func NewValidator(config *ValidationConfig) *SchemaValidator

NewValidator creates a new schema validator with the given configuration

Example:

config := validation.DefaultConfig()
config.DockerApproach = validation.ApproachTwoDatabases
validator := validation.NewValidator(config)

type StatementClass

type StatementClass string

StatementClass describes the side-effect profile of a single SQL statement.

const (
	// StatementReadOnly statements cannot modify data, schema, or server state.
	StatementReadOnly StatementClass = "read_only"
	// StatementWrite statements modify data (or may do so, e.g. DO blocks,
	// procedure calls, and side-effecting functions such as setval/nextval).
	StatementWrite StatementClass = "write"
	// StatementDDL statements modify schema objects (CREATE/ALTER/DROP/...,
	// including SELECT ... INTO which creates a table).
	StatementDDL StatementClass = "ddl"
	// StatementMaintenance statements affect server or session state without
	// directly writing user data (VACUUM, SET, BEGIN/COMMIT, LOCK, ...).
	// They are NOT read-only.
	StatementMaintenance StatementClass = "maintenance"
)

type StaticValidator

type StaticValidator = internal_validation.StaticValidator

StaticValidator performs AST-based checking of SQL rules

func NewPostFlightValidator

func NewPostFlightValidator() *StaticValidator

NewPostFlightValidator returns a validator optimized for final verification (strict)

func NewPreFlightValidator

func NewPreFlightValidator() *StaticValidator

NewPreFlightValidator returns a validator optimized for initial checks (fast, hygiene focused)

func NewStaticValidator

func NewStaticValidator(config *StaticValidatorConfig) *StaticValidator

NewStaticValidator creates a new static validator with configured rules

type StaticValidatorConfig

type StaticValidatorConfig = config.StaticValidatorConfig

StaticValidatorConfig configures the static validator

func BuildStaticValidatorConfig

func BuildStaticValidatorConfig(base *StaticValidatorConfig, enableRules, disableRules []string, strict bool) (*StaticValidatorConfig, error)

BuildStaticValidatorConfig applies runtime overrides (enable/disable/strict) to a base static-validator config and returns the resolved validator config.

func CloneStaticValidatorConfig

func CloneStaticValidatorConfig(conf *StaticValidatorConfig) *StaticValidatorConfig

CloneStaticValidatorConfig returns a deep copy of the provided static-validator config. If conf is nil, it returns a copy of the engine defaults.

func DefaultStaticValidatorConfig

func DefaultStaticValidatorConfig() *StaticValidatorConfig

DefaultStaticValidatorConfig returns a copy of the engine default static-validator config.

func MergeStaticValidatorConfig

func MergeStaticValidatorConfig(base, overlay *StaticValidatorConfig) *StaticValidatorConfig

MergeStaticValidatorConfig overlays `overlay` onto `base` using engine semantics: - EnabledRules: if overlay has values, they replace base enabled rules. - RuleOptions: deep-merged (base first, then overlay keys overwrite). - TreatWarningsAsErrors: overlay value replaces base value.

If base is nil, engine defaults are used.

type ValidationApproach

type ValidationApproach = internal_validation.ValidationApproach

ValidationApproach defines Docker-based validation strategies

const (
	// ApproachTwoContainers uses separate containers for original and squashed migrations (most accurate)
	ApproachTwoContainers ValidationApproach = internal_validation.ApproachTwoContainers

	// ApproachTwoDatabases uses one container with two databases (best balance)
	ApproachTwoDatabases ValidationApproach = internal_validation.ApproachTwoDatabases

	// ApproachSchemaDiff uses sequential application and schema diff (fastest)
	ApproachSchemaDiff ValidationApproach = internal_validation.ApproachSchemaDiff
)

Validation approaches

type ValidationConfig

type ValidationConfig = internal_validation.ValidationConfig

ValidationConfig configures validation behavior

func DefaultConfig

func DefaultConfig() *ValidationConfig

DefaultConfig returns a recommended configuration for validation

type ValidationError

type ValidationError = internal_validation.ValidationError

ValidationError represents a validation error

type ValidationFix

type ValidationFix = internal_validation.ValidationFix

ValidationFix represents a fix applied during validation

type ValidationLevel

type ValidationLevel = internal_validation.ValidationLevel

ValidationLevel represents the level of validation to perform

const (
	// LevelBasic performs basic SQL parsing and syntax validation
	LevelBasic ValidationLevel = internal_validation.ValidationLevelBasic

	// LevelStandard includes basic checks plus dependency validation (recommended)
	LevelStandard ValidationLevel = internal_validation.ValidationLevelStandard

	// LevelThorough includes standard checks plus performance analysis
	LevelThorough ValidationLevel = internal_validation.ValidationLevelThorough

	// LevelComprehensive performs the complete deterministic check suite
	// (all thorough checks plus full schema comparison)
	LevelComprehensive ValidationLevel = internal_validation.ValidationLevelComprehensive
)

Validation levels

type ValidationResult

type ValidationResult = internal_validation.ValidationResult

ValidationResult represents the result of schema validation

func QuickValidate

func QuickValidate(ctx context.Context, originalDir, squashedDir string) (*ValidationResult, error)

QuickValidate is a convenience function for fast validation with minimal setup. Uses the fastest validation approach (SchemaDiff) for quick feedback.

This is ideal for CI/CD pipelines or rapid development iteration where speed is more important than exhaustive validation.

Example:

result, err := validation.QuickValidate(context.Background(), "./original", "./squashed")
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Validation: %v (took %s)\n", result.Success, result.Duration)

func ThoroughValidate

func ThoroughValidate(ctx context.Context, originalDir, squashedDir string) (*ValidationResult, error)

ThoroughValidate performs comprehensive validation with all checks enabled. Uses the most accurate validation approach (TwoContainers) for maximum confidence.

This is recommended for production releases, final validation before deployment, or when schema accuracy is critical.

Example:

result, err := validation.ThoroughValidate(context.Background(), "./original", "./squashed")
if err != nil {
    log.Fatal(err)
}
if !result.Success {
    log.Printf("Found %d errors and %d warnings\n", len(result.Errors), len(result.Warnings))
}

func ValidateSchemaEquivalence

func ValidateSchemaEquivalence(
	ctx context.Context,
	originalDir string,
	squashedDir string,
	config *ValidationConfig,
) (*ValidationResult, error)

ValidateSchemaEquivalence is a convenience function that validates whether squashed migrations produce the same schema as the original migrations.

This is a high-level helper that sets up validation with recommended defaults and returns a simple pass/fail result with detailed comparison information.

Parameters:

  • ctx: Context for cancellation and timeouts
  • originalDir: Directory containing original migration files
  • squashedDir: Directory containing squashed migration files
  • config: Optional validation configuration (uses defaults if nil)

Returns:

  • ValidationResult with Success, Errors, Warnings, and SchemaComparison
  • Error if validation infrastructure fails (Docker, parsing, etc.)

Example:

ctx := context.Background()
result, err := validation.ValidateSchemaEquivalence(ctx, "./original", "./squashed", nil)
if err != nil {
    log.Fatalf("Validation infrastructure error: %v", err)
}

if result.Success {
    fmt.Println("✓ Schemas are equivalent!")
} else {
    fmt.Println("✗ Schema differences found:")
    for _, diff := range result.SchemaComparison.Differences {
        fmt.Printf("  - %s: %s\n", diff.Type, diff.Description)
    }
}

type ValidationWarning

type ValidationWarning = internal_validation.ValidationWarning

ValidationWarning represents a validation warning

type Violation

type Violation = internal_validation.Violation

Violation represents a rule violation found during static analysis

type ViolationCategory

type ViolationCategory = internal_validation.ViolationCategory

ViolationCategory represents the severity/type of a violation

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL