From 08f1bd4ff0ca44caf3e559d80c5bbb2f567c6173 Mon Sep 17 00:00:00 2001 From: Daniel Ponte Date: Mon, 4 Nov 2024 23:41:52 -0500 Subject: [PATCH] API begin --- internal/trending/item.go | 2 +- internal/trending/trending.go | 2 +- pkg/alerting/stats.go | 8 +- pkg/api/api.go | 17 +- pkg/database/extend.go | 11 ++ pkg/database/querier.go | 4 +- pkg/database/talkgroups.sql.go | 243 +++++++++++++++++++++------- pkg/database/talkgroups.sql_test.go | 41 ++++- pkg/pb/stillbox.pb.go | 2 +- pkg/talkgroups/cache.go | 85 +++++++--- sql/postgres/queries/talkgroups.sql | 38 ++++- 11 files changed, 351 insertions(+), 102 deletions(-) create mode 100644 pkg/database/extend.go diff --git a/internal/trending/item.go b/internal/trending/item.go index aa5dc24..058274e 100644 --- a/internal/trending/item.go +++ b/internal/trending/item.go @@ -31,7 +31,7 @@ func newItem[K comparable](id K, options *options[K]) *item[K] { } } -func (i *item[K]) score(id K) Score[K] { +func (i *item[K]) score() Score[K] { recentCount, count := i.computeCounts() if recentCount < i.options.countThreshold { return Score[K]{} diff --git a/internal/trending/trending.go b/internal/trending/trending.go index 1814225..db76f2b 100644 --- a/internal/trending/trending.go +++ b/internal/trending/trending.go @@ -192,7 +192,7 @@ func (s *Scorer[K]) addToItem(item *item[K], tm time.Time) { func (s *Scorer[K]) Score() Scores[K] { var scores Scores[K] for id, item := range s.items { - score := item.score(id) + score := item.score() score.ID = id scores = append(scores, score) } diff --git a/pkg/alerting/stats.go b/pkg/alerting/stats.go index e513edd..0d5c3be 100644 --- a/pkg/alerting/stats.go +++ b/pkg/alerting/stats.go @@ -69,20 +69,20 @@ func (as *alerter) tgStatsHandler(w http.ResponseWriter, r *http.Request) { ctx := r.Context() db := database.FromCtx(ctx) - tgs, err := db.GetTalkgroupsByPackedIDs(ctx, as.packedScoredTGs()) + tgs, err := db.GetTalkgroupsWithLearnedByPackedIDs(ctx, as.packedScoredTGs()) if err != nil { log.Error().Err(err).Msg("stats TG get failed") http.Error(w, err.Error(), http.StatusInternalServerError) return } - tgMap := make(map[talkgroups.ID]database.GetTalkgroupsByPackedIDsRow, len(tgs)) + tgMap := make(map[talkgroups.ID]database.GetTalkgroupsWithLearnedByPackedIDsRow, len(tgs)) for _, t := range tgs { - tgMap[talkgroups.ID{System: uint32(t.System.ID), Talkgroup: uint32(t.Talkgroup.ID)}] = t + tgMap[talkgroups.ID{System: uint32(t.System.ID), Talkgroup: uint32(t.Talkgroup.Tgid)}] = t } renderData := struct { - TGs map[talkgroups.ID]database.GetTalkgroupsByPackedIDsRow + TGs map[talkgroups.ID]database.GetTalkgroupsWithLearnedByPackedIDsRow Scores trending.Scores[talkgroups.ID] LastScore time.Time Simulation *Simulation diff --git a/pkg/api/api.go b/pkg/api/api.go index eb7eb7e..19ab3ef 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -58,13 +58,14 @@ func httpCode(err error) int { return http.StatusInternalServerError } -func (a *api) writeJSON(w http.ResponseWriter, r *http.Request, data interface{}, err error) { +func (a *api) writeResponse(w http.ResponseWriter, r *http.Request, data interface{}, err error) { if err != nil { log.Error().Str("path", r.URL.Path).Err(err).Msg("request failed") http.Error(w, err.Error(), httpCode(err)) return } + w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) err = enc.Encode(data) if err != nil { @@ -83,9 +84,9 @@ func decodeParams(d interface{}, r *http.Request) error { } dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ - Metadata: nil, - Result: d, - TagName: "param", + Metadata: nil, + Result: d, + TagName: "param", WeaklyTypedInput: true, }) if err != nil { @@ -100,6 +101,7 @@ func (a *api) badReq(w http.ResponseWriter, err error) { } func (a *api) talkgroup(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() p := struct { System *int `param:"system"` ID *int `param:"id"` @@ -114,9 +116,12 @@ func (a *api) talkgroup(w http.ResponseWriter, r *http.Request) { var res interface{} switch { case p.System != nil && p.ID != nil: - res, err = a.tgs.TG(r.Context(), talkgroups.TG(*p.System, *p.ID)) + res, err = a.tgs.TG(ctx, talkgroups.TG(*p.System, *p.ID)) case p.System != nil: + res, err = a.tgs.SystemTGs(ctx, int32(*p.System)) default: + res, err = a.tgs.TGs(ctx, nil) } - a.writeJSON(w, r, res, err) + + a.writeResponse(w, r, res, err) } diff --git a/pkg/database/extend.go b/pkg/database/extend.go new file mode 100644 index 0000000..3a96cd1 --- /dev/null +++ b/pkg/database/extend.go @@ -0,0 +1,11 @@ +package database + +func (d GetTalkgroupsWithLearnedByPackedIDsRow) GetTalkgroup() Talkgroup { return d.Talkgroup } +func (d GetTalkgroupsWithLearnedByPackedIDsRow) GetSystem() System { return d.System } +func (d GetTalkgroupsWithLearnedByPackedIDsRow) GetLearned() bool { return d.Learned } +func (g GetTalkgroupsWithLearnedRow) GetTalkgroup() Talkgroup { return g.Talkgroup } +func (g GetTalkgroupsWithLearnedRow) GetSystem() System { return g.System } +func (g GetTalkgroupsWithLearnedRow) GetLearned() bool { return g.Learned } +func (g GetTalkgroupsWithLearnedBySystemRow) GetTalkgroup() Talkgroup { return g.Talkgroup } +func (g GetTalkgroupsWithLearnedBySystemRow) GetSystem() System { return g.System } +func (g GetTalkgroupsWithLearnedBySystemRow) GetLearned() bool { return g.Learned } diff --git a/pkg/database/querier.go b/pkg/database/querier.go index 4bf2177..9d8d057 100644 --- a/pkg/database/querier.go +++ b/pkg/database/querier.go @@ -26,10 +26,12 @@ type Querier interface { GetTalkgroupIDsByTags(ctx context.Context, anytags []string, alltags []string, nottags []string) ([]GetTalkgroupIDsByTagsRow, error) GetTalkgroupTags(ctx context.Context, sys int, tg int) ([]string, error) GetTalkgroupWithLearned(ctx context.Context, systemID int, tgid int) (GetTalkgroupWithLearnedRow, error) - GetTalkgroupWithLearnedByPackedIDs(ctx context.Context, dollar_1 []int64) ([]GetTalkgroupWithLearnedByPackedIDsRow, error) GetTalkgroupsByPackedIDs(ctx context.Context, dollar_1 []int64) ([]GetTalkgroupsByPackedIDsRow, error) GetTalkgroupsWithAllTags(ctx context.Context, tags []string) ([]GetTalkgroupsWithAllTagsRow, error) GetTalkgroupsWithAnyTags(ctx context.Context, tags []string) ([]GetTalkgroupsWithAnyTagsRow, error) + GetTalkgroupsWithLearned(ctx context.Context) ([]GetTalkgroupsWithLearnedRow, error) + GetTalkgroupsWithLearnedByPackedIDs(ctx context.Context, dollar_1 []int64) ([]GetTalkgroupsWithLearnedByPackedIDsRow, error) + GetTalkgroupsWithLearnedBySystem(ctx context.Context, system int32) ([]GetTalkgroupsWithLearnedBySystemRow, error) GetUserByID(ctx context.Context, id int32) (User, error) GetUserByUID(ctx context.Context, id int32) (User, error) GetUserByUsername(ctx context.Context, username string) (User, error) diff --git a/pkg/database/talkgroups.sql.go b/pkg/database/talkgroups.sql.go index 8700be2..b32deb3 100644 --- a/pkg/database/talkgroups.sql.go +++ b/pkg/database/talkgroups.sql.go @@ -151,67 +151,6 @@ func (q *Queries) GetTalkgroupWithLearned(ctx context.Context, systemID int, tgi return i, err } -const getTalkgroupWithLearnedByPackedIDs = `-- name: GetTalkgroupWithLearnedByPackedIDs :many -SELECT -tg.id, tg.system_id, tg.tgid, tg.name, tg.alpha_tag, tg.tg_group, tg.frequency, tg.metadata, tg.tags, tg.alert, tg.alert_config, tg.weight, sys.id, sys.name, -FALSE learned -FROM talkgroups tg -JOIN systems sys ON tg.system_id = sys.id -WHERE tg.id = ANY($1::INT8[]) -UNION -SELECT -tgl.id::INT8, tgl.system_id::INT4, tgl.tgid::INT4, tgl.name, -tgl.alpha_tag, tgl.alpha_tag, NULL::INTEGER, NULL::JSONB, -CASE WHEN tgl.alpha_tag IS NULL THEN NULL ELSE ARRAY[tgl.alpha_tag] END, -TRUE, NULL::JSONB, 1.0, sys.id, sys.name, -TRUE learned -FROM talkgroups_learned tgl -JOIN systems sys ON tgl.system_id = sys.id -WHERE systg2id(tgl.system_id, tgl.tgid) = ANY($1::INT8[]) AND ignored IS NOT TRUE -` - -type GetTalkgroupWithLearnedByPackedIDsRow struct { - Talkgroup Talkgroup `json:"talkgroup"` - System System `json:"system"` - Learned bool `json:"learned"` -} - -func (q *Queries) GetTalkgroupWithLearnedByPackedIDs(ctx context.Context, dollar_1 []int64) ([]GetTalkgroupWithLearnedByPackedIDsRow, error) { - rows, err := q.db.Query(ctx, getTalkgroupWithLearnedByPackedIDs, dollar_1) - if err != nil { - return nil, err - } - defer rows.Close() - var items []GetTalkgroupWithLearnedByPackedIDsRow - for rows.Next() { - var i GetTalkgroupWithLearnedByPackedIDsRow - if err := rows.Scan( - &i.Talkgroup.ID, - &i.Talkgroup.SystemID, - &i.Talkgroup.Tgid, - &i.Talkgroup.Name, - &i.Talkgroup.AlphaTag, - &i.Talkgroup.TgGroup, - &i.Talkgroup.Frequency, - &i.Talkgroup.Metadata, - &i.Talkgroup.Tags, - &i.Talkgroup.Alert, - &i.Talkgroup.AlertConfig, - &i.Talkgroup.Weight, - &i.System.ID, - &i.System.Name, - &i.Learned, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const getTalkgroupsByPackedIDs = `-- name: GetTalkgroupsByPackedIDs :many SELECT tg.id, tg.system_id, tg.tgid, tg.name, tg.alpha_tag, tg.tg_group, tg.frequency, tg.metadata, tg.tags, tg.alert, tg.alert_config, tg.weight, sys.id, sys.name FROM talkgroups tg JOIN systems sys ON tg.system_id = sys.id @@ -342,6 +281,188 @@ func (q *Queries) GetTalkgroupsWithAnyTags(ctx context.Context, tags []string) ( return items, nil } +const getTalkgroupsWithLearned = `-- name: GetTalkgroupsWithLearned :many +SELECT +tg.id, tg.system_id, tg.tgid, tg.name, tg.alpha_tag, tg.tg_group, tg.frequency, tg.metadata, tg.tags, tg.alert, tg.alert_config, tg.weight, sys.id, sys.name, +FALSE learned +FROM talkgroups tg +JOIN systems sys ON tg.system_id = sys.id +UNION +SELECT +tgl.id::INT8, tgl.system_id::INT4, tgl.tgid::INT4, tgl.name, +tgl.alpha_tag, tgl.alpha_tag, NULL::INTEGER, NULL::JSONB, +CASE WHEN tgl.alpha_tag IS NULL THEN NULL ELSE ARRAY[tgl.alpha_tag] END, +TRUE, NULL::JSONB, 1.0, sys.id, sys.name, +TRUE learned +FROM talkgroups_learned tgl +JOIN systems sys ON tgl.system_id = sys.id +WHERE ignored IS NOT TRUE +` + +type GetTalkgroupsWithLearnedRow struct { + Talkgroup Talkgroup `json:"talkgroup"` + System System `json:"system"` + Learned bool `json:"learned"` +} + +func (q *Queries) GetTalkgroupsWithLearned(ctx context.Context) ([]GetTalkgroupsWithLearnedRow, error) { + rows, err := q.db.Query(ctx, getTalkgroupsWithLearned) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTalkgroupsWithLearnedRow + for rows.Next() { + var i GetTalkgroupsWithLearnedRow + if err := rows.Scan( + &i.Talkgroup.ID, + &i.Talkgroup.SystemID, + &i.Talkgroup.Tgid, + &i.Talkgroup.Name, + &i.Talkgroup.AlphaTag, + &i.Talkgroup.TgGroup, + &i.Talkgroup.Frequency, + &i.Talkgroup.Metadata, + &i.Talkgroup.Tags, + &i.Talkgroup.Alert, + &i.Talkgroup.AlertConfig, + &i.Talkgroup.Weight, + &i.System.ID, + &i.System.Name, + &i.Learned, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTalkgroupsWithLearnedByPackedIDs = `-- name: GetTalkgroupsWithLearnedByPackedIDs :many +SELECT +tg.id, tg.system_id, tg.tgid, tg.name, tg.alpha_tag, tg.tg_group, tg.frequency, tg.metadata, tg.tags, tg.alert, tg.alert_config, tg.weight, sys.id, sys.name, +FALSE learned +FROM talkgroups tg +JOIN systems sys ON tg.system_id = sys.id +WHERE tg.id = ANY($1::INT8[]) +UNION +SELECT +tgl.id::INT8, tgl.system_id::INT4, tgl.tgid::INT4, tgl.name, +tgl.alpha_tag, tgl.alpha_tag, NULL::INTEGER, NULL::JSONB, +CASE WHEN tgl.alpha_tag IS NULL THEN NULL ELSE ARRAY[tgl.alpha_tag] END, +TRUE, NULL::JSONB, 1.0, sys.id, sys.name, +TRUE learned +FROM talkgroups_learned tgl +JOIN systems sys ON tgl.system_id = sys.id +WHERE systg2id(tgl.system_id, tgl.tgid) = ANY($1::INT8[]) AND ignored IS NOT TRUE +` + +type GetTalkgroupsWithLearnedByPackedIDsRow struct { + Talkgroup Talkgroup `json:"talkgroup"` + System System `json:"system"` + Learned bool `json:"learned"` +} + +func (q *Queries) GetTalkgroupsWithLearnedByPackedIDs(ctx context.Context, dollar_1 []int64) ([]GetTalkgroupsWithLearnedByPackedIDsRow, error) { + rows, err := q.db.Query(ctx, getTalkgroupsWithLearnedByPackedIDs, dollar_1) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTalkgroupsWithLearnedByPackedIDsRow + for rows.Next() { + var i GetTalkgroupsWithLearnedByPackedIDsRow + if err := rows.Scan( + &i.Talkgroup.ID, + &i.Talkgroup.SystemID, + &i.Talkgroup.Tgid, + &i.Talkgroup.Name, + &i.Talkgroup.AlphaTag, + &i.Talkgroup.TgGroup, + &i.Talkgroup.Frequency, + &i.Talkgroup.Metadata, + &i.Talkgroup.Tags, + &i.Talkgroup.Alert, + &i.Talkgroup.AlertConfig, + &i.Talkgroup.Weight, + &i.System.ID, + &i.System.Name, + &i.Learned, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTalkgroupsWithLearnedBySystem = `-- name: GetTalkgroupsWithLearnedBySystem :many +SELECT +tg.id, tg.system_id, tg.tgid, tg.name, tg.alpha_tag, tg.tg_group, tg.frequency, tg.metadata, tg.tags, tg.alert, tg.alert_config, tg.weight, sys.id, sys.name, +FALSE learned +FROM talkgroups tg +JOIN systems sys ON tg.system_id = sys.id +WHERE tg.system_id = $1 +UNION +SELECT +tgl.id::INT8, tgl.system_id::INT4, tgl.tgid::INT4, tgl.name, +tgl.alpha_tag, tgl.alpha_tag, NULL::INTEGER, NULL::JSONB, +CASE WHEN tgl.alpha_tag IS NULL THEN NULL ELSE ARRAY[tgl.alpha_tag] END, +TRUE, NULL::JSONB, 1.0, sys.id, sys.name, +TRUE learned +FROM talkgroups_learned tgl +JOIN systems sys ON tgl.system_id = sys.id +WHERE tgl.system_id = $1 AND ignored IS NOT TRUE +` + +type GetTalkgroupsWithLearnedBySystemRow struct { + Talkgroup Talkgroup `json:"talkgroup"` + System System `json:"system"` + Learned bool `json:"learned"` +} + +func (q *Queries) GetTalkgroupsWithLearnedBySystem(ctx context.Context, system int32) ([]GetTalkgroupsWithLearnedBySystemRow, error) { + rows, err := q.db.Query(ctx, getTalkgroupsWithLearnedBySystem, system) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTalkgroupsWithLearnedBySystemRow + for rows.Next() { + var i GetTalkgroupsWithLearnedBySystemRow + if err := rows.Scan( + &i.Talkgroup.ID, + &i.Talkgroup.SystemID, + &i.Talkgroup.Tgid, + &i.Talkgroup.Name, + &i.Talkgroup.AlphaTag, + &i.Talkgroup.TgGroup, + &i.Talkgroup.Frequency, + &i.Talkgroup.Metadata, + &i.Talkgroup.Tags, + &i.Talkgroup.Alert, + &i.Talkgroup.AlertConfig, + &i.Talkgroup.Weight, + &i.System.ID, + &i.System.Name, + &i.Learned, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const setTalkgroupTags = `-- name: SetTalkgroupTags :exec UPDATE talkgroups SET tags = $3 WHERE id = systg2id($1, $2) diff --git a/pkg/database/talkgroups.sql_test.go b/pkg/database/talkgroups.sql_test.go index cc39c55..248b3dc 100644 --- a/pkg/database/talkgroups.sql_test.go +++ b/pkg/database/talkgroups.sql_test.go @@ -43,7 +43,46 @@ JOIN systems sys ON tgl.system_id = sys.id WHERE tgl.system_id = $1 AND tgl.tgid = $2 AND ignored IS NOT TRUE ` +const getTalkgroupsWithLearnedBySystemTest = `-- name: GetTalkgroupsWithLearnedBySystem :many +SELECT +tg.id, tg.system_id, tg.tgid, tg.name, tg.alpha_tag, tg.tg_group, tg.frequency, tg.metadata, tg.tags, tg.alert, tg.alert_config, tg.weight, sys.id, sys.name, +FALSE learned +FROM talkgroups tg +JOIN systems sys ON tg.system_id = sys.id +WHERE tg.system_id = $1 +UNION +SELECT +tgl.id::INT8, tgl.system_id::INT4, tgl.tgid::INT4, tgl.name, +tgl.alpha_tag, tgl.alpha_tag, NULL::INTEGER, NULL::JSONB, +CASE WHEN tgl.alpha_tag IS NULL THEN NULL ELSE ARRAY[tgl.alpha_tag] END, +TRUE, NULL::JSONB, 1.0, sys.id, sys.name, +TRUE learned +FROM talkgroups_learned tgl +JOIN systems sys ON tgl.system_id = sys.id +WHERE tg.system_id = $1 AND ignored IS NOT TRUE +` + +const getTalkgroupsWithLearnedTest = `-- name: GetTalkgroupsWithLearned :many +SELECT +tg.id, tg.system_id, tg.tgid, tg.name, tg.alpha_tag, tg.tg_group, tg.frequency, tg.metadata, tg.tags, tg.alert, tg.alert_config, tg.weight, sys.id, sys.name, +FALSE learned +FROM talkgroups tg +JOIN systems sys ON tg.system_id = sys.id +UNION +SELECT +tgl.id::INT8, tgl.system_id::INT4, tgl.tgid::INT4, tgl.name, +tgl.alpha_tag, tgl.alpha_tag, NULL::INTEGER, NULL::JSONB, +CASE WHEN tgl.alpha_tag IS NULL THEN NULL ELSE ARRAY[tgl.alpha_tag] END, +TRUE, NULL::JSONB, 1.0, sys.id, sys.name, +TRUE learned +FROM talkgroups_learned tgl +JOIN systems sys ON tgl.system_id = sys.id +WHERE ignored IS NOT TRUE +` + func TestQueryColumnsMatch(t *testing.T) { - require.Equal(t, getTalkgroupWithLearnedByPackedIDsTest, getTalkgroupWithLearnedByPackedIDs) + require.Equal(t, getTalkgroupsWithLearnedByPackedIDsTest, getTalkgroupWithLearnedByPackedIDs) require.Equal(t, getTalkgroupWithLearnedTest, getTalkgroupWithLearned) + require.Equal(t, getTalkgroupsWithLearnedBySystemTest, getTalkgroupsWithLearnedBySystem) + require.Equal(t, getTalkgroupsWithLearnedTest, getTalkgroupsWithLearned) } diff --git a/pkg/pb/stillbox.pb.go b/pkg/pb/stillbox.pb.go index c5b119c..64329b2 100644 --- a/pkg/pb/stillbox.pb.go +++ b/pkg/pb/stillbox.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.33.0 -// protoc v5.28.2 +// protoc v5.28.3 // source: stillbox.proto package pb diff --git a/pkg/talkgroups/cache.go b/pkg/talkgroups/cache.go index dd7a6cb..d6a866f 100644 --- a/pkg/talkgroups/cache.go +++ b/pkg/talkgroups/cache.go @@ -24,6 +24,9 @@ type Store interface { // TGs retrieves many talkgroups from the Store. TGs(ctx context.Context, tgs IDs) ([]*Talkgroup, error) + // SystemTGs retrieves all Talkgroups associated with a System. + SystemTGs(ctx context.Context, systemID int32) ([]*Talkgroup, error) + // SystemName retrieves a system name from the store. It returns the record and whether one was found. SystemName(ctx context.Context, id int) (string, bool) @@ -131,33 +134,23 @@ func (t *cache) add(rec *Talkgroup) error { return t.AlertConfig.UnmarshalTGRules(tg, rec.Talkgroup.AlertConfig) } -func rowToTalkgroup(r database.GetTalkgroupWithLearnedByPackedIDsRow) *Talkgroup { +type row interface { + database.GetTalkgroupsWithLearnedByPackedIDsRow | database.GetTalkgroupsWithLearnedRow | + database.GetTalkgroupsWithLearnedBySystemRow + GetTalkgroup() database.Talkgroup + GetSystem() database.System + GetLearned() bool +} + +func rowToTalkgroup[T row](r T) *Talkgroup { return &Talkgroup{ - Talkgroup: r.Talkgroup, - System: r.System, - Learned: r.Learned, + Talkgroup: r.GetTalkgroup(), + System: r.GetSystem(), + Learned: r.GetLearned(), } } -func (t *cache) TGs(ctx context.Context, tgs IDs) ([]*Talkgroup, error) { - r := make([]*Talkgroup, 0, len(tgs)) - toGet := make(IDs, 0, len(tgs)) - t.RLock() - for _, id := range tgs { - rec, has := t.tgs[id] - if has { - r = append(r, rec) - } else { - toGet = append(toGet, id) - } - } - t.RUnlock() - - tgRecords, err := database.FromCtx(ctx).GetTalkgroupWithLearnedByPackedIDs(ctx, toGet.Packed()) - if err != nil { - return nil, err - } - +func addToRowList[T row](t *cache, r []*Talkgroup, tgRecords []T) ([]*Talkgroup, error) { for _, rec := range tgRecords { tg := rowToTalkgroup(rec) err := t.add(tg) @@ -171,8 +164,40 @@ func (t *cache) TGs(ctx context.Context, tgs IDs) ([]*Talkgroup, error) { return r, nil } +func (t *cache) TGs(ctx context.Context, tgs IDs) ([]*Talkgroup, error) { + r := make([]*Talkgroup, 0, len(tgs)) + var err error + if tgs != nil { + toGet := make(IDs, 0, len(tgs)) + t.RLock() + for _, id := range tgs { + rec, has := t.tgs[id] + if has { + r = append(r, rec) + } else { + toGet = append(toGet, id) + } + } + t.RUnlock() + + tgRecords, err := database.FromCtx(ctx).GetTalkgroupsWithLearnedByPackedIDs(ctx, toGet.Packed()) + if err != nil { + return nil, err + } + return addToRowList(t, r, tgRecords) + } + + // get all talkgroups + + tgRecords, err := database.FromCtx(ctx).GetTalkgroupsWithLearned(ctx) + if err != nil { + return nil, err + } + return addToRowList(t, r, tgRecords) +} + func (t *cache) Load(ctx context.Context, tgs []int64) error { - tgRecords, err := database.FromCtx(ctx).GetTalkgroupWithLearnedByPackedIDs(ctx, tgs) + tgRecords, err := database.FromCtx(ctx).GetTalkgroupsWithLearnedByPackedIDs(ctx, tgs) if err != nil { return err } @@ -203,6 +228,16 @@ func (t *cache) Weight(ctx context.Context, id ID, tm time.Time) float64 { return float64(m) } +func (t *cache) SystemTGs(ctx context.Context, systemID int32) ([]*Talkgroup, error) { + recs, err := database.FromCtx(ctx).GetTalkgroupsWithLearnedBySystem(ctx, systemID) + if err != nil { + return nil, err + } + + r := make([]*Talkgroup, 0, len(recs)) + return addToRowList(t, r, recs) +} + func (t *cache) TG(ctx context.Context, tg ID) (*Talkgroup, error) { t.RLock() rec, has := t.tgs[tg] @@ -212,7 +247,7 @@ func (t *cache) TG(ctx context.Context, tg ID) (*Talkgroup, error) { return rec, nil } - recs, err := database.FromCtx(ctx).GetTalkgroupWithLearnedByPackedIDs(ctx, []int64{tg.Pack()}) + recs, err := database.FromCtx(ctx).GetTalkgroupsWithLearnedByPackedIDs(ctx, []int64{tg.Pack()}) switch err { case nil: case pgx.ErrNoRows: diff --git a/sql/postgres/queries/talkgroups.sql b/sql/postgres/queries/talkgroups.sql index a2ab786..d201d0e 100644 --- a/sql/postgres/queries/talkgroups.sql +++ b/sql/postgres/queries/talkgroups.sql @@ -51,7 +51,7 @@ FROM talkgroups_learned tgl JOIN systems sys ON tgl.system_id = sys.id WHERE tgl.system_id = sqlc.arg(system_id) AND tgl.tgid = sqlc.arg(tgid) AND ignored IS NOT TRUE; --- name: GetTalkgroupWithLearnedByPackedIDs :many +-- name: GetTalkgroupsWithLearnedByPackedIDs :many SELECT sqlc.embed(tg), sqlc.embed(sys), FALSE learned @@ -69,5 +69,41 @@ FROM talkgroups_learned tgl JOIN systems sys ON tgl.system_id = sys.id WHERE systg2id(tgl.system_id, tgl.tgid) = ANY($1::INT8[]) AND ignored IS NOT TRUE; +-- name: GetTalkgroupsWithLearnedBySystem :many +SELECT +sqlc.embed(tg), sqlc.embed(sys), +FALSE learned +FROM talkgroups tg +JOIN systems sys ON tg.system_id = sys.id +WHERE tg.system_id = @system +UNION +SELECT +tgl.id::INT8, tgl.system_id::INT4, tgl.tgid::INT4, tgl.name, +tgl.alpha_tag, tgl.alpha_tag, NULL::INTEGER, NULL::JSONB, +CASE WHEN tgl.alpha_tag IS NULL THEN NULL ELSE ARRAY[tgl.alpha_tag] END, +TRUE, NULL::JSONB, 1.0, sys.id, sys.name, +TRUE learned +FROM talkgroups_learned tgl +JOIN systems sys ON tgl.system_id = sys.id +WHERE tgl.system_id = @system AND ignored IS NOT TRUE; + +-- name: GetTalkgroupsWithLearned :many +SELECT +sqlc.embed(tg), sqlc.embed(sys), +FALSE learned +FROM talkgroups tg +JOIN systems sys ON tg.system_id = sys.id +UNION +SELECT +tgl.id::INT8, tgl.system_id::INT4, tgl.tgid::INT4, tgl.name, +tgl.alpha_tag, tgl.alpha_tag, NULL::INTEGER, NULL::JSONB, +CASE WHEN tgl.alpha_tag IS NULL THEN NULL ELSE ARRAY[tgl.alpha_tag] END, +TRUE, NULL::JSONB, 1.0, sys.id, sys.name, +TRUE learned +FROM talkgroups_learned tgl +JOIN systems sys ON tgl.system_id = sys.id +WHERE ignored IS NOT TRUE; + + -- name: GetSystemName :one SELECT name FROM systems WHERE id = sqlc.arg(system_id);