model

package
v0.9.0 Latest Latest
Warning

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

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

Documentation

Overview

Package model reads tanGO models: plain Go structs whose fields, through their tango:"…" struct tags, describe a table's columns, primary key, unique and indexed columns, and foreign keys.

Apps register their models with a Registry, which validates each one and records its ModelMeta and FieldMeta. The rest of tanGO (the store, the migration generator and the admin) works from that metadata. See https://tangoframework.com/docs/guides/models-and-tags/.

Index

Constants

View Source
const MaxVarcharLength = 10485760

MaxVarcharLength is the largest length tango:"varchar=n" accepts: the largest VARCHAR(n) PostgreSQL allows, so tanGO adds no ceiling of its own.

Variables

View Source
var ErrDuplicateModel = errors.New("tango: duplicate model name")

ErrDuplicateModel is returned by Registry.Register when a model with the same derived Name has already been registered.

View Source
var ErrEmbeddedField = errors.New("tango: embedded fields are not supported")

ErrEmbeddedField is returned by Registry.Register when a struct has an embedded (anonymous) field. Embedded fields are rejected outright, not flattened.

View Source
var ErrInvalidDate = errors.New("tango: invalid date")

ErrInvalidDate is returned for a calendar date that does not exist, for a year outside 0001 through 9999, and for text that is not exactly YYYY-MM-DD.

View Source
var ErrInvalidFieldTag = errors.New("tango: invalid field tag")

ErrInvalidFieldTag is returned by Registry.Register when a field's tango tag declares a string length wrongly: varchar without a positive length, a length beyond MaxVarcharLength, varchar together with text, a repeated varchar or text, or either on a field that is not a string. The error names the model and field.

View Source
var ErrInvalidRelation = errors.New("tango: invalid relation")

ErrInvalidRelation is returned by Registry.Register when a belongs_to or has_many tag sits on a field of the wrong Go type, is combined with another tango option, or has no value; and by Registry.ValidateRelations when a declared relation names a target or foreign key that does not match it. The error names the model and field.

View Source
var ErrMultiplePrimaryKeys = errors.New("tango: model has multiple primary key fields")

ErrMultiplePrimaryKeys is returned by Registry.Register when a struct has more than one field tagged tango:"pk".

View Source
var ErrNoPrimaryKey = errors.New("tango: model has no primary key field")

ErrNoPrimaryKey is returned by Registry.Register when a struct has no field tagged tango:"pk".

View Source
var ErrUnknownForeignKeyTarget = errors.New("tango: foreign key targets an unregistered model")

ErrUnknownForeignKeyTarget is returned by ValidateForeignKeys when a field's tango:"fk=X" tag names a model X that no installed app ever registered.

View Source
var ErrUnsupportedField = errors.New("tango: unsupported field type")

ErrUnsupportedField is returned by Registry.Register when a field's kind isn't supported by the metadata layer.

Functions

This section is empty.

Types

type Date added in v0.9.0

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

Date is a calendar date with no time of day and no zone. Its fields are unexported, so only the constructors build one and every Date is a real day. The zero value means no date and is distinct from 0001-01-01. Dates are comparable with ==.

func DateOf added in v0.9.0

func DateOf(t time.Time) (Date, error)

DateOf returns the calendar date that t shows in its own location, as t.Date() reports it. It never converts t to UTC. It returns ErrInvalidDate when that year is outside 0001 through 9999.

func MustDate added in v0.9.0

func MustDate(year int, month time.Month, day int) Date

MustDate is NewDate for literals and tests. It panics on an invalid date.

func NewDate added in v0.9.0

func NewDate(year int, month time.Month, day int) (Date, error)

NewDate returns the date year-month-day, or ErrInvalidDate if no such date exists or the year is outside 0001 through 9999.

func ParseDate added in v0.9.0

func ParseDate(text string) (Date, error)

ParseDate parses exactly YYYY-MM-DD. It rejects every other form, including a datetime, unpadded fields and an empty string.

func (Date) AddDays added in v0.9.0

func (d Date) AddDays(n int) (Date, error)

AddDays returns the date n days after d. The zero Date stays zero. It returns ErrInvalidDate when the result leaves years 0001 through 9999.

func (Date) After added in v0.9.0

func (d Date) After(other Date) bool

func (Date) Before added in v0.9.0

func (d Date) Before(other Date) bool

Before, After and Equal report the order of d relative to other.

func (Date) Compare added in v0.9.0

func (d Date) Compare(other Date) int

Compare returns -1, 0 or 1 as d is before, the same as, or after other. The zero Date sorts before every real date.

func (Date) Day added in v0.9.0

func (d Date) Day() int

func (Date) Equal added in v0.9.0

func (d Date) Equal(other Date) bool

func (Date) In added in v0.9.0

func (d Date) In(loc *time.Location) time.Time

In returns midnight at the start of d's calendar date in loc. The zero Date returns the zero time.Time. To take today's date in a zone, use DateOf(time.Now().In(loc)).

func (Date) IsZero added in v0.9.0

func (d Date) IsZero() bool

IsZero reports whether d is the zero value, which means no date.

func (Date) MarshalJSON added in v0.9.0

