database

package
v0.3.5 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package database holds the named sql connections a phpscript runtime resolves through. It is a copy of the provider in github.com/titpetric/platform, which lives in an internal package and cannot be imported, so that a provider can be scoped to a virtual host instead of being process global.

Index

Constants

This section is empty.

Variables

View Source
var ErrReadOnly = errors.New("database is read-only")

ErrReadOnly is what a refusal by a read-only client matches with errors.Is. The runtime surfaces the refusal to PHP as a thrown exception, so a script catches it like any other database error.

Functions

func Open

func Open(driver, dsn string) (*sqlx.DB, error)

Open creates a *sqlx.DB from a driver name and a DSN. It is the default open function of DatabaseProvider.

The connection is not instrumented. Query level spans belong to the driver, not to the provider, so a caller that wants them supplies an instrumented open function instead.

func Register

func Register(rt *runner.Runtime)

Register installs the Database and Database\Migrate bindings on rt.

func RegisterConnections added in v0.3.3

func RegisterConnections(rt *runner.Runtime)

RegisterConnections installs the statics that let a script see and extend the set of connections it can open.

Connection names normally come from the environment the host was started with, which is right when the operator owns the list. An application that keeps its connections in a table owns the list itself, and has nowhere to put them: the provider is built once, before the first request, and putenv writes to the script environment, which the provider never reads.

func RegisterMigrate

func RegisterMigrate(rt *runner.Runtime)

RegisterMigrate installs the Database\Migrate binding.

Types

type Database

type Database struct {
	Bridge *client.Bridge
	ID     string

	// IsReadonly restricts the client to statements that only read. It is a
	// property of the client, not of the connection: PHP reads and writes it as
	// `$db->is_readonly`, and it lives as long as the client does, which for a
	// served request is the request.
	//
	// It refuses insert(), replace() and update() outright, and refuses any
	// statement passed to query(), get() or get_all() that does not start with
	// a read-only keyword (see readOnlyStatements). Transactions, connection
	// pinning and the result accessors stay available, since a read-only
	// transaction is a read.
	//
	// The restriction is a boundary for the code holding this client, not a
	// sandbox around the script: the script that set it can unset it. A
	// connection that must not write belongs to a database user without the
	// grant to, and this marks the code that must not write.
	IsReadonly bool
	// contains filtered or unexported fields
}

Database adds request tracing to the database binding.

func (*Database) Begin

func (b *Database) Begin(ctx context.Context) (any, error)

Begin starts a transaction and opens the span measuring it. The span stays open until Commit or Rollback, so a transaction is one region in the trace rather than an open marker and a close marker to pair up.

func (*Database) Close

func (b *Database) Close(ctx context.Context) (any, error)

Close releases an exclusive connection back to the pool.

func (*Database) Commit

func (b *Database) Commit(ctx context.Context) (any, error)

Commit commits the active transaction and ends its span.

func (*Database) Connect

func (b *Database) Connect(ctx context.Context) (any, error)

Connect reserves an exclusive connection from the pool.

func (*Database) Get

func (b *Database) Get(ctx context.Context, query string, args ...any) (any, error)

Get returns the first result row, or false when the query matches no rows.

A row is a native map: foreach walks it, $row["col"] indexes it, and $row["extra"] = 1 writes to it. A map carries no column order, so `foreach ($row as $column => $value)` visits columns in arbitrary order; a script that needs a stable order names its columns in the SELECT and indexes them.

func (*Database) GetAll

func (b *Database) GetAll(ctx context.Context, query string, args ...any) (any, error)

GetAll returns all result rows. See Get for the row representation.

func (*Database) Insert

func (b *Database) Insert(ctx context.Context, table string, value any) (any, error)

Insert inserts a dynamically typed named value.

func (*Database) InsertID

func (b *Database) InsertID(ctx context.Context) (any, error)

InsertID returns the ID generated by the last insert.

func (*Database) Query

func (b *Database) Query(ctx context.Context, query string, args ...any) (any, error)

Query executes a statement with dynamically typed arguments.

func (*Database) Replace

func (b *Database) Replace(ctx context.Context, table string, value any) (any, error)

