added action arg to the before Dao hook to allow skipping the default persist behavior
This commit is contained in:
parent
6da94aef8d
commit
cdeb9a94ed
|
@ -119,6 +119,7 @@
|
||||||
There is a system migration that will convert the existing view `relation` fields to `json` (multiple) and `text` (single) fields.
|
There is a system migration that will convert the existing view `relation` fields to `json` (multiple) and `text` (single) fields.
|
||||||
This could be a breaking change if you have `relation` to view and use `expand` or some of the `relation` view fields as part of a collection rule.
|
This could be a breaking change if you have `relation` to view and use `expand` or some of the `relation` view fields as part of a collection rule.
|
||||||
|
|
||||||
|
- **!** (@todo docs) Added action argument to the Dao hooks to allow skipping the default persist behavior.
|
||||||
|
|
||||||
## v0.16.10
|
## v0.16.10
|
||||||
|
|
||||||
|
|
36
core/base.go
36
core/base.go
|
@ -1049,58 +1049,58 @@ func (app *BaseApp) initDataDB() error {
|
||||||
func (app *BaseApp) createDaoWithHooks(concurrentDB, nonconcurrentDB dbx.Builder) *daos.Dao {
|
func (app *BaseApp) createDaoWithHooks(concurrentDB, nonconcurrentDB dbx.Builder) *daos.Dao {
|
||||||
dao := daos.NewMultiDB(concurrentDB, nonconcurrentDB)
|
dao := daos.NewMultiDB(concurrentDB, nonconcurrentDB)
|
||||||
|
|
||||||
dao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
dao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
e := new(ModelEvent)
|
e := new(ModelEvent)
|
||||||
e.Dao = eventDao
|
e.Dao = eventDao
|
||||||
e.Model = m
|
e.Model = m
|
||||||
|
|
||||||
return app.OnModelBeforeCreate().Trigger(e)
|
return app.OnModelBeforeCreate().Trigger(e, func(e *ModelEvent) error {
|
||||||
|
return action()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
dao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) {
|
dao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
e := new(ModelEvent)
|
e := new(ModelEvent)
|
||||||
e.Dao = eventDao
|
e.Dao = eventDao
|
||||||
e.Model = m
|
e.Model = m
|
||||||
|
|
||||||
if err := app.OnModelAfterCreate().Trigger(e); err != nil && app.isDebug {
|
return app.OnModelAfterCreate().Trigger(e)
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
dao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
e := new(ModelEvent)
|
e := new(ModelEvent)
|
||||||
e.Dao = eventDao
|
e.Dao = eventDao
|
||||||
e.Model = m
|
e.Model = m
|
||||||
|
|
||||||
return app.OnModelBeforeUpdate().Trigger(e)
|
return app.OnModelBeforeUpdate().Trigger(e, func(e *ModelEvent) error {
|
||||||
|
return action()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
dao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) {
|
dao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
e := new(ModelEvent)
|
e := new(ModelEvent)
|
||||||
e.Dao = eventDao
|
e.Dao = eventDao
|
||||||
e.Model = m
|
e.Model = m
|
||||||
|
|
||||||
if err := app.OnModelAfterUpdate().Trigger(e); err != nil && app.isDebug {
|
return app.OnModelAfterUpdate().Trigger(e)
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
dao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
e := new(ModelEvent)
|
e := new(ModelEvent)
|
||||||
e.Dao = eventDao
|
e.Dao = eventDao
|
||||||
e.Model = m
|
e.Model = m
|
||||||
|
|
||||||
return app.OnModelBeforeDelete().Trigger(e)
|
return app.OnModelBeforeDelete().Trigger(e, func(e *ModelEvent) error {
|
||||||
|
return action()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
dao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) {
|
dao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
e := new(ModelEvent)
|
e := new(ModelEvent)
|
||||||
e.Dao = eventDao
|
e.Dao = eventDao
|
||||||
e.Model = m
|
e.Model = m
|
||||||
|
|
||||||
if err := app.OnModelAfterDelete().Trigger(e); err != nil && app.isDebug {
|
return app.OnModelAfterDelete().Trigger(e)
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dao
|
return dao
|
||||||
|
|
207
daos/base.go
207
daos/base.go
|
@ -5,6 +5,8 @@ package daos
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
|
@ -45,12 +47,12 @@ type Dao struct {
|
||||||
ModelQueryTimeout time.Duration
|
ModelQueryTimeout time.Duration
|
||||||
|
|
||||||
// write hooks
|
// write hooks
|
||||||
BeforeCreateFunc func(eventDao *Dao, m models.Model) error
|
BeforeCreateFunc func(eventDao *Dao, m models.Model, action func() error) error
|
||||||
AfterCreateFunc func(eventDao *Dao, m models.Model)
|
AfterCreateFunc func(eventDao *Dao, m models.Model) error
|
||||||
BeforeUpdateFunc func(eventDao *Dao, m models.Model) error
|
BeforeUpdateFunc func(eventDao *Dao, m models.Model, action func() error) error
|
||||||
AfterUpdateFunc func(eventDao *Dao, m models.Model)
|
AfterUpdateFunc func(eventDao *Dao, m models.Model) error
|
||||||
BeforeDeleteFunc func(eventDao *Dao, m models.Model) error
|
BeforeDeleteFunc func(eventDao *Dao, m models.Model, action func() error) error
|
||||||
AfterDeleteFunc func(eventDao *Dao, m models.Model)
|
AfterDeleteFunc func(eventDao *Dao, m models.Model) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// DB returns the default dao db builder (*dbx.DB or *dbx.TX).
|
// DB returns the default dao db builder (*dbx.DB or *dbx.TX).
|
||||||
|
@ -151,56 +153,75 @@ func (dao *Dao) RunInTransaction(fn func(txDao *Dao) error) error {
|
||||||
txDao := New(tx)
|
txDao := New(tx)
|
||||||
|
|
||||||
if dao.BeforeCreateFunc != nil {
|
if dao.BeforeCreateFunc != nil {
|
||||||
txDao.BeforeCreateFunc = func(eventDao *Dao, m models.Model) error {
|
txDao.BeforeCreateFunc = func(eventDao *Dao, m models.Model, action func() error) error {
|
||||||
return dao.BeforeCreateFunc(eventDao, m)
|
return dao.BeforeCreateFunc(eventDao, m, action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dao.BeforeUpdateFunc != nil {
|
if dao.BeforeUpdateFunc != nil {
|
||||||
txDao.BeforeUpdateFunc = func(eventDao *Dao, m models.Model) error {
|
txDao.BeforeUpdateFunc = func(eventDao *Dao, m models.Model, action func() error) error {
|
||||||
return dao.BeforeUpdateFunc(eventDao, m)
|
return dao.BeforeUpdateFunc(eventDao, m, action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dao.BeforeDeleteFunc != nil {
|
if dao.BeforeDeleteFunc != nil {
|
||||||
txDao.BeforeDeleteFunc = func(eventDao *Dao, m models.Model) error {
|
txDao.BeforeDeleteFunc = func(eventDao *Dao, m models.Model, action func() error) error {
|
||||||
return dao.BeforeDeleteFunc(eventDao, m)
|
return dao.BeforeDeleteFunc(eventDao, m, action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dao.AfterCreateFunc != nil {
|
if dao.AfterCreateFunc != nil {
|
||||||
txDao.AfterCreateFunc = func(eventDao *Dao, m models.Model) {
|
txDao.AfterCreateFunc = func(eventDao *Dao, m models.Model) error {
|
||||||
afterCalls = append(afterCalls, afterCallGroup{"create", eventDao, m})
|
afterCalls = append(afterCalls, afterCallGroup{"create", eventDao, m})
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dao.AfterUpdateFunc != nil {
|
if dao.AfterUpdateFunc != nil {
|
||||||
txDao.AfterUpdateFunc = func(eventDao *Dao, m models.Model) {
|
txDao.AfterUpdateFunc = func(eventDao *Dao, m models.Model) error {
|
||||||
afterCalls = append(afterCalls, afterCallGroup{"update", eventDao, m})
|
afterCalls = append(afterCalls, afterCallGroup{"update", eventDao, m})
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dao.AfterDeleteFunc != nil {
|
if dao.AfterDeleteFunc != nil {
|
||||||
txDao.AfterDeleteFunc = func(eventDao *Dao, m models.Model) {
|
txDao.AfterDeleteFunc = func(eventDao *Dao, m models.Model) error {
|
||||||
afterCalls = append(afterCalls, afterCallGroup{"delete", eventDao, m})
|
afterCalls = append(afterCalls, afterCallGroup{"delete", eventDao, m})
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fn(txDao)
|
return fn(txDao)
|
||||||
})
|
})
|
||||||
|
if txError != nil {
|
||||||
if txError == nil {
|
return txError
|
||||||
// execute after event calls on successful transaction
|
|
||||||
// (note: using the non-transaction dao to allow following queries in the after hooks)
|
|
||||||
for _, call := range afterCalls {
|
|
||||||
switch call.Action {
|
|
||||||
case "create":
|
|
||||||
dao.AfterCreateFunc(dao, call.Model)
|
|
||||||
case "update":
|
|
||||||
dao.AfterUpdateFunc(dao, call.Model)
|
|
||||||
case "delete":
|
|
||||||
dao.AfterDeleteFunc(dao, call.Model)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return txError
|
// execute after event calls on successful transaction
|
||||||
|
// (note: using the non-transaction dao to allow following queries in the after hooks)
|
||||||
|
var errs []error
|
||||||
|
for _, call := range afterCalls {
|
||||||
|
var err error
|
||||||
|
switch call.Action {
|
||||||
|
case "create":
|
||||||
|
err = dao.AfterCreateFunc(dao, call.Model)
|
||||||
|
case "update":
|
||||||
|
err = dao.AfterUpdateFunc(dao, call.Model)
|
||||||
|
case "delete":
|
||||||
|
err = dao.AfterDeleteFunc(dao, call.Model)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(errs) > 0 {
|
||||||
|
// @todo after go 1.20+ upgrade consider replacing with errors.Join()
|
||||||
|
var errsMsg strings.Builder
|
||||||
|
for _, err := range errs {
|
||||||
|
errsMsg.WriteString(err.Error())
|
||||||
|
errsMsg.WriteString("; ")
|
||||||
|
}
|
||||||
|
return fmt.Errorf("after transaction errors: %s", errsMsg.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("failed to start transaction (unknown dao.NonconcurrentDB() instance)")
|
return errors.New("failed to start transaction (unknown dao.NonconcurrentDB() instance)")
|
||||||
|
@ -213,21 +234,23 @@ func (dao *Dao) Delete(m models.Model) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return dao.lockRetry(func(retryDao *Dao) error {
|
return dao.lockRetry(func(retryDao *Dao) error {
|
||||||
if retryDao.BeforeDeleteFunc != nil {
|
action := func() error {
|
||||||
if err := retryDao.BeforeDeleteFunc(retryDao, m); err != nil {
|
if err := retryDao.NonconcurrentDB().Model(m).Delete(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if retryDao.AfterDeleteFunc != nil {
|
||||||
|
retryDao.AfterDeleteFunc(retryDao, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := retryDao.NonconcurrentDB().Model(m).Delete(); err != nil {
|
if retryDao.BeforeDeleteFunc != nil {
|
||||||
return err
|
return retryDao.BeforeDeleteFunc(retryDao, m, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
if retryDao.AfterDeleteFunc != nil {
|
return action()
|
||||||
retryDao.AfterDeleteFunc(retryDao, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,35 +281,35 @@ func (dao *Dao) update(m models.Model) error {
|
||||||
|
|
||||||
m.RefreshUpdated()
|
m.RefreshUpdated()
|
||||||
|
|
||||||
|
action := func() error {
|
||||||
|
if v, ok := any(m).(models.ColumnValueMapper); ok {
|
||||||
|
dataMap := v.ColumnValueMap()
|
||||||
|
|
||||||
|
_, err := dao.NonconcurrentDB().Update(
|
||||||
|
m.TableName(),
|
||||||
|
dataMap,
|
||||||
|
dbx.HashExp{"id": m.GetId()},
|
||||||
|
).Execute()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if err := dao.NonconcurrentDB().Model(m).Update(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if dao.AfterUpdateFunc != nil {
|
||||||
|
return dao.AfterUpdateFunc(dao, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if dao.BeforeUpdateFunc != nil {
|
if dao.BeforeUpdateFunc != nil {
|
||||||
if err := dao.BeforeUpdateFunc(dao, m); err != nil {
|
return dao.BeforeUpdateFunc(dao, m, action)
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := any(m).(models.ColumnValueMapper); ok {
|
return action()
|
||||||
dataMap := v.ColumnValueMap()
|
|
||||||
|
|
||||||
_, err := dao.NonconcurrentDB().Update(
|
|
||||||
m.TableName(),
|
|
||||||
dataMap,
|
|
||||||
dbx.HashExp{"id": m.GetId()},
|
|
||||||
).Execute()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := dao.NonconcurrentDB().Model(m).Update(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if dao.AfterUpdateFunc != nil {
|
|
||||||
dao.AfterUpdateFunc(dao, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dao *Dao) create(m models.Model) error {
|
func (dao *Dao) create(m models.Model) error {
|
||||||
|
@ -306,36 +329,36 @@ func (dao *Dao) create(m models.Model) error {
|
||||||
m.RefreshUpdated()
|
m.RefreshUpdated()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action := func() error {
|
||||||
|
if v, ok := any(m).(models.ColumnValueMapper); ok {
|
||||||
|
dataMap := v.ColumnValueMap()
|
||||||
|
if _, ok := dataMap["id"]; !ok {
|
||||||
|
dataMap["id"] = m.GetId()
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := dao.NonconcurrentDB().Insert(m.TableName(), dataMap).Execute()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if err := dao.NonconcurrentDB().Model(m).Insert(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// clears the "new" model flag
|
||||||
|
m.MarkAsNotNew()
|
||||||
|
|
||||||
|
if dao.AfterCreateFunc != nil {
|
||||||
|
return dao.AfterCreateFunc(dao, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if dao.BeforeCreateFunc != nil {
|
if dao.BeforeCreateFunc != nil {
|
||||||
if err := dao.BeforeCreateFunc(dao, m); err != nil {
|
return dao.BeforeCreateFunc(dao, m, action)
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := any(m).(models.ColumnValueMapper); ok {
|
return action()
|
||||||
dataMap := v.ColumnValueMap()
|
|
||||||
if _, ok := dataMap["id"]; !ok {
|
|
||||||
dataMap["id"] = m.GetId()
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := dao.NonconcurrentDB().Insert(m.TableName(), dataMap).Execute()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := dao.NonconcurrentDB().Model(m).Insert(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// clears the "new" model flag
|
|
||||||
m.MarkAsNotNew()
|
|
||||||
|
|
||||||
if dao.AfterCreateFunc != nil {
|
|
||||||
dao.AfterCreateFunc(dao, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dao *Dao) lockRetry(op func(retryDao *Dao) error) error {
|
func (dao *Dao) lockRetry(op func(retryDao *Dao) error) error {
|
||||||
|
|
|
@ -49,33 +49,37 @@ func TestDaoClone(t *testing.T) {
|
||||||
dao := daos.NewMultiDB(testApp.Dao().ConcurrentDB(), testApp.Dao().NonconcurrentDB())
|
dao := daos.NewMultiDB(testApp.Dao().ConcurrentDB(), testApp.Dao().NonconcurrentDB())
|
||||||
dao.MaxLockRetries = 1
|
dao.MaxLockRetries = 1
|
||||||
dao.ModelQueryTimeout = 2
|
dao.ModelQueryTimeout = 2
|
||||||
dao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
dao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
hookCalls["BeforeDeleteFunc"]++
|
hookCalls["BeforeDeleteFunc"]++
|
||||||
return nil
|
return action()
|
||||||
}
|
}
|
||||||
dao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
dao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
hookCalls["BeforeUpdateFunc"]++
|
hookCalls["BeforeUpdateFunc"]++
|
||||||
return nil
|
return action()
|
||||||
}
|
}
|
||||||
dao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
dao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
hookCalls["BeforeCreateFunc"]++
|
hookCalls["BeforeCreateFunc"]++
|
||||||
|
return action()
|
||||||
|
}
|
||||||
|
dao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
|
hookCalls["AfterDeleteFunc"]++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
dao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) {
|
dao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
hookCalls["AfterDeleteFunc"]++
|
|
||||||
}
|
|
||||||
dao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) {
|
|
||||||
hookCalls["AfterUpdateFunc"]++
|
hookCalls["AfterUpdateFunc"]++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
dao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) {
|
dao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
hookCalls["AfterCreateFunc"]++
|
hookCalls["AfterCreateFunc"]++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
clone := dao.Clone()
|
clone := dao.Clone()
|
||||||
clone.MaxLockRetries = 3
|
clone.MaxLockRetries = 3
|
||||||
clone.ModelQueryTimeout = 4
|
clone.ModelQueryTimeout = 4
|
||||||
clone.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) {
|
clone.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
hookCalls["NewAfterCreateFunc"]++
|
hookCalls["NewAfterCreateFunc"]++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if dao.MaxLockRetries == clone.MaxLockRetries {
|
if dao.MaxLockRetries == clone.MaxLockRetries {
|
||||||
|
@ -86,16 +90,18 @@ func TestDaoClone(t *testing.T) {
|
||||||
t.Fatal("Expected different ModelQueryTimeout")
|
t.Fatal("Expected different ModelQueryTimeout")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emptyAction := func() error { return nil }
|
||||||
|
|
||||||
// trigger hooks
|
// trigger hooks
|
||||||
dao.BeforeDeleteFunc(nil, nil)
|
dao.BeforeDeleteFunc(nil, nil, emptyAction)
|
||||||
dao.BeforeUpdateFunc(nil, nil)
|
dao.BeforeUpdateFunc(nil, nil, emptyAction)
|
||||||
dao.BeforeCreateFunc(nil, nil)
|
dao.BeforeCreateFunc(nil, nil, emptyAction)
|
||||||
dao.AfterDeleteFunc(nil, nil)
|
dao.AfterDeleteFunc(nil, nil)
|
||||||
dao.AfterUpdateFunc(nil, nil)
|
dao.AfterUpdateFunc(nil, nil)
|
||||||
dao.AfterCreateFunc(nil, nil)
|
dao.AfterCreateFunc(nil, nil)
|
||||||
clone.BeforeDeleteFunc(nil, nil)
|
clone.BeforeDeleteFunc(nil, nil, emptyAction)
|
||||||
clone.BeforeUpdateFunc(nil, nil)
|
clone.BeforeUpdateFunc(nil, nil, emptyAction)
|
||||||
clone.BeforeCreateFunc(nil, nil)
|
clone.BeforeCreateFunc(nil, nil, emptyAction)
|
||||||
clone.AfterDeleteFunc(nil, nil)
|
clone.AfterDeleteFunc(nil, nil)
|
||||||
clone.AfterUpdateFunc(nil, nil)
|
clone.AfterUpdateFunc(nil, nil)
|
||||||
clone.AfterCreateFunc(nil, nil)
|
clone.AfterCreateFunc(nil, nil)
|
||||||
|
@ -129,26 +135,29 @@ func TestDaoWithoutHooks(t *testing.T) {
|
||||||
dao := daos.NewMultiDB(testApp.Dao().ConcurrentDB(), testApp.Dao().NonconcurrentDB())
|
dao := daos.NewMultiDB(testApp.Dao().ConcurrentDB(), testApp.Dao().NonconcurrentDB())
|
||||||
dao.MaxLockRetries = 1
|
dao.MaxLockRetries = 1
|
||||||
dao.ModelQueryTimeout = 2
|
dao.ModelQueryTimeout = 2
|
||||||
dao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
dao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
hookCalls["BeforeDeleteFunc"]++
|
hookCalls["BeforeDeleteFunc"]++
|
||||||
return nil
|
return action()
|
||||||
}
|
}
|
||||||
dao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
dao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
hookCalls["BeforeUpdateFunc"]++
|
hookCalls["BeforeUpdateFunc"]++
|
||||||
return nil
|
return action()
|
||||||
}
|
}
|
||||||
dao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
dao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
hookCalls["BeforeCreateFunc"]++
|
hookCalls["BeforeCreateFunc"]++
|
||||||
|
return action()
|
||||||
|
}
|
||||||
|
dao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
|
hookCalls["AfterDeleteFunc"]++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
dao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) {
|
dao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
hookCalls["AfterDeleteFunc"]++
|
|
||||||
}
|
|
||||||
dao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) {
|
|
||||||
hookCalls["AfterUpdateFunc"]++
|
hookCalls["AfterUpdateFunc"]++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
dao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) {
|
dao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
hookCalls["AfterCreateFunc"]++
|
hookCalls["AfterCreateFunc"]++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
new := dao.WithoutHooks()
|
new := dao.WithoutHooks()
|
||||||
|
@ -481,12 +490,13 @@ func TestDaoRetryCreate(t *testing.T) {
|
||||||
retryBeforeCreateHookCalls := 0
|
retryBeforeCreateHookCalls := 0
|
||||||
retryAfterCreateHookCalls := 0
|
retryAfterCreateHookCalls := 0
|
||||||
retryDao := daos.New(testApp.DB())
|
retryDao := daos.New(testApp.DB())
|
||||||
retryDao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
retryDao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
retryBeforeCreateHookCalls++
|
retryBeforeCreateHookCalls++
|
||||||
return errors.New("database is locked")
|
return errors.New("database is locked")
|
||||||
}
|
}
|
||||||
retryDao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) {
|
retryDao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
retryAfterCreateHookCalls++
|
retryAfterCreateHookCalls++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
model := &models.Admin{Email: "new@example.com"}
|
model := &models.Admin{Email: "new@example.com"}
|
||||||
|
@ -507,7 +517,7 @@ func TestDaoRetryCreate(t *testing.T) {
|
||||||
// with non-locking error
|
// with non-locking error
|
||||||
retryBeforeCreateHookCalls = 0
|
retryBeforeCreateHookCalls = 0
|
||||||
retryAfterCreateHookCalls = 0
|
retryAfterCreateHookCalls = 0
|
||||||
retryDao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
retryDao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
retryBeforeCreateHookCalls++
|
retryBeforeCreateHookCalls++
|
||||||
return errors.New("non-locking error")
|
return errors.New("non-locking error")
|
||||||
}
|
}
|
||||||
|
@ -539,12 +549,13 @@ func TestDaoRetryUpdate(t *testing.T) {
|
||||||
retryBeforeUpdateHookCalls := 0
|
retryBeforeUpdateHookCalls := 0
|
||||||
retryAfterUpdateHookCalls := 0
|
retryAfterUpdateHookCalls := 0
|
||||||
retryDao := daos.New(testApp.DB())
|
retryDao := daos.New(testApp.DB())
|
||||||
retryDao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
retryDao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
retryBeforeUpdateHookCalls++
|
retryBeforeUpdateHookCalls++
|
||||||
return errors.New("database is locked")
|
return errors.New("database is locked")
|
||||||
}
|
}
|
||||||
retryDao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) {
|
retryDao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
retryAfterUpdateHookCalls++
|
retryAfterUpdateHookCalls++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := retryDao.Save(model); err != nil {
|
if err := retryDao.Save(model); err != nil {
|
||||||
|
@ -564,7 +575,7 @@ func TestDaoRetryUpdate(t *testing.T) {
|
||||||
// with non-locking error
|
// with non-locking error
|
||||||
retryBeforeUpdateHookCalls = 0
|
retryBeforeUpdateHookCalls = 0
|
||||||
retryAfterUpdateHookCalls = 0
|
retryAfterUpdateHookCalls = 0
|
||||||
retryDao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
retryDao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
retryBeforeUpdateHookCalls++
|
retryBeforeUpdateHookCalls++
|
||||||
return errors.New("non-locking error")
|
return errors.New("non-locking error")
|
||||||
}
|
}
|
||||||
|
@ -590,12 +601,13 @@ func TestDaoRetryDelete(t *testing.T) {
|
||||||
retryBeforeDeleteHookCalls := 0
|
retryBeforeDeleteHookCalls := 0
|
||||||
retryAfterDeleteHookCalls := 0
|
retryAfterDeleteHookCalls := 0
|
||||||
retryDao := daos.New(testApp.DB())
|
retryDao := daos.New(testApp.DB())
|
||||||
retryDao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
retryDao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
retryBeforeDeleteHookCalls++
|
retryBeforeDeleteHookCalls++
|
||||||
return errors.New("database is locked")
|
return errors.New("database is locked")
|
||||||
}
|
}
|
||||||
retryDao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) {
|
retryDao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
retryAfterDeleteHookCalls++
|
retryAfterDeleteHookCalls++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
model, _ := retryDao.FindAdminByEmail("test@example.com")
|
model, _ := retryDao.FindAdminByEmail("test@example.com")
|
||||||
|
@ -616,7 +628,7 @@ func TestDaoRetryDelete(t *testing.T) {
|
||||||
// with non-locking error
|
// with non-locking error
|
||||||
retryBeforeDeleteHookCalls = 0
|
retryBeforeDeleteHookCalls = 0
|
||||||
retryAfterDeleteHookCalls = 0
|
retryAfterDeleteHookCalls = 0
|
||||||
retryDao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
retryDao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
retryBeforeDeleteHookCalls++
|
retryBeforeDeleteHookCalls++
|
||||||
return errors.New("non-locking error")
|
return errors.New("non-locking error")
|
||||||
}
|
}
|
||||||
|
@ -643,13 +655,13 @@ func TestDaoBeforeHooksError(t *testing.T) {
|
||||||
|
|
||||||
baseDao := testApp.Dao()
|
baseDao := testApp.Dao()
|
||||||
|
|
||||||
baseDao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
baseDao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
return errors.New("before_create")
|
return errors.New("before_create")
|
||||||
}
|
}
|
||||||
baseDao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
baseDao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
return errors.New("before_update")
|
return errors.New("before_update")
|
||||||
}
|
}
|
||||||
baseDao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
baseDao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
return errors.New("before_delete")
|
return errors.New("before_delete")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,27 +700,30 @@ func TestDaoTransactionHooksCallsOnFailure(t *testing.T) {
|
||||||
|
|
||||||
baseDao := testApp.Dao()
|
baseDao := testApp.Dao()
|
||||||
|
|
||||||
baseDao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
baseDao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
beforeCreateFuncCalls++
|
beforeCreateFuncCalls++
|
||||||
return nil
|
return action()
|
||||||
}
|
}
|
||||||
baseDao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
baseDao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
beforeUpdateFuncCalls++
|
beforeUpdateFuncCalls++
|
||||||
return nil
|
return action()
|
||||||
}
|
}
|
||||||
baseDao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
baseDao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
beforeDeleteFuncCalls++
|
beforeDeleteFuncCalls++
|
||||||
return nil
|
return action()
|
||||||
}
|
}
|
||||||
|
|
||||||
baseDao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) {
|
baseDao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
afterCreateFuncCalls++
|
afterCreateFuncCalls++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
baseDao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) {
|
baseDao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
afterUpdateFuncCalls++
|
afterUpdateFuncCalls++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
baseDao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) {
|
baseDao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
afterDeleteFuncCalls++
|
afterDeleteFuncCalls++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
existingModel, _ := testApp.Dao().FindAdminByEmail("test@example.com")
|
existingModel, _ := testApp.Dao().FindAdminByEmail("test@example.com")
|
||||||
|
@ -776,27 +791,30 @@ func TestDaoTransactionHooksCallsOnSuccess(t *testing.T) {
|
||||||
|
|
||||||
baseDao := testApp.Dao()
|
baseDao := testApp.Dao()
|
||||||
|
|
||||||
baseDao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
baseDao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
beforeCreateFuncCalls++
|
beforeCreateFuncCalls++
|
||||||
return nil
|
return action()
|
||||||
}
|
}
|
||||||
baseDao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
baseDao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
beforeUpdateFuncCalls++
|
beforeUpdateFuncCalls++
|
||||||
return nil
|
return action()
|
||||||
}
|
}
|
||||||
baseDao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
baseDao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
beforeDeleteFuncCalls++
|
beforeDeleteFuncCalls++
|
||||||
return nil
|
return action()
|
||||||
}
|
}
|
||||||
|
|
||||||
baseDao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) {
|
baseDao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
afterCreateFuncCalls++
|
afterCreateFuncCalls++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
baseDao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) {
|
baseDao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
afterUpdateFuncCalls++
|
afterUpdateFuncCalls++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
baseDao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) {
|
baseDao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) error {
|
||||||
afterDeleteFuncCalls++
|
afterDeleteFuncCalls++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
existingModel, _ := testApp.Dao().FindAdminByEmail("test@example.com")
|
existingModel, _ := testApp.Dao().FindAdminByEmail("test@example.com")
|
||||||
|
|
|
@ -744,36 +744,44 @@ func (form *RecordUpsert) Submit(interceptors ...InterceptorFunc[*models.Record]
|
||||||
|
|
||||||
// upload new files (if any)
|
// upload new files (if any)
|
||||||
//
|
//
|
||||||
// note: executed after the default BeforeCreateFunc and BeforeUpdateFunc hooks
|
// note: executed after the default BeforeCreateFunc and BeforeUpdateFunc hook actions
|
||||||
// to allow uploading AFTER the before app model hooks (eg. in case of an id change)
|
// to allow uploading AFTER the before app model hooks (eg. in case of an id change)
|
||||||
// but BEFORE the actual record db persistence
|
// but BEFORE the actual record db persistence
|
||||||
// ---
|
// ---
|
||||||
dao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
dao.BeforeCreateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
if form.dao.BeforeCreateFunc != nil {
|
newAction := func() error {
|
||||||
if err := form.dao.BeforeCreateFunc(eventDao, m); err != nil {
|
if m.TableName() == form.record.TableName() && m.GetId() == form.record.GetId() {
|
||||||
return err
|
if err := form.processFilesToUpload(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return action()
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.TableName() == form.record.TableName() && m.GetId() == form.record.GetId() {
|
if form.dao.BeforeCreateFunc != nil {
|
||||||
return form.processFilesToUpload()
|
return form.dao.BeforeCreateFunc(eventDao, m, newAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return newAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
dao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model) error {
|
dao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model, action func() error) error {
|
||||||
if form.dao.BeforeUpdateFunc != nil {
|
newAction := func() error {
|
||||||
if err := form.dao.BeforeUpdateFunc(eventDao, m); err != nil {
|
if m.TableName() == form.record.TableName() && m.GetId() == form.record.GetId() {
|
||||||
return err
|
if err := form.processFilesToUpload(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return action()
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.TableName() == form.record.TableName() && m.GetId() == form.record.GetId() {
|
if form.dao.BeforeUpdateFunc != nil {
|
||||||
return form.processFilesToUpload()
|
return form.dao.BeforeUpdateFunc(eventDao, m, newAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return newAction()
|
||||||
}
|
}
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue