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
|
package calls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmp"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"slices"
|
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FilterQuery struct {
|
type FilterQuery struct {
|
||||||
|
@ -28,24 +28,7 @@ type Filter struct {
|
||||||
TalkgroupTagsAny []string `json:"talkgroupTagsAny,omitempty"`
|
TalkgroupTagsAny []string `json:"talkgroupTagsAny,omitempty"`
|
||||||
TalkgroupTagsNot []string `json:"talkgroupTagsNot,omitempty"`
|
TalkgroupTagsNot []string `json:"talkgroupTagsNot,omitempty"`
|
||||||
|
|
||||||
talkgroups map[Talkgroup]bool
|
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 {
|
func PackedTGs(tg []Talkgroup) []int64 {
|
||||||
|
@ -58,71 +41,50 @@ func PackedTGs(tg []Talkgroup) []int64 {
|
||||||
return s
|
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)
|
f.talkgroups = make(map[Talkgroup]bool)
|
||||||
for _, tg := range f.Talkgroups {
|
for _, tg := range f.Talkgroups {
|
||||||
f.talkgroups[tg] = true
|
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 {
|
for _, tg := range f.TalkgroupsNot {
|
||||||
f.talkgroups[tg] = false
|
f.talkgroups[tg] = false
|
||||||
}
|
}
|
||||||
|
|
||||||
f.talkgroupTagsAll = make(map[string]bool)
|
return nil
|
||||||
for _, tag := range f.TalkgroupTagsAll {
|
|
||||||
f.talkgroupTagsAll[tag] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
f.talkgroupTagsAny = make(map[string]bool)
|
|
||||||
for _, tag := range f.TalkgroupTagsAny {
|
|
||||||
f.talkgroupTagsAny[tag] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tag := range f.TalkgroupTagsNot {
|
|
||||||
f.talkgroupTagsNot[tag] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
f.query = f.filterQuery()
|
|
||||||
|
|
||||||
return f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Filter) normalize() {
|
func (f *Filter) Test(ctx context.Context, call *Call) bool {
|
||||||
tgSort := func(a, b Talkgroup) int {
|
if f == nil { // no filter means all calls
|
||||||
if n := cmp.Compare(a.System, b.System); n != 0 {
|
return true
|
||||||
return n
|
}
|
||||||
|
|
||||||
|
if f.talkgroups == nil {
|
||||||
|
err := f.compile(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Filter) Test(call *Call) bool {
|
|
||||||
return false
|
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 {
|
type Talkgroup struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
SystemID int `json:"system_id"`
|
SystemID int32 `json:"system_id"`
|
||||||
Tgid *int32 `json:"tgid"`
|
Tgid int32 `json:"tgid"`
|
||||||
Name *string `json:"name"`
|
Name *string `json:"name"`
|
||||||
TgGroup *string `json:"tg_group"`
|
TgGroup *string `json:"tg_group"`
|
||||||
Frequency *int32 `json:"frequency"`
|
Frequency *int32 `json:"frequency"`
|
||||||
|
|
|
@ -19,6 +19,7 @@ type Querier interface {
|
||||||
DeleteAPIKey(ctx context.Context, apiKey string) error
|
DeleteAPIKey(ctx context.Context, apiKey string) error
|
||||||
DeleteUser(ctx context.Context, username string) error
|
DeleteUser(ctx context.Context, username string) error
|
||||||
GetAPIKey(ctx context.Context, apiKey string) (ApiKey, 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)
|
GetTalkgroupTags(ctx context.Context, sys int, tg int) ([]string, error)
|
||||||
GetTalkgroupsWithAllTags(ctx context.Context, tags []string) ([]Talkgroup, error)
|
GetTalkgroupsWithAllTags(ctx context.Context, tags []string) ([]Talkgroup, error)
|
||||||
GetTalkgroupsWithAnyTags(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
|
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
|
const getTalkgroupTags = `-- name: GetTalkgroupTags :one
|
||||||
SELECT tags FROM talkgroups
|
SELECT tags FROM talkgroups
|
||||||
WHERE id = systg2id($1, $2)
|
WHERE id = systg2id($1, $2)
|
||||||
|
|
|
@ -46,8 +46,8 @@ $$;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS talkgroups(
|
CREATE TABLE IF NOT EXISTS talkgroups(
|
||||||
id INT8 PRIMARY KEY,
|
id INT8 PRIMARY KEY,
|
||||||
system_id INTEGER REFERENCES systems(id) NOT NULL GENERATED ALWAYS AS (id >> 32) STORED,
|
system_id INT4 REFERENCES systems(id) NOT NULL GENERATED ALWAYS AS (id >> 32) STORED,
|
||||||
tgid INTEGER GENERATED ALWAYS AS (id & x'ffffffff'::BIGINT) STORED,
|
tgid INT4 NOT NULL GENERATED ALWAYS AS (id & x'ffffffff'::BIGINT) STORED,
|
||||||
name TEXT,
|
name TEXT,
|
||||||
tg_group TEXT,
|
tg_group TEXT,
|
||||||
frequency INTEGER,
|
frequency INTEGER,
|
||||||
|
|
|
@ -6,6 +6,12 @@ WHERE tags @> ARRAY[$1];
|
||||||
SELECT * FROM talkgroups
|
SELECT * FROM talkgroups
|
||||||
WHERE tags && ARRAY[$1];
|
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
|
-- name: GetTalkgroupTags :one
|
||||||
SELECT tags FROM talkgroups
|
SELECT tags FROM talkgroups
|
||||||
WHERE id = systg2id($1, $2);
|
WHERE id = systg2id($1, $2);
|
||||||
|
|
Loading…
Reference in a new issue