orm

package module
v0.11.4 Latest Latest
Warning

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

Go to latest
Published: Jul 19, 2026 License: MIT Imports: 3 Imported by: 2

README

tinywasm/orm

Ultra-lightweight, strongly-typed ORM engineered for WebAssembly and backend environments.

Features

  • Declarative Source of Truth: Hand-written model.Definition literals as the source for code generation.
  • Zero Reflection: Interface-driven schema via github.com/tinywasm/model with generated code.
  • Isomorphic: Same generated code works in Go (backend) and WASM (frontend).
  • 0-alloc Codec: Symmetric, reflection-free serialization/deserialization methods generated for every model.
  • Query Builder: Reflection-free, type-safe query building.
  • Backend-Agnostic: orm.DB wraps a storage.Conn — no storage contract is defined here, so any backend implementing tinywasm/storage (Postgres, SQLite, in-memory, IndexedDB, ...) works unchanged.

Ecosystem

This repository is the ergonomic layer only — the equivalent of database/sql. It defines no storage contract of its own. Other parts of the ecosystem:

Component Repository Role
storage tinywasm/storage Storage port (Executor/Compiler/Query/Condition/Plan, mock, mem) — the equivalent of database/sql/driver. A backend implements storage.Conn; orm.New(conn) takes one.
ormc tinywasm/ormc Build-time code generator.
ddlc tinywasm/ddlc SQL Schema (DDL) exporter and utilities.
sqlmcp tinywasm/sqlmcp MCP tool provider for LLM interaction.

Installation

go get github.com/tinywasm/orm

To install the code generator:

go install github.com/tinywasm/ormc/cmd/ormc@latest

Declarative Workflow

In this ORM, you write the typed definition of your model, and ormc generates the concrete struct and the rest of the code. This ensures your schema is a compile-time checked symbol, eliminating errors from fragile string tags.

1. Define your models

Create a model.go or models.go file. Define your models as model.Definition variables ending in Model.

package user

import (
    "github.com/tinywasm/model"
)

var UserModel = model.Definition{
    Name: "user",
    Fields: model.Fields{
        {Name: "id",    Type: model.Int(),  DB: &model.FieldDB{PK: true, AutoInc: true}},
        {Name: "name",  Type: model.Text(), NotNull: true, Permitted: model.Permitted{Minimum: 2}},
        {Name: "email", Type: model.Text(), NotNull: true, DB: &model.FieldDB{Unique: true}},
        {Name: "bio",   Type: model.Text(), OmitEmpty: true},
        {Name: "addr",  Type: model.Struct(), Ref: &AddressModel},
    },
}

var AddressModel = model.Definition{
    Name: "address",
    Fields: model.Fields{
        {Name: "street", Type: model.Text()},
        {Name: "city",   Type: model.Text()},
    },
}
2. Generate
ormc

Generates model_orm.go next to each source file, containing the type User struct, type Address struct, and all interface implementations.

3. Use it
func GetUser(db *orm.DB, id int64) (*user.User, error) {
    return user.ReadOneUser(
        db.Query(&user.User{}).Where("id").Eq(id),
        &user.User{},
    )
}

Definition Reference

model.Field Options
Field Meaning
Name wire/DB column name (snake_case). Becomes PascalCase in the generated struct.
Type model.Kind (e.g. model.Text(), model.Int(), model.Struct()).
NotNull NOT NULL constraint in DB.
OmitEmpty Skips field if zero-value in codecs.
Exclude Field exists in generated struct but is skipped in Schema(), Pointers(), and codecs (e.g. for password_hash).
Widget Binding for UI rendering (see tinywasm/form/input).
DB Database-specific metadata (PK, Unique, AutoInc, RefColumn, OnDelete).
Ref Points to another *model.Definition. Used for composition or scalar Foreign Keys.
Permitted Validation rules (Minimum, Maximum, Letters, Numbers, etc.).
Relations
  1. Composition: When Type is model.Struct() or model.StructSlice(). The field becomes a nested struct or slice of structs part of the same row/JSON.
  2. Scalar Foreign Key: When Type is a scalar (e.g. model.Int()) and Ref is non-nil. Adds DDL metadata for FOREIGN KEY constraints.
{Name: "user_id", Type: model.Int(), Ref: &UserModel, DB: &model.FieldDB{RefColumn: "id", OnDelete: "CASCADE"}}

Schema Types Mapping

model.Kind Generated Go Type Codec Method
model.Text(), model.Raw() string String / Raw
model.Int() int64 Int
model.Float() float64 Float
model.Bool() bool Bool
model.Blob() []byte Bytes
model.IntSlice() []int Array
model.Struct() T (from Ref) Object
model.StructSlice() []*T (from Ref) Array

Generated Code

The ormc generator produces:

  • type T struct declaration.
  • Schema() []model.Field, Pointers() []any (parallel, zero-alloc).
  • EncodeFields(model.FieldWriter), DecodeFields(model.FieldReader) (symmetric codec).
  • IsNil() bool.
  • Validate(action byte) error (calling model.ValidateFields). Always generated.
  • ModelName() string.
  • ReadOneT(), ReadAllT(), TList type (for DB models).
  • SchemaExt() []ddlc.FieldExt (requires tinywasm/ddlc).

More Documentation

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	Eq        = storage.Eq
	Neq       = storage.Neq
	Gt        = storage.Gt
	Gte       = storage.Gte
	Lt        = storage.Lt
	Lte       = storage.Lte
	Like      = storage.Like
	In        = storage.In
	Or        = storage.Or
	IsNotNull = storage.IsNotNull
	Asc       = storage.Asc
	Desc      = storage.Desc
)
View Source
var ErrEmptyTable = fmt.Err("name", "table", "empty")

