stillbox/pkg/calls/filter.go

133 lines
2.8 KiB
Go
Raw Normal View History

2024-08-06 11:19:30 -04:00
package calls
2024-08-06 13:54:15 -04:00
import (
"cmp"
"encoding/json"
"slices"
)
type FilterQuery struct {
2024-08-06 11:19:30 -04:00
Query string
Params []interface{}
}
type Talkgroup struct {
System uint32
Talkgroup uint32
}
func (t Talkgroup) Pack() int64 {
// P25 system IDs are 12 bits, so we can fit them in a signed 8 byte int (int64, pg INT8)
return int64((int64(t.System) << 32) | int64(t.Talkgroup))
}
type Filter struct {
2024-08-06 13:54:15 -04:00
Talkgroups []Talkgroup `json:"talkgroups,omitempty"`
TalkgroupsNot []Talkgroup `json:"talkgroupsNot,omitempty"`
TalkgroupTagsAll []string `json:"talkgroupTagsAll,omitempty"`
TalkgroupTagsAny []string `json:"talkgroupTagsAny,omitempty"`
TalkgroupTagsNot []string `json:"talkgroupTagsNot,omitempty"`
2024-08-06 11:19:30 -04:00
talkgroups map[Talkgroup]bool
talkgroupTagsAll map[string]bool
talkgroupTagsAny map[string]bool
talkgroupTagsNot map[string]bool
2024-08-06 13:54:15 -04:00
query *FilterQuery
2024-08-06 11:19:30 -04:00
}
func queryParams(s string, p ...any) (string, []any) {
return s, p
}
2024-08-06 13:54:15 -04:00
func (f *Filter) filterQuery() FilterQuery {
2024-08-06 11:19:30 -04:00
var q string
var args []interface{}
q, args = 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)
2024-08-06 13:54:15 -04:00
return FilterQuery{Query: q, Params: args}
2024-08-06 11:19:30 -04:00
}
2024-08-06 13:54:15 -04:00
func PackedTGs(tg []Talkgroup) []int64 {
s := make([]int64, len(tg))
2024-08-06 11:19:30 -04:00
for i, v := range tg {
s[i] = v.Pack()
}
return s
}
2024-08-06 13:54:15 -04:00
func (f *Filter) compile() *Filter {
2024-08-06 11:19:30 -04:00
f.talkgroups = make(map[Talkgroup]bool)
for _, tg := range f.Talkgroups {
f.talkgroups[tg] = 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
}
f.talkgroupTagsAny = make(map[string]bool)
for _, tag := range f.TalkgroupTagsAny {
f.talkgroupTagsAny[tag] = true
}
for _, tag := range f.TalkgroupTagsNot {
f.talkgroupTagsNot[tag] = true
}
q := f.filterQuery()
f.query = &q
return f
}
2024-08-06 13:54:15 -04:00
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 err != nil {
panic(err)
}
return string(buf)
}
func (f *Filter) Test(call *Call) bool {
return false
}
2024-08-06 11:19:30 -04:00
type FilterCache struct {
cache map[string]Filter
}
2024-08-06 13:54:15 -04:00
func NewFilterCache() *FilterCache {
return &FilterCache{
cache: make(map[string]Filter),
}
}