database

package
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: MIT Imports: 17 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 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.

Rows reach PHP as the bridge produced them, a map[string]any per row and a []map[string]any per result set, rather than being copied into a *model.Array. The VM reads both natively: foreach walks them, $row["col"] indexes them, and $row["extra"] = 1 writes to them, since a Go map is a reference type. The copy cost two allocations plus an interface box per column on every row of every query.

The one thing a map does not carry is column order, and neither did the *model.Array: the bridge's map had already lost it, so `foreach ($row as $column => $value)` has always produced an arbitrary order. It is now arbitrary per iteration rather than fixed per row; scripts that need a stable order should name their columns in the SELECT and index 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.

func (*DatabaseMigrate) Load

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

Load reads migrations matching pattern from the runtime source filesystem.

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. The function is not concurrency safe, database credentials can't be changed during the lifetime of the provider.

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