repoutils

package module
v0.0.0-...-aafe24b Latest Latest
Warning

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

Go to latest
Published: Sep 4, 2023 License: MIT Imports: 11 Imported by: 2

README

repoutils

Utility functions for content repositories.

Documentation

Overview

Package repoutils provides utility types and funcs for packages [repo] and [sqlite]. It exists mainly to prevent circular dependencies.

Index

Constants

View Source
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

View Source
var ColumnSpecs_SqlarRow = []D.ColumnSpec{}

ColumnSpecs_SqlarRow specifies TBS.

View Source
var ErrNotFound = errors.New("DB record not found")

ErrNotFound is returned when no row is found for an SQL query.

View Source
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;",
}
View Source
var TableDescriptor_SqlarRow = TableDescriptor{
	"sqlar",
	"sqlar",
	"idx_sqlar",
	"FIXME",

	ColumnSpecs_SqlarRow,
}

TableDescriptor_SqlarRow specifies TBS.

Functions

func Close

func Close()

func Create

func Create(ctx context.Context, q string, args ...any) (int64, error)

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 DB

func DB() *sql.DB

func GetField

func GetField[T Field](ctx context.Context, q string, args ...any) (T, error)

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

func GetFields[T Field](ctx context.Context, q string, args ...any) ([]T, error)

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

func GetRow[T any, PT Row[T]](ctx context.Context, q string, args ...any) (T, error)

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

func GetRows[T any, PT Row[T]](ctx context.Context, q string, args ...any) ([]T, error)

GetRows returns rows from the DB as type []T. T must implement PtrFields() with a ptr receiver type.

func InArgs

func InArgs[T Field](inArgs []T) (string, []any)

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 Init

func Init()

func StringifyAnyArgs

func StringifyAnyArgs(args ...any) string

Types

type DAO

type DAO struct{}

These are in app model packages but not here I guess.

type DbOp

type DbOp string

type Field

type Field interface {
	~byte | ~int16 | ~int32 | ~int64 | ~float64 |
		~string | ~bool | time.Time
}

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 Repo

type Repo struct {
	*sql.DB
	Path string
}
var R Repo

func (*Repo) RunQuery1

func (R *Repo) RunQuery1(qs QuerySpec) (any, error)

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 SqlarRow

type SqlarRow struct {
}

SqlarRow gas structure defined by SQLite.

func (*SqlarRow) String

func (p *SqlarRow) String() string

String implements Stringer.

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 "_".

.

type Times

type Times struct {
	T_Cre string
	T_Imp string
	T_Edt string
}

Times has (create, import, last edit) and uses only ISO-8601 / RFC 3339.

Jump to

Keyboard shortcuts

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