ErrEmptyTable is returned when ModelName() returns an empty string.

View Source
var ErrNoTxSupport = fmt.Err("transaction", "not", "supported")

ErrNoTxSupport is returned by DB.Tx() when the underlying storage.Conn does not implement storage.TxExecutor.

View Source
var ErrNotFound = fmt.Err("record", "not", "found")

ErrNotFound is returned when ReadOne() finds no matching row. Translates storage.ErrNoRows — storage itself has no concept of "not found", only "no rows" (see qb.go's ReadOne).

View Source
var ErrValidation = fmt.Err("error", "validation")

ErrValidation is returned when validate() finds a mismatch.

Functions

This section is empty.

Types

type Clause added in v0.0.8

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

Clause represents an intermediate state for building a query condition.

func (*Clause) Eq added in v0.0.8

func (c *Clause) Eq(value any) *QB

func (*Clause) Gt added in v0.0.8

func (c *Clause) Gt(value any) *QB

func (*Clause) Gte added in v0.0.8

func (c *Clause) Gte(value any) *QB

func (*Clause) In added in v0.0.12

func (c *Clause) In(value any) *QB

func (*Clause) Like added in v0.0.8

func (c *Clause) Like(value any) *QB

func (*Clause) Lt added in v0.0.8

func (c *Clause) Lt(value any) *QB

func (*Clause) Lte added in v0.0.8

func (c *Clause) Lte(value any) *QB

func (*Clause) Neq added in v0.0.8

func (c *Clause) Neq(value any) *QB

type Condition

type Condition = storage.Condition

Re-exports of storage's DML value types and condition/order constructors, so that a consumer calling Update/Delete (which take a storage.Condition explicitly) doesn't need a second import just for Eq/Gt/etc. These are aliases, not new types/wrappers — orm.Condition IS storage.Condition, orm.Eq IS storage.Eq. Zero duplication, zero conversion. See docs/PLAN.md §3.

type DB

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

DB represents an ergonomic handle over a storage backend (a storage.Conn). Consumers instantiate it via New(). This type owns no contract — storage.Conn is the contract; DB is the fluent layer on top of it (see docs/ARQUITECTURE.md).

func New

func New(conn storage.Conn) *DB

New wraps a storage.Conn (a backend's Executor+Compiler pair, e.g. sqlt.Open(dsn) or mem.New()) in the ergonomic DB handle. One argument, not two: storage.Conn already unifies Executor+Compiler so an Executor from one backend can never be paired with a Compiler from another.

func (*DB) Close added in v0.0.10

func (d *DB) Close() error

Close closes the underlying connection.

func (*DB) Create

func (d *DB) Create(m model.Model) error

Create inserts a new model into the database.

func (*DB) Delete

func (d *DB) Delete(m model.Model, cond storage.Condition, rest ...storage.Condition) error

Delete deletes a model from the database. At least one Condition is required. Providing zero conditions is a compile-time error, preventing accidental full-table DELETE statements.

func (*DB) Query

func (d *DB) Query(m model.Model) *QB

Query creates a new QB instance.

func (*DB) RawConn added in v0.11.0

func (d *DB) RawConn() storage.Conn

RawConn returns the underlying storage.Conn. Renamed from RawExecutor: what's underneath is a full Conn (Executor+Compiler), not just an Executor.

func (*DB) SetLog added in v0.9.1

func (d *DB) SetLog(fn func(messages ...any))

SetLog sets the log function for warnings and informational messages. If not set, messages are silently discarded.

func (*DB) Tx

func (d *DB) Tx(fn func(tx *DB) error) error

Tx executes a function within a transaction. The underlying storage.Conn must implement storage.TxExecutor (type-asserted here) — most backends do; mem.New() also implements it as a no-op so tests can exercise this path without a real transactional backend.

func (*DB) Update

func (d *DB) Update(m model.Model, cond storage.Condition, rest ...storage.Condition) error

Update modifies an existing row. At least one Condition is required. Providing zero conditions is a compile-time error — there is no variadic fallback — preventing accidental full-table UPDATE statements.

type Order

type Order = storage.Order

type OrderClause added in v0.0.8

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

OrderClause represents an intermediate state for building an order by clause.

func (*OrderClause) Asc added in v0.0.8

func (o *OrderClause) Asc() *QB

Asc sets the order direction to ascending.

func (*OrderClause) Desc added in v0.0.8

func (o *OrderClause) Desc() *QB

Desc sets the order direction to descending.

type QB

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

QB represents a query builder. Consumers hold a *QB reference in variables for incremental building.

func (*QB) GroupBy

func (qb *QB) GroupBy(columns ...string) *QB

GroupBy adds a group by clause to the query.

func (*QB) Limit

func (qb *QB) Limit(limit int) *QB

Limit sets the limit for the query.

func (*QB) Offset

func (qb *QB) Offset(offset int) *QB

Offset sets the offset for the query.

func (*QB) Or added in v0.0.8

func (qb *QB) Or() *QB

Or sets the next condition to use OR logic instead of AND.

func (*QB) OrderBy

func (qb *QB) OrderBy(column string) *OrderClause

OrderBy starts a new order clause for the given column.

func (*QB) ReadAll

func (qb *QB) ReadAll(new func() model.Model, onRow func(model.Model)) error

ReadAll executes the query and returns all results.

func (*QB) ReadOne

func (qb *QB) ReadOne() error

ReadOne executes the query and returns a single result.

func (*QB) Where

func (qb *QB) Where(column string) *Clause

Where starts a new condition clause for the given column.

Directories

Path Synopsis
ormcp module

Jump to

Keyboard shortcuts

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