dal

package
v0.64.4 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 16 Imported by: 145

Documentation

Index

Constants

View Source
const (
	SUM     = "SUM"
	COUNT   = "COUNT"
	MIN     = "MIN"
	MAX     = "MAX"
	AVERAGE = "AVG"
)

Variables

View Source
var DefaultRandomStringIDLength = 16
View Source
var ErrExceedsMaxNumberOfAttempts = fmt.Errorf("exceeds maximum number of attempts")
View Source
var ErrHookFailed = errors.New("failed in dalgo hook")

ErrHookFailed indicates that error occurred during hook execution

View Source
var ErrInsertOptionNotHonored = errors.New("dal: insert option not honored: record key has no id after a successful insert")

ErrInsertOptionNotHonored is returned by Collection[K, T].Insert when the underlying WriteSession reports success but leaves the record's key without an id — i.e. the adapter ignored the InsertOption generator. It makes a generated Insert fail LOUDLY on a non-honoring adapter instead of reporting a false success under a <nil> id.

View Source
var ErrLimitReached = fmt.Errorf("%w: limit reached", ErrNoMoreRecords)
View Source
var ErrNoMoreRecords = fmt.Errorf("%w: no more errors", io.EOF)

ErrNoMoreRecords indicates there is no more records

View Source
var ErrNotImplementedYet = errors.New("not implemented yet")

ErrNotImplementedYet - return this if db name does not support requested operation yet.

View Source
var ErrNotSupported = errors.New("not supported")

ErrNotSupported - return this if db name does not support requested operation. (for example no support for transactions)

View Source
var ErrReaderClosed = errors.New("reader closed")
View Source
var ErrReaderNotStarted = errors.New("reader not started")

Functions

func AddBeforeDeleteHook added in v0.64.0

func AddBeforeDeleteHook(hooks ...RecordHook)

AddBeforeDeleteHook registers hooks that the write pipeline calls before a delete reaches the storage adapter. The hook receives a record carrying only the key being deleted; there is no data to validate.

func AddBeforeSaveHook added in v0.64.0

func AddBeforeSaveHook(hooks ...RecordHook)

AddBeforeSaveHook registers hooks that the write pipeline calls before a record-bearing write reaches the storage adapter. Hooks run in registration order and the first error aborts the write, wrapped in ErrHookFailed.

The registry is process-wide, which is why it is append-only: a package registers its hooks once at init and they apply to every DB built by NewDB.

func ApplyChanges added in v0.63.1

func ApplyChanges(ctx context.Context, tx ReadwriteTransaction, changes *record.Changes, excludeKeys ...*record.Key) error

ApplyChanges applies a persistence-neutral record change set through tx. It clears changes only after every queued operation succeeds.

func As added in v0.64.0

func As[T any](db DB) (value T, ok bool)

As reports whether db — or the Backend it delegates to — implements the optional capability interface T, and returns it.

DALgo advertises optional capabilities by type assertion (dbschema.SchemaReader, ddl.SchemaModifier, ddl.TransactionalDDL, …). A DB returned by NewDB decorates its Backend, so a plain assertion on the DB would stop seeing capabilities the adapter does implement. As is what consumers should use instead.

func BeforeDelete added in v0.64.0

func BeforeDelete(ctx context.Context, _ DB, key *record.Key) error

BeforeDelete runs the registered before-delete hooks for key. A delete has no record data, so nothing is validated; the operation still participates in the pipeline so that the write path is uniform.

func BeforeSave added in v0.2.9

func BeforeSave(ctx context.Context, db DB, r record.Record) error

BeforeSave enforces the record invariants DALgo declares for a write that carries record data: the data is validated (when it implements ValidatableRecord) and then the registered before-save hooks run.

It is the single enforcement point for those invariants. Callers do not normally invoke it: a DB built by NewDB runs it on every record-bearing write before delegating to the storage adapter.

func ExecuteQueryAndReadAllToRecords added in v0.35.1

func ExecuteQueryAndReadAllToRecords(ctx context.Context, query Query, qe QueryExecutor, options ...ReaderOption) (records []record.Record, err error)

func ExecuteQueryAndReadAllToRecordset added in v0.38.0

func ExecuteQueryAndReadAllToRecordset(ctx context.Context, query Query, qe QueryExecutor, options ...ReaderOption) (rs recordset.Recordset, err error)

func GetNonTransactionalContext

func GetNonTransactionalContext(ctx context.Context) context.Context

GetNonTransactionalContext returns non transaction context (e.g. Parent of transactional context) TODO: This is can be dangerous if child context creates a new context with a deadline for example

func GetRecordWithIDIntoData added in v0.61.0

func GetRecordWithIDIntoData[K comparable, D any](ctx context.Context, s ReadSession, key *record.Key, id K, data D) (record.DataWithID[K, D], error)

GetRecordWithIDIntoData fetches the record at key, decoding it INTO the caller-supplied data value, and returns a typed record.DataWithID[K, D].

Unlike Collection.GetRecordWithDataAndID (which allocates new(T) and therefore needs a concrete T), this takes the data value from the caller, so D may be an interface holding a concrete pointer (the factory pattern used by frameworks whose model types are interfaces). It is a free function because Go forbids type parameters on methods, so the decoupled data type D cannot be expressed as a Collection[K, T] method.

data must be a non-nil pointer or interface referencing a struct or a map (see record.NewDataWithID, which validates it). On not-found it returns the built value together with the session's not-found error.

func InsertRecordWithDataAndID added in v0.62.0

func InsertRecordWithDataAndID[K comparable, D any](ctx context.Context, s WriteSession, key *record.Key, id K, data D) (record.DataWithID[K, D], error)

InsertRecordWithDataAndID inserts the caller-supplied data value at key (under id) and returns a typed record.DataWithID[K, D].

It is the write twin of GetRecordWithIDIntoData: data is used as-is (never new(T)), so D may be an interface holding a concrete pointer — the factory pattern used by frameworks whose model types are interfaces. It is a free function because Go forbids type parameters on methods, so the decoupled data type D cannot be expressed as a Collection[K, T] method.

data must be a non-nil pointer or interface referencing a struct or a map (see record.NewDataWithID, which validates it). On failure it returns the built value together with the session Insert error.

func InsertWithIdGenerator added in v0.20.0

func InsertWithIdGenerator(
	ctx context.Context,
	r record.Record,
	generateID IDGenerator,
	maxAttempts int,
	exists func(*record.Key) error,
	insert func(record.Record) error,
) error

func IsGroupOperator added in v0.2.6

func IsGroupOperator(o Operator) bool

IsGroupOperator says if an operator is a group operator

func NewContextWithTransaction

func NewContextWithTransaction(nonTransactionalContext context.Context, tx Transaction) context.Context

NewContextWithTransaction stores transaction and original context intoRecord a transactional context

func NewErrNotFoundByKey

func NewErrNotFoundByKey(key *record.Key, cause error) error

NewErrNotFoundByKey creates an error that indicates that entity was not found by value

func NewRollbackError

func NewRollbackError(rollbackErr, originalErr error) error

NewRollbackError creates a rollback error

func Prefix added in v0.3.3

func Prefix(prefix string) func(options *randomStringOptions)

Prefix sets prefix for a random string

func RandomLength added in v0.3.3

func RandomLength(length int) func(options *randomStringOptions)

