scaffold

package
v0.55.0 Latest Latest
Warning

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

Go to latest
Published: Sep 28, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrProjectNameRequired reports a missing project name.
	ErrProjectNameRequired = errors.New("project name is required")
	// ErrDirectoryNotEmpty reports that the target directory already holds files.
	ErrDirectoryNotEmpty = errors.New("target directory is not empty")
	// ErrInvalidModulePath reports a go.mod module path the Go tool would reject.
	ErrInvalidModulePath = errors.New("invalid module path")
)
View Source
var (
	// ErrInvalidDependency reports a malformed --deps entry.
	ErrInvalidDependency = errors.New("invalid dependency, expected field:Type")
	// ErrServiceNameRequired reports an empty service name.
	ErrServiceNameRequired = errors.New("service name is required")
)
View Source
var ErrFileExists = errors.New("file already exists (pass --force to overwrite)")

ErrFileExists reports that a generated file is already present. Scaffolding hands a file to the developer the moment it is written, so overwriting one has to be asked for.

View Source
var ErrInvalidSearchSpec = errors.New("invalid --search entry, expected column:operator")

ErrInvalidSearchSpec reports a malformed --search entry.

View Source
var ErrUnknownOperation = errors.New("unknown crud operation")

ErrUnknownOperation reports an operation name the generator cannot render.

Functions

func Command

func Command() *cobra.Command

Command returns the `new` command group: the scaffolding half of the CLI.

The split from the generate-* commands is the contract with the developer. Everything under `new` is written once and then belongs to them — no generated-file header, no expectation that it stays machine-shaped — while the generate-* commands own their output forever and overwrite it on every run.

func GenerateProject

func GenerateProject(req ProjectRequest, plan *Plan) error

GenerateProject plans every file a fresh project starts with.

func GenerateResource

func GenerateResource(ctx context.Context, proj *project.Project, req ResourceRequest, plan *Plan) error

GenerateResource derives a model, a payload and an API resource from a database table, and registers them in the module's registries.

func GenerateService

func GenerateService(proj *project.Project, req ServiceRequest, plan *Plan) error

GenerateService writes a service skeleton and registers it with its module.

func KnownOperations

func KnownOperations() []string

KnownOperations lists every renderable operation name, sorted, for help text and error messages.

Types

type Dependency

type Dependency struct {
	// Field is the struct field name.
	Field string
	// Type is the field's type as written in Go source.
	Type string
}

Dependency is one constructor-injected field of a generated service.

type Entity

type Entity struct {
	// Module is the business module the entity belongs to, possibly nested.
	Module string
	// Table is the physical table name.
	Table string
	// Alias is the table's query alias.
	Alias string
	// Name is the Go type name.
	Name string
	// Snake is the entity's snake_case name, used for file and resource names.
	Snake string
	// Comment is the table comment, rendered as the model's doc comment.
	Comment string
	// AuditEmbed is the framework audit mixin the table's columns matched,
	// empty when none did.
	AuditEmbed string
	// HasIDField reports whether the model ends up with a single string ID
	// field, which is what decides if the create/update payload carries one.
	HasIDField bool
	// KeylessTable reports that the table declares no primary key, so nothing
	// the generator writes can give crud one.
	KeylessTable bool
	// Fields are the business columns, audit columns excluded.
	Fields []Field
	// ResourceName is the api.NewRPCResource name.
	ResourceName string
	// Ops are the CRUD operations the resource embeds.
	Ops []Operation
	// AuditUserModel is the qualified WithAuditUserNames argument, empty when
	// the project declares none.
	AuditUserModel string
	// AuditUserModelImport is the package AuditUserModel is selected from.
	AuditUserModelImport string
	// AuditUserModelAlias is the local name that import takes, empty when the
	// package name does not collide with the entity's own model package.
	AuditUserModelAlias string
	// UnmappedColumns names columns whose declared type this tool did not
	// recognize and therefore typed as string.
	UnmappedColumns []string
}

Entity is a table reduced to everything the templates need to render a model, a payload and a resource.

func BuildEntity

func BuildEntity(table *schema.TableSchema, opts EntityOptions) Entity

BuildEntity reduces an inspected table into the entity the templates render.

func (Entity) SearchFields

func (e Entity) SearchFields() []Field

SearchFields are the fields a generated search payload carries.

type EntityOptions

type EntityOptions struct {
	// Module is the business module the entity is generated into.
	Module string
	// Entity is the snake_case entity name.
	Entity string
	// Alias overrides the derived table alias.
	Alias string
	// Search decides which columns become search criteria; nil means every
	// scalar column does.
	Search map[string]searchOperator
}

EntityOptions carry the caller's choices into entity construction.

type Field

type Field struct {
	// Column is the database column name.
	Column string
	// Name is the Go field name.
	Name string
	// JSONName is the field's json tag name.
	JSONName string
	// Type is the Go type spelling, already carrying a pointer for a nullable
	// column.
	Type string
	// Nullable reports whether the column accepts NULL, which decides both the
	// pointer and the validation prefix.
	Nullable bool
	// Label is the column comment, surfaced through the label tag that drives
	// validation messages and export headers.
	Label string
	// MaxLength is the declared character bound, zero when unbounded.
	MaxLength int
	// PrimaryKey reports whether the column is part of the table's primary
	// key and therefore needs a bun pk tag on the generated field.
	PrimaryKey bool
	// Search is the search operator this field takes in a search payload.
	Search searchOperator
	// ImportPath is the package the field's type needs, empty for builtins.
	ImportPath string
}

