Help us shape the future of Go! Take the 2026 Go Developer Survey

dbunit

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

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

Go to latest
Published: Oct 21, 2026 License: Apache-2.0 Imports: 34 Imported by: 0

README

dbunit

SQL database fixtures, preparation, and assertions for Go and Endly.

dbunit helps test application behavior through the state of its database: load a known dataset, run the application, and verify the resulting rows. It uses Go's database/sql, SQLX for batch and native loading, and toolbox/data for fixture expressions.

It is the SQL-focused successor to dsunit. Assets are selected explicitly—through file roots, URLs, inline data, or embed.FS—and never inferred from test names or source-code locations.

Contents

Features

  • Prepare rows with insert, replace, sparse upsert, and key-based deletion.
  • Preserve the difference between an absent field, SQL NULL, and zero/false/empty values.
  • Read JSON, NDJSON, CSV/TSV, typed Go slices, and maps from explicit assets.
  • Expand toolbox variables and UDFs such as $AsInt(...), including nested records.
  • Generate fixture sequences and UUIDs, resolve references, and capture generated values.
  • Project logical fixtures into related physical tables with dependency ordering and key-based deduplication.
  • Compare full tables, selected keys, or explicit queries with precise numeric comparison and assertion predicates.
  • Load and extract native schema, export query results as fixtures, and compare database queries.
  • Use caller-owned database handles and explicit transaction policies.
  • Integrate with Go tests and Endly workflows through the same core engine.

Project status and installation

This repository is a development version; its API may evolve before a tagged release. Changes are tracked in CHANGELOG.md. Use Go 1.25.8 or newer, as declared in go.mod.

Install the module with:

go get github.com/viant/dbunit

Dependencies are pinned in go.mod. See the implementation plan for remaining parity work.

From dbunit, build and test with:

GOWORK=off go test ./...

Register the SQL driver and corresponding SQLX metadata product in your application. Native loading additionally requires its SQLX loader registration. The library does not own or close your *sql.DB.

Quick start

This example uses the pure-Go SQLite driver. PostgreSQL and MySQL use the same core API with their own drivers and SQL placeholder syntax.

package example

import (
    "context"
    "database/sql"
    "testing"

    "github.com/viant/dbunit"
    "github.com/viant/dbunit/dbtest"
    "github.com/viant/dbunit/fixture"
    "github.com/viant/toolbox/data"
    _ "github.com/viant/sqlx/metadata/product/sqlite"
    _ "modernc.org/sqlite"
)

func TestCustomer(t *testing.T) {
    ctx := context.Background()
    db, err := sql.Open("sqlite", ":memory:")
    if err != nil { t.Fatal(err) }
    defer db.Close()
    db.SetMaxOpenConns(1)

    engine, err := dbunit.New(db)
    if err != nil { t.Fatal(err) }

    report, err := engine.Run(ctx, dbunit.Case{
        State: data.Map{"customerID": "42"},
        Schema: []dbunit.Statement{{SQL: `CREATE TABLE customer (
            id INTEGER PRIMARY KEY, name TEXT, active BOOLEAN DEFAULT true
        )`}},
        Prepare: []dbunit.Dataset{{
            Table: dbunit.Table("customer"),
            Source: fixture.Maps([]map[string]any{{
                "id": "$AsInt($customerID)", "name": "Alice",
            }}),
        }},
        Act: func(ctx context.Context, run *dbunit.Run) error {
            _, err := run.Executor.ExecContext(ctx,
                "UPDATE customer SET name = ? WHERE id = ?", "Updated", 42)
            return err
        },
        Expect: []dbunit.Expectation{{
            Table: dbunit.Table("customer"),
            Scope: dbunit.Full,
            Expected: fixture.Maps([]map[string]any{{
                "id": 42, "name": "Updated", "active": true,
            }}),
            Match: dbunit.MatchOptions{Keys: []string{"id"}},
        }},
    })
    dbtest.Require(t, report, err)
}

Table("schema", "customer") is a qualified identifier. Table("customer.archive") is one literal identifier containing a dot. Generated SQL quotes identifiers and binds data values.

Embedded fixtures

//go:embed testdata
var assets embed.FS

engine, err := dbunit.New(db,
    dbunit.WithFixtures(fixture.Embed(&assets, "testdata")),
)
// A dataset with fixture.File("customers.json") reads from this embed.FS.

