localentity

package
v0.89.0 Latest Latest
Warning

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

Go to latest
Published: Oct 17, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package localentity declares records that live in the visitor's browser and renders the forms and lists that edit them, with no server table and no JavaScript in the app.

var Team = localdb.New("team")
var Members = localentity.Define(Team, "members", []schema.Field{
    {Name: "name", Type: schema.String, Required: true, Max: ptr(20)},
    {Name: "level", Type: schema.Int, Min: ptr(1), Max: ptr(100)},
}, localentity.Indexed("level"), localentity.MaxRecords(6))

A declared entity is a core-ui/localdb store with three built-in fields: id (a UUIDv7 string minted in the browser), created_at and updated_at (RFC 3339 strings). Its forms and lists render through the design system on the server, like every other page; the localentity-form behaviour then saves form submissions into IndexedDB, and the localentity behaviour fills each list by cloning its server-rendered row template, setting text only. Every tab of the site re-renders when any tab writes.

Nothing here talks to the server after the page loads, and the server never sees the records. A later sync layer can carry them to a real database; the declarations use core/schema field types so the same fields can describe a server entity.

Index

Constants

View Source
const (
	FieldID        = "id"
	FieldCreatedAt = "created_at"
	FieldUpdatedAt = "updated_at"
)

The built-in fields every local entity carries.

Variables

View Source
var DefaultMessages = Messages{
	Required: "This field is required.",
	Number:   "Enter a number.",
	Integer:  "Enter a whole number.",
	Min:      "Must be at least {n}.",
	Max:      "Must be at most {n}.",
	MinLen:   "Must be at least {n} characters.",
	MaxLen:   "Must be at most {n} characters.",
	Pattern:  "Use the requested format.",
	Choice:   "Choose one of the listed options.",
	Date:     "Enter a valid date.",
	Full:     "This list is full ({n} at most).",
	Failed:   "Could not save on this device.",
}

DefaultMessages are the English defaults.

Functions

This section is empty.

Types

type Entity

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

Entity is one declared local entity.

func Define

func Define(db *localdb.DB, name string, fields []schema.Field, opts ...Option) *Entity

Define declares a local entity named name in db, with the given fields, and returns it. It declares the backing store itself (keyed by id, created_at and updated_at indexed, plus Indexed fields), so name must not already be a store in db. Field names are lowercase snake_case ([a-z][a-z0-9_]*, at most 61 bytes, so "by_<name>" is a valid index name), not "constructor" or "prototype", and must not reuse a built-in. An Indexed field must be Required. Every refusal is a panic at startup.

func (*Entity) Count

func (e *Entity) Count() render.HTML

Count renders a span the behaviour fills with how many records the entity holds, kept current across tabs.

func (*Entity) Fields

func (e *Entity) Fields() []schema.Field

Fields returns a copy of the declared fields (built-ins excluded).

func (*Entity) Form

func (e *Entity) Form(id string, form render.HTML) render.HTML

Form wraps a design-system form (ui.Form) so its submissions are saved into this entity instead of posted. Each control's name is a field name; controls with other names (the CSRF input, a button) are ignored. id names the carrier, for Row.Edit. The browser's own constraint validation runs first; the behaviour then coerces and checks each value against the field declarations and places any refusal beside its field.

ui.Form still needs an Action: without JavaScript the form posts there natively, so point it at a route that explains the page needs script, or at the page itself.

func (*Entity) List

func (e *Entity) List(cfg ListConfig) List

List returns a list over the entity's records.

func (*Entity) Name

func (e *Entity) Name() string

Name returns the entity's store name.

func (*Entity) Store

func (e *Entity) Store() *localdb.Store

Store returns the backing localdb store, for page scripts that read the records through __gofastr.localdb directly.

type List

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

List is a configured list of an entity's records. Compose it inside a layout component: the rows become that component's children.

l := Members.List(localentity.ListConfig{OrderBy: "level", Desc: true})
ui.Grid(ui.GridConfig{Min: "14rem"}, l.Render(
    l.Row(func(r localentity.Row) render.HTML { return ui.Card(...) }),
    l.Empty(ui.EmptyState(...)),
))

func (List) Empty

func (l List) Empty(content render.HTML) render.HTML

Empty renders what the list shows when it has no records. One root element, like Row.

func (List) Render

func (l List) Render(row, empty render.HTML) render.HTML

Render returns the list carrier holding its row and empty templates. Until the behaviour fills it, it shows nothing: the server cannot see the visitor's records.

func (List) Row

func (l List) Row(fn func(Row) render.HTML) render.HTML

Row renders the row template. fn builds one row from the design system; Row's helpers mark where each record's values go. The template must have exactly one root element, and should carry no id attributes: every record clones it.

type ListConfig

type ListConfig struct {
	// OrderBy is the field rows are ordered by: created_at (the
	// default), updated_at, or a field declared Indexed. IndexedDB
	// does the ordering through the index; page script never sorts.
	OrderBy string
	// Desc reverses the order (newest first, highest first).
	Desc bool
	// Limit caps how many rows render. 0 renders every record.
	Limit int
}

ListConfig configures a List.

type Messages

type Messages struct {
	Required string `json:"required"`
	Number   string `json:"number"`
	Integer  string `json:"integer"`
	Min      string `json:"min"`
	Max      string `json:"max"`
	MinLen   string `json:"minlen"`
	MaxLen   string `json:"maxlen"`
	Pattern  string `json:"pattern"`
	Choice   string `json:"choice"`
	Date     string `json:"date"`
	Full     string `json:"full"`
	Failed   string `json:"failed"`
}

Messages are the words the behaviour places beside a field (or toasts, for Full and Failed) when a submission is refused. The browser's own validation runs first on any control the form renders with required/min/max/maxlength/pattern; these cover the rest and a form rendered without them.

type Option

type Option func(*options)

Option configures Define.

func Indexed

func Indexed(fields ...string) Option

Indexed adds an IndexedDB index over each named field, so a list can order by it (ListConfig.OrderBy). created_at and updated_at are always indexed. A Bool field cannot be indexed: IndexedDB keys are never booleans.

func MaxRecords

func MaxRecords(n int) Option

MaxRecords caps how many records the entity holds. A create past the cap is refused with Messages.Full and nothing is written; edits still work. 0 means no cap.

func WithMessages

func WithMessages(m Messages) Option

WithMessages replaces the validation messages the behaviour shows. Empty fields keep their defaults. {n} is replaced by the bound.

type Row

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

Row marks where a record's values go inside a row template.

func (Row) Delete

func (r Row) Delete(control render.HTML) render.HTML

Delete wraps a control (a ui.Button with Type "button") so a click deletes this row's record.

func (Row) Edit

func (r Row) Edit(formID string, control render.HTML) render.HTML

Edit wraps a control so a click loads this row's record into the entity form whose carrier id is formID (Entity.Form); the next save of that form updates the record instead of creating one, and the form's reset button ends the edit.

func (Row) Text

func (r Row) Text(field string) render.HTML

Text renders a span the behaviour fills with the record's value for field, as text (never markup). Built-ins are allowed: id, created_at, updated_at. An unknown field panics.

Jump to

Keyboard shortcuts

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