RandomLength sets length for a random string

func ReadAllToRecords added in v0.33.0

func ReadAllToRecords(ctx context.Context, reader RecordsReader, options ...ReaderOption) (records []record.Record, err error)

ReadAllToRecords is a helper method that for a given reader returns all records as a slice.

func RequiresEscaping added in v0.2.17

func RequiresEscaping(s string) bool

func SelectAll added in v0.5.0

func SelectAll(ctx context.Context, reader RecordsReader, addItem func(r record.Record), options ...ReaderOption) (err error)

SelectAll reads records from the provided RecordsReader and converts each record.Record to T using getItem. Behavior and caveats: - Panics if reader is nil (existing behavior). - Respects WithOffset by discarding the first offset records. - If WithLimit <= 0, reads until RecordsReader.Next() returns ErrNoMoreRecords. - Ensures reader.Close() is called; if Close returns an error and no prior error occurred, that error is returned. - Any panic inside getItem will propagate to the caller.

func SelectAllIDs added in v0.2.14

func SelectAllIDs[T comparable](ctx context.Context, reader RecordsReader, options ...ReaderOption) (ids []T, err error)

SelectAllIDs is a helper method that for a given reader returns all IDs as a strongly typed slice. Note: This will panic at runtime if the underlying ID types are not assignable to T.

func WithAfterLoad added in v0.4.0

func WithAfterLoad(hook RecordDataHook) func(rd *recordData)

func WithBeforeSave added in v0.4.0

func WithBeforeSave(hook RecordDataHook) func(rd *recordData)

func WithIDGenerator

func WithIDGenerator(ctx context.Context, g IDGenerator) record.KeyOption

WithIDGenerator sets ID generator for a random string (usually random)

func WithRandomStringID

func WithRandomStringID(options ...randomStringOption) record.KeyOption

WithRandomStringID sets ID generator to random string

Types

type Adapter added in v0.7.0

type Adapter interface {

	// Name of the dalgo adapter
	Name() string

	// Version of the name if applicable
	Version() string
}

Adapter describes adapter that provides access to data either through DB native client or direct implementation.

func NewAdapter added in v0.7.0

func NewAdapter(name, version string) Adapter

NewAdapter creates new client info. Former ClientInfo.

type AggregateFunc added in v0.51.0

type AggregateFunc interface {
	Expression
	FuncName() string
	FuncArgs() []Expression
}

AggregateFunc is implemented by aggregate function expressions (SUM, COUNT, MIN, MAX, AVG) so adapters can introspect the function name and its arguments without depending on the unexported concrete type.

type Array added in v0.23.0

type Array struct {
	Value any `json:"value"`
}

func NewArray added in v0.23.0

func NewArray(v any) Array

func (Array) Equal added in v0.23.0

func (v Array) Equal(b Array) bool

func (Array) String added in v0.23.0

func (v Array) String() string

String returns string representation of a Constant

type Backend added in v0.64.0

type Backend interface {

	// ID is an identifier provided at time of DB creation
	ID() string

	// Adapter provides information about underlying name to access data
	Adapter() Adapter

	// Schema provides schema for the DB - for example, how keys are mapped to columns
	Schema() Schema

	// TransactionCoordinator provides shortcut methods to work with transactions
	// without opening a connection explicitly.
	TransactionCoordinator

	// ReadSession implements a virtual read session that opens connection/session for each read call on DB level
	// TODO: consider to sacrifice some simplicity for the sake of interoperability?
	ReadSession

	// ConcurrencyAware reports whether this backend supports concurrent
	// open connections. Drivers should embed NoConcurrency or
	// ConcurrencyAvailable in their concrete type to satisfy this.
	ConcurrencyAware
}

Backend is the interface a DALgo storage adapter implements. It is the shape dal.DB used to have, unchanged.

A Backend is not handed to callers directly: an adapter's constructor passes it to NewDB, which returns a DB that owns the write pipeline. That is what makes the record invariants DALgo declares (see ValidatableRecord and BeforeSave) impossible for an adapter to skip — they run before the adapter's code is entered.

func BackendOf added in v0.64.0

func BackendOf(db DB) Backend

BackendOf returns the Backend that db delegates to, or db itself when it is not a DB produced by NewDB (a decorator, for example).

It exists for adapter internals that need their own concrete type back — the dalgo2memory branching provider recovers its *database this way. Writing through the returned Backend bypasses the framework write pipeline, so a call to BackendOf is exactly as visible and greppable as one to WithoutValidation, and should be just as rare.

type Changes

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

Changes tracks records that a DAL workflow intends to persist with Set or SetMulti. It is distinct from record.Changes, which is a declarative insert/update/delete command envelope executed by ApplyChanges.

func (*Changes) FlagAsChanged

func (changes *Changes) FlagAsChanged(rec record.Record)

FlagAsChanged marks rec as changed and tracks it once per key.

func (*Changes) HasChanges

func (changes *Changes) HasChanges() bool

HasChanges reports whether at least one record is tracked.

func (*Changes) IsChanged

func (changes *Changes) IsChanged(rec record.Record) bool

IsChanged reports whether a record with the same key is already tracked.

func (*Changes) Records added in v0.2.4

func (changes *Changes) Records() []record.Record

Records returns a copy of the tracked records.

type Collection added in v0.58.0

