Core schema, validation, and codec types for tinywasm ecosystem. This package provides the foundational interfaces and types used across ORM, JSON serialization, form handling, and API layers.
model provides the foundational type definitions and contracts for the tinywasm ecosystem. It focuses on:
- Schema Metadata -
Field,Fielder, andFieldTypefor reflection-less struct introspection - Validation -
PermittedandValidatorfor data integrity - Typed Serialization -
Encodable,Decodable,FieldWriter,FieldReaderfor 0-alloc codec patterns
- 📐 Model Definition - Author schemas manually with
DefinitionandFields - 🏗️ Schema-first design - Describe struct fields without reflection
- ✅ Validation by contract - Character whitelists, length constraints, custom validators
- 🔄 Typed codecs -
Encodable/Decodablefor 0-alloc serialization - 🧵 Concurrency safe - Thread-safe schema metadata and codecs
- 📦 Zero dependencies - No reflection, no maps, no
anyboxing in codec paths - ⚡ WebAssembly optimized - Small binary footprint for WASM targets
go get github.com/tinywasm/modelThe source of truth for a model is now a Definition literal:
var UserModel = model.Definition{
Name: "user",
Fields: model.Fields{
{Name: "id", Type: model.FieldInt, DB: &model.FieldDB{PK: true, AutoInc: true}},
{Name: "name", Type: model.FieldText, NotNull: true, Permitted: model.Permitted{Minimum: 2}},
{Name: "email", Type: model.FieldText, NotNull: true},
},
}Typically generated by ormc, but here's the manual pattern:
import "github.com/tinywasm/model"
type User struct {
ID string
Name string
Age int
}
func (u *User) Schema() []model.Field {
return []model.Field{
{
Name: "id",
Type: model.FieldText,
DB: &model.FieldDB{PK: true},
},
{
Name: "name",
Type: model.FieldText,
NotNull: true,
Permitted: model.Permitted{Letters: true, Spaces: true},
},
{
Name: "age",
Type: model.FieldInt,
},
}
}
func (u *User) Pointers() []any {
return []any{&u.ID, &u.Name, &u.Age}
}
func (u *User) Validate(action byte) error {
return model.ValidateFields(action, u)
}Usage:
err := model.ValidateFields(model.ActionUpdate, user)Generated EncodeFields and DecodeFields methods follow the typed codec pattern:
func (u *User) EncodeFields(w model.FieldWriter) {
w.String("id", u.ID)
if u.Name != "" {
w.String("name", u.Name)
}
w.Int("age", int64(u.Age))
}
func (u *User) DecodeFields(r model.FieldReader) {
if id, ok := r.String("id"); ok {
u.ID = id
}
if name, ok := r.String("name"); ok {
u.Name = name
}
if age, ok := r.Int("age"); ok {
u.Age = int(age)
}
}- Field and Fielder API - Schema metadata and reflection-less access
- Codec API - Typed serialization contract (0-alloc)
- Why 64-bit Only - Rationale for
int64/float64as the only numeric types - Codec vs Field/Fielder - Architectural separation and roles
- Permitted Validation - Character whitelists and length constraints
Separation of Concerns:
| Concern | Type | Used By |
|---|---|---|
| DDL & Column Metadata | Field.DB |
orm, sqlt, postgres |
| Data Validation | Field + Permitted |
orm, form, json |
| UI Bindings | Field.Widget |
form, ormc codegen |
| SQL Scanning | Pointers() |
orm/qb (positional via database/sql) |
| Serialization | Encodable/Decodable + codec |
json, jsvalue, transports |
One schema (Field) serves all layers. Serialization uses the typed codec (Encodable/Decodable) for 0-alloc, map-free performance.
tinywasm/fmt- String manipulation and conversiontinywasm/orm- Database layer (usesSchema(),Pointers(),Validate())tinywasm/json- JSON encoder/decoder (uses codec)tinywasm/form- Form handling and widgets (usesField+Widget)