test(09-05): add failing tests for scoped record lifecycle
- Record routes must enforce permission before ids or bodies and return D-10 envelopes - Create, update, and delete run Before and After hooks once inside the transaction - Out-of-scope and missing records are indistinguishable, and hook failure rolls back
This commit is contained in:
@@ -75,10 +75,8 @@ func (crudRow) Fillable() []string { return []string{"name", "note"} }
|
||||
func (crudRow) Rules() map[string]string { return crudRuleSet }
|
||||
|
||||
func (r *crudRow) BeforeValidate(tx *gorm.DB) error {
|
||||
ctx := context.Background()
|
||||
if tx != nil && tx.Statement != nil && tx.Statement.Context != nil {
|
||||
ctx = tx.Statement.Context
|
||||
}
|
||||
ctx := txContext(tx)
|
||||
recordHook(ctx, "before_validate")
|
||||
if clear, _ := ctx.Value(clearNameKey{}).(bool); clear {
|
||||
if r.Name == "" {
|
||||
return errors.New("fill did not run before validate")
|
||||
@@ -88,6 +86,71 @@ func (r *crudRow) BeforeValidate(tx *gorm.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *crudRow) BeforeSave(tx *gorm.DB) error {
|
||||
recordHook(txContext(tx), "before_save")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *crudRow) BeforeCreate(tx *gorm.DB) error {
|
||||
recordHook(txContext(tx), "before_create")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *crudRow) AfterCreate(tx *gorm.DB) error {
|
||||
recordHook(txContext(tx), "after_create")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *crudRow) AfterSave(tx *gorm.DB) error {
|
||||
recordHook(txContext(tx), "after_save")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *crudRow) BeforeUpdate(tx *gorm.DB) error {
|
||||
recordHook(txContext(tx), "before_update")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *crudRow) AfterUpdate(tx *gorm.DB) error {
|
||||
recordHook(txContext(tx), "after_update")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *crudRow) BeforeDelete(tx *gorm.DB) error {
|
||||
ctx := txContext(tx)
|
||||
recordHook(ctx, "before_delete")
|
||||
if fail, _ := ctx.Value(failDeleteKey{}).(bool); fail {
|
||||
return errors.New("secret-hook-boom")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *crudRow) AfterDelete(tx *gorm.DB) error {
|
||||
recordHook(txContext(tx), "after_delete")
|
||||
return nil
|
||||
}
|
||||
|
||||
type hookSinkKey struct{}
|
||||
type failDeleteKey struct{}
|
||||
|
||||
func txContext(tx *gorm.DB) context.Context {
|
||||
if tx != nil && tx.Statement != nil && tx.Statement.Context != nil {
|
||||
return tx.Statement.Context
|
||||
}
|
||||
return context.Background()
|
||||
}
|
||||
|
||||
func recordHook(ctx context.Context, name string) {
|
||||
if ctx == nil {
|
||||
return
|
||||
}
|
||||
sink, _ := ctx.Value(hookSinkKey{}).(*[]string)
|
||||
if sink == nil {
|
||||
return
|
||||
}
|
||||
*sink = append(*sink, name)
|
||||
}
|
||||
|
||||
type crudNoRules struct {
|
||||
ID uint `gorm:"column:id;primaryKey"`
|
||||
Name string `gorm:"column:name"`
|
||||
|
||||
Reference in New Issue
Block a user