emit

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package emit renders generated Go code from a proven mapping.

It discovers nothing. Every fact it needs — which table an entity maps to, which columns it exposes, what each column's PostgreSQL type is and whether it is nullable — was established by gen/reconcile and arrives in a model.Mapping. The emitter's whole job is to write that down in Go, which is why it can be tested against a mapping built by hand and why generation can never disagree with the check that preceded it.

What gets generated

For each entity package, three files:

orm_tables.gen.go   the table descriptor and its typed columns
orm_meta.gen.go     the entity metadata and its scanner
orm_db.gen.go       the DB struct that wires repositories to metadata

Capabilities come from PostgreSQL

Which descriptor a column receives is decided by its PostgreSQL type, not by whatever Go type sits opposite it. A jsonb column does not get Gt merely because some Go representation of it happens to be comparable, and a text column gets ILike because PostgreSQL has ILIKE, not because Go strings have methods. The capability lattice is the schema's, and the generator is where that is enforced.

Determinism

Two runs over the same structs and the same schema produce identical bytes. Entities and columns come out in a fixed order, imports are sorted, no map is ranged without sorting, and nothing carries a timestamp or a version. The output is formatted with go/format before it is written, so a formatting change in the emitter cannot show up as a diff.

Index

Constants

View Source
const (
	// DBTypeName is the generated per-package database handle.
	DBTypeName = "DB"
	// DBCtorName constructs it.
	DBCtorName = "New"
)

The naming policy.

Public names come from the table, private ones from the entity. That split is not arbitrary: the descriptor a caller writes — Users.Email — reads as the table it queries, and the table is the thing PostgreSQL owns. The internal identifiers are per-entity because two entities that generate into one directory under one name is exactly what E014 reports, and deriving them from the entity keeps that check honest.

entity User, table public.users

Users            the table descriptor value          (from the table)
DB.Users         the repository field                (from the table)
usersSource      the table occurrence Users reads    (from the table)
userTable        the descriptor's type               (from the entity)
newUserTable     builds descriptors for one alias    (from the entity)
userMeta         the generated entity metadata       (from the entity)
userDest         the generated scanner               (from the entity)
userValue        the generated value accessor        (from the entity)

Nothing is renamed to avoid a clash. A generated identifier that collides with one the author already wrote is reported, because silently becoming Users2 would leave the caller reading documentation that describes Users.

View Source
const Header = "// Code generated by orm. DO NOT EDIT."

Header marks every generated file. The convention is the one the Go tool itself recognises, so tooling that skips generated code skips these.

Variables

View Source
var GeneratedFiles = []string{tablesFile, metaFile, relFile, dbFile}

GeneratedFiles are the names emit writes into a package. Callers that need to tell generated code from hand-written code — the collision check does — use this rather than guessing.

Functions

func IsGenerated

func IsGenerated(name string) bool

IsGenerated reports whether a file name is one emit writes.

Types

type File

type File struct {
	// Path is where the file belongs.
	Path string
	// Content is formatted Go source.
	Content []byte
}

File is one rendered, formatted source file.

func Generate

func Generate(in Input) ([]File, error)

Generate renders every generated file for every package in the mapping.

It renders all of them or none. A caller that wrote the first file and then discovered the second could not be generated would leave a package that no longer compiles, which is a worse state than the one it started in.

type Input

type Input struct {
	Mapping *model.Mapping
	// Reserved lists, per package path, the identifiers the author's own files
	// already declare. A generated name that collides with one of them is
	// reported rather than renamed.
	Reserved map[string][]string
}

Input is what generation needs. Everything in it was established by reconciliation; nothing here is discovered.

Jump to

Keyboard shortcuts

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