fixture.Embed uses the AFS embed provider and retains the supplied filesystem for each read. Other resolvers include fixture.Directory("/absolute/root"), fixture.FS(fsys, root), and fixture.AFS(service, baseURL, options...).

Fixture paths are relative only to the declared root. manifest.Load reads strict versioned JSON/YAML case manifests through the same resolver. See the usage guide for formats, limits, and source options.

Expressions and presence

[
  {"id":"$AsInt($customerID)","name":"$ToUpper(alice)","active":"$AsBool(false)"}
]

Standalone UDF expressions retain their result type. Embedded expressions become text. Each run has its own registry of predefined toolbox UDFs; caller functions can override or extend it through data.UDFKey.

Fixture field Meaning
Field absent Omit the column and retain its database default
null Write SQL NULL
0, false, "" Write that explicit value

The underlying structology.Maps adapter preserves nested presence through dynamic Go structs and Has markers. Hydration and mapping return fixture.Source values marked expanded: true; preparation does not evaluate their strings again. fixture.Resolved(rows) provides the same boundary for already-concrete data.

Toolbox's own error behavior is preserved: an unresolved or failed expression can remain literal text. Invalid typed column values fail conversion, but text columns can retain that text. See the usage guide for custom UDFs and conversion rules.

Hydration and sequences

Hydration builds concrete fixture rows before insertion. It supports named local sequences, ordered generation rules, UUIDs, tags/references, and captures. Sequence seeds can come from explicit database queries; a seed is a snapshot, not a concurrent database reservation.

Hydration does not insert records. Its returned identifiers and captures describe planned fixtures until preparation succeeds. The API and examples are detailed in fixture generation and mappings.

Mapping logical fixtures

A mapping projects one logical fixture into multiple physical table datasets. It supports nested and repeated source paths, parent/root references, literal defaults, required fields, explicit composite keys, and table dependencies.

Repeated keys merge complementary absent fields; conflicting present values fail. Explicit null, zero and empty values remain distinct from absence. Mapping outputs are concrete datasets ready for Prepare.

See fixture generation and mappings for a complete parent/child example and the exact path and conflict rules.

Verification policies

Dbunit preserves the two SQL verification scopes used by dsunit:

dsunit dbunit Rows checked
FullTableDatasetCheckPolicy Scope: dbunit.Full The whole table; extra or missing rows fail by default
SnapshotDatasetCheckPolicy Scope: dbunit.Keys with Match.Keys Rows selected by the expected key tuples; unrelated rows are ignored
expectation := dbunit.Expectation{
    Table: dbunit.Table("customer"),
    Scope: dbunit.Keys,
    Match: dbunit.MatchOptions{Keys: []string{"id"}},
    Expected: fixture.Maps([]map[string]any{{"id": 42, "name": "Updated"}}),
}

Snapshot keys are explicit and can be composite. Missing selected rows or duplicate actual keys fail. An empty full-table expectation asserts that the table is empty; an empty snapshot requires AllowEmpty because it selects no rows.

Assertly evaluates predicate assertions and <ds:...> macros. Dbunit controls row selection, one-to-one matching, exact numeric comparison, and failure aggregation. Expected fields are a subset by default; StrictFields also rejects extra fields. Contains explicitly allows additional rows within the selected scope. These options are independent of full-table versus snapshot selection.

Legacy @ directives are not silently interpreted; supported matching options are explicit fields on MatchOptions.

Transactions and loading

Default preparation owns one transaction, commits on success, and rolls back on error. WithTransaction(tx) borrows a caller transaction without completing it. CaseRollback wraps preparation, the application callback and assertions in a transaction that is rolled back; the callback must use run.Executor. Schema setup precedes that transaction.

Batch and default Auto use SQLX batches. WithNativeLoad explicitly enables a registered native loader with its transaction/format capabilities. BulkRequired fails when its requirements cannot be met. Nontransactional loaders require ExplicitNonAtomic; failed native writes are never retried as a batch.

Dialect Verification and limits
SQLite Local schema, preparation, assertion, transaction, and workflow tests
PostgreSQL Live PostgreSQL 16 schema/native-load tests; schema extractor targets ordinary PostgreSQL 14+ tables
MySQL Live MySQL 8 schema/native-load tests; native server warnings fail the load
BigQuery Nested adaptation covered locally; live loading/schema completeness remains unverified

