sq/libsq/core/schema/schema.go
Neil O'Toole 7c56377b40
Struct alignment (#369)
* Field alignment
2024-01-27 00:11:24 -07:00

128 lines
3.4 KiB
Go

// Package schema provides functionality for modeling SQL constructs.
package schema
import (
"strings"
"github.com/neilotoole/sq/libsq/core/errz"
"github.com/neilotoole/sq/libsq/core/kind"
)
// Table models a database table definition.
type Table struct { //nolint:govet // field alignment
// Name is the table name.
Name string `json:"name"`
// PKColName is the name of the primary key column, or empty.
//
// REVISIT: this construct does not allow for composite PK.
PKColName string `json:"primary_key,omitempty"`
// AutoIncrement, if true, indicates that a PK column
// should autoincrement.
//
// REVISIT: this construct does not allow for composite PK.
AutoIncrement bool `json:"auto_increment"`
// Cols is the table's column definitions.
Cols []*Column `json:"cols"`
}
// NewTable is a convenience constructor for creating
// a simple table definition.
func NewTable(tblName string, colNames []string, colKinds []kind.Kind) *Table {
tblDef := &Table{Name: tblName}
cols := make([]*Column, len(colNames))
for i := range colNames {
cols[i] = &Column{Table: tblDef, Name: colNames[i], Kind: colKinds[i]}
}
tblDef.Cols = cols
return tblDef
}
// ColNames returns a new slice containing the names
// of t's columns.
func (t *Table) ColNames() []string {
names := make([]string, len(t.Cols))
for i, col := range t.Cols {
names[i] = col.Name
}
return names
}
// ColKinds returns a new slice containing the kinds
// of t's columns.
func (t *Table) ColKinds() []kind.Kind {
kinds := make([]kind.Kind, len(t.Cols))
for i, col := range t.Cols {
kinds[i] = col.Kind
}
return kinds
}
func (t *Table) String() string {
return t.Name + "(" + strings.Join(t.ColNames(), ",") + ")"
}
// ColsByName returns the ColDefs for each named column, or an error if any column
// is not matched.
func (t *Table) ColsByName(cols []string) ([]*Column, error) {
defs := make([]*Column, len(cols))
for i, name := range cols {
found := false
for _, def := range t.Cols {
if def.Name == name {
defs[i] = def
found = true
break
}
}
if !found {
return nil, errz.Errorf("could not find column definition {%s} in table {%s}", name, t.Name)
}
}
return defs, nil
}
// FindCol returns the named Column or nil if not found.
func (t *Table) FindCol(name string) (*Column, error) {
for _, col := range t.Cols {
if col.Name == name {
return col, nil
}
}
return nil, errz.Errorf("could not find column definition {%s} in table {%s}", name, t.Name)
}
// Column models a table column definition.
type Column struct { //nolint:govet // field alignment
Name string `json:"name"`
Table *Table `json:"-"`
Kind kind.Kind `json:"kind"`
NotNull bool `json:"not_null"`
HasDefault bool `json:"has_default"`
// Size typically applies to text fields, e.g. VARCHAR(255).
Size int `json:"size"`
Unique bool `json:"unique"`
ForeignKey *FKConstraint `json:"foreign_key,omitempty"`
}
// FKConstraint models a foreign key constraint.
type FKConstraint struct {
// RefTable is the name of the referenced parent table.
RefTable string `json:"ref_table"`
// RefCol is the name of the referenced col in the parent table.
RefCol string `json:"ref_col"`
// OnDelete is one of CASCADE or SET_NULL, defaults to CASCADE.
OnDelete string `json:"on_delete"`
// OnUpdate is one of CASCADE or SET_NULL, defaults to CASCADE.
OnUpdate string `json:"on_update"`
}