Documentation
¶
Overview ¶
Package repoutils provides utility types and funcs for packages [repo] and [sqlite]. It exists mainly to prevent circular dependencies.
Index ¶
- Constants
- Variables
- func Close()
- func Create(ctx context.Context, q string, args ...any) (int64, error)
- func DB() *sql.DB
- func GetField[T Field](ctx context.Context, q string, args ...any) (T, error)
- func GetFields[T Field](ctx context.Context, q string, args ...any) ([]T, error)
- func GetRow[T any, PT Row[T]](ctx context.Context, q string, args ...any) (T, error)
- func GetRows[T any, PT Row[T]](ctx context.Context, q string, args ...any) ([]T, error)
- func InArgs[T Field](inArgs []T) (string, []any)
- func Init()
- func StringifyAnyArgs(args ...any) string
- type DAO
- type DbOp
- type Field
- type QuerySpec
- type Repo
- type Row
- type SqlarRow
- type TableDescriptor
- type Times
Constants ¶
const ( // Odd ops OpCreateTable DbOp = "CreateTable" OpCount = "Count" // () (int, error) // Ops on single items: // - 5 functions (2 generic) - lacking ModByID // - All operate by using the ID, except of course Add(T) OpAdd = "Add" // (T) (int, error) OpDel = "Del" // (T) error OpMod = "Mod" // (T) error OpGetByID = "GetByID" // [T](int) (T, error) OpDelByID = "DelByID" // [T](int) error // Ops on multiple items where the count is KNOWN: // - 6 functions (3 generic) OpGetByIDs = "GetByIDs" // [T]([]int) ([]T, []error) OpDelByIDs = "DelByIDs" // [T]([]int) []error OpModByIDs = "ModByIDs" // [T]([]int, actions ...string) []error OpAddAll = "AddAll" // ([]T) ([]int, []error) OpDelAll = "DelAll" // ([]T) []error OpModAll = "ModAll" // ([]T) []error // Ops on multiple items (WHERE, Everything) // where the count is NOT known: // - 6 functions (all generic) - lacking ModEverything OpGetIDsWhere = "GetIDsWhere" // [T](cond string) ([]int64, error) OpGetWhere = "GetWhere" // [T](cond string) ([]T, error) OpDelWhere = "DelWhere" // [T](cond string) ([]int64, error) OpModWhere = "ModWhere" // [T](cond s, action s) ([]int64, e) OpGetEverything = "GetEverything" // [T]() ([]T, error) OpDelEverything = "DelEverything" // [T]() (error) )
Variables ¶
var ColumnSpecs_SqlarRow = []D.ColumnSpec{}
ColumnSpecs_SqlarRow specifies TBS.
var ErrNotFound = errors.New("DB record not found")
ErrNotFound is returned when no row is found for an SQL query.
var QueriesByOp = map[DbOp]string{
OpCount: "SELECT COUNT(*) from %s;",
OpCreateTable: "!TBS!",
OpAdd: "INSERT into %s (%s) values (?, ?, ?);",
OpGetByID: "SELECT ID, %s from %s where ID = ? limit 1;",
OpGetByIDs: "SELECT ID, %s from %s where ID in (%s) order by id;",
OpGetIDsWhere: "SELECT ID from %s where %s;",
}
var TableDescriptor_SqlarRow = TableDescriptor{ "sqlar", "sqlar", "idx_sqlar", "FIXME", ColumnSpecs_SqlarRow, }
TableDescriptor_SqlarRow specifies TBS.
Functions ¶
func Create ¶
Create executes the INSERT statement found in q. It returns the last inserted ID if any, as an int64. Thus it does not need (or use) generics. .
func GetField ¶
GetField returns a single column value from the DB as type T. If no column is found, it returns the T zero value with no error.
Example:
- func GetField [T Field](ctx, q, args ...any) (T, error)
- return db.GetField[int64](ctx, q_getCount)
.
func GetFields ¶
GetFields returns fields from the DB as type []T. T must satisfy the Field constraint: T must be a basic Go data type. As the main use case, an int64 primary index satisfies this constraint.
Example:
- func GetFields[T Field](ctx, q, args ...any) ([]T, error)
- return db.GetFields[int64](ctx, q_getByIDsWithBio)
.
func GetRow ¶
GetRow returns a single row from the DB as type T. If no row is found, it returns the T zero value and ErrNotFound.
Example: retval,e := db.GetRow[User](ctx, q_getByID, id) // retval.(User) is true. .
func GetRows ¶
GetRows returns rows from the DB as type []T. T must implement PtrFields() with a ptr receiver type.
func InArgs ¶
InArgs returns ( placeholders and args ) as formatted for a WHERE IN clause. For example, calling InArgs([]int{1,2,3}) will return ("?,?,?", []any{1,2,3}).
func StringifyAnyArgs ¶
Types ¶
type Field ¶
Field is a type constraint for types that represent
- a single database column, or
- any other non-struct datum, such as an int64 primary index.
type QuerySpec ¶
type QuerySpec struct {
DbOp
// Table must not be empty; if it is treated as
// case-insensitive then no validity checking
// is done.
Table string
// Fields must not be empty, for consistency
// in technique re. using ptrs everywhere in
// order to enable generics and Scan(..).
Fields string
// ID can safely be ignored if
// (IDs != nil) && (ID == 0 || ID == -1)
ID int64
// IDs != nil is an error if ID is valid.
IDs []int64
Where string
}
QuerySpec is the basic strings that get plugged into a query: table name, column names, "where" clause. It is meant to be passed to query composers (not "builders") that are specific to various DBs. Which means, for now, SQLite.
A query composer might also be a query executor, which would mean distinguiishing at the API level among return values of int64, []int64, Row, and []Row.
There is redundancy built in, to help ensure against errors in usage: the DB op, the presence or absence of a WHERE clause, the number of IDs passed (0, 1, N). .
type Row ¶
type Row[T any] interface { // PtrFields returns a slice of // ptrs, one per struct field, // for use with [Row.Scan]. // Implement it for - and call // it with - ptr receivers ONLY. PtrFields() []any // TODO Try []*any *T }
Row is a type constraint for types that
- represent a single database row, and
- therefore correspond to a Go struct.
According to this definition, a Row can
- cough up a set of ptrs suitable for setting every field/column, and
- have its own address be taken (and passed around), making it writable.
type TableDescriptor ¶
type TableDescriptor struct {
// Name is the name of the table in the DB,
// e.g. inbatch, contentity, topicref.
Name string
// Shortname is a short version for use in the
// names of other variables, e.g. inb, cnt, trf.
ShortName string
// IDName is the name of the index field, which (for now)
// we use in the same format BOTH for a primary key AND
// as a foreign key.
IDName string
// ColumnNames is all column names (except primary key), in a
// specified order, comma-separated, for use in SQL statements.
// We omit the primary key so that we can use this for SQL
// INSERT staements too.
ColumnNames string
// We used to have ForenKeys defined by name only, but this is
// insufficient information, because we need the field name AND
// the table name. In principle we could derive one from the
// other using our other DB-related data structures, and maybe
// we used to, but it adds significant complexity.
// ForenKeys []string
ColumnSpecs []D.ColumnSpec
}
TableDescriptor describes the field structure of a database table. or each table, a primary key is assumed and foreign keys are allowed.
All text fields should be in lower-case. Enforcement of this will inevitably be patchy.
Notes on particular fields:
- The field [ColumnSpecs] is a slice of [db.ColumnSpec], which is [dsmnd.Datum] and has four text fields: [Fundatype], StorNam, DispName, Descrription.
- The field [ForenKeys] may be nil or length [0].
- TODO: (Maybe): the field [ColumnSpecs] could be nil or len 0. If so then it should "probably" be autogenerated (partially only) by reflection from the contents of a same-named table currently existing in the DB.
Notes on date-time fields:
- These are not an issue for SQLite, since either a string or an int can be used. However, date-time fields referenced using THIS system (i.e. [db.TableDescriptor] and [db.DbColumnSpec]) use strings (SQLite DDL "TEXT"), which are expected to be ISO-8601 / RFC 3339 (and probly UTC). It is the first option listed in https://www.sqlite.org/datatype3.html#date_and_time_datatype:
- TEXT: "YYYY-MM-DD HH:MM:SS.SSS"
- REAL as Julian day numbers: the day count since 24 November 4714 BC
- INTEGER as Unix time: the seconds count since 1970-01-01 00:00:00 UTC
- NOTE: For TEXT "YYYY-MM-DD HH:MM:SS.SSS", this might often end up in ISO format, which has a "T" instead of the blank " " . So for better readability, and to avoid line breaks, we have a utility that replaces either a blank (" ") or an ISO "T" with a "_".
.