PostgreSQL native COPY currently restricts identifier shapes; use batch loading for unsupported cases. Advanced schema objects are supported only where documented by SQLX. See the usage guide for matching limits and transaction details.

Schema and snapshots

  • ApplySchema: apply explicit SQL files, statements, or extracted artifacts.
  • ExtractSchema: extract selected tables with dependency and completeness policies.
  • Export: return JSON/NDJSON fixtures from an explicit bounded query.
  • Compare: compare two explicit queries, including named databases.
  • Exec: execute direct DML statements with bound-argument expansion and transaction ownership.

Schema artifacts include omissions and a checksum. Incomplete exports require explicit acceptance. Extraction is a same-dialect test-schema operation, not a full database backup or universal migration tool.

Endly

The Endly dbunit service exposes the core operations through workflow actions and MCP. Database pools and fixture resolvers are session-scoped; legacy dsunit remains available during migration. Inline fixtures and query arguments are deferred to the core so stateful expressions run once.

Compose sequence, hydrate, map, and prepare using explicit captures and state selectors. Seed each counter from its named database binding; bind each child to its parent through a tag reference or MappingParentRow. See cross-database counters and parent/child IDs. Preparation is atomic within one database; separate database actions do not share a distributed transaction.

See the Endly checkout's service/testing/dbunit/README.md for action contracts, native loading options, captures, and embedding APIs. The new fixture-generation API does not replace or modify the legacy global AsTableRecords UDF.

Testing and contributing

GOWORK=off go test ./...
GOWORK=off go test -race ./...
GOWORK=off go vet ./...
CGO_ENABLED=0 GOWORK=off go test ./...

Native PostgreSQL/MySQL tests are opt-in. See CONTRIBUTING.md for setup, test-service requirements, and benchmark commands. Bug reports and pull requests should include a small reproducible fixture and database/driver versions.

License and acknowledgements

Licensed under the Apache License, Version 2.0. Attribution is retained in NOTICE; both files were copied from dsunit.

This project builds on Viant's dsunit, SQLX, structology, toolbox, AFS, and assertly.

Documentation

Overview

Package dbunit prepares and validates explicit SQL database fixtures.

Index

Constants

This section is empty.

Variables

View Source
var ErrMappingConflict = errors.New("conflicting mapped row")

Functions

func SortMismatches

func SortMismatches(m []Mismatch)

SortMismatches provides deterministic presentation for consumers merging reports.

Types

type AssertionError

type AssertionError struct{ Report *Report }

func (*AssertionError) Error

func (a *AssertionError) Error() string

type Case

type Case struct {
	Name    string
	State   data.Map
	Schema  []Statement
	Prepare []Dataset
	Act     func(context.Context, *Run) error
	Expect  []Expectation
	Cleanup []Statement
}

type ColumnSpec

type ColumnSpec struct {
	Name     string                 `json:"name"`
	Type     reflect.Type           `json:"-"`
	Fields   []structology.MapField `json:"-"`
	Repeated bool                   `json:"repeated,omitempty"`
	JSON     bool                   `json:"json,omitempty"`
}

type CompareRequest

type CompareRequest struct {
	Name     string       `json:"name,omitempty"`
	Expected QueryRequest `json:"expected"`
	Actual   QueryRequest `json:"actual"`
	Match    MatchOptions `json:"match"`
}

CompareRequest compares two explicit query results, including named databases. The caller supplies deterministic ORDER BY clauses when Ordered is enabled.

type Dataset

type Dataset struct {
	Name      string         `json:"name,omitempty"`
	Database  string         `json:"database,omitempty"`
	Table     Identifier     `json:"table"`
	Source    fixture.Source `json:"source"`
	Operation Operation      `json:"operation,omitempty"`
	Load      LoadOptions    `json:"load,omitempty"`
	Columns   []ColumnSpec   `json:"columns,omitempty"`
	Keys      []string       `json:"keys,omitempty"`
	DependsOn []string       `json:"dependsOn,omitempty"`
}

type Engine

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

func New

func New(db *sql.DB, options ...Option) (*Engine, error)

func (*Engine) ApplySchema

func (e *Engine) ApplySchema(ctx context.Context, req SchemaApplyRequest) (*SchemaResult, error)