type Collection[K comparable, T any] interface {
	// GetData returns the record stored at id decoded as a T. On not-found it
	// returns the zero T and the not-found error from the session Get call (use
	// record.IsNotFound to test it).
	GetData(ctx context.Context, s ReadSession, id K) (T, error)

	// Get is a deprecated alias for GetData.
	//
	// Deprecated: use GetData.
	Get(ctx context.Context, s ReadSession, id K) (T, error)

	// GetRecord returns the underlying record.Record stored at id, with its Data set to
	// a *T. On not-found it returns the record (Exists() == false) together with
	// the not-found error from the session Get call.
	GetRecord(ctx context.Context, s ReadSession, id K) (record.Record, error)

	// GetRecordWithID reads id and returns a typed record.WithID[K] (id + key +
	// record, no typed data). On not-found it returns the zero value and the
	// session's not-found error.
	GetRecordWithID(ctx context.Context, s ReadSession, id K) (record.WithID[K], error)

	// GetRecordWithDataAndID reads id and returns a record.DataWithID[K, *T]
	// whose Data is the decoded *T (the same pointer held by the record.Record). On
	// not-found it returns the zero value and the session's not-found error.
	GetRecordWithDataAndID(ctx context.Context, s ReadSession, id K) (record.DataWithID[K, *T], error)

	// All returns every record in the collection, each decoded into a freshly
	// allocated value so results never alias. It surfaces ErrNotSupported from
	// backends that cannot run the query.
	All(ctx context.Context, s ReadSession) ([]T, error)

	// Count returns the number of records in the collection. It surfaces
	// ErrNotSupported from backends that cannot run the underlying query rather
	// than a silent 0.
	Count(ctx context.Context, s ReadSession) (int, error)

	// Exists reports whether a record exists at id. A not-found result maps to
	// (false, nil); any other failure is returned as (false, err).
	Exists(ctx context.Context, s ReadSession, id K) (bool, error)

	// First returns the first record in the collection (an underlying limit-1
	// query). An empty collection yields (zero T, false, nil); an incapable
	// backend surfaces ErrNotSupported.
	First(ctx context.Context, s ReadSession) (value T, found bool, err error)

	// Insert inserts value under a GENERATED id and returns the assigned key.
	// When opts is empty a default generator (WithRandomStringKey) is injected.
	// Only this terminal accepts InsertOption — generators cannot reach the
	// id-taking terminals.
	Insert(ctx context.Context, s WriteSession, value T, opts ...InsertOption) (*record.Key, error)

	// InsertWithID inserts value at a known id and returns the record's key.
	InsertWithID(ctx context.Context, s WriteSession, id K, value T) (*record.Key, error)

	// InsertRecord inserts a caller-built record. It is the shared primitive the
	// other inserts delegate to; opts carry an id generator for generated inserts.
	InsertRecord(ctx context.Context, s WriteSession, r record.Record, opts ...InsertOption) error

	// SetByID stores (upserts) value at id.
	SetByID(ctx context.Context, s WriteSession, id K, value T) error

	// Set is a deprecated alias for SetByID.
	//
	// Deprecated: use SetByID.
	Set(ctx context.Context, s WriteSession, id K, value T) error

	// SetRecord stores (upserts) a caller-built record.
	SetRecord(ctx context.Context, s WriteSession, r record.Record) error

	// UpdateByID applies field-level updates to the record at id.
	UpdateByID(ctx context.Context, s WriteSession, id K, updates []update.Update, preconditions ...Precondition) error

	// Update is a deprecated alias for UpdateByID.
	//
	// Deprecated: use UpdateByID.
	Update(ctx context.Context, s WriteSession, id K, updates []update.Update, preconditions ...Precondition) error

	// UpdateByKey applies field-level updates to the record at an explicit key.
	UpdateByKey(ctx context.Context, s WriteSession, k *record.Key, updates []update.Update, preconditions ...Precondition) error

	// DeleteByID deletes the record at id.
	DeleteByID(ctx context.Context, s WriteSession, id K) error

	// Delete is a deprecated alias for DeleteByID.
	//
	// Deprecated: use DeleteByID.
	Delete(ctx context.Context, s WriteSession, id K) error

	// DeleteByKey deletes the record at an explicit key.
	DeleteByKey(ctx context.Context, s WriteSession, k *record.Key) error

	// In returns a handle scoped under parent (one level of nesting).
	In(parent *record.Key) Collection[K, T]
}

Collection is a session-less, generic, reusable handle to a collection of records of type T keyed by id type K. It carries only path identity (a composed CollectionRef) and the phantom types K, T — it holds no session or connection, so a single value can be declared once (e.g. a package-level var) and reused across calls.

K is the (scalar) id type — id arguments are strongly typed as K rather than any. Composite / multi-field keys are addressed through the *ByKey terminals (build a *record.Key with record.NewKeyWithFields).

Read terminals take a ReadSession; write terminals take a WriteSession. Because dal.DB satisfies ReadSession but not WriteSession, calling a write terminal with a plain DB is a compile error — writes go through a read-write transaction handle (see RunReadwriteTransaction).

func CollectionAt added in v0.58.0

func CollectionAt[K comparable, T any](name string, opts ...CollectionOption) Collection[K, T]

CollectionAt returns a Collection[K, T] with an explicit collection name.

func CollectionOf added in v0.58.0

func CollectionOf[K comparable, T CollectionNamer](opts ...CollectionOption) Collection[K, T]

CollectionOf returns a Collection[K, T] whose name is resolved from T's value-receiver CollectionName method.

type CollectionGroupRef added in v0.22.0

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

func NewCollectionGroupRef added in v0.22.0

func NewCollectionGroupRef(name, alias string) CollectionGroupRef

func (CollectionGroupRef) Alias added in v0.22.0

func (v CollectionGroupRef) Alias() string

func (CollectionGroupRef) Name added in v0.22.0

func (v CollectionGroupRef) Name() string

func (CollectionGroupRef) String added in v0.22.0

func (v CollectionGroupRef) String() string

type CollectionNamer added in v0.58.0

type CollectionNamer interface {
	CollectionName() string
}

CollectionNamer is implemented by a record type that knows its own collection name. The CollectionName method MUST be declared on a value receiver so that CollectionOf[K, T]() can resolve the name from the zero value of T.

type CollectionOption added in v0.60.0

type CollectionOption func(*collectionOptions)

CollectionOption configures a Collection at construction time.

func WithKeyOptions added in v0.60.0

func WithKeyOptions(keyOptions ...record.KeyOption) CollectionOption

WithKeyOptions configures KeyOptions applied to every key the collection builds from a typed id (e.g. record.WithFields for composite keys, a parent key, or a custom IDKind). The id passed to a terminal is set first; these options are applied after, so an option may augment or override the resulting key.

type CollectionRef

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

CollectionRef points to a recordsetSource (e.g. table) in a database

func NewCollectionRef added in v0.2.17

func NewCollectionRef(name, alias string, parent *record.Key) (collectionRef CollectionRef)

func NewRootCollectionRef added in v0.15.0

func NewRootCollectionRef(name, alias string) CollectionRef

func (CollectionRef) Alias added in v0.2.16

func (v CollectionRef) Alias() string

func (CollectionRef) Equal added in v0.27.0

func (v CollectionRef) Equal(other CollectionRef, ignoreAlias bool) bool

func (CollectionRef) Name

func (v CollectionRef) Name() string

func (CollectionRef) Parent

func (v CollectionRef) Parent() *record.Key

func (CollectionRef) Path

func (v CollectionRef) Path() string

func (CollectionRef) String added in v0.2.16

func (v CollectionRef) String() string

type Column added in v0.2.6

type Column struct {
	Alias      string     `json:"Alias"`
	Expression Expression `json:"expression"`
}

Column reference a column in a SELECT statement

func AverageAs added in v0.2.6

func AverageAs(expression Expression, alias string) Column

AverageAs returns average value for a given expression

func Count added in v0.51.0

func Count() Column

Count returns a COUNT(*) aggregate column counting all rows in a group regardless of nulls. Count() is the alias for COUNT(*); use the returned Column's Alias field to name the output. The existing CountAs(field, alias) keeps its field-count (skip-nulls) semantics.

func CountAs added in v0.2.6

func CountAs(expression Expression, alias string) Column

CountAs aggregate function (see SQL COUNT())

func MaxAs added in v0.2.6

func MaxAs(expression Expression, alias string) Column

MaxAs returns maximum value for a given expression

func MinAs added in v0.2.6

func MinAs(expression Expression, alias string) Column

MinAs returns minimum value for a given expression

func SumAs added in v0.2.6

func SumAs(expression Expression, alias string) Column

SumAs aggregate function (see SQL SUM())

func (Column) String added in v0.2.6

func (v Column) String() string

String stringifies column value

type Comparison added in v0.2.6

type Comparison struct {
	Operator Operator
	Left     Expression
	Right    Expression
}

Comparison defines a contact for a comparison

func NewComparison added in v0.2.6

func NewComparison(left Expression, o Operator, right Expression) Comparison

NewComparison creates new Comparison

func (Comparison) Equal added in v0.2.6

func (v Comparison) Equal(b Comparison) bool

func (Comparison) String added in v0.2.6

func (v Comparison) String() string

String returns string representation of a comparison

type ConcurrencyAvailable added in v0.42.0

