Skip to content

tinywasm/model

Repository files navigation

tinywasm/model

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.

Overview

model provides the foundational type definitions and contracts for the tinywasm ecosystem. It focuses on:

  • Schema Metadata - Field, Fielder, and FieldType for reflection-less struct introspection
  • Validation - Permitted and Validator for data integrity
  • Typed Serialization - Encodable, Decodable, FieldWriter, FieldReader for 0-alloc codec patterns

Key Features

  • 📐 Model Definition - Author schemas manually with Definition and Fields
  • 🏗️ Schema-first design - Describe struct fields without reflection
  • Validation by contract - Character whitelists, length constraints, custom validators
  • 🔄 Typed codecs - Encodable/Decodable for 0-alloc serialization
  • 🧵 Concurrency safe - Thread-safe schema metadata and codecs
  • 📦 Zero dependencies - No reflection, no maps, no any boxing in codec paths
  • WebAssembly optimized - Small binary footprint for WASM targets

Installation

go get github.com/tinywasm/model

Quick Start

Defining a Model Definition

The 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},
    },
}

Defining a Schema

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)

Using the Codec

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)
    }
}

Documentation

Architecture

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.

Related Packages



About

A model module

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages