Documentation
¶
Index ¶
- Variables
- func Register(api huma.API, db sqlb.Executor) error
- func RegisterHooks()
- func RegisterPostSoftDelete(api huma.API, db sqlb.Executor)
- type Author
- type AuthorCreate
- type AuthorPatch
- type AuthorUpdate
- func (u *AuthorUpdate) SetCreatedAt(v time.Time) *AuthorUpdate
- func (u *AuthorUpdate) SetEmail(v string) *AuthorUpdate
- func (u *AuthorUpdate) SetName(v string) *AuthorUpdate
- func (u *AuthorUpdate) SetOrgID(v string) *AuthorUpdate
- func (u *AuthorUpdate) SetPasswordHash(v string) *AuthorUpdate
- func (u *AuthorUpdate) SetUpdatedAt(v time.Time) *AuthorUpdate
- func (u *AuthorUpdate) Stmt() *sqlb.Update[Author]
- func (u *AuthorUpdate) Where(preds ...sqlb.Pred) *AuthorUpdate
- type Org
- type OrgUpdate
- func (u *OrgUpdate) SetCreatedAt(v time.Time) *OrgUpdate
- func (u *OrgUpdate) SetName(v string) *OrgUpdate
- func (u *OrgUpdate) SetSlug(v string) *OrgUpdate
- func (u *OrgUpdate) SetUpdatedAt(v time.Time) *OrgUpdate
- func (u *OrgUpdate) Stmt() *sqlb.Update[Org]
- func (u *OrgUpdate) Where(preds ...sqlb.Pred) *OrgUpdate
- type Post
- type PostCreate
- type PostPatch
- type PostStatus
- type PostUpdate
- func (u *PostUpdate) AddViewCount(n int64) *PostUpdate
- func (u *PostUpdate) SetAuthorID(v string) *PostUpdate
- func (u *PostUpdate) SetBody(v string) *PostUpdate
- func (u *PostUpdate) SetCreatedAt(v time.Time) *PostUpdate
- func (u *PostUpdate) SetDeletedAt(v *time.Time) *PostUpdate
- func (u *PostUpdate) SetOrgID(v string) *PostUpdate
- func (u *PostUpdate) SetPublishedAt(v *time.Time) *PostUpdate
- func (u *PostUpdate) SetStatus(v PostStatus) *PostUpdate
- func (u *PostUpdate) SetTitle(v string) *PostUpdate
- func (u *PostUpdate) SetUpdatedAt(v time.Time) *PostUpdate
- func (u *PostUpdate) SetViewCount(v int64) *PostUpdate
- func (u *PostUpdate) Stmt() *sqlb.Update[Post]
- func (u *PostUpdate) Where(preds ...sqlb.Pred) *PostUpdate
Constants ¶
This section is empty.
Variables ¶
var AuthorCols = authorColumns{ ID: sqlb.Typed[string]("id"), OrgID: sqlb.Typed[string]("org_id"), Email: sqlb.TextColumn[string]("email"), Name: sqlb.TextColumn[string]("name"), CreatedAt: sqlb.Typed[time.Time]("created_at"), UpdatedAt: sqlb.Typed[time.Time]("updated_at"), }
AuthorCols are the typed columns of authors. Hidden columns are omitted: a predicate against one should not compile.
var OrgCols = orgColumns{ ID: sqlb.Typed[string]("id"), Name: sqlb.TextColumn[string]("name"), Slug: sqlb.TextColumn[string]("slug"), CreatedAt: sqlb.Typed[time.Time]("created_at"), UpdatedAt: sqlb.Typed[time.Time]("updated_at"), }
OrgCols are the typed columns of orgs.
var PostCols = postColumns{ ID: sqlb.Typed[string]("id"), OrgID: sqlb.Typed[string]("org_id"), AuthorID: sqlb.Typed[string]("author_id"), Title: sqlb.TextColumn[string]("title"), Body: sqlb.TextColumn[string]("body"), Status: sqlb.Typed[PostStatus]("status"), ViewCount: sqlb.Typed[int64]("view_count"), PublishedAt: sqlb.Typed[time.Time]("published_at"), CreatedAt: sqlb.Typed[time.Time]("created_at"), UpdatedAt: sqlb.Typed[time.Time]("updated_at"), DeletedAt: sqlb.Typed[time.Time]("deleted_at"), }
PostCols are the typed columns of posts.
Functions ¶
func Register ¶
Register mounts every exposed resource on api.
The handlers are rest.Resource, instantiated per model. Registration is generic rather than reflective because query hooks are keyed by type: a BeforeQuery hook registered on a model applies to its REST reads too, which is how tenant scoping stops being something each handler must remember.
func RegisterHooks ¶
func RegisterHooks()
Hand-written domain rules, in a file the generator does not touch.
RegisterHooks installs the predicate that makes schema.SoftDelete mean something. The schema adds posts.deleted_at and stops there — nothing in the runtime reads the column — so hiding the deleted rows is a registration, and BeforeQuery is where it goes: one registration constrains every read of Post, including the ones the generated REST handlers issue. That is the argument of ADR-0008, and this is what it looks like applied.
It is an exported function rather than an init so the registration is visible at the call site, and so a test can choose not to make it.
Tenant scoping belongs on the same hook — `q.Where(sqlb.F("org_id").Eq(org))`, reading the org out of ctx. It is left out here because the example has no authentication to read it from, not because it is a separate mechanism.
func RegisterPostSoftDelete ¶
RegisterPostSoftDelete serves DELETE /posts/{id} as an update to deleted_at.
Post leaves OpDelete out of its Expose, because the generated delete is a real DELETE and this table's deletes are meant to be soft. No hook can bridge that: BeforeDelete receives a *Delete, so it can abort the statement or amend its predicate, but not turn it into an UPDATE. The endpoint is written here instead — which is the same seam post_ext.go uses, for the same reason.
The BeforeQuery registration in hooks.go is the other half. Without it this endpoint would hide nothing, and the row would come straight back on the next list.
Types ¶
type Author ¶
type Author struct {
ID string `db:"id" json:"id" sqlb:"type:uuid,pk,default,filter,readonly"`
OrgID string `db:"org_id" json:"org_id" sqlb:"type:uuid,filter,expand"`
Org *Org `db:"-" json:"org,omitempty" sqlb:"expands=org_id"` // filled in by ?expand=org
Email string `db:"email" json:"email" sqlb:"type:text,filter,search"`
Name string `db:"name" json:"name" sqlb:"type:text,filter,sort,search"`
PasswordHash string `db:"password_hash" json:"-" sqlb:"type:text,hidden"`
CreatedAt time.Time `db:"created_at" json:"created_at" sqlb:"type:timestamptz,default,sort,readonly"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at" sqlb:"type:timestamptz,default,sort,readonly"`
Posts *sqlb.Collection[Post] `db:"-" json:"posts,omitempty" sqlb:"expands=author_id,order=-published_at,limit=2"` // filled in by ?expand=posts
}
Author is a row of authors.
type AuthorCreate ¶
type AuthorCreate struct {
OrgID string `json:"org_id"`
Email string `json:"email"`
Name string `json:"name"`
}
AuthorCreate is the request body for creating a Author.
Read-only columns are absent: the database or a BeforeCreate hook owns them. A column with a default is optional, so leaving it out means the database supplies the value rather than the zero value overwriting it.
func (AuthorCreate) Row ¶
func (c AuthorCreate) Row() (*Author, error)
Row builds the row to insert. It satisfies rest.CreateBody.
type AuthorPatch ¶
type AuthorPatch struct {
OrgID *string `json:"org_id,omitempty"`
Email *string `json:"email,omitempty"`
Name *string `json:"name,omitempty"`
// contains filtered or unexported fields
}
AuthorPatch is the request body for patching a Author.
Every field is a pointer and every field is optional, so a request writes only the columns it names. Immutable columns are absent: they are settable once, at create.
func (AuthorPatch) Changes ¶
func (u AuthorPatch) Changes() (map[string]any, error)
Changes reports the columns the request named. It satisfies rest.UpdateBody.
func (*AuthorPatch) UnmarshalJSON ¶
func (u *AuthorPatch) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes the body and remembers which properties were present.
Without this a nil pointer would be ambiguous: `{}` and `{"org_id": null}` decode identically, but the first must change nothing and the second must write NULL.
type AuthorUpdate ¶
type AuthorUpdate struct {
// contains filtered or unexported fields
}
AuthorUpdate is a typed update statement for authors.
func (*AuthorUpdate) SetCreatedAt ¶
func (u *AuthorUpdate) SetCreatedAt(v time.Time) *AuthorUpdate
SetCreatedAt sets created_at.
func (*AuthorUpdate) SetEmail ¶
func (u *AuthorUpdate) SetEmail(v string) *AuthorUpdate
SetEmail sets email.
func (*AuthorUpdate) SetName ¶
func (u *AuthorUpdate) SetName(v string) *AuthorUpdate
SetName sets name.
func (*AuthorUpdate) SetOrgID ¶
func (u *AuthorUpdate) SetOrgID(v string) *AuthorUpdate
SetOrgID sets org_id.
func (*AuthorUpdate) SetPasswordHash ¶
func (u *AuthorUpdate) SetPasswordHash(v string) *AuthorUpdate
SetPasswordHash sets password_hash.
func (*AuthorUpdate) SetUpdatedAt ¶
func (u *AuthorUpdate) SetUpdatedAt(v time.Time) *AuthorUpdate
SetUpdatedAt sets updated_at.
func (*AuthorUpdate) Stmt ¶
func (u *AuthorUpdate) Stmt() *sqlb.Update[Author]
Stmt exposes the underlying statement for what the wrapper does not cover, such as Everything, SetExpr, Exec and One.
func (*AuthorUpdate) Where ¶
func (u *AuthorUpdate) Where(preds ...sqlb.Pred) *AuthorUpdate
Where narrows the affected rows.
type Org ¶
type Org struct {
ID string `db:"id" json:"id" sqlb:"type:uuid,pk,default,filter,readonly"`
Name string `db:"name" json:"name" sqlb:"type:text,filter,sort,search"`
Slug string `db:"slug" json:"slug" sqlb:"type:text,filter"`
CreatedAt time.Time `db:"created_at" json:"created_at" sqlb:"type:timestamptz,default,sort,readonly"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at" sqlb:"type:timestamptz,default,sort,readonly"`
Authors *sqlb.Collection[Author] `db:"-" json:"authors,omitempty" sqlb:"expands=org_id,order=name,limit=50"` // filled in by ?expand=authors
}
Org a tenant. Every other table is scoped to one.
type OrgUpdate ¶
type OrgUpdate struct {
// contains filtered or unexported fields
}
OrgUpdate is a typed update statement for orgs.
func (*OrgUpdate) SetCreatedAt ¶
SetCreatedAt sets created_at.
func (*OrgUpdate) SetUpdatedAt ¶
SetUpdatedAt sets updated_at.
type Post ¶
type Post struct {
ID string `db:"id" json:"id" sqlb:"type:uuid,pk,default,filter,readonly"`
OrgID string `db:"org_id" json:"org_id" sqlb:"type:uuid"`
AuthorID string `db:"author_id" json:"author_id" sqlb:"type:uuid,filter,expand"`
Author *Author `db:"-" json:"author,omitempty" sqlb:"expands=author_id"` // filled in by ?expand=author
Title string `db:"title" json:"title" sqlb:"type:text,filter,sort,search"`
Body string `db:"body" json:"body" sqlb:"type:text,filter,search"`
Status PostStatus `db:"status" json:"status" sqlb:"type:enum,default,filter,sort"`
ViewCount int64 `db:"view_count" json:"view_count" sqlb:"type:bigint,default,filter,sort,readonly"`
PublishedAt *time.Time `db:"published_at" json:"published_at" sqlb:"type:timestamptz,filter,sort"`
CreatedAt time.Time `db:"created_at" json:"created_at" sqlb:"type:timestamptz,default,sort,readonly"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at" sqlb:"type:timestamptz,default,sort,readonly"`
DeletedAt *time.Time `db:"deleted_at" json:"deleted_at" sqlb:"type:timestamptz,readonly,softdelete"`
}
Post a blog post.
type PostCreate ¶
type PostCreate struct {
OrgID string `json:"org_id"`
AuthorID string `json:"author_id"`
Title string `json:"title"`
Body string `json:"body"`
Status *PostStatus `json:"status,omitempty" enum:"draft,review,published"`
PublishedAt *time.Time `json:"published_at,omitempty"`
}
PostCreate is the request body for creating a Post.
Read-only columns are absent: the database or a BeforeCreate hook owns them. A column with a default is optional, so leaving it out means the database supplies the value rather than the zero value overwriting it.
func (PostCreate) Row ¶
func (c PostCreate) Row() (*Post, error)
Row builds the row to insert. It satisfies rest.CreateBody.
type PostPatch ¶
type PostPatch struct {
OrgID *string `json:"org_id,omitempty"`
AuthorID *string `json:"author_id,omitempty"`
Title *string `json:"title,omitempty"`
Body *string `json:"body,omitempty"`
Status *PostStatus `json:"status,omitempty" enum:"draft,review,published"`
PublishedAt *time.Time `json:"published_at,omitempty"`
// contains filtered or unexported fields
}
PostPatch is the request body for patching a Post.
Every field is a pointer and every field is optional, so a request writes only the columns it names. Immutable columns are absent: they are settable once, at create.
func (PostPatch) Changes ¶
Changes reports the columns the request named. It satisfies rest.UpdateBody.
func (*PostPatch) UnmarshalJSON ¶
UnmarshalJSON decodes the body and remembers which properties were present.
Without this a nil pointer would be ambiguous: `{}` and `{"org_id": null}` decode identically, but the first must change nothing and the second must write NULL.
type PostStatus ¶
type PostStatus string
PostStatus is the posts.status column's value set.
const ( PostStatusDraft PostStatus = "draft" PostStatusReview PostStatus = "review" PostStatusPublished PostStatus = "published" )
type PostUpdate ¶
type PostUpdate struct {
// contains filtered or unexported fields
}
PostUpdate is a typed update statement for posts.
func (*PostUpdate) AddViewCount ¶
func (u *PostUpdate) AddViewCount(n int64) *PostUpdate
AddViewCount increments the counter in the database rather than reading it first, so concurrent increments do not lose updates.
The generator cannot produce this: view_count is ReadOnly in the schema, so there is no SetViewCount, and the read-modify-write it would replace is a correctness decision rather than a mechanical one.
func (*PostUpdate) SetAuthorID ¶
func (u *PostUpdate) SetAuthorID(v string) *PostUpdate
SetAuthorID sets author_id.
func (*PostUpdate) SetCreatedAt ¶
func (u *PostUpdate) SetCreatedAt(v time.Time) *PostUpdate
SetCreatedAt sets created_at.
func (*PostUpdate) SetDeletedAt ¶
func (u *PostUpdate) SetDeletedAt(v *time.Time) *PostUpdate
SetDeletedAt sets deleted_at.
func (*PostUpdate) SetOrgID ¶
func (u *PostUpdate) SetOrgID(v string) *PostUpdate
SetOrgID sets org_id.
func (*PostUpdate) SetPublishedAt ¶
func (u *PostUpdate) SetPublishedAt(v *time.Time) *PostUpdate
SetPublishedAt sets published_at.
func (*PostUpdate) SetStatus ¶
func (u *PostUpdate) SetStatus(v PostStatus) *PostUpdate
SetStatus sets status.
func (*PostUpdate) SetTitle ¶
func (u *PostUpdate) SetTitle(v string) *PostUpdate
SetTitle sets title.
func (*PostUpdate) SetUpdatedAt ¶
func (u *PostUpdate) SetUpdatedAt(v time.Time) *PostUpdate
SetUpdatedAt sets updated_at.
func (*PostUpdate) SetViewCount ¶
func (u *PostUpdate) SetViewCount(v int64) *PostUpdate
SetViewCount sets view_count.
func (*PostUpdate) Stmt ¶
func (u *PostUpdate) Stmt() *sqlb.Update[Post]
Stmt exposes the underlying statement for what the wrapper does not cover, such as Everything, SetExpr, Exec and One.
func (*PostUpdate) Where ¶
func (u *PostUpdate) Where(preds ...sqlb.Pred) *PostUpdate
Where narrows the affected rows.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package blogschema is the schema definition for the blog example: the single source of truth that an author, or an agent, edits.
|
Package blogschema is the schema definition for the blog example: the single source of truth that an author, or an agent, edits. |