datarepo

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

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

Go to latest
Published: Apr 25, 2024 License: MIT Imports: 13 Imported by: 1

README

datarepo

Prototype of an all-weather all-terrain data repository for Go, defaulting to SQLite.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DEFAULT_FILENAME = "m5.db"

Functions

This section is empty.

Types

type AppTableSetter

type AppTableSetter interface {
	// SetAppTables specifies the schemata of the specified app's
	// tables, which this interface creates and/or manages.
	//  - Multiple calls, whether with tables previously specified
	//    or not before seen do not conflict
	//  - If a table name is repeated but with a different schema,
	//    the result is undefined
	//  - If the tables already exist in the DB, it is not verified
	//    that their structure matches what this schema specifies
	SetAppTables(string, []DRM.TableDetails) error
	// EmptyAllTables deletes (app-level) data from the app's tables
	// but does not delete any tables (i.e. no DROP TABLE are done).
	EmptyAppTables() error
	// CreateTables creates the app's tables per already-supplied
	// schema(ta); if the tables exist, they are emptied of data.
	CreateAppTables() error
}

AppTableSetter is table-related methods for a specified app's schema. The app name is case-insensitive, and used as all lower case, and pre- fixed to table names as "appname_". If the app name is left blank (""), a default namespace is used and no prefix is added to table names.

type Backupable

type Backupable interface {
	MoveToBackup() (string, error)
	CopyToBackup() (string, error)
	RestoreFromMostRecentBackup() (string, error)
}

Backupable methods are invoked directly by the DB being backed up, rather than by some sort of higher-level "Manager". The methods work with locations, whose type (filepath, dir path, or URI/URL) and naming convention (incorporating date & time) are determined by the implementation for each DB. Methods exist to move DB to, copy DB to, or restore DB from a location. Each method returns the location of the new backup or restored-from backup.

There are equivalent sqlite3 commands at the CLI:

  • sqlite3 my_database.db ".backup 'backup_file.db'"
  • sqlite3 my_database.db ".backup m_database.db.bak"
  • sqlite3 my_database .backup > my_database.back

.

type DBManager

type DBManager interface {
	// OpenAtPath should be
	// OpenAtPath(string) (SimpleRepo, error) // recommended
	OpenAtPath(string) (*sqlite.SqliteRepo, error) // recommended
	// NewAtPath should be
	// NewAtPath(string) (SimpleRepo, error)
	NewAtPath(string) (*sqlite.SqliteRepo, error)
	// OpenExistingAtPath should be
	// OpenExistingAtPath(string) (SimpleRepo, error)
	OpenExistingAtPath(string) (*sqlite.SqliteRepo, error)
	// InitznPragmas is assumed to be multiline
	InitznPragmas() string
	// ReadonlyPragma is assumed to be a single pragma that
	// returns some sort of status message
	ReadonlyPragma() string
}

DBManager has methods to create, open, and configure databases.

NOTE: The recommended action is to call OpenAtPath, which then selects one of the other two. .

var DB_Manager DBManager

DB_Manager is a global, maybe for SQLite, maybe for ebberyting,

type Entity

type Entity interface {
	// Handle (noun) is the handle to the DB.
	Handle() *sql.DB
	// Type has value DB_SQLite ("sqlite", equiv.to "sqlite3").
	Type() D.DB_type
	// Path is the file/URL (or dir/URL, if uses multiple files) to the DB.
	Path() string
	// IsURL is false for a local SQLite file.
	IsURL() bool
	// IsSingleFile is true for SQLite.
	IsSingleFile() bool
}

Entity provides operations for database entities (i.e. instances).

type Init9nArgs

type Init9nArgs struct {
	// D.DB_type is so far only D.DB_SQLite = "sqlite"
	D.DB_type
	// BaseFilename defaults to "m5.db"
	BaseFilename string
	Dir          string
	// LogWriter is (so far) used only by package [datarepo/sqlite]
	// and is initialized to [io.Discard]. If it is an open file, it
	// is passed using func [datarepo/sqlite.SqliteRepo.SetLogWriter].
	// It could actually be just an io.WriterCloser.
	// LogWriter *os.File
	// DoImport requires DB access, so it is present
	// here, but it is not otherwise processed here.
	DoImport bool
	// DoZeroOut says initialize the DB with the
	// app's tables but with no data in them
	DoZeroOut bool
	// DoBackup says before DoingZeroOut on an
	// existing DB, first copy it to a backup
	// copy using a hard-coded naming scheme
	DoBackup bool
	// TableDetailz are app tables' details
	TableDetailz []DRM.TableDetails
}

Init9nArgs is for database management. Note that if field [UseDB] is false, the contents and usage of this struct are undefined.

func (*Init9nArgs) ProcessInit9nArgs

func (p *Init9nArgs) ProcessInit9nArgs() (SimpleRepo, error)

ProcessInit9nArgs processes DN initialization arguments. It can process either a new DB OR an existing DB.

If the returned error is non-nil, it need not be fatal. Check whether the SimpleRepo return value is nil.

