Custom model struct
The available models.Record
and its helpers
is usually the preferred way to interact with your data
, but in some cases you may want to query and update your data using a typed struct. You can
define your own model structs by implementing the
models.Model
interface.
To make it a little bit easier, PocketBase also comes with a models.BaseModel
struct that you
can embed in your model, leaving only the TableName()
method to be implemented (aka. your collection
name). For example:
// article.go
package main
import (
"github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/tools/types"
)
// ensures that the Article struct satisfy the models.Model interface
var _ models.Model = (*Article)(nil)
type Article struct {
models.BaseModel
Title string `db:"title" json:"title"`
Slug string `db:"slug" json:"slug"`
Description string `db:"description" json:"description"`
Published types.DateTime `db:"published" json:"published"`
}
func (m *Article) TableName() string {
return "articles" // the name of your collection
}
Working with the custom model struct
Please note that the internal
Record API and other related hooks
works only with the
models.Record
and you'll have to manually convert the models.Record
to your
custom struct if you want to use it inside the event hooks.
There are plans to improve this workflow in the future with codegeneration (see Discussion#2697).
To query your custom "Article" model you can use the app.Dao()
instance and its query builder
(dbx).
Fetch articles
// article_query.go
package main
import (
"strings"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
)
func ArticleQuery(dao *daos.Dao) *dbx.SelectQuery {
return dao.ModelQuery(&Article{})
}
func FindArticleById(dao *daos.Dao, id string) (*Article, error) {
article := &Article{}
err := ArticleQuery(dao).
AndWhere(dbx.HashExp{"id": id}).
Limit(1).
One(article)
if err != nil {
return nil, err
}
return article, nil
}
func FindArticleBySlug(dao *daos.Dao, slug string) (*Article, error) {
article := &Article{}
err := ArticleQuery(dao).
// case insensitive match
AndWhere(dbx.NewExp("LOWER(slug)={:slug}", dbx.Params{
"slug": strings.ToLower(slug),
})).
Limit(1).
One(article)
if err != nil {
return nil, err
}
return article, nil
}
func FindLast10Articles(dao *daos.Dao, slug string) ([]*Article, error) {
articles := []*Article{}
err := ArticleQuery(dao).
Limit(10).
OrderBy("published desc").
All(&articles)
if err != nil {
return nil, err
}
return articles, nil
}
Create article
article := &Article{
Title: "Lorem ipsum",
Slug: "lorem-ipsum",
}
// the id is autogenerated, but you can set a specific one if you want to:
// article.SetId("...")
if err := app.Dao().Save(article); err != nil {
return err
}
Update article
article, err := FindArticleBySlug(app.Dao(), "lorem-ipsum")
if err != nil {
return err
}
article.Description = "Hello World!"
if err := app.Dao().Save(article); err != nil {
return err
}
Delete article
// optionally wrap in a transaction
err := app.Dao().RunInTransaction(func(txDao *daos.Dao) error {
article, err := FindArticleBySlug(txDao, "lorem-ipsum")
if err != nil {
return err
}
return txDao.Delete(article);
})