type ConcurrencyAvailable struct{}

ConcurrencyAvailable is a zero-value embeddable struct that satisfies ConcurrencyAware by reporting that concurrent connections ARE supported. Drivers whose backend tolerates multiple concurrent connections (such as a server-side RDBMS like PostgreSQL) should embed ConcurrencyAvailable to inherit the permissive answer with no method body of their own:

type PostgresDB struct {
	dal.ConcurrencyAvailable
	// ...
}

See ConcurrencyAware for the full contract.

func (ConcurrencyAvailable) SupportsConcurrentConnections added in v0.42.0

func (ConcurrencyAvailable) SupportsConcurrentConnections() bool

SupportsConcurrentConnections always returns true.

type ConcurrencyAware added in v0.42.0

type ConcurrencyAware interface {
	// SupportsConcurrentConnections reports whether the underlying
	// backend tolerates more than one open connection from a single
	// client process at the same time. See [ConcurrencyAware] for the
	// stability and asymmetry contract.
	SupportsConcurrentConnections() bool
}

ConcurrencyAware is implemented by DB values that can report whether the underlying backend supports multiple concurrent open connections from a single client process.

The returned value is constant from the moment a DB value is returned by its constructor until it is discarded. Drivers MUST NOT change the answer in response to reconnects, failovers, transient errors, or runtime configuration reloads against the same DB handle. Callers are entitled to memoize the value once per DB value.

The boolean intentionally does not distinguish read-vs-write concurrency. A driver like SQLite that supports concurrent readers but serializes writers collapses to false. Refining this surface (or adding a sibling) is a future change if a real consumer needs the distinction.

ConcurrencyAware is embedded into DB; every DB implementation therefore answers the question. Drivers SHOULD embed one of the reusable structs NoConcurrency or ConcurrencyAvailable rather than hand-writing the method.

type Condition added in v0.2.6

type Condition interface {
	fmt.Stringer
}

func WhereField added in v0.2.6

func WhereField(name string, operator Operator, v any) Condition

type Constant added in v0.2.15

type Constant struct {
	Value any `json:"value"`
}

func NewConstant added in v0.23.0

func NewConstant(v any) Constant

func (Constant) Equal added in v0.2.15

func (v Constant) Equal(b Constant) bool

func (Constant) String added in v0.2.15

func (v Constant) String() string

String returns string representation of a Constant

type Cursor added in v0.2.19

type Cursor string

type DB added in v0.8.0

type DB interface {
	Backend
	// contains filtered or unexported methods
}

DB is the caller-facing database handle. It has the same shape as Backend and is additionally sealed: the unexported marker method means only this package can produce a value satisfying DB, so every DB a caller holds has been through NewDB and therefore through the framework write pipeline.

Sealing enforces provenance, not behaviour — the pipeline enforces the behaviour. Together they mean a caller cannot be handed a database that silently skips the invariants.

A decorator (a caching layer, an access-policy layer, a tracing layer) still works: embed DB in the decorating type and the marker method is promoted along with everything else the decorator does not override. See access.SecureDB in this repository, or dalgo-memcache-appengine, for worked examples.

func NewDB added in v0.64.0

func NewDB(backend Backend) DB

NewDB wraps a storage adapter's Backend in the framework-owned write pipeline and returns the sealed, caller-facing DB.

It is the only way to obtain a DB, and it is the one line an adapter's public constructor changes:

func NewDB(options ...Option) dal.DB {
	return dal.NewDB(newDatabase(options...))
}

Every read-write transaction the returned DB starts hands the worker a transaction whose writes run BeforeSave first, so record validation and before-save hooks happen before the adapter's code is entered. When the backend also supports writes outside a transaction (it implements WriteSession), the returned DB exposes those through the same pipeline.

NewDB is idempotent: a value that already satisfies DB has already been through the pipeline and is returned unchanged, so wrapping twice cannot run hooks twice.

It is named NewDB rather than New to match this package's other constructors (NewAdapter, NewInsertOptions, NewTransactionOptions) and to read unambiguously at an adapter call site, where the adapter has a NewDB of its own.

type DataToKeyFunc added in v0.25.0

type DataToKeyFunc func(incompleteKey *record.Key, data any) (key *record.Key, err error)

DataToKeyFunc takes data retrieved from DB table/view/query and maps primary key columns to the record key.

type DataWrapper added in v0.4.0

type DataWrapper interface {
	Data() any
}

DataWrapper is a wrapper for data transfer objects (DTOs). TODO: document intended usage or consider removing as it makes implementation of RecordsReader more complex.

func MakeRecordData added in v0.2.7

func MakeRecordData(data any, options ...RecordDataOption) DataWrapper

MakeRecordData creates a DataWrapper with the given data and options.

type Deleter added in v0.2.27

type Deleter interface {

	// Delete deletes a single record from database by key
	Delete(ctx context.Context, key *record.Key) error
}

Deleter defines a function to delete a single record from database by key

type EmptyReader added in v0.3.1

type EmptyReader struct{}

func (EmptyReader) Close added in v0.3.1

func (e EmptyReader) Close() error

func (EmptyReader) Cursor added in v0.3.1

func (e EmptyReader) Cursor() (string, error)

func (EmptyReader) Next added in v0.3.1

func (e EmptyReader) Next() (record.Record, error)

type ErrDuplicateUser

type ErrDuplicateUser struct {
	// TODO: Should it be moved out of this package to strongo/app/user?
	SearchCriteria   string
	DuplicateUserIDs []string
}

ErrDuplicateUser indicates there is a duplicate user // TODO: move to strongo/app?

func (ErrDuplicateUser) Error

func (err ErrDuplicateUser) Error() string

Error implements error interface

type ErrNotFoundByKey

type ErrNotFoundByKey interface {
	Key() *record.Key
	Cause() error
	error
}

ErrNotFoundByKey indicates error was not found by value

type Expression added in v0.2.6

type Expression interface {
	fmt.Stringer
}

Expression represent either a FieldRef, Constant or a formula

func ID added in v0.2.6

func ID(name string, value any) Expression

ID creates an expression that compares an ID with a constant

func String added in v0.2.6

func String(v string) Expression

String creates a new Constant expression

type ExtraField added in v0.25.0

type ExtraField interface {
	Name() string
	Value() any
}

func NewExtraField added in v0.25.0

func NewExtraField(name string, value any) ExtraField

type FieldName added in v0.25.0

type FieldName string

FieldName represents a field name as string (for backward compatibility)

func (FieldName) String added in v0.25.0

func (f FieldName) String() string

String implements Expression interface

type FieldRef added in v0.2.6

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

func Field added in v0.2.6

func Field(name string) FieldRef

Field creates an unqualified FieldRef with the given name (empty source, i.e. the single From base recordset). Use NewFieldRef to qualify by source.

func NewFieldRef added in v0.25.0

func NewFieldRef(source, name string) FieldRef

NewFieldRef creates an expression that represents a FieldRef value. source qualifies the field with its recordset; an empty source denotes the single From base recordset.

func (FieldRef) Equal added in v0.2.6

func (f FieldRef) Equal(b FieldRef) bool

func (FieldRef) EqualTo added in v0.2.6

func (f FieldRef) EqualTo(v any) Condition

EqualTo creates equality condition for a field

func (FieldRef) IsID added in v0.2.6

