I have not found a basic how-to example on using hooks.
For my purpose, I've created a db, created tables, added rows, and I just want to add a BeforeUpdate hook. However, the documentation at this time assumes a level of existing expertise with hooks. Even after reading code in the repository and lots of googling, the closest I've gotten to working is this error message,
"panic: Product.BeforeUpdate must be updated - https://github.com/go-pg/pg/wiki/Model-Hooks",
which doesn't really tell me anything.
Example function definition
func (product *Product) BeforeUpdate(db orm.DB) error {
product.UpdatedOn = time.Now()
return nil
}
Do I need to register the hook in some manner?
I think this type of documentation would help out people who are new to the project. Of course, with a working hook.
package main
import (
"github.com/go-pg/pg"
"github.com/go-pg/pg/orm"
"log"
"time"
)
type Product struct {
Id int
Name string sql:",unique,notnull"
Price float32
CreatedOn time.Time sql:"created_on,notnull,default:now()"
UpdatedOn time.Time sql:"updated_on,notnull,default:now()"
}
//func (product *Product) BeforeUpdate(db orm.DB) error {
// product.UpdatedOn = time.Now()
// return nil
//}
func SelectProductByName(db pg.DB, product *Product, name string) {
filter := func(q *orm.Query) (orm.Query, error) {
q = q.Where("name = ?", name)
return q, nil
}
err := db.Model(product).
Apply(filter).
Select()
if err != nil {
log.Panicf("SelectProductByName: %v", err)
}
}
func main() {
db := pg.Connect(&pg.Options{
Network: "tcp",
Addr: "0.0.0.0:5432",
User: "test",
Password: "test",
Database: "dbTest",
})
defer db.Close()
if err := db.CreateTable(&Product{}, &orm.CreateTableOptions{
IfNotExists: true,
}); err != nil {
log.Panicf("createProductTable: %v", err)
}
product := Product{
Name: "Product 1",
Price: 9.99,
}
if err := db.Insert(&product); err != nil {
log.Panicf("AddProduct: %v", err)
}
productReturn := Product{}
SelectProductByName(db, &productReturn, "Product 1")
product.Price = 4.49
if err := db.Update(&product); err != nil {
log.Panicf("UpdateProduct: %v", err)
}
productReturn2 := Product{}
SelectProductByName(db, &productReturn2, "Product 1")
log.Println("Original product return: %v", productReturn)
log.Println("Updated product return: %v", productReturn2)
// NOTE: Price and UpdatedOn should not match
}
What version are you on? The latest API requires context object to be passed in and out https://github.com/go-pg/pg/wiki/Model-Hooks. There has been some API changes surrounding this so I suggest to update to the latest go-pg
I just started working in this world recently. I'm running version "[email protected]+incompatible".
If I change to passing context, the pre-update change is not made or, if I attempt to register the BeforeUpdateHook, I get an error.
package main
import (
"context"
"github.com/go-pg/pg"
"github.com/go-pg/pg/orm"
"log"
"time"
)
type Product struct {
Id int
Name string `sql:",unique,notnull"`
Price float32
CreatedOn time.Time `sql:"created_on,notnull,default:now()"`
UpdatedOn time.Time `sql:"updated_on,notnull,default:now()"`
}
var _ orm.BeforeUpdateHook = (*Product)(nil)
func (product *Product) BeforeUpdate(ctx context.Context) (context.Context, error) {
return ctx, updateProductUpdateTime(product)
}
func updateProductUpdateTime(product *Product) error {
product.UpdatedOn = time.Now()
return nil
}
func SelectProductByName(db *pg.DB, product *Product, name string) {
filter := func(q *orm.Query) (*orm.Query, error) {
q = q.Where("name = ?", name)
return q, nil
}
err := db.Model(product).
Apply(filter).
Select()
if err != nil {
log.Panicf("SelectProductByName: %v", err)
}
}
func main() {
db := pg.Connect(&pg.Options{
Network: "tcp",
Addr: "0.0.0.0:5432",
User: "test",
Password: "test",
Database: "dbTest",
})
defer db.Close()
if err := db.CreateTable(&Product{}, &orm.CreateTableOptions{
IfNotExists: true,
}); err != nil {
log.Panicf("createProductTable: %v", err)
}
product := Product{
Name: "Product 1",
Price: 9.99,
}
if err := db.Insert(&product); err != nil {
log.Panicf("AddProduct: %v", err)
}
productReturn := Product{}
SelectProductByName(db, &productReturn, "Product 1")
product.Price = 4.49
if err := db.Update(&product); err != nil {
log.Panicf("UpdateProduct: %v", err)
}
productReturn2 := Product{}
SelectProductByName(db, &productReturn2, "Product 1")
log.Println("Original product return: %v", productReturn)
log.Println("Updated product return: %v", productReturn2)
// NOTE: Price and UpdatedOn should not match
}
| => go run testmain.go
# command-line-arguments
./testmain.go:21:7: undefined: orm.BeforeUpdateHook
So, where is the disconnect between the documentation and the implementation.
First of all, it would really help to format things properly using triple forward quotes + file extension: ```go YOUR CODE
Followed by closing triple forward quotes: ```
Example:
func (t *HookTest) BeforeUpdate(c context.Context) (context.Context, error) {
t.beforeUpdate++
return c, nil
}
I haven't tried using latest PG myself, but the https://github.com/go-pg/pg/blob/master/hook_test.go should be instructive. Maybe you need to use specific versioned imports which seems to be this repo's direction at the moment...
@vmihailenco I don't know why you closed this. The lacking of documentation is one of the biggest killers of open source projects.
While I greatly appreciate the input from ernsheong, he didn't really know the answer to my question. The code I supplied is self-documenting, works, can be used as a starting point for people considering adopting pg, and only requires someone with a knowledge of hooks to make a couple of edits to also illustrate how hooks work.
The hook documentation hasn't changed. Therefore, the problem with how do hooks work in practice is still unanswered.
It should be not be surprising that you don't get an answer when you don't format your code and at the same time require better docs. And writing good examples how to use hooks is not as easy as it may look - people want to do all the smart/stupid things with hooks you can imagine. In your case - why do you need a hook to set UpdatedAt field? I am sure you have a good reason (everyone has) but I think you should not use hooks to do it.
undefined: orm.BeforeUpdateHook suggests that you need to update import path to github.com/go-pg/pg/v9 and use Go modules.
@vmihailenco What derives from your reply is using hooks maybe is not a decent way for dealing with something like setting UpdateAt field so what's your approach?
Maybe a simple repository method?
I'm willing to know how you handle it.
Thanks.
You already have struct and db.Update call. All you need to add is
model.UpdatedAt = time.Now()
Most helpful comment
You already have struct and
db.Updatecall. All you need to add is