func (*Engine) Compare

func (e *Engine) Compare(ctx context.Context, req CompareRequest, options ...RunOption) (*Report, error)

func (*Engine) Compile

func (e *Engine) Compile(ctx context.Context, c Case) (*Plan, error)

func (*Engine) Exec

func (e *Engine) Exec(ctx context.Context, req ExecRequest, options ...RunOption) (result *ExecResult, err error)

func (*Engine) Expect

func (e *Engine) Expect(ctx context.Context, req ExpectRequest, options ...RunOption) (*Report, error)

func (*Engine) Export

func (e *Engine) Export(ctx context.Context, req ExportRequest, options ...RunOption) (*ExportResult, error)

func (*Engine) ExtractSchema

func (e *Engine) ExtractSchema(ctx context.Context, req SchemaExtractRequest) (*SchemaArtifact, error)

func (*Engine) Hydrate

func (e *Engine) Hydrate(ctx context.Context, req HydrateRequest, options ...RunOption) (*HydrateResult, error)

func (*Engine) Map

func (e *Engine) Map(ctx context.Context, req MapRequest, options ...RunOption) (*MapResult, error)

func (*Engine) Ping

func (e *Engine) Ping(ctx context.Context) error

func (*Engine) Prepare

func (e *Engine) Prepare(ctx context.Context, req PrepareRequest, options ...RunOption) (result *PrepareResult, err error)

func (*Engine) Query

func (e *Engine) Query(ctx context.Context, req QueryRequest, options ...RunOption) (*QueryResult, error)

func (*Engine) Run

func (e *Engine) Run(ctx context.Context, definition Case, options ...RunOption) (report *Report, err error)

func (*Engine) RunPlan

func (e *Engine) RunPlan(ctx context.Context, p *Plan, options ...RunOption) (*Report, error)

func (*Engine) Sequence

func (e *Engine) Sequence(ctx context.Context, req SequenceRequest, options ...RunOption) (*SequenceResult, error)

type ExecRequest

type ExecRequest struct {
	Database   string      `json:"database,omitempty"`
	Statements []Statement `json:"statements"`
	State      data.Map    `json:"state,omitempty"`
}

ExecRequest runs explicit SQL statements against a single connection/transaction. Only bound arguments are expanded; SQL text is sent as authored. Statements are direct INSERT/UPDATE/DELETE/MERGE/REPLACE commands; CTE-wrapped commands are unsupported. Statements are DML; use ApplySchema for DDL and transaction options for ownership.

type ExecResult

type ExecResult struct {
	RowsAffected int64  `json:"rowsAffected"`
	Statements   int    `json:"statements"`
	Transaction  string `json:"transaction"`
}

type Executor

type Executor interface {
	ExecContext(context.Context, string, ...any) (sql.Result, error)
	QueryContext(context.Context, string, ...any) (*sql.Rows, error)
	QueryRowContext(context.Context, string, ...any) *sql.Row
}

type ExpectRequest

type ExpectRequest struct {
	Expectations []Expectation `json:"expectations"`
	State        data.Map      `json:"state,omitempty"`
}

type Expectation

type Expectation struct {
	Name     string         `json:"name,omitempty"`
	Database string         `json:"database,omitempty"`
	Table    Identifier     `json:"table,omitempty"`
	Query    *QuerySpec     `json:"query,omitempty"`
	Expected fixture.Source `json:"expected"`
	Scope    Scope          `json:"scope,omitempty"`
	Match    MatchOptions   `json:"match,omitempty"`
}

type ExportRequest

type ExportRequest struct {
	Query  QueryRequest `json:"query"`
	Format string       `json:"format,omitempty"`
}

ExportRequest captures an explicit bounded query as a reusable fixture. Persist Content to an explicit destination chosen by the caller.

type ExportResult

type ExportResult struct {
	Format  string `json:"format"`
	Content []byte `json:"content"`
	Rows    int    `json:"rows"`
}

type FixtureSequence

type FixtureSequence struct {
	Name  string `json:"name"`
	Start int64  `json:"start,omitempty"`
	// StartFrom is an explicit private-state path for continuation. It is not a template.
	StartFrom string        `json:"startFrom,omitempty"`
	Step      int64         `json:"step,omitempty"`
	Seed      *QueryRequest `json:"seed,omitempty"`
}

