fixed realtime delete event to be called after the record was deleted from the db

This commit is contained in:
Gani Georgiev 2023-05-29 22:28:07 +03:00
parent 729f9f142e
commit 7de346b532
3 changed files with 62 additions and 12 deletions

View File

@ -21,6 +21,10 @@
- (@todo docs) Changed the After* hooks to be called right before writing the user response, allowing users to return response errors from the after hooks. - (@todo docs) Changed the After* hooks to be called right before writing the user response, allowing users to return response errors from the after hooks.
- Fixed realtime delete event to be called after the record was deleted from the DB (_including transactions and cascade delete operations_).
- Added `subscriptions.Client.Unset()` helper to remove a single cached item from the client store.
## v0.16.4-WIP ## v0.16.4-WIP

View File

@ -267,7 +267,7 @@ func (api *realtimeApi) bindEvents() {
api.app.OnModelAfterCreate().PreAdd(func(e *core.ModelEvent) error { api.app.OnModelAfterCreate().PreAdd(func(e *core.ModelEvent) error {
if record := api.resolveRecord(e.Model); record != nil { if record := api.resolveRecord(e.Model); record != nil {
if err := api.broadcastRecord("create", record); err != nil && api.app.IsDebug() { if err := api.broadcastRecord("create", record, false); err != nil && api.app.IsDebug() {
log.Println(err) log.Println(err)
} }
} }
@ -276,7 +276,7 @@ func (api *realtimeApi) bindEvents() {
api.app.OnModelAfterUpdate().PreAdd(func(e *core.ModelEvent) error { api.app.OnModelAfterUpdate().PreAdd(func(e *core.ModelEvent) error {
if record := api.resolveRecord(e.Model); record != nil { if record := api.resolveRecord(e.Model); record != nil {
if err := api.broadcastRecord("update", record); err != nil && api.app.IsDebug() { if err := api.broadcastRecord("update", record, false); err != nil && api.app.IsDebug() {
log.Println(err) log.Println(err)
} }
} }
@ -285,7 +285,16 @@ func (api *realtimeApi) bindEvents() {
api.app.OnModelBeforeDelete().Add(func(e *core.ModelEvent) error { api.app.OnModelBeforeDelete().Add(func(e *core.ModelEvent) error {
if record := api.resolveRecord(e.Model); record != nil { if record := api.resolveRecord(e.Model); record != nil {
if err := api.broadcastRecord("delete", record); err != nil && api.app.IsDebug() { if err := api.broadcastRecord("delete", record, true); err != nil && api.app.IsDebug() {
log.Println(err)
}
}
return nil
})
api.app.OnModelAfterDelete().Add(func(e *core.ModelEvent) error {
if record := api.resolveRecord(e.Model); record != nil {
if err := api.broadcastDryCachedRecord("delete", record); err != nil && api.app.IsDebug() {
log.Println(err) log.Println(err)
} }
} }
@ -367,7 +376,7 @@ type recordData struct {
Record *models.Record `json:"record"` Record *models.Record `json:"record"`
} }
func (api *realtimeApi) broadcastRecord(action string, record *models.Record) error { func (api *realtimeApi) broadcastRecord(action string, record *models.Record, dryCache bool) error {
collection := record.Collection() collection := record.Collection()
if collection == nil { if collection == nil {
return errors.New("Record collection not set.") return errors.New("Record collection not set.")
@ -399,9 +408,6 @@ func (api *realtimeApi) broadcastRecord(action string, record *models.Record) er
dataBytes, err := json.Marshal(data) dataBytes, err := json.Marshal(data)
if err != nil { if err != nil {
if api.app.IsDebug() {
log.Println(err)
}
return err return err
} }
@ -438,17 +444,46 @@ func (api *realtimeApi) broadcastRecord(action string, record *models.Record) er
} }
} }
routine.FireAndForget(func() { if dryCache {
if !client.IsDiscarded() { client.Set(action+"/"+data.Record.Id, msg)
client.Channel() <- msg } else {
} routine.FireAndForget(func() {
}) if !client.IsDiscarded() {
client.Channel() <- msg
}
})
}
} }
} }
return nil return nil
} }
// broadcastDryCachedRecord broadcasts record if it is cached in the client context.
func (api *realtimeApi) broadcastDryCachedRecord(action string, record *models.Record) error {
clients := api.app.SubscriptionsBroker().Clients()
for _, client := range clients {
key := action + "/" + record.Id
msg, ok := client.Get(key).(subscriptions.Message)
if !ok {
continue
}
client.Unset(key)
client := client
routine.FireAndForget(func() {
if !client.IsDiscarded() {
client.Channel() <- msg
}
})
}
return nil
}
type getter interface { type getter interface {
Get(string) any Get(string) any
} }

View File

@ -35,6 +35,9 @@ type Client interface {
// Set stores any value to the client's context. // Set stores any value to the client's context.
Set(key string, value any) Set(key string, value any)
// Unset removes a single value from the client's context.
Unset(key string)
// Get retrieves the key value from the client's context. // Get retrieves the key value from the client's context.
Get(key string) any Get(key string) any
@ -157,6 +160,14 @@ func (c *DefaultClient) Set(key string, value any) {
c.store[key] = value c.store[key] = value
} }
// Unset implements the [Client.Unset] interface method.
func (c *DefaultClient) Unset(key string) {
c.mux.Lock()
defer c.mux.Unlock()
delete(c.store, key)
}
// Discard implements the [Client.Discard] interface method. // Discard implements the [Client.Discard] interface method.
func (c *DefaultClient) Discard() { func (c *DefaultClient) Discard() {
c.mux.Lock() c.mux.Lock()