Replace replaces a row using a dynamically typed named value.

func (*Database) Rollback

func (b *Database) Rollback(ctx context.Context) (any, error)

Rollback rolls back the active transaction and ends its span.

func (*Database) RowsAffected

func (b *Database) RowsAffected(ctx context.Context) (any, error)

RowsAffected returns the affected row count from the last write.

func (*Database) SetID

func (b *Database) SetID(id string)

SetID records the PHP variable receiving this constructed client.

func (*Database) Update

func (b *Database) Update(ctx context.Context, table string, value any, keyColumns ...any) (any, error)

Update updates a row using dynamically typed named values and key columns.

type DatabaseMigrate

type DatabaseMigrate struct {
	// contains filtered or unexported fields
}

DatabaseMigrate loads and runs SQL migrations against a platform database.

The project is the connection name the binding was constructed with, and is what mig records applied files under.

func (*DatabaseMigrate) Load

func (m *DatabaseMigrate) Load(pattern string) error

Load selects the migrations to run, as a glob against the runtime source filesystem. Nothing is read here: mig reads the files it applies, and a pattern matching nothing is only known to be wrong once Run looks.

A script names its migrations relative to itself ("./schema/*.up.sql"), so the work directory is joined in to reach them from the root of the runtime filesystem. What the pattern matched is also what mig records, so a file is recorded as "schema/bookmarks.up.sql" where this binding used to record the base name alone, under no project at all. A database migrated by the older binding holds no row under either new name and applies every file again, which for a CREATE TABLE is an error rather than a repeat.

func (*DatabaseMigrate) Run

func (m *DatabaseMigrate) Run(ctx context.Context) error

Run applies the loaded migrations. It is one span rather than one per file: migrations run at startup, where what matters is how long the schema took and whether it failed, not a row per statement.

type DatabaseOption

type DatabaseOption struct {
	MaxOpenConns int
	MaxIdleConns int
}

DatabaseOption configures database connection pooling settings.

func (*DatabaseOption) Apply

func (o *DatabaseOption) Apply(client *sqlx.DB)

Apply applies the database option settings to a database connection.

type DatabaseProvider

type DatabaseProvider struct {
	// contains filtered or unexported fields
}

DatabaseProvider holds a list of named sql connection credentials.

func New

func New(environment []string) *DatabaseProvider

New returns a provider holding only the connections named in environment, in PLATFORM_DB_<NAME>=<dsn> form, plus the built-in default. A provider built this way sees nothing but what it was given, which is what keeps one virtual host out of another's databases.

func NewDatabaseProvider

func NewDatabaseProvider(open func(string, string) (*sqlx.DB, error)) *DatabaseProvider

NewDatabaseProvider will allocate a valid `*DatabaseProvider` and return it.

func (*DatabaseProvider) Connect

func (r *DatabaseProvider) Connect(ctx context.Context, names ...string) (*sqlx.DB, error)

Connect issues a PingContext to verify a live connection before returning. The context is used to propagate tracing detail so ping is grouped correctly.

func (*DatabaseProvider) List

func (r *DatabaseProvider) List() []string

List will return the list of credential names.

func (*DatabaseProvider) Open

func (r *DatabaseProvider) Open(_ context.Context, names ...string) (*sqlx.DB, error)

Open is the same as sql.Open. It creates a client from a named connection.

func (*DatabaseProvider) Register

func (r *DatabaseProvider) Register(name string, config string)

Register will add a new named credential into the provider.

A host that keeps its connections in a database registers them per request, from whichever goroutine is serving it, so the credentials map is guarded like the pool cache beside it.

Re-registering a name with the same configuration is free. Re-registering it with a different one drops the pool that was opened for the old credentials: the cache is keyed by name, and a name that now means a different database must not keep answering with the old one.

type Provider

type Provider = model.DatabaseProvider

Provider is what a runtime resolves named connections through. The interface is declared in model, which a runtime can name in its options without depending on this package.

var Default Provider = New(os.Environ())

Default is the provider used when a runtime's options name none. It is the process environment, which is what a CLI run has.

Jump to

Keyboard shortcuts

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