Documentation
¶
Index ¶
- Variables
- func CodegenVersion() string
- func ComputeFunctionChecksums(namedFunctions []NamedFunction) map[string]string
- func ComputeSchemaChecksum(content string) string
- func Migrate(ctx context.Context, db Execer, schemaPath string) error
- func MigrateFromString(ctx context.Context, db Execer, content string) error
- func MigrateWithOptions(ctx context.Context, db Execer, schemaPath string, opts MigrateOptions) (skipped bool, err error)
- type Execer
- type GeneratedSQL
- type InternalMigrateOptions
- type ListGeneratedSQL
- type MigrateOptions
- type MigrationRecord
- type Migrator
- func (m *Migrator) ApplyDDL(ctx context.Context) error
- func (m *Migrator) DatabaseSchema() string
- func (m *Migrator) GetLastMigration(ctx context.Context) (*MigrationRecord, error)
- func (m *Migrator) GetStatus(ctx context.Context) (*Status, error)
- func (m *Migrator) HasSchema() bool
- func (m *Migrator) MigrateWithTypes(ctx context.Context, types []TypeDefinition) error
- func (m *Migrator) MigrateWithTypesAndOptions(ctx context.Context, types []TypeDefinition, opts InternalMigrateOptions) error
- func (m *Migrator) SchemaPath() string
- func (m *Migrator) SetDatabaseSchema(databaseSchema string)
- type NamedFunction
- type Status
- type TypeDefinition
Constants ¶
This section is empty.
Variables ¶
var ( DetectCycles = schema.DetectCycles ComputeRelationClosure = schema.ComputeRelationClosure AnalyzeRelations = sqlgen.AnalyzeRelations ComputeCanGenerate = sqlgen.ComputeCanGenerate GenerateSQL = sqlgen.GenerateSQL GenerateListSQL = sqlgen.GenerateListSQL CollectFunctionNames = sqlgen.CollectFunctionNames )
Function aliases from schema and sqlgen packages.
Functions ¶
func CodegenVersion ¶
func CodegenVersion() string
CodegenVersion returns the melange version used to identify which codegen produced the SQL. Combined with function checksums, this allows skip detection and change tracking across migrations.
func ComputeFunctionChecksums ¶ added in v0.7.4
func ComputeFunctionChecksums(namedFunctions []NamedFunction) map[string]string
ComputeFunctionChecksums computes SHA256 hashes for each named function's SQL body. The returned map is stored in the migration record and used by `generate migration --db` to determine which functions have changed and need to be included in the migration.
func ComputeSchemaChecksum ¶
ComputeSchemaChecksum returns a SHA256 hash of the schema content. Used to detect schema changes for skip-if-unchanged optimization.
func Migrate ¶
Migrate parses an OpenFGA schema file and applies it to the database in one operation. This is the recommended high-level API for most applications.
The function is idempotent - safe to call on every application startup. It validates the schema, generates specialized SQL functions per relation, and applies everything atomically within a transaction (when db supports BeginTx).
Migration workflow:
- Reads the schema file at schemaPath
- Parses OpenFGA DSL using the official parser
- Validates schema (cycle detection, referential integrity)
- Generates specialized check_permission and list_accessible functions
- Applies generated SQL atomically via transaction
Example usage on application startup:
if err := migrator.Migrate(ctx, db, "schemas/schema.fga"); err != nil {
log.Fatalf("migration failed: %v", err)
}
For embedded schemas (no file I/O), use MigrateFromString. For fine-grained control (dry-run, skip optimization), use MigrateWithOptions. For programmatic use with pre-parsed types, use Migrator directly:
types, _ := parser.ParseSchema("schemas/schema.fga")
m := migrator.NewMigrator(db, "schemas/schema.fga")
err := m.MigrateWithTypes(ctx, types)
func MigrateFromString ¶
MigrateFromString parses schema content and applies it to the database. Useful for testing or when schema is embedded in the application binary.
This allows bundling the authorization schema with the application rather than reading from disk, which simplifies deployment and versioning.
Example:
//go:embed schema.fga var embeddedSchema string err := migrator.MigrateFromString(ctx, db, embeddedSchema)
The migration is idempotent and transactional (when using *sql.DB).
func MigrateWithOptions ¶
func MigrateWithOptions(ctx context.Context, db Execer, schemaPath string, opts MigrateOptions) (skipped bool, err error)
MigrateWithOptions performs migration with control over dry-run and skip behavior. Use this when you need to preview migrations, force re-application, or detect skips.
Skip detection has two phases. Phase 1 compares the schema content hash and melange version against the last migration — if both match, migration is skipped entirely (skipped=true). Phase 2 generates SQL and compares function checksums; if the output is identical to what's already applied, the functions are not re-applied (only the migration record is updated). This avoids redundant function regeneration even across melange version upgrades when the generated SQL hasn't changed.
Returns (skipped, error):
- skipped=true if migration was skipped due to unchanged schema (only when Force=false and DryRun=nil)
- error is non-nil if migration failed (parse error, validation error, DB error)
Example: Generate migration script without applying
var buf bytes.Buffer
_, err := migrator.MigrateWithOptions(ctx, db, "schemas/schema.fga", migrator.MigrateOptions{
DryRun: &buf,
})
os.WriteFile("migrations/001_authz.sql", buf.Bytes(), 0644)
Example: Force re-migration (e.g., after manual schema corruption)
skipped, err := migrator.MigrateWithOptions(ctx, db, "schemas/schema.fga", migrator.MigrateOptions{
Force: true,
})
Types ¶
type Execer ¶
type Execer interface {
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
}
Execer is the minimal interface needed for schema migration operations. Implemented by *sql.DB, *sql.Tx, and *sql.Conn.
type InternalMigrateOptions ¶
type InternalMigrateOptions struct {
DryRun io.Writer
Force bool
// Version is the melange CLI/library version (e.g., "v0.4.3").
// Recorded in melange_migrations for traceability.
Version string
// SchemaContent is the raw schema text used for checksum calculation to detect schema changes.
// If empty, skip-if-unchanged optimization is disabled.
SchemaContent string
}
InternalMigrateOptions extends MigrateOptions with internal fields.
type ListGeneratedSQL ¶
type ListGeneratedSQL = sqlgen.ListGeneratedSQL
Type aliases for cleaner code.
type MigrateOptions ¶
type MigrateOptions struct {
// DryRun outputs SQL to the provided writer without applying changes to the database.
// If nil, migration proceeds normally. Use for previewing migrations or generating migration scripts.
DryRun io.Writer
// Force re-runs migration even if schema/codegen unchanged. Use when manually fixing corrupted state or testing.
Force bool
// Version is the melange CLI/library version (e.g., "v0.4.3").
// Recorded in melange_migrations for traceability.
Version string
// DatabaseSchema is the Postgres schema where the objects will be created.
DatabaseSchema string
}
MigrateOptions controls migration behavior (public API).
type MigrationRecord ¶
type MigrationRecord struct {
MelangeVersion string
SchemaChecksum string
CodegenVersion string
FunctionNames []string
// FunctionChecksums maps function_name → SHA256(sql_body) for each function
// installed by this migration. Populated only when the database schema includes
// the function_checksums column (added in v0.7.3). Nil on records written by
// older versions; callers should treat nil as "no checksum data available" and
// fall back to full-mode generation.
FunctionChecksums map[string]string
}
MigrationRecord represents a row in the melange_migrations table.
type Migrator ¶
type Migrator struct {
// contains filtered or unexported fields
}
Migrator handles loading authorization schemas into PostgreSQL. The migrator is idempotent - safe to run on every application startup.
The migration process:
- Creates/replaces check_permission and list_accessible_* functions
- Loads generated SQL entrypoints into the database
Usage ¶
Use the convenience functions in pkg/migrator for most use cases:
import "github.com/pthm/melange/pkg/migrator" err := migrator.Migrate(ctx, db, "schemas/schema.fga")
For embedded schemas (no file I/O):
err := migrator.MigrateFromString(ctx, db, schemaContent)
Use the Migrator directly when you have pre-parsed TypeDefinitions or need fine-grained control (DDL-only, status checks, etc.):
types, _ := parser.ParseSchema("schemas/schema.fga")
m := migrator.NewMigrator(db, "schemas/schema.fga")
err := m.MigrateWithTypes(ctx, types)
func NewMigrator ¶
NewMigrator creates a new schema migrator. The schemaPath should point to an OpenFGA DSL schema file (e.g., "schemas/schema.fga"). The Execer is typically *sql.DB but can be *sql.Tx for testing.
func (*Migrator) ApplyDDL ¶
ApplyDDL applies any base schema required by Melange. With fully generated SQL entrypoints, no base DDL is required.
func (*Migrator) DatabaseSchema ¶ added in v0.8.0
DatabaseSchema returns the database schema.
func (*Migrator) GetLastMigration ¶
func (m *Migrator) GetLastMigration(ctx context.Context) (*MigrationRecord, error)
GetLastMigration returns the most recent migration record, or nil if none exists. It queries against the migrator's own database connection, making it suitable for external callers such as the generate migration command.
Internal migration code uses the private getLastMigration with an explicit Execer to participate in an in-progress transaction.
func (*Migrator) GetStatus ¶
GetStatus returns the current migration status. Useful for health checks or migration diagnostics.
func (*Migrator) HasSchema ¶
HasSchema returns true if the schema file exists. Use this to conditionally run migration or skip if not configured.
func (*Migrator) MigrateWithTypes ¶
func (m *Migrator) MigrateWithTypes(ctx context.Context, types []TypeDefinition) error
MigrateWithTypes performs database migration using pre-parsed type definitions. This is the core migration method used by the tooling package's Migrate function.
The method:
- Validates the schema (checks for cycles)
- Computes derived data (closure)
- Analyzes relations and generates specialized SQL functions
- Applies everything atomically in a transaction: - Generated specialized functions and dispatcher
This is idempotent - safe to run multiple times with the same types.
Uses a transaction if the db supports it (*sql.DB). This ensures the schema is updated atomically or not at all.
func (*Migrator) MigrateWithTypesAndOptions ¶
func (m *Migrator) MigrateWithTypesAndOptions(ctx context.Context, types []TypeDefinition, opts InternalMigrateOptions) error
MigrateWithTypesAndOptions performs database migration with options. This is the full-featured migration method that supports dry-run, two-phase skip detection, and orphan cleanup.
Skip detection has two phases:
- Phase 1: If both the schema checksum and melange version match the last migration, skip entirely without generating SQL.
- Phase 2: If phase 1 didn't skip (schema or version changed), generate the SQL and compare function checksums against the last migration. If every function is identical and no orphans exist, skip applying and only record the new migration state.
See MigrateWithTypes for basic usage without options.
func (*Migrator) SchemaPath ¶
SchemaPath returns the path to the schema file.
func (*Migrator) SetDatabaseSchema ¶ added in v0.8.0
SetDatabaseSchema sets the PostgreSQL schema for melange objects.
type NamedFunction ¶ added in v0.7.4
type NamedFunction = sqlgen.NamedFunction
NamedFunction pairs a function name with its generated SQL body.
type Status ¶
type Status struct {
// SchemaExists indicates if the schema.fga file exists on disk.
SchemaExists bool
// TuplesExists indicates if the melange_tuples relation exists (view, table, or materialized view).
// This must be created by the user to map their domain tables.
TuplesExists bool
}
Status represents the current migration state. Use GetStatus to check if the authorization system is properly configured.