FixtureSequence is a local deterministic counter. Start includes zero; Step defaults to one. Seed replaces Start using one exact integer query result. A database seed is a snapshot, never a concurrent database ID reservation.

type FixtureSequenceState

type FixtureSequenceState struct {
	Next      int64 `json:"next"`
	Step      int64 `json:"step"`
	Allocated int64 `json:"allocated"`
	Seeded    bool  `json:"seeded,omitempty"`
}

type Generation

type Generation struct {
	Field     []string `json:"field,omitempty"`
	State     string   `json:"state,omitempty"`
	Sequence  string   `json:"sequence,omitempty"`
	UUID      bool     `json:"uuid,omitempty"`
	Value     any      `json:"value,omitempty"`
	HasValue  bool     `json:"hasValue,omitempty"`
	Overwrite bool     `json:"overwrite,omitempty"`
}

Generation selects exactly one of Sequence, UUID, or Value. HasValue permits an explicit nil Value. Field is an exact nested map path, never dotted SQL. An existing Field is retained without consuming a value unless Overwrite. State optionally names a private state alias available to following steps.

type HydrateRequest

type HydrateRequest struct {
	State     data.Map          `json:"state,omitempty"`
	Sequences []FixtureSequence `json:"sequences,omitempty"`
	Tables    []HydrationTable  `json:"tables"`
	// UUID is an invocation-local test hook; nil uses crypto/rand UUID v4.
	UUID          func() (string, error)  `json:"-"`
	MaxRows       int                     `json:"maxRows,omitempty"`
	StateCaptures []HydrationStateCapture `json:"stateCaptures,omitempty"`
}

type HydrateResult

type HydrateResult struct {
	Tables    []HydratedTable                      `json:"tables"`
	Sequences map[string]FixtureSequenceState      `json:"sequences"`
	Captures  data.Map                             `json:"captures"`
	Tags      map[string]map[string]map[string]any `json:"tags,omitempty"`
}

type HydratedTable

type HydratedTable struct {
	Name   string         `json:"name"`
	Table  Identifier     `json:"table,omitempty"`
	Source fixture.Source `json:"source"`
}

type HydrationCapture

type HydrationCapture struct {
	Field  []string `json:"field,omitempty"`
	Path   string   `json:"path"`
	Append bool     `json:"append,omitempty"`
}

HydrationCapture publishes a final row or field under an explicit state path. Append collects ordered values; duplicate non-append destinations are errors.

type HydrationStateCapture

type HydrationStateCapture struct {
	From string `json:"from"`
	Path string `json:"path"`
}

type HydrationTable

type HydrationTable struct {
	Name   string         `json:"name,omitempty"`
	Table  Identifier     `json:"table,omitempty"`
	Source fixture.Source `json:"source"`
	// TagField explicitly selects and removes a tag field, e.g. ["!tag"].
	TagField []string `json:"tagField,omitempty"`
	// Before runs once, even for an empty source, and writes state aliases only.
	Before   []Generation `json:"before,omitempty"`
	Generate []Generation `json:"generate,omitempty"`
	// PostIncrement runs once per nonempty table entry after its rows expand.
	PostIncrement []string           `json:"postIncrement,omitempty"`
	References    []RecordReference  `json:"references,omitempty"`
	Captures      []HydrationCapture `json:"captures,omitempty"`
}

type Identifier

type Identifier []string

Identifier preserves components: Table("a.b") names one identifier containing a dot.

func Table

func Table(parts ...string) Identifier

func (*Identifier) UnmarshalJSON

func (i *Identifier) UnmarshalJSON(data []byte) error

type LoadOptions

type LoadOptions struct {
	Strategy  Strategy `json:"strategy,omitempty"`
	BatchSize int      `json:"batchSize,omitempty"`
}

type MapRequest

type MapRequest struct {
	Mapping Mapping        `json:"mapping"`
	Source  fixture.Source `json:"source"`
	State   data.Map       `json:"state,omitempty"`
}

MapRequest projects an explicitly selected logical fixture into physical tables. Source expressions are expanded once; mapping defaults are literal values.

type MapResult

type MapResult struct {
	Datasets []Dataset `json:"datasets"`
}

MapResult contains concrete, detached datasets ready for Prepare. Mapping does not write to the database or reserve generated identifiers.

