burterm/internal/project/query.go
2026-09-14 10:55:07 +03:00

71 lines
2.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package project
import "strings"
// ParseQuery разбирает строку поиска в духе GitHub/Gmail-фильтров:
// токены вида "key:value" распознаются как поля Filter (host, method,
// status, color, minlen, maxlen), всё остальное склеивается и идёт
// в полнотекстовый запрос. Так один текстовый инпут в TUI закрывает
// и структурированную фильтрацию, и полнотекстовый поиск, без десятка
// отдельных полей ввода на экране.
//
// Пример: "host:example.com method:POST status:200-299 color:red токен сессии"
// даёт Filter{Host: "example.com", Method: "POST", Status: "200-299",
// ColorLabel: "red", FTSQuery: "токен сессии"}.
//
// Известный нюанс: если пользователь наберёт в свободнотекстовой части
// что-то похожее на "слово:значение" с неизвестным ключом (не из
// распознаваемого набора), этот токен уйдёт в FTSQuery как есть — а
// FTS5 сам поддерживает синтаксис column-filter с двоеточием, так что
// в редких случаях это может интерпретироваться иначе, чем ожидается.
// Осознанный компромисс ради простоты, а не баг, который стоит чинить
// экранированием на каждый чих.
func ParseQuery(q string) Filter {
var f Filter
var ftsWords []string
for _, tok := range strings.Fields(q) {
idx := strings.Index(tok, ":")
if idx <= 0 {
ftsWords = append(ftsWords, tok)
continue
}
key := strings.ToLower(tok[:idx])
val := tok[idx+1:]
switch key {
case "host":
f.Host = val
case "method":
f.Method = val
case "status":
f.Status = val
case "color":
f.ColorLabel = ColorLabel(val)
case "minlen":
f.MinLength = parseInt64(val)
case "maxlen":
f.MaxLength = parseInt64(val)
default:
ftsWords = append(ftsWords, tok)
}
}
f.FTSQuery = strings.Join(ftsWords, " ")
return f
}
// parseInt64 — терпимый разбор числа: некорректный ввод просто даёт 0
// (что для minlen/maxlen эквивалентно "фильтр не задан"), без лишней
// возни с обработкой ошибки в вызывающем коде ради этого частного случая.
func parseInt64(s string) int64 {
var n int64
for _, r := range s {
if r < '0' || r > '9' {
return 0
}
n = n*10 + int64(r-'0')
}
return n
}