codegen

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Jun 15, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DiffSchemas added in v0.3.0

func DiffSchemas(old, newSchema Schema, dialect string) (upSQL, downSQL string)

DiffSchemas compares an old (previous snapshot) schema against a new (desired) schema and produces incremental up/down migration SQL containing only the changes. It returns ("", "") when the schemas are equivalent.

Coverage (up order; down is the sensible inverse):

  • new enums (Postgres only): CREATE TYPE / down DROP TYPE
  • new tables: CREATE TABLE + indexes / down DROP TABLE
  • dropped tables: DROP TABLE / down recreate
  • per-table column add/drop, type changes, NOT NULL changes
  • per-table index add/drop

SQLite cannot ALTER COLUMN TYPE or SET/DROP NOT NULL; those changes are emitted as clearly-marked WARNING comments rather than silently skipped. Column renames are not detected and surface as a drop + add.

func EmitDBFile

func EmitDBFile(models []ModelInfo, dbPkgName string) string

EmitDBFile generates the aggregated DB struct file that wires up all repositories. dbPkgName is the Go package name for the output file (e.g. "db").

func EmitModelFile

func EmitModelFile(m ModelInfo) string

EmitModelFile generates the complete per-model _drel.go file content.

func EmitModelFileChecked

func EmitModelFileChecked(m ModelInfo) (string, error)

EmitModelFileChecked generates the per-model file, returning an error if the model uses unsupported features. Multi-column value objects are fully supported (see emitMultiValHelpers / expanded scan/diff/DDL).

func Generate

func Generate(configPath string) error

Generate runs the full code generation pipeline atomically: it loads config, scans packages, validates the model set, emits and gofmts every output file in memory, and only then writes anything to disk (write-to-temp + rename). A failure at any step before the write phase leaves the working tree untouched.

Stale generated *_drel.go files that would obstruct the package scan (because they reference deleted model types) are removed before scanning, but their contents are saved so they can be restored if any later step fails. After a successful write, truly stale files that no longer back any scanned model are permanently removed.

func GenerateCreateTable

func GenerateCreateTable(m ModelInfo, fks map[string]string, dialect string) string

GenerateCreateTable emits a CREATE TABLE statement for a single model. fks maps column names to referenced table names for foreign key constraints. dialect controls SQL type mappings and syntax ("postgres" or "sqlite").

func GenerateDropSchema

func GenerateDropSchema(models []ModelInfo) string

GenerateDropSchema emits DROP TABLE statements in reverse order to respect foreign key dependencies.

func GenerateSchema

func GenerateSchema(models []ModelInfo, dialect string) string

GenerateSchema emits the full schema DDL for a slice of models, including enum type definitions, foreign key constraints, and many-to-many pivot tables. dialect controls SQL type mappings and syntax ("postgres" or "sqlite").

func GenerateWatch added in v0.5.0

func GenerateWatch(ctx context.Context, configPath string, pollInterval time.Duration) error

GenerateWatch runs Generate once, then re-runs it whenever a .go source file under the scanned package directories changes. It blocks until ctx is cancelled, at which point it returns nil. Generated *_drel.go files and the DB output file are ignored when detecting changes so regeneration never self-triggers. pollInterval controls the mtime poll cadence; pass 0 for the default (500ms). Watch uses only the standard library (no fsnotify) to honour the zero-runtime-dependency rule.

func GoTypeToSQL

func GoTypeToSQL(goType string, dialect string) string

GoTypeToSQL maps a Go type string to its corresponding SQL type for the given dialect. Pointer types are unwrapped to their base type. Unknown types default to "text"/"TEXT". Supported dialects: "postgres" (default), "sqlite".

func ResolveModuleRoot added in v0.5.0

func ResolveModuleRoot(startDir string) string

ResolveModuleRoot finds the Go module root (the nearest ancestor directory containing go.mod) by walking up from startDir. It falls back to startDir when no go.mod is found, preserving the prior behaviour for configs that already sit at the module root.

func SaveSnapshot added in v0.3.0

func SaveSnapshot(path string, s Schema) error

SaveSnapshot writes the schema to path as pretty-printed JSON, creating the parent directory if needed. The file is written with 0644 permissions.

func ValidateModels added in v0.5.0

func ValidateModels(models []ModelInfo) error

ValidateModels checks the aggregated model set for problems that would otherwise produce non-compiling or invalid generated code, and that the existing emit pipeline silently tolerated:

  • two models that generate the same DB-struct field name (pluralize(Name)), which yields duplicate struct fields that do not compile;
  • a relation field whose target model is not in the scanned set (typo or a package missing from drel.yaml), which was silently dropped;
  • a model with no db-mapped columns, which emits an empty INSERT column list and an invalid `INSERT INTO t () VALUES ()` at runtime.

It is called from Generate before any file is written so a failure leaves the working tree untouched.

Types

type Column added in v0.3.0

type Column struct {
	Name    string `json:"name"`
	Type    string `json:"type"`
	NotNull bool   `json:"notNull"`
	Default string `json:"default,omitempty"`
	Check   string `json:"check,omitempty"`
	Ref     string `json:"ref,omitempty"`
	PK      bool   `json:"pk,omitempty"`
}

