Documentation
¶
Overview ¶
Package structable /* Structable is a struct-to-table mapper for databases.
Index ¶
- Constants
- type DbRecorder
- func (s *DbRecorder) Bind(tableName string, ar Record) Recorder
- func (s *DbRecorder) Builder() *squirrel.StatementBuilderType
- func (s *DbRecorder) Columns(includeKeys bool) []string
- func (s *DbRecorder) DB() squirrel.DBProxyBeginner
- func (s *DbRecorder) Delete() error
- func (s *DbRecorder) Driver() string
- func (s *DbRecorder) Exists() (bool, error)
- func (s *DbRecorder) ExistsWhere(pred interface{}, args ...interface{}) (bool, error)
- func (s *DbRecorder) FieldReferences(withKeys bool) []interface{}
- func (s *DbRecorder) Init(db squirrel.DBProxyBeginner, flavor string)
- func (s *DbRecorder) Insert() error
- func (s *DbRecorder) Interface() interface{}
- func (s *DbRecorder) Key() []string
- func (s *DbRecorder) Load() error
- func (s *DbRecorder) LoadWhere(pred interface{}, args ...interface{}) error
- func (s *DbRecorder) TableName() string
- func (s *DbRecorder) Transaction(f func() error) error
- func (s *DbRecorder) Update() error
- func (s *DbRecorder) WhereIds() map[string]interface{}
- type Describer
- type Haecceity
- type Loader
- type Model
- type Record
- type Recorder
- type Saver
- type WhereFunc
Constants ¶
const StructableTag = "stbl"
StructableTag 'stbl' is the main tag used for annotating Structable Records.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type DbRecorder ¶
type DbRecorder struct {
// contains filtered or unexported fields
}
DbRecorder Implements the Recorder interface, and stores data in a DB.
func New ¶
func New(db squirrel.DBProxyBeginner, flavor string) *DbRecorder
New creates a new DbRecorder.
(The squirrel.DBProxy interface defines the functions normal for a database connection or a prepared statement cache.)
func (*DbRecorder) Bind ¶
func (s *DbRecorder) Bind(tableName string, ar Record) Recorder
Bind binds a DbRecorder to a Record.
This takes a given structable.Record and binds it to the recorder. That means that the recorder will track all changes to the Record.
The table name tells the recorder which database table to link this record to. All storage operations will use that table.
func (*DbRecorder) Builder ¶
func (s *DbRecorder) Builder() *squirrel.StatementBuilderType
Builder returns the statement builder for this recorder.
func (*DbRecorder) Columns ¶
func (s *DbRecorder) Columns(includeKeys bool) []string
Columns returns the names of the columns on this table.
If includeKeys is false, the columns that are marked as keys are omitted from the returned list.
func (*DbRecorder) DB ¶
func (s *DbRecorder) DB() squirrel.DBProxyBeginner
DB returns the database (DBProxyBeginner) for this recorder.
func (*DbRecorder) Delete ¶
func (s *DbRecorder) Delete() error
Delete deletes the record from the underlying table.
The fields on the present record will remain set, but not saved in the database.
func (*DbRecorder) Driver ¶
func (s *DbRecorder) Driver() string
Driver returns the string name of the driver.
func (*DbRecorder) Exists ¶
func (s *DbRecorder) Exists() (bool, error)
Exists returns `true` if and only if there is at least one record that matches the primary keys for this Record.
If the primary key on the Record has no value, this will look for records with no value (or the default value).
func (*DbRecorder) ExistsWhere ¶
func (s *DbRecorder) ExistsWhere(pred interface{}, args ...interface{}) (bool, error)
ExistsWhere returns `true` if and only if there is at least one record that matches one (or multiple) conditions.
Conditions are expressed in the form of predicates and expected values that together build a WHERE clause. See Squirrel's Where(pred, args)
func (*DbRecorder) FieldReferences ¶
func (s *DbRecorder) FieldReferences(withKeys bool) []interface{}
FieldReferences returns a list of references to fields on this object.
If withKeys is true, fields that compose the primary key will also be included. Otherwise, only non-primary key fields will be included.
This is used for processing SQL results:
dest := s.FieldReferences(false) q := s.builder.Select(s.Columns(false)...).From(s.table) err := q.QueryRow().Scan(dest...)
func (*DbRecorder) Init ¶
func (s *DbRecorder) Init(db squirrel.DBProxyBeginner, flavor string)
Init initializes a DbRecorder
func (*DbRecorder) Insert ¶
func (s *DbRecorder) Insert() error
Insert puts a new record into the database.
This operation is particularly sensitive to DB differences in cases where AUTO_INCREMENT is set on a member of the Record.
func (*DbRecorder) Interface ¶
func (s *DbRecorder) Interface() interface{}
func (*DbRecorder) Key ¶
func (s *DbRecorder) Key() []string
Key gets the string names of the fields used as primary key.
func (*DbRecorder) Load ¶
func (s *DbRecorder) Load() error
Load selects the record from the database and loads the values into the bound Record.
Load uses the table's PRIMARY KEY(s) as the sole criterion for matching a record. Essentially, it is akin to `SELECT * FROM table WHERE primary_key = ?`.
This modifies the Record in-place. Other than the primary key fields, any other field will be overwritten by the value retrieved from the database.
func (*DbRecorder) LoadWhere ¶
func (s *DbRecorder) LoadWhere(pred interface{}, args ...interface{}) error
LoadWhere loads an object based on a WHERE clause.
This can be used to define alternate loaders:
func (s *MyStructable) LoadUuid(uuid string) error {
return s.LoadWhere("uuid = ?", uuid)
}
This functions similarly to Load, but with the notable difference that it loads the entire object (it does not skip keys used to do the lookup).
func (*DbRecorder) TableName ¶
func (s *DbRecorder) TableName() string
TableName returns the table name of this recorder.
func (*DbRecorder) Transaction ¶
func (s *DbRecorder) Transaction(f func() error) error
func (*DbRecorder) Update ¶
func (s *DbRecorder) Update() error
Update updates the values on an existing entry.
This updates records where the Record's primary keys match the record in the database. Essentially, it runs `UPDATE table SET names=values WHERE id=?`
If no entry is found, update will NOT create (INSERT) a new record.
func (*DbRecorder) WhereIds ¶
func (s *DbRecorder) WhereIds() map[string]interface{}
WhereIds gets a list of names and a list of values for all columns marked as primary keys.
type Describer ¶
type Describer interface {
// Columns gets the columns on this table.
Columns(bool) []string
// FieldReferences gets references to the fields on this object.
FieldReferences(bool) []interface{}
// WhereIds returns a map of ID fields to (current) ID values.
//
// This is useful to quickly generate where clauses.
WhereIds() map[string]interface{}
// TableName returns the table name.
TableName() string
// Builder returns the builder
Builder() *squirrel.StatementBuilderType
// DB returns a DB-like handle.
DB() squirrel.DBProxyBeginner
Driver() string
Init(d squirrel.DBProxyBeginner, flavor string)
Transaction(func() error) error
}
Describer is a structable object that can describe its table structure.
type Haecceity ¶
type Haecceity interface {
// Exists verifies that a thing exists and is of this type.
// This uses the PRIMARY_KEY to verify that a record exists.
Exists() (bool, error)
// ExistsWhere verifies that a thing exists and is of the expected type.
// It takes a WHERE clause, and it needs to gaurantee that at least one
// record matches. It need not assure that *only* one item exists.
ExistsWhere(interface{}, ...interface{}) (bool, error)
}
Haecceity indicates whether a thing exists.
Actually, it is responsible for testing whether a thing exists, and is what we think it is.
type Loader ¶
type Loader interface {
// Load loads the entire Record using the value of the PRIMARY_KEY(s)
// This will only fetch columns that are mapped on the bound Record. But you can think of it
// as doing something like this:
//
// SELECT * FROM bound_table WHERE id=? LIMIT 1
//
// And then mapping the result to the currently bound Record.
Load() error
// LoadWhere Load by a WHERE-like clause. See Squirrel's Where(pred, args)
LoadWhere(interface{}, ...interface{}) error
}
type Recorder ¶
type Recorder interface {
// Bind this Recorder to a table and to a Record.
//
// The table name is used verbatim. DO NOT TRUST USER-SUPPLIED VALUES.
//
// The struct is examined for tags, and those tags are parsed and used to determine
// details about each field.
Bind(string, Record) Recorder
// Interface provides a way of fetching the record from the Recorder.
//
// A record is bound to a Recorder via Bind, and retrieved from a Recorder
// via Interface().
//
// This is conceptually similar to reflect.Value.Interface().
Interface() interface{}
Loader
Haecceity
Saver
Describer
}
A Recorder is responsible for managing the persistence of a Record. A Recorder is bound to a struct, which it then examines for fields that should be stored in the database. From that point on, a recorder can manage the persistent lifecycle of the record.
func List ¶
List returns a list of objects of the given kind.
This runs a Select of the given kind, and returns the results.
func ListWhere ¶
ListWhere takes a Recorder and a query modifying function and executes a query.
The WhereFunc will be given a SELECT d.Colsumns() FROM d.TableName() statement, and may modify it. Note that while joining is supported, changing the column list will have unpredictable side effects. It is advised that joins be done using Squirrel instead.
This will return a list of Recorder objects, where the underlying type of each matches the underlying type of the passed-in 'd' Recorder.
type Saver ¶
type Saver interface {
// Insert inserts the bound Record into the bound table.
Insert() error
// Update updates all the fields on the bound Record based on the PRIMARY_KEY fields.
//
// Essentially, it does something like this:
// UPDATE bound_table SET every=?, field=?, but=?, keys=? WHERE primary_key=?
Update() error
// Delete a Record based on its PRIMARY_KEY(s).
Delete() error
}
type WhereFunc ¶
type WhereFunc func(desc Describer, query squirrel.SelectBuilder) (squirrel.SelectBuilder, error)
WhereFunc modifies a basic select operation to add conditions.
Technically, conditions are not limited to adding where clauses. It will receive a select statement with the 'SELECT ... FROM tablename' portion composed already.