func (d Date) MarshalJSON() ([]byte, error)

MarshalJSON writes the zero Date as null and any other as "YYYY-MM-DD".

func (Date) MarshalText added in v0.9.0

func (d Date) MarshalText() ([]byte, error)

MarshalText writes the zero Date as the empty string and any other as YYYY-MM-DD.

func (Date) Month added in v0.9.0

func (d Date) Month() time.Month

func (*Date) Scan added in v0.9.0

func (d *Date) Scan(src any) error

Scan implements sql.Scanner. It accepts NULL (the zero Date), a time.Time (the calendar components in that value's own location, with no zone conversion), and an exact YYYY-MM-DD string or bytes. Anything else is an error, including a datetime string.

func (Date) String added in v0.9.0

func (d Date) String() string

String returns YYYY-MM-DD, and the empty string for the zero Date.

func (*Date) UnmarshalJSON added in v0.9.0

func (d *Date) UnmarshalJSON(data []byte) error

UnmarshalJSON reads null as the zero Date and otherwise requires an exact "YYYY-MM-DD" string. The empty string is rejected.

func (*Date) UnmarshalText added in v0.9.0

func (d *Date) UnmarshalText(text []byte) error

UnmarshalText reads the empty string as the zero Date and otherwise requires an exact YYYY-MM-DD.

func (Date) Value added in v0.9.0

func (d Date) Value() (driver.Value, error)

Value implements driver.Valuer. A nonzero date is bound as the exact string YYYY-MM-DD, which every dialect stores in a DATE column. The zero Date is NULL.

func (Date) Year added in v0.9.0

func (d Date) Year() int

Year, Month and Day return the date's components; the zero Date has zeros.

type FieldMeta

type FieldMeta struct {
	Name       string
	Type       reflect.Type
	PrimaryKey bool
	Unique     bool
	Indexed    bool
	Editable   bool
	ForeignKey string // target model name from tango:"fk=<Name>"; "" if not a foreign key
	// MaxLength is the most runes a bounded string may hold, from
	// tango:"varchar=n"; 0 means unbounded (a bare string or tango:"text").
	MaxLength int
	// JSON is true for a string field declared tango:"json": it holds JSON
	// text, which Store.Create and Store.Update check is valid. The column is
	// ordinary text.
	JSON bool
}

FieldMeta describes an exported Go struct field.

type ModelMeta

type ModelMeta struct {
	Name   string
	App    string
	Type   reflect.Type
	Fields []FieldMeta
	// Relations are the fields declared with tango:"belongs_to=…" or
	// tango:"has_many=…". They are not columns and never appear in Fields.
	Relations []RelationMeta
}

ModelMeta describes a registered Go struct model.

type Registry

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

Registry stores model metadata by Go type name.

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns an empty, ready-to-use model Registry.

func (*Registry) All

func (r *Registry) All() []ModelMeta

All returns every registered model's metadata, sorted by Name for a deterministic order.

func (*Registry) Get

func (r *Registry) Get(name string) (ModelMeta, bool)

Get returns model metadata by Go type name.

func (*Registry) Register

func (r *Registry) Register(value any) error

Register introspects a struct value and stores its model metadata. It returns an error, and registers nothing, if the struct's derived name is already registered, if it has zero or multiple primary key fields, if it has an embedded field, or if any field's kind is unsupported.

func (*Registry) SetCurrentApp

func (r *Registry) SetCurrentApp(name string)

SetCurrentApp records the name of the App currently registering models, populating ModelMeta.App for every model Register call that follows, until the next SetCurrentApp call. It is intended to be called by tango.Registry.RunRegistration immediately before invoking each app's Register callback, not by app authors directly.

func (*Registry) ValidateForeignKeys

func (r *Registry) ValidateForeignKeys() error

ValidateForeignKeys checks that every registered field's tango:"fk=X" tag names a model X that is also registered in this same Registry. It is intended to run once, after every installed app has finished registering (e.g. from tango.Check), not per-model at Register time — so InstalledApps order never constrains which app may declare a foreign key relative to the app that registers its target.

func (*Registry) ValidateRelations added in v0.9.0

func (r *Registry) ValidateRelations() error

ValidateRelations checks every relation recorded in ModelMeta.Relations against the registered models: the target must be registered, a belongs_to key must be an fk= to that target, a has_many key must be an fk= back to the owner, and each key's Go type must equal the primary key type it refers to. Like ValidateForeignKeys it runs once, after every installed app has registered, so registration order does not matter.

type RelationMeta added in v0.9.0

type RelationMeta struct {
	Name      string // Go field name, e.g. "Account"
	Direction string // the tag keyword: "belongs_to" or "has_many"
	// ForeignKey is the field the tag names. For belongs_to it is the owner's
	// field holding the target's key; for has_many it is the target's field
	// that refers back to the owner.
	ForeignKey string
	Target     string       // target model name, the Go type name of the related struct
	Type       reflect.Type // the field's Go type: *Account or []Comment
	TargetType reflect.Type // the related struct type: Account or Comment
}

RelationMeta describes a relation field: a pointer to a struct tagged belongs_to, or a slice of structs tagged has_many.

Jump to

Keyboard shortcuts

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