Column describes a single column. Type is the dialect-resolved SQL type (already including any quoted enum type name). Ref, when non-empty, is the referenced table name for a foreign key on this column (always referencing that table's "id").

type Config

type Config struct {
	Packages []string     `yaml:"packages"`
	Output   OutputConfig `yaml:"output"`
	Dialect  string       `yaml:"dialect"`
	// Seed is an optional path to a Go main package that seeds the database.
	// `drel seed` runs it with `go run`, passing through DATABASE_URL.
	Seed string `yaml:"seed"`
}

func LoadConfig

func LoadConfig(path string) (*Config, error)

type EnumDef added in v0.3.0

type EnumDef struct {
	Name     string   `json:"name"`
	Values   []string `json:"values"`
	IsInt    bool     `json:"isInt,omitempty"`
	BaseType string   `json:"baseType,omitempty"`
}

EnumDef describes an enum type. Name is the lower-cased local Go type name. String enums are emitted as a Postgres CREATE TYPE; integer enums never get a CREATE TYPE (they map to an integer column + CHECK) and are excluded here.

type FieldInfo

type FieldInfo struct {
	Name             string
	GoType           string
	ColumnName       string
	IsExported       bool
	RelTag           string
	Relation         *RelationFieldInfo
	IsVO             bool     // implements sql.Scanner + driver.Valuer (single-column VO)
	VOBaseType       string   // single-column VO: underlying basic Go type (e.g. "string", "int64"); empty if not derivable
	HasEqual         bool     // single-column VO defines an Equal(T) bool method usable for diffing
	IsComparable     bool     // single-column VO's Go type is comparable with == / != (types.Comparable)
	HasIsZero        bool     // single-column VO defines IsZero() bool, enabling the zero<->NULL bridge
	IsMultiColVO     bool     // implements drel.MultiColumnMapper (multi-column VO)
	MultiColPrefix   string   // db tag used as column prefix for multi-column VOs
	MultiColNames    []string // expanded sub-column names from the db tag (multi-column VOs)
	MultiColTypes    []string // resolved SQL types per sub-column (default "text"; multi-column VOs)
	LocalGoType      string   // type name without package qualifier, for same-package generated code
	TypePkgPath      string   // import path of the field type's package (empty for primitives/same-package)
	IsPointer        bool     // whether the field is a pointer type
	IsEnum           bool
	EnumValues       []string
	EnumIsInt        bool   // enum's underlying basic kind is integer (not string)
	EnumBaseType     string // Go base type of the enum, e.g. "string", "int", "int64"
	IsNamedPrimitive bool   // named type over a comparable basic kind with no enum consts (e.g. type Priority int)
	Unique           bool   // db tag option: unique index on this column
	Indexed          bool   // db tag option: index on this column
	IndexName        string // explicit index name (db:"...,index=name"); fields sharing a name form a composite index
	CheckExpr        string // db tag option: column CHECK constraint expression (db:"...,check=expr")
	Default          string // db tag option: column DEFAULT value (db:"...,default=expr")
	TypeOverride     string // db tag option: explicit SQL type (db:"...,type=jsonb"); overrides inference
	IsJSON           bool   // map/slice/struct mapped as JSON/jsonb (default for non-primitive, non-VO, non-enum container types)
	IsArray          bool   // slice field (JSON array by default; native T[] when TypeOverride is set on Postgres)
}

type Index added in v0.3.0

type Index struct {
	Name    string   `json:"name"`
	Columns []string `json:"columns"`
	Unique  bool     `json:"unique,omitempty"`
}

Index describes a single (possibly composite, possibly unique) index.

type ModelInfo

type ModelInfo struct {
	Name          string
	PkgPath       string
	PkgName       string
	PKType        string // display type for generated code (e.g., "int", "uuid.UUID")
	PKTypeFull    string // fully qualified (e.g., "github.com/google/uuid.UUID")
	PKTypePkg     string // import path for external PK types (empty for primitives)
	TableName     string
	Fields        []FieldInfo
	HasSoftDelete bool
	HasVersioned  bool
	HasAudit      bool
	Dir           string // filesystem directory of the package
}

func ScanPackages

func ScanPackages(patterns []string, dir ...string) ([]ModelInfo, error)

type OutputConfig

type OutputConfig struct {
	DB         string `yaml:"db"`
	Migrations string `yaml:"migrations"`
}

type RelationFieldInfo

type RelationFieldInfo struct {
	Type        string // "has_many", "has_one", "belongs_to", "many_to_many"
	FK          string // foreign key column
	JoinTable   string // for many_to_many
	RefColumn   string // target FK column in pivot table (many-to-many)
	TargetModel string // target model name for foreign key resolution
}

RelationFieldInfo holds parsed relationship metadata from a `rel:"..."` struct tag.

type Schema added in v0.3.0

type Schema struct {
	Tables []Table   `json:"tables"`
	Enums  []EnumDef `json:"enums,omitempty"`
}

Schema is a JSON-serializable, dialect-resolved logical representation of the full database schema. It is the canonical input to the structured migration diff engine and the persisted migration snapshot.

func BuildSchema added in v0.3.0

func BuildSchema(models []ModelInfo, dialect string) Schema

BuildSchema produces the full logical schema for the given models and dialect. It includes all tables (models + many-to-many pivots), all columns (user columns + trait columns), all indexes (explicit/unique/composite from db tag options), and enum type definitions (Postgres only).

Ordering is deterministic: tables preserve model declaration order (pivots appended after, in discovery order), columns preserve PK-first then field order then trait order, and indexes within a table are sorted by name.

func LoadSnapshot added in v0.3.0

func LoadSnapshot(path string) (Schema, bool, error)

LoadSnapshot reads a schema snapshot from path. The returned bool is false when the file does not exist (which is not treated as an error).

type Table added in v0.3.0

type Table struct {
	Name       string   `json:"name"`
	Columns    []Column `json:"columns"`
	Indexes    []Index  `json:"indexes,omitempty"`
	PrimaryKey []string `json:"primaryKey,omitempty"`
}

Table describes a single relation (table or pivot) and its columns/indexes. PrimaryKey, when non-empty, declares a composite (table-level) primary key used by many-to-many pivot tables; for regular tables the primary key is the single column whose PK field is true.

Jump to

Keyboard shortcuts

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