storage

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: MIT Imports: 2 Imported by: 0

README

tinywasm/storage

Storage port for tinywasm: Executor/Compiler contract, DML value types, conformance and in-memory reference backend.

Overview

storage defines the foundational storage port for the tinywasm ecosystem. It specifies standard database driver interfaces (Executor & Compiler, unified as Conn) and agnostic DML value structures (e.g., Query, Condition, Order, Plan) that cross the boundary between query builders and drivers. It is designed specifically to be fully isomorphic and compatible with standard Go and TinyGo (GOOS=js GOARCH=wasm).

API Usage Documentation

This library provides raw DML constructs and interfaces without relying on a full ORM or heavy database drivers.

1. Connecting and Query Compilation

Use storage.Conn to execute and compile actions. Every backend driver (like sqlt or storage/mem) implements storage.Conn:

import (
	"github.com/tinywasm/storage"
	"github.com/tinywasm/storage/mem"
)

func main() {
	// Initialize the reference in-memory storage connection
	var conn storage.Conn = mem.New()
	defer conn.Close()
}
2. Formulating Queries and Conditions

Queries are represented as agnostic structured values using storage.Query:

// Define a query to read widgets where qty is greater than 10 and sorting by name descending
q := storage.Query{
	Action: storage.ActionReadAll,
	Table:  "widgets",
	Conditions: []storage.Condition{
		storage.Gt("qty", 10),
		storage.Eq("active", true),
	},
	OrderBy: []storage.Order{
		storage.Desc("name"),
	},
	Limit: 5,
}

Available conditions constructors:

  • storage.Eq(field, value)
  • storage.Neq(field, value)
  • storage.Gt(field, value)
  • storage.Gte(field, value)
  • storage.Lt(field, value)
  • storage.Lte(field, value)
  • storage.Like(field, pattern)
  • storage.In(field, slice)
  • storage.Or(condition) (wraps an existing condition with OR logic)
  • storage.IsNotNull(field)
3. Compiling and Executing Plans

Pass a storage.Query and its model.Model target to a Compiler to compile it into an engine-specific Plan, and execute it with the Executor:

// Compile the query against a model schema target
plan, err := conn.Compile(q, myModel)
if err != nil {
	log.Fatal(err)
}

// execute the query and retrieve rows iterator
rows, err := conn.Query(plan.Query, plan.Args...)
if err != nil {
	log.Fatal(err)
}
defer rows.Close()

for rows.Next() {
	var id string
	var name string
	var qty int64
	var active bool

	// scan values into destination pointers
	if err := rows.Scan(&id, &name, &qty, &active); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Row: %s %s %d %t\n", id, name, qty, active)
}
4. Direct Operations (Exec and QueryRow)
// For Create/Update/Delete operations
plan, _ := conn.Compile(insertQuery, myModel)
err := conn.Exec(plan.Query, plan.Args...)

// For scanning a single row
plan, _ = conn.Compile(singleQuery, myModel)
var name string
err = conn.QueryRow(plan.Query, plan.Args...).Scan(&name)
if errors.Is(err, storage.ErrNoRows) {
	fmt.Println("No rows matched the criteria")
}
5. Transactions

Backends that support transactions optionally implement storage.TxExecutor. You can type-assert and use it as follows:

if txConn, ok := conn.(storage.TxExecutor); ok {
	tx, err := txConn.BeginTx()
	if err != nil {
		log.Fatal(err)
	}
	defer tx.Rollback()

	// Execute on transaction
	tx.Exec("INSERT INTO widgets ...", ...)

	tx.Commit()
}
6. Mapping Scanned Values via ScanAny

The package includes a robust zero-reflection conversion function ScanAny(v any, dest any) error which converts JSON-decoded types (e.g. string, float64, boolean) safely into typed destination pointers. It is automatically utilized by storage/mem and other compliant drivers.

var dest int64
// converts raw float64 value from json decode safely into int64 pointer
err := storage.ScanAny(float64(42), &dest)

Running Tests

Tests are centralized in the tests/ directory and can be executed via the gotest command:

gotest

WASM compilation compatibility is checked via:

GOOS=js GOARCH=wasm go build ./...

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrNoRows = fmt.Err("no", "rows")

ErrNoRows is the agnostic sentinel for "query returned no rows". Conn implementations (postgres, sqlt) must map their driver-specific no-rows error to this value so callers can detect it without importing database/sql. This is the raw contract sentinel; orm.QB.ReadOne translates it to the ergonomic orm.ErrNotFound — db itself never does that translation.