type Mapping

type Mapping struct {
	Name   string         `json:"name" yaml:"name"`
	Tables []MappingTable `json:"tables" yaml:"tables"`
}

Mapping projects one logical fixture into explicitly named physical datasets. It has no mutable registry, expression evaluator or database connection.

type MappingColumn

type MappingColumn struct {
	Name       string       `json:"name" yaml:"name"`
	Path       []string     `json:"path,omitempty" yaml:"path,omitempty"`
	Scope      MappingScope `json:"scope,omitempty" yaml:"scope,omitempty"`
	Default    any          `json:"default,omitempty" yaml:"default,omitempty"`
	HasDefault bool         `json:"hasDefault,omitempty" yaml:"hasDefault,omitempty"`
	Required   bool         `json:"required,omitempty" yaml:"required,omitempty"`
}

MappingColumn preserves absent/null/zero distinctions. An empty Path defaults to [Name], except for Element. Defaults are literal values applied only when the source field is absent. HasDefault permits an explicit null default in Go; JSON decoding sets it when a default property is present. Required means present and non-null, including false, zero and the empty string.

func (*MappingColumn) UnmarshalJSON

func (c *MappingColumn) UnmarshalJSON(content []byte) error

func (*MappingColumn) UnmarshalYAML

func (c *MappingColumn) UnmarshalYAML(node *yaml.Node) error

type MappingConflictError

type MappingConflictError struct {
	Mapping  string
	Dataset  string
	Row      int
	Path     string
	Column   string
	Existing any
	Incoming any
}

MappingConflictError identifies a conflicting physical column without hiding either value. No output datasets are returned after a conflict.

func (*MappingConflictError) Error

func (e *MappingConflictError) Error() string

func (*MappingConflictError) Unwrap

func (e *MappingConflictError) Unwrap() error

type MappingPlan

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

MappingPlan is an immutable compiled mapping. Concurrent Map calls share no rows, deduplication state, defaults or input references.

func CompileMapping

func CompileMapping(spec Mapping) (*MappingPlan, error)

CompileMapping validates and snapshots a deterministic dependency graph. Cycles and duplicate physical destinations are rejected before any fixture is read. Separate projections to one table must be expressed as one mapping node.

func (*MappingPlan) Map

func (p *MappingPlan) Map(ctx context.Context, rows []map[string]any) ([]Dataset, error)

Map projects concrete logical rows without evaluating expressions or generating identities. Its fresh inline sources are marked Expanded so Prepare preserves literal values. Numeric key values normalize exactly across Go widths and json.Number; strings, numbers, booleans and times occupy distinct key domains. Composite components are length-delimited. Nested column values are atomic: conflicting JSON objects are rejected instead of implicitly deep-merged.

type MappingScope

type MappingScope string

MappingScope identifies the object used by a column path. Parent is the nearest association's source; ParentRow is its projected physical row. Root is the original logical record. Element projects an entire repeated scalar (or object) and requires an empty path.

const (
	MappingSource    MappingScope = "source"
	MappingRoot      MappingScope = "root"
	MappingParent    MappingScope = "parent"
	MappingParentRow MappingScope = "parentRow"
	MappingElement   MappingScope = "element"
)

type MappingTable

type MappingTable struct {
	Name              string                `json:"name" yaml:"name"`
	Table             Identifier            `json:"table" yaml:"table"`
	Path              []string              `json:"path,omitempty" yaml:"path,omitempty"`
	Columns           []MappingColumn       `json:"columns" yaml:"columns"`
	Keys              []string              `json:"keys,omitempty" yaml:"keys,omitempty"`
	DependsOn         []string              `json:"dependsOn,omitempty" yaml:"dependsOn,omitempty"`
	Associations      []MappingTable        `json:"associations,omitempty" yaml:"associations,omitempty"`
	Database          string                `json:"database,omitempty" yaml:"database,omitempty"`
	Operation         Operation             `json:"operation,omitempty" yaml:"operation,omitempty"`
	Load              LoadOptions           `json:"load,omitempty" yaml:"load,omitempty"`
	OnMissingRequired MissingRequiredPolicy `json:"onMissingRequired,omitempty" yaml:"onMissingRequired,omitempty"`
}

