Documentation
¶
Overview ¶
Package modelschema resolves the database columns of a model struct.
It is the single place where a Go struct field is mapped to a database column: the mapping is delegated to gorm's own schema parser, so column names always match what gorm actually emits, including the column tag, the ignore markers, embedded struct lifting, and gorm's commonInitialisms handling (which a plain snake case conversion does not reproduce).
Index ¶
- func FilterableIndex(typ reflect.Type) (map[string]Column, error)
- func GoNameIndex(typ reflect.Type) (map[string]Column, error)
- func IsJSONType(typ reflect.Type) bool
- func JSONColumnSet(typ reflect.Type) map[string]struct{}
- func QueryColumnName(field reflect.StructField) string
- func TimeColumnSet(typ reflect.Type) map[string]struct{}
- type Column
- type ColumnClass
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FilterableIndex ¶
FilterableIndex returns the client-filterable columns of a model type indexed by the URL parameter name clients filter with, resolved once per type and cached. The type may be a struct or a pointer to one.
Both the parameter name and the database column name come from the parsed columns, so a filter can never name a column gorm does not emit; fields hidden from JSON stay out, because clients must not filter on them.
func GoNameIndex ¶
GoNameIndex returns the columns of a model type indexed by Go struct field name, resolved once per type and cached. The type may be a struct or a pointer to one.
func IsJSONType ¶
IsJSONType reports whether a column type stores as a JSON document. The answer comes from the type itself through gorm's GormDataTypeInterface, which is how the gorm.io/datatypes types (JSON, JSONType, JSONSlice, JSONMap) and custom JSON wrappers declare their column type. Pointers are dereferenced, and the method is looked up on both receivers.
The declared name is matched by its "json" prefix rather than by equality: the datatypes family does not spell one name (JSONMap declares "jsonmap", the others "json"), and a dialect-flavored wrapper may declare "jsonb".
Consumers use it to keep text operators away from JSON columns where a dialect is strict about operand types; see the WithQuery JSON handling in the database package.
func JSONColumnSet ¶
JSONColumnSet reports the JSON-typed columns of a model type by database name, resolved once per type and cached. The type may be a struct or a pointer to one.
Its consumers are the like-family cast in the filter renderer and the exact-match fail-closed rule in WithQuery; on a type whose columns cannot be resolved the columns render without the cast — hence nil on failure rather than an error.
func QueryColumnName ¶
func QueryColumnName(field reflect.StructField) string
QueryColumnName resolves the URL parameter name of a struct field: the query tag wins over the json tag, which wins over the field name, and the result is converted to snake case. A "-" tag is skipped rather than used as a name, so the next source decides.
This is the client-facing name only. It never decides the database column name, which comes from gorm (see Column). Column resolution above and the urlquery decode plan are its two consumers, which is what keeps a field's bare key and its operator-filter key on one naming rule.
func TimeColumnSet ¶
TimeColumnSet reports the time-typed columns of a model type by database name, resolved once per type and cached. The type may be a struct or a pointer to one.
Its consumer is the filter renderer normalizing time comparisons; on a type whose columns cannot be resolved it renders without normalization, which is the exact SQL every column renders on the dialects that compare time natively — hence nil on failure rather than an error.
Types ¶
type Column ¶
type Column struct {
GoName string // Go struct field name.
QueryName string // URL parameter name: query tag, else json tag, else field name, in snake case.
DBName string // Database column name resolved by gorm.
Type reflect.Type // Go type of the underlying struct field.
Index []int // Struct field index path, usable with reflect.Value.FieldByIndex.
Filterable bool // Whether clients may filter on the column through the URL.
}
Column is one database column of a model.
QueryName and DBName are deliberately separate: QueryName is the URL parameter clients filter by and stays a front-end contract, while DBName is whatever gorm writes into SQL. They are usually equal, and diverge when a model carries a column tag or a field name gorm renders differently.
type ColumnClass ¶
type ColumnClass int
ColumnClass is the aggregate capability a column type carries. It decides which reference gg gen writes for the column and which aggregate functions the string-name constructors accept for it, so both consumers read the same rule rather than each carrying a copy that could drift.
const ( // ColumnClassOther carries the aggregate functions that cannot be silently // wrong on any type: COUNT, COUNT DISTINCT, MIN and MAX. ColumnClassOther ColumnClass = iota // ColumnClassNumeric additionally carries SUM and AVG. ColumnClassNumeric // ColumnClassTime additionally carries time bucketing. ColumnClassTime )
func ClassifyColumn ¶
func ClassifyColumn(typ reflect.Type) ColumnClass
ClassifyColumn reports the aggregate capability of a column type. Pointers are dereferenced, since an aggregate reads the pointed-to value.
Classification reads reflect.Kind only. Recognizing decimal types through driver.Valuer looks tempting, but uuid, JSON and enum types stored as text implement it too, and treating those as numeric would reintroduce exactly the failure the split exists to prevent: MySQL and SQLite answer SUM over a text column with 0 and a warning rather than an error, so the mistake reaches a report as a plausible wrong number instead of a failure. A decimal stored as a struct is therefore classified as other, and is summed through SumOf, whose column is checked against the model schema at build time.