Functions

func ScanAny

func ScanAny(v any, dest any) error

ScanAny maps a JSON-decoded Go value (any) into a typed pointer. Used by host-side adapters (REST, SQLite driver) and by db/mem, where values come from json.Unmarshal-shaped data rather than from js.Value.

Types

type Action

type Action int

Action represents the type of database DML operation. Purely DML — no DDL here (see §2).

const (
	ActionCreate Action = iota
	ActionReadOne
	ActionUpdate
	ActionDelete
	ActionReadAll
)

type Compiler

type Compiler interface {
	Compile(q Query, m model.Model) (Plan, error)
}

Compiler converts agnostic Query values into engine-specific Plans. Each backend dialect (postgres, sqlite) implements this to render its own SQL.

type Condition

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

Condition represents a filter for a query. Sealed value type constructed via helper functions.

func Eq

func Eq(field string, value any) Condition

Eq creates a condition for checking equality.

func Gt

func Gt(field string, value any) Condition

Gt creates a condition for checking if a value is greater than another.

func Gte

func Gte(field string, value any) Condition

Gte creates a condition for checking if a value is greater than or equal to another.

func In

func In(field string, value any) Condition

In creates a condition for checking if a value is in a list of values.

func IsNotNull

func IsNotNull(field string) Condition

IsNotNull creates a condition for checking if a value is not null.

func Like

func Like(field string, value any) Condition

Like creates a condition for checking if a value matches a pattern.

func Lt

func Lt(field string, value any) Condition

Lt creates a condition for checking if a value is less than another.

func Lte

func Lte(field string, value any) Condition

Lte creates a condition for checking if a value is less than or equal to another.

func Neq

func Neq(field string, value any) Condition

Neq creates a condition for checking inequality.

func Or

func Or(c Condition) Condition

Or creates a condition with OR logic (wraps an existing condition).

func (Condition) Field

func (c Condition) Field() string

func (Condition) Logic

func (c Condition) Logic() string

func (Condition) Operator

func (c Condition) Operator() string

func (Condition) Value

func (c Condition) Value() any

type Conn

type Conn interface {
	Executor
	Compiler
}

Conn is what a storage backend implements: the union of Executor and Compiler. Every real backend (postgres, sqlt, indexdb) is a single concrete type satisfying both halves — Conn names that pairing so it travels as one value instead of two arguments that could be mismatched (an Executor from one backend paired with a Compiler from another is an illegal state that used to be representable as two constructor args; Conn makes it impossible).

type Executor

type Executor interface {
	Exec(query string, args ...any) error
	QueryRow(query string, args ...any) Scanner
	Query(query string, args ...any) (Rows, error)
	Close() error
}

Executor represents the database connection abstraction. It must remain compatible with sql.DB, sql.Tx, mocks, and WASM drivers.

type Order

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

Order represents a sort order for a query. Sealed value type — construct with Asc/Desc.

func Asc

func Asc(column string) Order

Asc creates an ascending sort order for column.

func Desc

func Desc(column string) Order

Desc creates a descending sort order for column.

func (Order) Column

func (o Order) Column() string

func (Order) Dir

func (o Order) Dir() string

type Plan

type Plan struct {
	Mode  Action
	Query string
	Args  []any
}

Plan describes how a Conn should run the operation: the compiled query and its arguments.

type Query

type Query struct {
	Action     Action
	Table      string
	Columns    []string
	Values     []any
	Conditions []Condition
	OrderBy    []Order
	GroupBy    []string
	Limit      int
	Offset     int
}

Query represents a database DML query to be compiled and run by a Conn. Compilers read these fields to build a Plan.

type Rows

type Rows interface {
	Next() bool
	Scan(dest ...any) error
	Columns() ([]string, error)
	Close() error
	Err() error
}

Rows represents an iterator over query results.

type Scanner

type Scanner interface {
	Scan(dest ...any) error
}

Scanner represents a single row scanner.

type TxBoundExecutor

type TxBoundExecutor interface {
	Executor
	Commit() error
	Rollback() error
}

TxBoundExecutor represents an executor bound to a transaction.

type TxExecutor

type TxExecutor interface {
	Executor
	BeginTx() (TxBoundExecutor, error)
}

TxExecutor represents an executor that supports transactions. A Conn optionally implements this (type-assert it) to signal transaction support.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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