MappingTable selects objects or repeated elements using literal path segments. Paths are relative to the logical root for top-level tables and to the nearest parent's selected object for associations. Arrays are traversed in input order. Missing/null paths and empty collections emit no rows. A skipped required row skips its descendants. Associations depend on the parent table automatically; other physical prerequisites are explicit DependsOn names.

Keys enable row deduplication. Without Keys every selected object emits a row. Duplicate keys merge absent columns; conflicting present values are errors. Every table yields a Dataset, including an empty one (so Replace can clear it).

type MatchOptions

type MatchOptions struct {
	Keys         []string `json:"keys,omitempty"`
	Ordered      bool     `json:"ordered,omitempty"`
	OrderBy      []string `json:"orderBy,omitempty"`
	Multiset     bool     `json:"multiset,omitempty"`
	Contains     bool     `json:"contains,omitempty"`
	StrictFields bool     `json:"strictFields,omitempty"`
	AllowEmpty   bool     `json:"allowEmpty,omitempty"`
	MaxRows      int      `json:"maxRows,omitempty"`
	JSONColumns  []string `json:"jsonColumns,omitempty"`
}

type Mismatch

type Mismatch struct {
	Expectation string `json:"expectation,omitempty"`
	Path        string `json:"path"`
	Category    string `json:"category"`
	Expected    any    `json:"expected,omitempty"`
	Actual      any    `json:"actual,omitempty"`
	Message     string `json:"message,omitempty"`
}

type MissingRequiredPolicy

type MissingRequiredPolicy string
const (
	MissingRequiredError MissingRequiredPolicy = "error"
	MissingRequiredSkip  MissingRequiredPolicy = "skip"
)

type NativeLoadOptions

type NativeLoadOptions struct {
	Transactional bool   `json:"transactional,omitempty"`
	Format        string `json:"format,omitempty"`
	MinRows       int    `json:"minRows,omitempty"`
}

NativeLoadOptions is an explicit caller assertion that the registered SQLX loader has been certified for this driver and workload. Auto remains Batch unless this option is supplied.

type Operation

type Operation string
const (
	Insert         Operation = "insert"
	Replace        Operation = "replace"
	Upsert         Operation = "upsert"
	DeleteMatching Operation = "deleteMatching"
)

type OperationError

type OperationError struct {
	Operation, Dataset string
	Row                int
	Err                error
}

func (*OperationError) Error

func (e *OperationError) Error() string

func (*OperationError) Unwrap

func (e *OperationError) Unwrap() error

type Option

type Option func(*Engine) error

func WithDatabase

func WithDatabase(name string, db *sql.DB) Option

func WithDialect

func WithDialect(name string) Option

func WithFixtures

func WithFixtures(r fixture.Resolver) Option

func WithMaxRows

func WithMaxRows(n int) Option

func WithNativeLoad

func WithNativeLoad(capability NativeLoadOptions) Option

func WithState

func WithState(state data.Map) Option

type Plan

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

type PrepareRequest

type PrepareRequest struct {
	Datasets []Dataset `json:"datasets"`
	State    data.Map  `json:"state,omitempty"`
}

type PrepareResult

type PrepareResult struct {
	Steps       []StepResult `json:"steps"`
	Rows        int64        `json:"rows"`
	Transaction string       `json:"transaction"`
}

type QueryRequest

type QueryRequest struct {
	Database string   `json:"database,omitempty"`
	SQL      string   `json:"sql"`
	Args     []any    `json:"args,omitempty"`
	State    data.Map `json:"state,omitempty"`
	MaxRows  int      `json:"maxRows,omitempty"`
}

type QueryResult

type QueryResult struct {
	Columns []string         `json:"columns"`
	Rows    structology.Maps `json:"rows"`
}

type QuerySpec

type QuerySpec struct {
	SQL  string `json:"sql"`
	Args []any  `json:"args,omitempty"`
}

type RecordReference

type RecordReference struct {
	Field     []string `json:"field"`
	Table     string   `json:"table"`
	Tag       string   `json:"tag"`
	From      []string `json:"from,omitempty"`
	Overwrite bool     `json:"overwrite,omitempty"`
}

RecordReference links tagged rows after all generation and template expansion. Forward references are allowed. References may depend on other references; cycles are rejected. From is an exact nested path; empty selects the whole row.

type Report