Field is one generated struct field derived from a table column.

func (Field) ModelTag

func (f Field) ModelTag() string

ModelTag renders the struct tag of the field's model declaration.

func (Field) ParamsTag

func (f Field) ParamsTag() string

ParamsTag renders the struct tag of the field's create/update declaration. It differs from the model tag by never marking a field omitempty: a params struct is what the client sends, and a nil there means "not supplied", which is the distinction the pointer already carries.

func (Field) SearchTag

func (f Field) SearchTag() string

SearchTag renders the struct tag of the field's search declaration.

func (Field) SearchType

func (f Field) SearchType() string

SearchType is the field's type inside a search payload, where every criterion is optional regardless of the column's nullability.

type Operation

type Operation struct {
	// Field is the struct field and embedded interface name.
	Field string
	// Embed is the full embedded type, such as
	// crud.FindPage[model.Holiday, payload.HolidaySearch].
	Embed string
	// Init is the complete initializer, constructor plus builder chain.
	Init string
}

Operation is a rendered crud operation, ready for the resource template.

type Plan

type Plan struct {
	// contains filtered or unexported fields
}

Plan collects every effect a scaffolding command would have, so the whole command can be previewed with --dry-run and so a failure part-way through planning leaves nothing half-written on disk.

func NewPlan

func NewPlan(proj *project.Project) *Plan

NewPlan starts an empty plan for a project.

func (*Plan) AddContent

func (p *Plan) AddContent(path string, content []byte)

AddContent plans a file whose content the caller has already produced, overwriting what is there. Use it for a file the plan itself patched rather than rendered.

func (*Plan) AddFile

func (p *Plan) AddFile(path string, content []byte, force bool)

AddFile plans a generated file. An existing path is skipped unless force is set, and an unchanged path is skipped either way so re-running a generator reports honestly instead of touching mtimes.

func (*Plan) AddPatch

func (p *Plan) AddPatch(path string, patch func(*gopatch.File) (bool, error)) error

AddPatch plans an edit to an existing file. The patch runs now, against the file's current contents, so planning surfaces a malformed target before any write happens; a patch reporting no change is recorded as a skip.

func (*Plan) AddPatchOrCreate

func (p *Plan) AddPatchOrCreate(path, initial string, patch func(*gopatch.File) (bool, error)) error

AddPatchOrCreate is AddPatch over a file that may not exist yet, starting from initial when it does not. It is what lets a generator target a module that has not been created: the registry files a resource must be appended to are the same files that define the module, so creating them on demand is the difference between "generate into a new module" working and failing with a missing-file error the developer has to resolve by hand.

func (*Plan) Apply

func (p *Plan) Apply(out io.Writer, output *termenv.Output) error

Apply writes every planned change, creating parent directories as needed, and reports the plan to out.

func (*Plan) Empty

func (p *Plan) Empty() bool

Empty reports whether the plan would change nothing.

func (*Plan) Note

func (p *Plan) Note(message string)

Note records something the generator could not do and the developer must, so a step it had to skip is reported rather than silently dropped.

func (*Plan) Preview

func (p *Plan) Preview(out io.Writer, output *termenv.Output)

Preview reports the plan without writing anything, printing the full content of each new file so --dry-run shows what would land rather than only where.

type ProjectRequest

type ProjectRequest struct {
	// Name is the application name.
	Name string
	// Module is the go.mod module path, defaulting to Name.
	Module string
	// Dir is the directory to create, defaulting to Name under the working
	// directory.
	Dir string
	// WithExample generates the starter business module.
	WithExample bool
	// SkipTidy leaves dependency resolution to the developer.
	SkipTidy bool
	// SkipGit leaves repository initialization to the developer.
	SkipGit bool
}

ProjectRequest is one `new project` invocation.

type ResourceRequest

type ResourceRequest struct {
	// Table is the physical table to derive the entity from.
	Table string
	// Module is the business module to generate into.
	Module string
	// Entity overrides the entity name derived from the table.
	Entity string
	// Alias overrides the derived table alias.
	Alias string
	// Ops overrides the project's configured operation set.
	Ops []string
	// Search overrides which columns become search criteria; nil applies the
	// default of every scalar column.
	Search map[string]searchOperator
	// ConfigPath overrides where application.toml is read from.
	ConfigPath string
	// Source names the data source to inspect; empty means primary.
	Source string
	// Force overwrites generated files that already exist.
	Force bool
}

ResourceRequest is one `new resource` invocation.

type ServiceRequest

type ServiceRequest struct {
	// Name is the service name, with or without the Service suffix.
	Name string
	// Module is the business module to generate into.
	Module string
	// Deps are the constructor-injected dependencies.
	Deps []Dependency
	// Force overwrites the service file if it already exists.
	Force bool
}

ServiceRequest is one `new service` invocation.

Jump to

Keyboard shortcuts

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