TODO: It should not use a complex logger (e.g. [mlog]), because we want to avoid that kind of dependency in a standalone library. .

type QueryRunner

type QueryRunner interface {
	RunQuery0(*DRU.QuerySpec) (any, error)   // ie. Exec()
	RunQuery1(*DRU.QuerySpec) (any, error)   // One row, like by_ID
	RunQueryN(*DRU.QuerySpec) ([]any, error) // Multiple rows
}

QueryRunner runs queries!

https://github.com/golang/go/wiki/SQLInterface

  • ExecContext is used when no rows are returned ("0")
  • QueryContext is used for retrieving rows ("N")
  • QueryRowContext is used where only a single row is expected ("1")

.

type SessionLifecycler

type SessionLifecycler interface {
	// Open is called on an existing repo file, and can be called
	// multiple times in a sessions, so it should not pragma-style
	// initialization; however, options passed in the connection
	// string (such as SQLite's "...?foreign_keys=on") are kosher.
	Open() error
	SetLogWriter(io.Writer) io.Writer
	// DoPragmas is provided mainly for use in initialization,
	// but it is not included by default in any other functions
	// in this interface because of variations in usage of pragmas.
	// It is the therefore the sole responsibility of a caller to
	// determine which pragmas(s) to execute, and when.
	DoPragmas(string) (string, error)
	// IsOpen also pings the DB as a health check.
	IsOpen() bool
	// Verify runs app-level sanity & consistency checks (but things
	// like foreign key integtrity should be delegated to DB setup).
	Verify() error
	Flush() error
	// Close remembers the path (like os.File does).
	Close() error
	CloseLogWriter()
}

SessionLifecycler is session lifecycle operations for databases. The database is treated as stateful.

type SimpleRepo

type SimpleRepo interface {
	// Implementation is func [DBImplementationName]
	// is currently limited to "sqlite"
	// Implementation
	// Entity is type, path, etc.
	Entity
	// Backupable is copy, move, restoreFrom
	Backupable
	// SessionLifecycler is open, close, etc.
	SessionLifecycler
	// StatementBuilder uses [TableDescriptor] and [QuerySpec]
	StatementBuilder
	// Transactioner is for transactions
	Transactioner

	// QueryRunner is for generics and has funcs that return 0,1,N rows
	QueryRunner

	AppTableSetter
}

SimpleRepo is an interface that combines several other interfaces, and can be fully described by

  1. (NOTE: OBS?) a [DBImplementation], currently limited to "sqlite", plus
  2. a filepath or a URL, which may be either relative or absolute

Each field in the struct is tipicly a ptr, and tipicly they all point to the same single object.

A SimpleRepo is expected to implement DBBackups. .

type StatementBuilder

type StatementBuilder interface {
	// BuildQueryStmt(*DRU.QuerySpec) (string, error)
	NewCreateTableStmt(*DRM.TableDetails) (string, error)
}

StatementBuilder is DB-specific and implemented by *sqlite.SqliteRepo

type StatementBuilder_generics

type StatementBuilder_generics[T DRM.RowModel] interface {
	// BuildQueryStmt(*DRU.QuerySpec) (string, error)
	NewCreateTableStmt(T) (string, error)
	NewSelectByIdStmt(T, int) (string, error)
}

StatementBuilder_generics is DB-specific and implemented by *sqlite.SqliteRepo

type StatementRunner

type StatementRunner interface {
	ExecInsertStmt(string) (int, error)
	ExecSelectOneStmt(stmt string) (DRM.RowModel, error)
}

StatementRunner is DB-specific and implemented by *sqlite.SqliteRepo

type StatementRunner_generics

type StatementRunner_generics[T DRM.RowModel] interface {
	ExecSelectOneStmt(string) (T, error)
}

StatementRunner_generics is DB-specific and implemented by *sqlite.SqliteRepo

type Transactioner

type Transactioner interface {
	GetTx() *sql.Tx
	IsInTx() bool
	// Begin on an sql.DB is: func (db *DB) Begin() (*Tx, error).
	// This method signature here has problems with re-entrancy,
	// and a re-entrant version would have a signature like:
	// Begin() (Transactioner, error)
	Begin() error
	BeginImmed() error
	Commit() error
	Rollback() error
	Exec(query string, args ...any) (sql.Result, error)
	Query(query string, args ...any) (*sql.Rows, error)
	QueryRow(query string, args ...any) *sql.Row
}

Transactioner methods come from the Go stdlib, but are modified to work with a single possibly-active transaction. If it is active, the trio of Exec/Query/QueryRow usw it, and if not, the calls go straight to the sql.DB .

There are a couple of problems with this, mainly when there are multiple threads accessing. The fix would be that a call to Begin would return the shared sql.DB but a unique sql.Tx .

Directories

Path Synopsis
Package sqlite provides func specific to SQLite-based implementations¨ of package [repo].
Package sqlite provides func specific to SQLite-based implementations¨ of package [repo].
Package utils provides utility types and funcs for packages [datarepo] and [sqlite].
Package utils provides utility types and funcs for packages [datarepo] and [sqlite].

Jump to

Keyboard shortcuts

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