smon/trigger.go

251 lines
4.6 KiB
Go
Raw Normal View History

2024-04-29 08:36:13 +02:00
package main
import (
// External
2024-06-01 09:18:56 +02:00
werr "git.gibonuddevalla.se/go/wrappederror"
2024-04-29 08:36:13 +02:00
"github.com/expr-lang/expr"
2024-05-01 10:02:33 +02:00
"github.com/lib/pq"
2024-04-29 08:36:13 +02:00
// Standard
2024-05-30 15:06:41 +02:00
"database/sql"
2024-04-29 08:36:13 +02:00
"encoding/json"
"fmt"
"strings"
)
type Trigger struct {
ID int
Name string
SectionID int `db:"section_id"`
Expression string
Datapoints []string
DatapointValues map[string]any
2024-04-29 08:36:13 +02:00
}
2024-05-30 15:06:41 +02:00
func TriggerCreate(sectionID int, name string) (t Trigger, err error) { // {{{
t.SectionID = sectionID
t.Name = name
t.Expression = "false"
err = t.Update()
return
} // }}}
2024-04-29 08:36:13 +02:00
func TriggersRetrieve() (areas []Area, err error) { // {{{
areas = []Area{}
row := service.Db.Conn.QueryRow(`
WITH section_triggers AS (
SELECT
s.id AS id,
s.area_id,
s.name AS name,
jsonb_agg(
to_jsonb(t.*)
) AS triggers
FROM section s
LEFT JOIN "trigger" t ON t.section_id = s.id
GROUP BY
s.id, s.name)
SELECT
jsonb_agg(jsonsections)
FROM (
SELECT
a.id,
a.name,
jsonb_agg(
to_jsonb(
s.*
)
) AS sections
FROM area a
LEFT JOIN section_triggers s ON s.area_id = a.id
GROUP BY
a.id, a.name
) jsonsections
`,
)
var jsonData []byte
err = row.Scan(&jsonData)
if err != nil {
2024-06-01 09:18:56 +02:00
err = werr.Wrap(err)
2024-04-29 08:36:13 +02:00
return
}
if jsonData == nil {
return
}
2024-04-29 08:36:13 +02:00
err = json.Unmarshal(jsonData, &areas)
if err != nil {
2024-06-01 09:18:56 +02:00
err = werr.Wrap(err)
2024-04-29 08:36:13 +02:00
return
}
return
} // }}}
2024-04-30 20:10:05 +02:00
func TriggersRetrieveByDatapoint(datapointName string) (triggers []Trigger, err error) { // {{{
triggers = []Trigger{}
row := service.Db.Conn.QueryRow(`
SELECT jsonb_agg(t.*)
FROM public."trigger" t
2024-04-30 20:10:05 +02:00
WHERE
datapoints @> $1
`,
fmt.Sprintf(`["%s"]`, datapointName),
)
var data []byte
err = row.Scan(&data)
2024-04-30 20:10:05 +02:00
if err != nil {
2024-06-01 09:18:56 +02:00
err = werr.Wrap(err).WithData(datapointName)
2024-04-30 20:10:05 +02:00
return
}
// no triggers found for this datapoint.
if data == nil {
return
}
err = json.Unmarshal(data, &triggers)
if err != nil {
2024-06-01 09:18:56 +02:00
err = werr.Wrap(err).WithData(datapointName)
return
2024-04-30 20:10:05 +02:00
}
return
} // }}}
2024-04-29 08:36:13 +02:00
func TriggerRetrieve(id int) (trigger Trigger, err error) { // {{{
row := service.Db.Conn.QueryRow(`SELECT to_jsonb(t.*) FROM "trigger" t WHERE id=$1`, id)
var jsonData []byte
err = row.Scan(&jsonData)
if err != nil {
2024-06-01 09:18:56 +02:00
err = werr.Wrap(err)
2024-04-29 08:36:13 +02:00
return
}
err = json.Unmarshal(jsonData, &trigger)
return
} // }}}
2024-04-30 20:10:05 +02:00
func (t *Trigger) Validate() (ok bool, err error) { // {{{
2024-04-29 08:36:13 +02:00
if strings.TrimSpace(t.Name) == "" {
err = fmt.Errorf("Name can't be empty")
return
}
if strings.TrimSpace(t.Expression) == "" {
err = fmt.Errorf("Expression can't be empty")
return
}
return true, nil
2024-04-30 20:10:05 +02:00
} // }}}
func (t *Trigger) Update() (err error) { // {{{
2024-04-29 08:36:13 +02:00
var ok bool
if ok, err = t.Validate(); !ok {
return
}
2024-05-01 10:02:33 +02:00
if t.Datapoints == nil {
t.Datapoints = []string{}
}
jsonDatapoints, _ := json.Marshal(t.Datapoints)
if t.ID == 0 {
2024-05-30 15:06:41 +02:00
var row *sql.Row
row = service.Db.Conn.QueryRow(`
2024-05-01 10:02:33 +02:00
INSERT INTO "trigger"(name, section_id, expression, datapoints)
VALUES($1, $2, $3, $4)
2024-05-30 15:06:41 +02:00
RETURNING id
2024-05-01 10:02:33 +02:00
`,
t.Name,
t.SectionID,
t.Expression,
jsonDatapoints,
)
2024-05-30 15:06:41 +02:00
err = row.Scan(&t.ID)
if err != nil {
2024-06-01 09:18:56 +02:00
err = werr.Wrap(err).WithData(
2024-05-30 15:06:41 +02:00
struct {
SectionID int
Name string
Expression string
JsonDataPoints []byte
}{
t.SectionID,
t.Name,
t.Expression,
jsonDatapoints,
},
)
return
}
2024-05-01 10:02:33 +02:00
} else {
_, err = service.Db.Conn.Exec(`
UPDATE "trigger"
SET
name=$2,
expression=$3,
datapoints=$4
WHERE
id=$1
`,
t.ID,
t.Name,
t.Expression,
jsonDatapoints,
)
}
if pqErr, ok := err.(*pq.Error); ok {
2024-06-01 09:18:56 +02:00
err = werr.Wrap(err).WithData(
2024-05-01 10:02:33 +02:00
struct {
Trigger *Trigger
PostgresCode pq.ErrorCode
PostgresMsg string
}{
t,
pqErr.Code,
pqErr.Code.Name(),
})
} else if err != nil {
2024-06-01 09:18:56 +02:00
err = werr.Wrap(err).WithData(t)
}
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)
2024-04-29 08:36:13 +02:00
}
return
2024-04-30 20:10:05 +02:00
} // }}}
func (t *Trigger) Run() (output any, err error) { // {{{
datapoints := make(map[string]Datapoint)
for _, dpname := range t.Datapoints {
var dp Datapoint
dp, err = DatapointRetrieve(0, dpname)
if err != nil {
2024-06-01 09:18:56 +02:00
err = werr.Wrap(err)
2024-04-30 20:10:05 +02:00
return
}
datapoints[dpname] = dp
}
2024-04-29 08:36:13 +02:00
t.DatapointValues = make(map[string]any)
2024-04-29 08:36:13 +02:00
for dpName, dp := range datapoints {
t.DatapointValues[dpName] = dp.LastDatapointValue.Value()
2024-04-29 08:36:13 +02:00
}
program, err := expr.Compile(t.Expression)
if err != nil {
return
}
output, err = expr.Run(program, t.DatapointValues)
2024-04-29 08:36:13 +02:00
if err != nil {
return
}
return
2024-04-30 20:10:05 +02:00
} // }}}