func (f FieldRef) IsID() bool

func (FieldRef) Name added in v0.2.6

func (f FieldRef) Name() string

func (FieldRef) Source added in v0.48.0

func (f FieldRef) Source() string

Source returns the recordset qualifier of the field. An empty source denotes the single From base recordset.

func (FieldRef) String added in v0.2.6

func (f FieldRef) String() string

String returns string representation of a field

type FromSource added in v0.28.0

type FromSource interface {
	Base() RecordsetSource
	Join(joint JoinedSource) FromSource
	Joins() []JoinedSource
	NewQuery() *QueryBuilder
}

func From added in v0.2.6

func From(source RecordsetSource) FromSource

From creates a new IQueryBuilder with optional conditions. We can use NewQueryBuilder() directly but this is shorter.

type Getter added in v0.2.27

type Getter interface {

	// Get gets a single record from a database by key
	Get(ctx context.Context, record record.Record) error

	// Exists returns true if a record with the given key exists
	Exists(ctx context.Context, key *record.Key) (bool, error)
}

Getter defines a method to get a single record by key or check its existence

type GroupCondition added in v0.2.15

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

func NewGroupCondition added in v0.47.0

func NewGroupCondition(operator Operator, conditions ...Condition) GroupCondition

NewGroupCondition creates a GroupCondition combining the given conditions with a group operator (e.g. And or Or). It is the public constructor for the otherwise unexported fields, enabling callers outside the dal package (such as the dtql serializer) to reconstruct group conditions.

func (GroupCondition) Conditions added in v0.2.15

func (v GroupCondition) Conditions() []Condition

func (GroupCondition) Operator added in v0.2.15

func (v GroupCondition) Operator() Operator

func (GroupCondition) String added in v0.2.15

func (v GroupCondition) String() string

type IDGenerator

type IDGenerator = func(ctx context.Context, record record.Record) error

IDGenerator defines a contract for ID generator function

func NewIDGenerator added in v0.20.0

func NewIDGenerator(f IDGenerator, maxAttempts int) IDGenerator

type IQueryBuilder added in v0.28.0

type IQueryBuilder interface {
	Clone() IQueryBuilder
	Offset(int) IQueryBuilder
	Limit(int) IQueryBuilder
	Where(conditions ...Condition) IQueryBuilder
	WhereField(name string, operator Operator, v any) IQueryBuilder
	WhereInArrayField(name string, v any) IQueryBuilder
	WhereArrayContains(name string, v any) IQueryBuilder
	WhereArrayContainsAny(name string, values any) IQueryBuilder
	GroupBy(expressions ...Expression) IQueryBuilder
	Having(conditions ...Condition) IQueryBuilder
	OrderBy(expressions ...OrderExpression) IQueryBuilder
	SelectIntoRecord(func() record.Record) StructuredQuery
	SelectIntoRecordset(options ...recordset.Option) StructuredQuery
	SelectKeysOnly(idKind reflect.Kind) StructuredQuery
	SelectColumns(columns ...Column) StructuredQuery
	StartFrom(cursor Cursor) IQueryBuilder
}

type InsertOption

type InsertOption func(options *insertOptions)

InsertOption defines a contract for an insert option

func WithAdapterGeneratedID added in v0.59.0

func WithAdapterGeneratedID() InsertOption

