diff --git a/main.go b/main.go index b29952f..5bfa48f 100644 --- a/main.go +++ b/main.go @@ -711,8 +711,15 @@ func actionDatapointUpdate(w http.ResponseWriter, r *http.Request, _ *session.T) var nodataSeconds int nodataSeconds, _ = strconv.Atoi(r.FormValue("nodata_seconds")) + // Datapoint needs to be retrieved from database for the name. + // If name has changed, trigger expressions needs to be updated. var dp Datapoint - dp.ID = id + dp, err = DatapointRetrieve(id, "") + if err != nil { + httpError(w, werr.Wrap(err).WithData(id).Log()) + return + } + prevDatapointName := dp.Name dp.Group = r.FormValue("group") dp.Name = r.FormValue("name") dp.Datatype = DatapointType(r.FormValue("datatype")) @@ -724,6 +731,29 @@ func actionDatapointUpdate(w http.ResponseWriter, r *http.Request, _ *session.T) return } + // Update the trigger expressions using this + // datapoint name if changed. + if prevDatapointName != dp.Name { + var triggers []Trigger + triggers, err = TriggersRetrieveByDatapoint(dp.Name) + if err != nil { + httpError(w, werr.Wrap(err).WithData(dp.Name)) + return + } + for _, trigger := range triggers { + err = trigger.RenameDatapoint(prevDatapointName, dp.Name) + if err != nil { + httpError(w, werr.Wrap(err).WithData([]string{prevDatapointName, dp.Name})) + return + } + err = trigger.Update() + if err != nil { + httpError(w, werr.Wrap(err).WithData([]string{prevDatapointName, dp.Name, trigger.Name})) + return + } + } + } + w.Header().Add("Location", "/datapoints") w.WriteHeader(302) } // }}} diff --git a/trigger.go b/trigger.go index 85f792f..d663564 100644 --- a/trigger.go +++ b/trigger.go @@ -4,6 +4,8 @@ import ( // External werr "git.gibonuddevalla.se/go/wrappederror" "github.com/expr-lang/expr" + "github.com/expr-lang/expr/ast" + "github.com/expr-lang/expr/parser" "github.com/lib/pq" // Standard @@ -22,6 +24,17 @@ type Trigger struct { DatapointValues map[string]any } +type ExprRenamePatcher struct { + OldName string + NewName string +} + +func (p ExprRenamePatcher) Visit(node *ast.Node) { + if n, ok := (*node).(*ast.IdentifierNode); ok && n.Value == p.OldName { + ast.Patch(node, &ast.IdentifierNode{Value: p.NewName}) + } +} + func TriggerCreate(sectionID int, name string) (t Trigger, err error) { // {{{ t.SectionID = sectionID t.Name = name @@ -127,6 +140,14 @@ func TriggerRetrieve(id int) (trigger Trigger, err error) { // {{{ err = json.Unmarshal(jsonData, &trigger) return } // }}} +func TriggerDelete(id int) (err error) { // {{{ + _, err = service.Db.Conn.Exec(`DELETE FROM public.trigger WHERE id=$1`, id) + if err != nil { + return werr.Wrap(err).WithData(id) + } + return +} // }}} + func (t *Trigger) Validate() (ok bool, err error) { // {{{ if strings.TrimSpace(t.Name) == "" { err = fmt.Errorf("Name can't be empty") @@ -212,14 +233,6 @@ func (t *Trigger) Update() (err error) { // {{{ } return } // }}} -func TriggerDelete(id int) (err error) { // {{{ - _, err = service.Db.Conn.Exec(`DELETE FROM public.trigger WHERE id=$1`, id) - if err != nil { - return werr.Wrap(err).WithData(id) - } - return -} // }}} - func (t *Trigger) Run() (output any, err error) { // {{{ datapoints := make(map[string]Datapoint) for _, dpname := range t.Datapoints { @@ -248,3 +261,14 @@ func (t *Trigger) Run() (output any, err error) { // {{{ } return } // }}} +func (t *Trigger) RenameDatapoint(from, to string) error { // {{{ + tree, err := parser.Parse(t.Expression) + if err != nil { + return werr.Wrap(err).WithData(t.Expression) + } + + ast.Walk(&tree.Node, ExprRenamePatcher{from, to}) + t.Expression = tree.Node.String() + + return nil +} // }}}