wip
This commit is contained in:
parent
7879715ce8
commit
d4dc80d116
6 changed files with 78 additions and 77 deletions
|
@ -1,9 +1,9 @@
|
|||
package calls
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"encoding/json"
|
||||
"slices"
|
||||
"context"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
)
|
||||
|
||||
type FilterQuery struct {
|
||||
|
@ -29,23 +29,6 @@ type Filter struct {
|
|||
TalkgroupTagsNot []string `json:"talkgroupTagsNot,omitempty"`
|
||||
|
||||
talkgroups map[Talkgroup]bool
|
||||
talkgroupTagsAll map[string]bool
|
||||
talkgroupTagsAny map[string]bool
|
||||
talkgroupTagsNot map[string]bool
|
||||
|
||||
query *FilterQuery
|
||||
}
|
||||
|
||||
func queryParams(q string, p ...any) FilterQuery {
|
||||
return FilterQuery{Query: q, Params: p}
|
||||
}
|
||||
|
||||
func (f *Filter) filterQuery() *FilterQuery {
|
||||
fq := queryParams(
|
||||
`((talkgroups.id = ANY(?) OR talkgroups.tags @> ARRAY[?]) OR (talkgroups.tags && ARRAY[?])) AND (talkgroups.id != ANY(?) AND NOT talkgroups.tags @> ARRAY[?])`,
|
||||
f.Talkgroups, f.TalkgroupTagsAny, f.TalkgroupTagsAll, f.TalkgroupsNot, f.TalkgroupTagsNot)
|
||||
|
||||
return &fq
|
||||
}
|
||||
|
||||
func PackedTGs(tg []Talkgroup) []int64 {
|
||||
|
@ -58,71 +41,50 @@ func PackedTGs(tg []Talkgroup) []int64 {
|
|||
return s
|
||||
}
|
||||
|
||||
func (f *Filter) compile() *Filter {
|
||||
func (f *Filter) hasTags() bool {
|
||||
return len(f.TalkgroupTagsAny) > 0 || len(f.TalkgroupTagsAll) > 0 || len(f.TalkgroupTagsNot) > 0
|
||||
}
|
||||
|
||||
func (f *Filter) GetFinalTalkgroups() map[Talkgroup]bool {
|
||||
return f.talkgroups
|
||||
}
|
||||
|
||||
func (f *Filter) compile(ctx context.Context) error {
|
||||
f.talkgroups = make(map[Talkgroup]bool)
|
||||
for _, tg := range f.Talkgroups {
|
||||
f.talkgroups[tg] = true
|
||||
}
|
||||
|
||||
if f.hasTags() { // don't bother with DB if no tags
|
||||
db := database.FromCtx(ctx)
|
||||
tagTGs, err := db.GetTalkgroupIDsByTags(ctx, f.TalkgroupTagsAny, f.TalkgroupTagsAll, f.TalkgroupTagsNot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, tg := range tagTGs {
|
||||
f.talkgroups[Talkgroup{System: uint32(tg.SystemID), Talkgroup: uint32(tg.Tgid)}] = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, tg := range f.TalkgroupsNot {
|
||||
f.talkgroups[tg] = false
|
||||
}
|
||||
|
||||
f.talkgroupTagsAll = make(map[string]bool)
|
||||
for _, tag := range f.TalkgroupTagsAll {
|
||||
f.talkgroupTagsAll[tag] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
f.talkgroupTagsAny = make(map[string]bool)
|
||||
for _, tag := range f.TalkgroupTagsAny {
|
||||
f.talkgroupTagsAny[tag] = true
|
||||
func (f *Filter) Test(ctx context.Context, call *Call) bool {
|
||||
if f == nil { // no filter means all calls
|
||||
return true
|
||||
}
|
||||
|
||||
for _, tag := range f.TalkgroupTagsNot {
|
||||
f.talkgroupTagsNot[tag] = true
|
||||
}
|
||||
|
||||
f.query = f.filterQuery()
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *Filter) normalize() {
|
||||
tgSort := func(a, b Talkgroup) int {
|
||||
if n := cmp.Compare(a.System, b.System); n != 0 {
|
||||
return n
|
||||
}
|
||||
|
||||
return cmp.Compare(a.Talkgroup, b.Talkgroup)
|
||||
}
|
||||
|
||||
slices.SortFunc(f.Talkgroups, tgSort)
|
||||
slices.SortFunc(f.TalkgroupsNot, tgSort)
|
||||
slices.SortFunc(f.TalkgroupTagsAll, cmp.Compare)
|
||||
slices.SortFunc(f.TalkgroupTagsAny, cmp.Compare)
|
||||
slices.SortFunc(f.TalkgroupTagsNot, cmp.Compare)
|
||||
}
|
||||
|
||||
func (f *Filter) cacheKey() string {
|
||||
f.normalize()
|
||||
buf, err := json.Marshal(f)
|
||||
if f.talkgroups == nil {
|
||||
err := f.compile(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
func (f *Filter) Test(call *Call) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type FilterCache struct {
|
||||
cache map[string]Filter
|
||||
}
|
||||
|
||||
func NewFilterCache() *FilterCache {
|
||||
return &FilterCache{
|
||||
cache: make(map[string]Filter),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,8 +69,8 @@ type System struct {
|
|||
|
||||
type Talkgroup struct {
|
||||
ID int64 `json:"id"`
|
||||
SystemID int `json:"system_id"`
|
||||
Tgid *int32 `json:"tgid"`
|
||||
SystemID int32 `json:"system_id"`
|
||||
Tgid int32 `json:"tgid"`
|
||||
Name *string `json:"name"`
|
||||
TgGroup *string `json:"tg_group"`
|
||||
Frequency *int32 `json:"frequency"`
|
||||
|
|
|
@ -19,6 +19,7 @@ type Querier interface {
|
|||
DeleteAPIKey(ctx context.Context, apiKey string) error
|
||||
DeleteUser(ctx context.Context, username string) error
|
||||
GetAPIKey(ctx context.Context, apiKey string) (ApiKey, error)
|
||||
GetTalkgroupIDsByTags(ctx context.Context, anytags []string, alltags []string, nottags []string) ([]GetTalkgroupIDsByTagsRow, error)
|
||||
GetTalkgroupTags(ctx context.Context, sys int, tg int) ([]string, error)
|
||||
GetTalkgroupsWithAllTags(ctx context.Context, tags []string) ([]Talkgroup, error)
|
||||
GetTalkgroupsWithAnyTags(ctx context.Context, tags []string) ([]Talkgroup, error)
|
||||
|
|
|
@ -19,6 +19,38 @@ func (q *Queries) BulkSetTalkgroupTags(ctx context.Context, iD int64, tags []str
|
|||
return err
|
||||
}
|
||||
|
||||
const getTalkgroupIDsByTags = `-- name: GetTalkgroupIDsByTags :many
|
||||
SELECT system_id, tgid FROM talkgroups
|
||||
WHERE (tags @> ARRAY[$1])
|
||||
AND (tags && ARRAY[$2])
|
||||
AND NOT (tags @> ARRAY[$3])
|
||||
`
|
||||
|
||||
type GetTalkgroupIDsByTagsRow struct {
|
||||
SystemID int32 `json:"system_id"`
|
||||
Tgid int32 `json:"tgid"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetTalkgroupIDsByTags(ctx context.Context, anytags []string, alltags []string, nottags []string) ([]GetTalkgroupIDsByTagsRow, error) {
|
||||
rows, err := q.db.Query(ctx, getTalkgroupIDsByTags, anytags, alltags, nottags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetTalkgroupIDsByTagsRow
|
||||
for rows.Next() {
|
||||
var i GetTalkgroupIDsByTagsRow
|
||||
if err := rows.Scan(&i.SystemID, &i.Tgid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getTalkgroupTags = `-- name: GetTalkgroupTags :one
|
||||
SELECT tags FROM talkgroups
|
||||
WHERE id = systg2id($1, $2)
|
||||
|
|
|
@ -46,8 +46,8 @@ $$;
|
|||
|
||||
CREATE TABLE IF NOT EXISTS talkgroups(
|
||||
id INT8 PRIMARY KEY,
|
||||
system_id INTEGER REFERENCES systems(id) NOT NULL GENERATED ALWAYS AS (id >> 32) STORED,
|
||||
tgid INTEGER GENERATED ALWAYS AS (id & x'ffffffff'::BIGINT) STORED,
|
||||
system_id INT4 REFERENCES systems(id) NOT NULL GENERATED ALWAYS AS (id >> 32) STORED,
|
||||
tgid INT4 NOT NULL GENERATED ALWAYS AS (id & x'ffffffff'::BIGINT) STORED,
|
||||
name TEXT,
|
||||
tg_group TEXT,
|
||||
frequency INTEGER,
|
||||
|
|
|
@ -6,6 +6,12 @@ WHERE tags @> ARRAY[$1];
|
|||
SELECT * FROM talkgroups
|
||||
WHERE tags && ARRAY[$1];
|
||||
|
||||
-- name: GetTalkgroupIDsByTags :many
|
||||
SELECT system_id, tgid FROM talkgroups
|
||||
WHERE (tags @> ARRAY[sqlc.arg(anyTags)])
|
||||
AND (tags && ARRAY[sqlc.arg(allTags)])
|
||||
AND NOT (tags @> ARRAY[sqlc.arg(notTags)]);
|
||||
|
||||
-- name: GetTalkgroupTags :one
|
||||
SELECT tags FROM talkgroups
|
||||
WHERE id = systg2id($1, $2);
|
||||
|
|
Loading…
Reference in a new issue