github.com/safing/portbase@v0.19.5/database/hook.go (about) 1 package database 2 3 import ( 4 "github.com/safing/portbase/database/query" 5 "github.com/safing/portbase/database/record" 6 ) 7 8 // Hook can be registered for a database query and 9 // will be executed at certain points during the life 10 // cycle of a database record. 11 type Hook interface { 12 // UsesPreGet should return true if the hook's PreGet 13 // should be called prior to loading a database record 14 // from the underlying storage. 15 UsesPreGet() bool 16 // PreGet is called before a database record is loaded from 17 // the underlying storage. A PreGet hookd may be used to 18 // implement more advanced access control on database keys. 19 PreGet(dbKey string) error 20 // UsesPostGet should return true if the hook's PostGet 21 // should be called after loading a database record from 22 // the underlying storage. 23 UsesPostGet() bool 24 // PostGet is called after a record has been loaded form the 25 // underlying storage and may perform additional mutation 26 // or access check based on the records data. 27 // The passed record is already locked by the database system 28 // so users can safely access all data of r. 29 PostGet(r record.Record) (record.Record, error) 30 // UsesPrePut should return true if the hook's PrePut method 31 // should be called prior to saving a record in the database. 32 UsesPrePut() bool 33 // PrePut is called prior to saving (creating or updating) a 34 // record in the database storage. It may be used to perform 35 // extended validation or mutations on the record. 36 // The passed record is already locked by the database system 37 // so users can safely access all data of r. 38 PrePut(r record.Record) (record.Record, error) 39 } 40 41 // RegisteredHook is a registered database hook. 42 type RegisteredHook struct { 43 q *query.Query 44 h Hook 45 } 46 47 // RegisterHook registers a hook for records matching the given 48 // query in the database. 49 func RegisterHook(q *query.Query, hook Hook) (*RegisteredHook, error) { 50 _, err := q.Check() 51 if err != nil { 52 return nil, err 53 } 54 55 c, err := getController(q.DatabaseName()) 56 if err != nil { 57 return nil, err 58 } 59 60 rh := &RegisteredHook{ 61 q: q, 62 h: hook, 63 } 64 65 c.hooksLock.Lock() 66 defer c.hooksLock.Unlock() 67 c.hooks = append(c.hooks, rh) 68 69 return rh, nil 70 } 71 72 // Cancel unregisteres the hook from the database. Once 73 // Cancel returned the hook's methods will not be called 74 // anymore for updates that matched the registered query. 75 func (h *RegisteredHook) Cancel() error { 76 c, err := getController(h.q.DatabaseName()) 77 if err != nil { 78 return err 79 } 80 81 c.hooksLock.Lock() 82 defer c.hooksLock.Unlock() 83 84 for key, hook := range c.hooks { 85 if hook.q == h.q { 86 c.hooks = append(c.hooks[:key], c.hooks[key+1:]...) 87 return nil 88 } 89 } 90 return nil 91 }