type Report struct {
	Name        string         `json:"name,omitempty"`
	Passed      int            `json:"passed"`
	Failed      int            `json:"failed"`
	Mismatches  []Mismatch     `json:"mismatches,omitempty"`
	Preparation *PrepareResult `json:"preparation,omitempty"`
	Duration    time.Duration  `json:"duration,omitempty"`
	// contains filtered or unexported fields
}

func (*Report) Err

func (r *Report) Err() error

type Run

type Run struct {
	State    data.Map
	Executor Executor
	// contains filtered or unexported fields
}

func (*Run) Query

func (r *Run) Query(ctx context.Context, req QueryRequest) (*QueryResult, error)

func (*Run) Set

func (r *Run) Set(path string, value any) error

type RunOption

type RunOption func(*runConfig) error

func WithRunState

func WithRunState(state data.Map) RunOption

func WithTransaction

func WithTransaction(tx *sql.Tx) RunOption

func WithTransactionMode

func WithTransactionMode(mode TransactionMode) RunOption

type SchemaApplyRequest

type SchemaApplyRequest struct {
	Database     string           `json:"database,omitempty"`
	Sources      []fixture.Source `json:"sources,omitempty"`
	Statements   []string         `json:"statements,omitempty"`
	Artifact     *SchemaArtifact  `json:"artifact,omitempty"`
	AllowPartial bool             `json:"allowPartial,omitempty"`
}

type SchemaArtifact

type SchemaArtifact struct {
	Product    string   `json:"product"`
	SQL        string   `json:"sql"`
	Statements []string `json:"statements"`
	Complete   bool     `json:"complete"`
	Omissions  []string `json:"omissions,omitempty"`
	Checksum   string   `json:"checksum"`
}

type SchemaExtractRequest

type SchemaExtractRequest struct {
	Database             string   `json:"database,omitempty"`
	Schema               string   `json:"schema,omitempty"`
	Tables               []string `json:"tables"`
	AllowPartial         bool     `json:"allowPartial,omitempty"`
	IncludeDependencies  bool     `json:"includeDependencies,omitempty"`
	IncludeViews         bool     `json:"includeViews,omitempty"`
	IncludeTriggers      bool     `json:"includeTriggers,omitempty"`
	IncludeSequenceState bool     `json:"includeSequenceState,omitempty"`
}

type SchemaResult

type SchemaResult struct {
	Statements  int    `json:"statements"`
	Transaction string `json:"transaction"`
}

type Scope

type Scope string
const (
	Full  Scope = "full"
	Keys  Scope = "keys"
	Query Scope = "query"
)

type SequenceRequest

type SequenceRequest struct {
	State     data.Map          `json:"state,omitempty"`
	Sequences []FixtureSequence `json:"sequences"`
}

type SequenceResult

type SequenceResult struct {
	Sequences map[string]FixtureSequenceState `json:"sequences"`
}

type Statement

type Statement struct {
	Database string `json:"database,omitempty"`
	SQL      string `json:"sql"`
	Args     []any  `json:"args,omitempty"`
}

type StepResult

type StepResult struct {
	Operation string        `json:"operation,omitempty"`
	Name      string        `json:"name,omitempty"`
	Table     Identifier    `json:"table,omitempty"`
	Rows      int64         `json:"rows"`
	Strategy  Strategy      `json:"strategy,omitempty"`
	Reason    string        `json:"reason,omitempty"`
	Duration  time.Duration `json:"duration,omitempty"`
	Error     string        `json:"error,omitempty"`
}

type Strategy

type Strategy string
const (
	Auto         Strategy = "auto"
	Batch        Strategy = "batch"
	BulkRequired Strategy = "bulkRequired"
)

type TransactionMode

type TransactionMode string
const (
	PrepareAtomic     TransactionMode = "prepareAtomic"
	CallerTransaction TransactionMode = "callerTransaction"
	CaseRollback      TransactionMode = "caseRollback"
	ExplicitNonAtomic TransactionMode = "nonAtomic"
)

Directories

Path Synopsis
Package dbtest integrates dbunit reports with Go's testing package.
Package dbtest integrates dbunit reports with Go's testing package.
Package fixture loads explicitly selected test data.
Package fixture loads explicitly selected test data.
Package manifest decodes explicit, versioned dbunit cases.
Package manifest decodes explicit, versioned dbunit cases.

Jump to

Keyboard shortcuts

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