WithAdapterGeneratedID requests that the storage adapter generates the record ID natively (e.g. Firestore's client-side auto-generated 20-char document IDs).

Contract for adapters:

  • An adapter SHOULD use its backend's native ID generation mechanism if it has one.
  • An adapter that has no native mechanism MUST fall back to the default random-string generator (WithRandomStringKey(DefaultRandomStringIDLength, 5)), so this option never fails on a compliant adapter.
  • If an explicit ID generator option (e.g. WithRandomStringKey) is supplied alongside this option, the explicit generator wins: adapters must check InsertOptions.IDGenerator() first and only consult InsertOptions.PreferAdapterGeneratedID() when it is nil.

Adapters introspect this option via InsertOptions.PreferAdapterGeneratedID().

func WithRandomStringKey added in v0.20.0

func WithRandomStringKey(length, maxAttempts int) InsertOption

func WithRandomStringKeyPrefixedByUnixTime added in v0.21.1

func WithRandomStringKeyPrefixedByUnixTime(randomLength, maxAttempts int) InsertOption

func WithTimeStampStringID added in v0.24.0

func WithTimeStampStringID(accuracy TimeStampAccuracy, base, maxAttempts int) InsertOption

type InsertOptions

type InsertOptions interface {
	IDGenerator() IDGenerator

	// PreferAdapterGeneratedID reports whether WithAdapterGeneratedID was passed.
	// See WithAdapterGeneratedID for the contract adapters must follow.
	PreferAdapterGeneratedID() bool
}

InsertOptions defines interface for insert options

func NewInsertOptions

func NewInsertOptions(opts ...InsertOption) InsertOptions

NewInsertOptions creates insert options

type Inserter added in v0.2.27

type Inserter interface {

	// Insert inserts a single record intoRecord a database
	Insert(ctx context.Context, record record.Record, opts ...InsertOption) error
}

Inserter defines a function to insert a single record intoRecord a database

type Item added in v0.58.0

type Item[K comparable, T any] struct {
	ID    K
	Value T
}

Item is a dal-native id+value pair for batch insert. Item deliberately does NOT reference the record package, so the batch API adds no dal -> record import.

type JoinType added in v0.48.0

type JoinType string

JoinType enumerates the kinds of join. JoinInner and JoinLeft are supported by executors; JoinRight, JoinFull and JoinCross are reserved for future support and rejected at execution time until implemented.

const (
	JoinInner JoinType = "INNER"
	JoinLeft  JoinType = "LEFT"
	JoinRight JoinType = "RIGHT"
	JoinFull  JoinType = "FULL"
	JoinCross JoinType = "CROSS"
)

type JoinedSource added in v0.28.0

type JoinedSource struct {
	RecordsetSource
	// contains filtered or unexported fields
}

func NewJoinedSource added in v0.48.0

func NewJoinedSource(src RecordsetSource, joinType JoinType, on ...Condition) JoinedSource

NewJoinedSource builds a JoinedSource of the given join type over src with the supplied ON conditions. It lets callers outside the dal package construct a fully-populated join (type + ON clause).

func (JoinedSource) JoinType added in v0.48.0

func (j JoinedSource) JoinType() JoinType

JoinType returns the kind of join (INNER, LEFT, ...).

func (JoinedSource) On added in v0.28.0

func (j JoinedSource) On() []Condition

On returns the join's ON conditions. The value receiver makes a join returned by From().Joins() readable without taking its address.

type KeyToFieldsFunc added in v0.25.0

type KeyToFieldsFunc func(key *record.Key, data any) (fields []ExtraField, err error)

KeyToFieldsFunc takes key and should either populate fields on a `data` struct or return extra fields to be stored to the target table.

type ManyInserter added in v0.58.0

type ManyInserter[K comparable, T any] interface {
	// InsertMany inserts each item at its known id and returns the keys in
	// input order.
	InsertMany(ctx context.Context, s WriteSession, items ...Item[K, T]) (keys []*record.Key, err error)
}

ManyInserter is the opt-in batch-insert interface, mirroring dalgo's Inserter/MultiInserter split. The concrete Collection[K, T] value satisfies it (obtain it via a type assertion: c.(dal.ManyInserter[K, T])).

type MultiDeleter added in v0.2.27

type MultiDeleter interface {

	// DeleteMulti deletes multiple records from database by keys
	DeleteMulti(ctx context.Context, keys []*record.Key) error
}

MultiDeleter defines a function to delete multiple records from database by keys

type MultiGetter added in v0.2.27

type MultiGetter interface {

	// GetMulti gets multiple records from a database by keys
	GetMulti(ctx context.Context, records []record.Record) error
}

MultiGetter defines method to get multiple records from a database by keys

type MultiInserter added in v0.13.0

type MultiInserter interface {
	// InsertMulti inserts multiple record intoRecord a database at once if possible, or fallback to batch of single inserts
	InsertMulti(ctx context.Context, records []record.Record, opts ...InsertOption) error
}

MultiInserter defines a function to insert multiple records intoRecord a database

type MultiSetter added in v0.2.27

type MultiSetter interface {

	// SetMulti stores multiples records intoRecord database by keys
	SetMulti(ctx context.Context, records []record.Record) error
}

MultiSetter defines a function to store multiple records intoRecord database by keys

type MultiUpdater added in v0.2.27

type MultiUpdater interface {

	// UpdateMulti updates multiples records in database by keys
	UpdateMulti(ctx context.Context, keys []*record.Key, updates []update.Update, preconditions ...Precondition) error
}

MultiUpdater defines a function to update multiples records in database by keys

type NoConcurrency added in v0.42.0

type NoConcurrency struct{}

NoConcurrency is a zero-value embeddable struct that satisfies ConcurrencyAware by reporting that concurrent connections are NOT supported. Drivers whose backend serializes connections (such as a single-writer SQLite, an unproven file-backed store, or a test stub) should embed NoConcurrency to inherit the conservative answer with no method body of their own:

type SQLiteDB struct {
	dal.NoConcurrency
	// ...
}

See ConcurrencyAware for the full contract.

func (NoConcurrency) SupportsConcurrentConnections added in v0.42.0

func (NoConcurrency) SupportsConcurrentConnections() bool

SupportsConcurrentConnections always returns false.

type Operator added in v0.2.6

type Operator string

Operator defines a Comparison operator

const (
	// Equal is a Comparison operator
	Equal Operator = "=="

	// In is a Comparison operator
	In Operator = "In"

	// GreaterThen is a Comparison operator
	GreaterThen Operator = ">"

	// GreaterOrEqual is a Comparison operator
	GreaterOrEqual Operator = ">="

	// LessThen is a Comparison operator
	LessThen Operator = "<"

	// LessOrEqual is a Comparison operator
	LessOrEqual Operator = "<="

	// And is a Comparison operator // TODO: Is it an operator?
	And = "AND"

	// Or is a Comparison operator // TODO: Is it an operator?
	Or = "OR"
)

type OrderExpression added in v0.2.6

type OrderExpression interface {
	fmt.Stringer
	Expression() Expression
	Descending() bool
}

func Ascending added in v0.2.6

func Ascending(expression Expression) OrderExpression

func AscendingField added in v0.2.6

func AscendingField(name string) OrderExpression

func Descending added in v0.2.6

func Descending(expression Expression) OrderExpression

func DescendingField added in v0.2.6

func DescendingField(name string) OrderExpression

type Precondition

type Precondition interface {
	// contains filtered or unexported methods
}

Precondition defines precondition

func WithExistsPrecondition

func WithExistsPrecondition() Precondition

WithExistsPrecondition sets exists precondition

func WithLastUpdateTimePrecondition

func WithLastUpdateTimePrecondition(t time.Time) Precondition

WithLastUpdateTimePrecondition sets last update time

type Preconditions

type Preconditions interface {
	Exists() bool
	LastUpdateTime() time.Time
}

Preconditions defines preconditions

func GetPreconditions

func GetPreconditions(items ...Precondition) Preconditions

GetPreconditions create Preconditions

type Query added in v0.2.6

type Query interface {
	String() string

	// Offset specifies the number of records to skip
	Offset() int

	// Limit specifies the maximum number of records to be returned
	Limit() int

	GetRecordsReader(ctx context.Context, qe QueryExecutor) (reader RecordsReader, err error)
	GetRecordsetReader(ctx context.Context, qe QueryExecutor) (reader RecordsetReader, err error)
}

type QueryArg added in v0.27.0

type QueryArg struct {
	Name  string
	Value any
}

type QueryBuilder added in v0.2.11

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

func NewQueryBuilder added in v0.15.0

func NewQueryBuilder(from FromSource) *QueryBuilder

NewQueryBuilder creates a new IQueryBuilder - it's an entry point to build a query. We can use From() directly but this is easier to remember.

func (*QueryBuilder) Clone added in v0.28.0

func (s *QueryBuilder) Clone() IQueryBuilder

func (*QueryBuilder) GroupBy added in v0.51.0

func (s *QueryBuilder) GroupBy(expressions ...Expression) IQueryBuilder

func (*QueryBuilder) Having added in v0.51.0

func (s *QueryBuilder) Having(conditions ...Condition) IQueryBuilder

func (*QueryBuilder) Limit added in v0.2.16

func (s *QueryBuilder) Limit(i int) IQueryBuilder

func (*QueryBuilder) Offset added in v0.2.16

func (s *QueryBuilder) Offset(i int) IQueryBuilder

func (*QueryBuilder) OrderBy added in v0.2.11

func (s *QueryBuilder) OrderBy(expressions ...OrderExpression) IQueryBuilder

func (*QueryBuilder) SelectColumns added in v0.50.0

func (s *QueryBuilder) SelectColumns(columns ...Column) StructuredQuery

func (*QueryBuilder) SelectIntoRecord added in v0.34.0

func (s *QueryBuilder) SelectIntoRecord(into func() record.Record) StructuredQuery

func (*QueryBuilder) SelectIntoRecordset added in v0.34.0

func (s *QueryBuilder) SelectIntoRecordset(options ...recordset.Option) StructuredQuery

func (*QueryBuilder) SelectKeysOnly added in v0.2.11

func (s *QueryBuilder) SelectKeysOnly(idKind reflect.Kind) StructuredQuery

func (*QueryBuilder) StartFrom added in v0.2.19

func (s *QueryBuilder) StartFrom(cursor Cursor) IQueryBuilder

func (*QueryBuilder) Where added in v0.2.11

func (s *QueryBuilder) Where(conditions ...Condition) IQueryBuilder

func (*QueryBuilder) WhereArrayContains added in v0.59.0

func (s *QueryBuilder) WhereArrayContains(name string, v any) IQueryBuilder

WhereArrayContains adds a condition that an array field contains the given value. Adapters translate it to the platform's array membership operator, e.g. Firestore's "array-contains". It is an alias for WhereInArrayField.

func (*QueryBuilder) WhereArrayContainsAny added in v0.59.0

func (s *QueryBuilder) WhereArrayContainsAny(name string, values any) IQueryBuilder

WhereArrayContainsAny adds a condition that an array field contains at least one element of the given values, e.g. Firestore's "array-contains-any". The values must be a dal.Array or a slice type supported by NewArray.

func (*QueryBuilder) WhereField added in v0.2.11

func (s *QueryBuilder) WhereField(name string, operator Operator, v any) IQueryBuilder

func (*QueryBuilder) WhereInArrayField added in v0.16.1

func (s *QueryBuilder) WhereInArrayField(name string, v any) IQueryBuilder

type QueryExecutor added in v0.2.14

type QueryExecutor interface {

	// ExecuteQueryToRecordsReader returns a reader for the given query to read records 1 by 1 sequentially.
	// The RecordsReader.Next() method returns ErrNoMoreRecords when there are no more records.
	ExecuteQueryToRecordsReader(ctx context.Context, query Query) (RecordsReader, error)

	// ExecuteQueryToRecordsetReader returns a RecordsetReader for the given query, allowing sequential read of records into the provided recordset.
	ExecuteQueryToRecordsetReader(ctx context.Context, query Query, options ...recordset.Option) (RecordsetReader, error)
}

QueryExecutor is a query executor that returns a reader and have few helper methods.

type ROTxWorker

type ROTxWorker = func(ctx context.Context, tx ReadTransaction) error

ROTxWorker defines a callback to be called to do work within a readonly transaction

type RWTxWorker

type RWTxWorker = func(ctx context.Context, tx ReadwriteTransaction) error

RWTxWorker defines a callback to be called to do work within a readwrite transaction

type RandomStringOptions

type RandomStringOptions interface {
	Prefix() string
	Length() int
}

RandomStringOptions defines settings for random string

type ReadSession

type ReadSession interface {
	Getter
	MultiGetter
	QueryExecutor
}

ReadSession defines methods that query data from DB and does not modify it

type ReadTransaction

type ReadTransaction interface {
	Transaction
	ReadSession
}

ReadTransaction defines an interface for a readonly transaction

type ReadTransactionCoordinator

type ReadTransactionCoordinator interface {

	// RunReadonlyTransaction starts readonly transaction
	RunReadonlyTransaction(ctx context.Context, f ROTxWorker, options ...TransactionOption) error
}

ReadTransactionCoordinator creates a readonly transaction

type Reader

type Reader interface {
	// Cursor points to a position in the result set. This can be used for pagination.
	Cursor() (string, error)

	// Close closes the reader
	Close() error
}

type ReaderOption added in v0.5.0

type ReaderOption = func(ro *ReaderOptions)

ReaderOption configures how SelectAll reads from the RecordsReader (e.g., limit, offset).

func WithLimit added in v0.5.0

func WithLimit(limit int) ReaderOption

WithLimit sets the maximum number of items to read. If limit <= 0, SelectAll reads until ErrNoMoreRecords.

func WithOffset added in v0.5.0

func WithOffset(offset int) ReaderOption

WithOffset skips the first N records before collecting results in SelectAll. If offset <= 0, no records are skipped.

type ReaderOptions added in v0.5.0

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

func (*ReaderOptions) Limit added in v0.5.0

func (ro *ReaderOptions) Limit() int

Limit specifies the maximum number of records to read, if 0 - unlimited

func (*ReaderOptions) Offset added in v0.5.0

func (ro *ReaderOptions) Offset() int

Offset specifies how many records to skip, if 0 - no records are skipped

type ReadwriteSession

type ReadwriteSession interface {
	ReadSession
	WriteSession
}

ReadwriteSession defines methods that can read & modify database. Some databases allow to modify data without transaction.

type ReadwriteTransaction

type ReadwriteTransaction interface {

	// ID returns a unique ID of a transaction if it is supported by the underlying DB client
	ID() string

	Transaction
	ReadwriteSession
}

ReadwriteTransaction defines an interface for a readwrite transaction

type ReadwriteTransactionCoordinator

type ReadwriteTransactionCoordinator interface {

	// RunReadwriteTransaction starts read-write transaction
	RunReadwriteTransaction(ctx context.Context, f RWTxWorker, options ...TransactionOption) error
}

ReadwriteTransactionCoordinator creates a read-write transaction

type RecordAfterLoadHook added in v0.2.7

type RecordAfterLoadHook interface {
	AfterLoad(ctx context.Context, key *record.Key) (err error)
}

type RecordBeforeSaveHook added in v0.2.7

type RecordBeforeSaveHook interface {
	BeforeSave(ctx context.Context, key *record.Key) (err error)
}

type RecordDataHook added in v0.2.9

type RecordDataHook = func(ctx context.Context, db DB, key *record.Key, data any) (err error)

type RecordDataOption added in v0.4.0

type RecordDataOption = func(rd *recordData)

type RecordHook added in v0.2.9

type RecordHook = func(ctx context.Context, record record.Record) error

type RecordsReader added in v0.3.1

type RecordsReader interface {
	Reader
	// Next returns the next record for a query.
	// If no more records, a nil record and ErrNoMoreRecords are returned.
	Next() (record.Record, error)
}

RecordsReader reads records one by one into record.Record

func NewRecordsReader added in v0.3.2

func NewRecordsReader(records []record.Record) RecordsReader

type RecordsetReader added in v0.34.0

type RecordsetReader interface {
	Reader
	Recordset() recordset.Recordset
	Next() (row recordset.Row, rs recordset.Recordset, err error)
}

RecordsetReader reads records one by one into recordset.Recordset

type RecordsetSource added in v0.22.0

type RecordsetSource interface {
	Name() string
	Alias() string
	// contains filtered or unexported methods
}

type Schema added in v0.25.0

type Schema interface {
	DataToKey(incompleteKey *record.Key, data any) (key *record.Key, err error)
	KeyToFields(key *record.Key, data any) (fields []ExtraField, err error)
}

func NewSchema added in v0.25.0

func NewSchema(keyToField KeyToFieldsFunc, dataToKey DataToKeyFunc) Schema

type SchemaBase added in v0.26.0

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

SchemaBase provides rules for mapping of fields, keys and collections

func (*SchemaBase) DataToKey added in v0.26.0

func (s *SchemaBase) DataToKey(incompleteKey *record.Key, data any) (key *record.Key, err error)

DataToKey creates a *record.Key from data read from DB

func (*SchemaBase) KeyToFields added in v0.26.0

func (s *SchemaBase) KeyToFields(key *record.Key, data any) (fields []ExtraField, err error)

KeyToFields maps key intoRecord DB fields. This is needed as relational DBs usually have key column(s) that are part of the record set, while key-value DBs can have key and data separated and data would not include the key.

type Setter added in v0.2.27

type Setter interface {

	// Set stores a single record intoRecord database by key
	Set(ctx context.Context, record record.Record) error
}

Setter defines a function to store a single record intoRecord database by key

type SingleSource added in v0.2.6

type SingleSource interface {
	Where(conditions ...Condition) IQueryBuilder
}

type StructuredQuery added in v0.27.0

type StructuredQuery interface {
	Query

	// From - defines target table/recordsetSource
	From() FromSource

	// Where defines filter condition
	Where() Condition

	// GroupBy defines expressions to group by
	GroupBy() []Expression

	// Having defines a post-aggregation filter condition
	Having() Condition

	// OrderBy defines expressions to order by
	OrderBy() []OrderExpression

	// Columns specifies columns to return
	Columns() []Column

	// IntoRecord provides a function that creates a record for a new row
	IntoRecord() record.Record // TODO: Should this be moved into Query.GetRecordsReader ?

	// IDKind defines the type of the ID
	IDKind() reflect.Kind // TODO: what about composite keys?

	// StartFrom specifies the startCursor/point to start from
	StartFrom() Cursor
}

StructuredQuery represents a query to a recordsetSource

type TextQuery added in v0.27.0

type TextQuery interface {
	Query
	Text() string
	Args() []QueryArg
}

TextQuery defines an interface to represent a query with text and associated arguments.

func NewTextQuery added in v0.27.0

func NewTextQuery(text string, getKey func(data any, args []QueryArg) *record.Key, args ...QueryArg) TextQuery

type TimeStampAccuracy added in v0.24.0

type TimeStampAccuracy int
const (
	TimeStampAccuracyNano TimeStampAccuracy = iota
	TimeStampAccuracyMicrosecond
	TimeStampAccuracyMillisecond
	TimeStampAccuracySecond
	TimeStampAccuracyMinute
	TimeStampAccuracyHour
	TimeStampAccuracyDay
)

type Transaction

type Transaction interface {
	// Options indicates parameters that were requested at time of transaction creation.
	// The message field is mutable during execution via TransactionOptions.SetMessage();
	// implementations should return options by shared reference so the update is observed.
	Options() TransactionOptions
}

Transaction defines an instance of DALgo transaction

func GetTransaction

func GetTransaction(ctx context.Context) Transaction

GetTransaction returns original transaction object

type TransactionCoordinator

type TransactionCoordinator interface {

	// ReadTransactionCoordinator can start a readonly transaction
	ReadTransactionCoordinator

	// ReadwriteTransactionCoordinator can start a readwrite transaction
	ReadwriteTransactionCoordinator
}

TransactionCoordinator provides methods to work with transactions

type TransactionOption

type TransactionOption func(options *txOptions)

TransactionOption defines contact for transaction option

func TxWithAttempts

func TxWithAttempts(attempts int) TransactionOption

TxWithAttempts specifies number of attempts to execute a transaction

func TxWithCrossGroup

func TxWithCrossGroup() TransactionOption

TxWithCrossGroup requires transaction that spans multiple entity groups

func TxWithIsolationLevel

func TxWithIsolationLevel(isolationLevel TxIsolationLevel) TransactionOption

TxWithIsolationLevel requests transaction with required isolation level

func TxWithMessage added in v0.45.0

func TxWithMessage(message string) TransactionOption

TxWithMessage sets a human-readable message on the transaction. The message can be read back via TransactionOptions.Message() and replaced during transaction execution via TransactionOptions.SetMessage().

func TxWithReadonly

func TxWithReadonly() TransactionOption

TxWithReadonly requests a readonly transaction

type TransactionOptions

type TransactionOptions interface {

	// Message returns an optional human-readable message describing the transaction.
	// Backends may surface it (e.g. dalgo2ingitdb uses it as a git commit message)
	// or include it in logs. It returns an empty string when no message was set.
	Message() string

	// SetMessage sets (replaces) the transaction message. It can be used at
	// transaction start via TxWithMessage, or during transaction execution.
	// It is available on both readonly and read-write transactions.
	SetMessage(message string)

	// IsolationLevel indicates requested isolation level
	IsolationLevel() TxIsolationLevel

	// IsReadonly indicates a readonly transaction
	IsReadonly() bool

	// IsCrossGroup indicates a cross-group transaction. Makes sense for Google App Engine.
	IsCrossGroup() bool

	// Attempts returns number of attempts to execute a transaction. This is used in Google Datastore for example.
	Attempts() int
}

TransactionOptions holds transaction settings

func NewTransactionOptions

func NewTransactionOptions(opts ...TransactionOption) TransactionOptions

NewTransactionOptions creates instance of TransactionOptions

type Transform

type Transform interface {

	// Name returns Name of a transform
	Name() string

	// Value returns arguments of transform
	Value() any
}

Transform defines a transform operation

func ArrayUnion

func ArrayUnion(elems ...any) Transform

ArrayUnion specifies elements to be added to whatever array already exists in the server, or to create an array if no value exists.

If a value exists and it's an array, values are appended to it. Any duplicate value is ignored. If a value exists and it's not an array, the value is replaced by an array of the values in the ArrayUnion. If a value does not exist, an array of the values in the ArrayUnion is created.

ArrayUnion must be the value of a field directly; it cannot appear in array or struct values, or in any value that is itself inside an array or struct.

func Increment

func Increment(v int) Transform

Increment defines an increment transform operation

func IsTransform

func IsTransform(v any) (t Transform, ok bool)

type TxIsolationLevel

type TxIsolationLevel int

TxIsolationLevel defines an isolation level for a transaction

const (
	// TxUnspecified indicates transaction level is not specified
	TxUnspecified TxIsolationLevel = iota

	// TxChaos - The pending changes from more highly isolated transactions cannot be overwritten.
	TxChaos

	// TxReadCommitted - Shared locks are held while the data is being read to avoid dirty reads,
	// but the data can be changed before the end of the transaction,
	// resulting in non-repeatable reads or phantom data.
	TxReadCommitted

	// TxReadUncommitted - A dirty read is possible, meaning that no shared locks are issued
	// and no exclusive locks are honored.
	TxReadUncommitted

	// TxRepeatableRead - Locks are placed on all data that is used in a query,
	// preventing other users from updating the data.
	// Prevents non-repeatable reads but phantom rows are still possible.
	TxRepeatableRead

	// TxSerializable - A range lock is placed on the DataSet, preventing other users
	// from updating or inserting rows intoRecord the dataset until the transaction is complete.
	TxSerializable

	// TxSnapshot - Reduces blocking by storing a version of data that one application can read
	// while another is modifying the same data.
	// Indicates that from one transaction you cannot see changes made in other transactions,
	// even if you requery.
	TxSnapshot
)

type Updater added in v0.2.27

type Updater interface {

	// Update updates a single record in a database by key
	Update(ctx context.Context, key *record.Key, updates []update.Update, preconditions ...Precondition) error

	// UpdateRecord updates a single record in a database.
	// For example, this is useful in case if we want to put the record.Data to memcache.
	// See https://github.com/dal-go/dalgo-memcache-appengine
	// A regular DB adapter should call update(record.Key()) inside this method.
	UpdateRecord(ctx context.Context, record record.Record, updates []update.Update, preconditions ...Precondition) error
}

Updater defines a function to update a single record in database by key

type ValidatableRecord added in v0.2.9

type ValidatableRecord interface {
	Validate() error
}

ValidatableRecord is implemented by record data that can check its own invariants. The framework write pipeline (see NewDB) calls Validate before a record reaches the storage adapter, so an adapter never gets the chance to skip it.

type WriteSession

WriteSession defines methods that can modify database

func WithoutValidation added in v0.64.0

func WithoutValidation(s WriteSession) WriteSession

WithoutValidation returns a write session that performs writes without validating record data. Registered hooks still run: this opts out of validation, not out of the pipeline.

It exists because some writes legitimately must skip validation — repair migrations, bulk import, writing a record that is known invalid in order to fix it later. The point is not to permit skipping but to make it visible and greppable at the call site instead of invisible inside an adapter:

if err := dal.WithoutValidation(tx).Set(ctx, rec); err != nil {

A session that is not framework-managed has no validation to skip and is returned unchanged.

Jump to

Keyboard shortcuts

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