mirror of
https://github.com/dstotijn/hetty.git
synced 2025-07-01 18:47:29 -04:00
109 lines
2.8 KiB
Go
109 lines
2.8 KiB
Go
![]() |
package sqlite
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
|
||
|
sq "github.com/Masterminds/squirrel"
|
||
|
"github.com/dstotijn/hetty/pkg/search"
|
||
|
)
|
||
|
|
||
|
var stringLiteralMap = map[string]string{
|
||
|
// http_requests
|
||
|
"req.id": "req.id",
|
||
|
"req.proto": "req.proto",
|
||
|
"req.url": "req.url",
|
||
|
"req.method": "req.method",
|
||
|
"req.body": "req.body",
|
||
|
"req.timestamp": "req.timestamp",
|
||
|
// http_responses
|
||
|
"res.id": "res.id",
|
||
|
"res.proto": "res.proto",
|
||
|
"res.statusCode": "res.status_code",
|
||
|
"res.statusReason": "res.status_reason",
|
||
|
"res.body": "res.body",
|
||
|
"res.timestamp": "res.timestamp",
|
||
|
// TODO: http_headers
|
||
|
}
|
||
|
|
||
|
func parseSearchExpr(expr search.Expression) (sq.Sqlizer, error) {
|
||
|
switch e := expr.(type) {
|
||
|
case *search.PrefixExpression:
|
||
|
return parsePrefixExpr(e)
|
||
|
case *search.InfixExpression:
|
||
|
return parseInfixExpr(e)
|
||
|
default:
|
||
|
return nil, fmt.Errorf("expression type (%v) not supported", expr)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func parsePrefixExpr(expr *search.PrefixExpression) (sq.Sqlizer, error) {
|
||
|
switch expr.Operator {
|
||
|
case search.TokOpNot:
|
||
|
// TODO: Find a way to prefix an `sq.Sqlizer` with "NOT".
|
||
|
return nil, errors.New("not implemented")
|
||
|
default:
|
||
|
return nil, errors.New("operator is not supported")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func parseInfixExpr(expr *search.InfixExpression) (sq.Sqlizer, error) {
|
||
|
switch expr.Operator {
|
||
|
case search.TokOpAnd:
|
||
|
left, err := parseSearchExpr(expr.Left)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
right, err := parseSearchExpr(expr.Right)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return sq.And{left, right}, nil
|
||
|
case search.TokOpOr:
|
||
|
left, err := parseSearchExpr(expr.Left)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
right, err := parseSearchExpr(expr.Right)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return sq.Or{left, right}, nil
|
||
|
}
|
||
|
|
||
|
left, ok := expr.Left.(*search.StringLiteral)
|
||
|
if !ok {
|
||
|
return nil, errors.New("left operand must be a string literal")
|
||
|
}
|
||
|
right, ok := expr.Right.(*search.StringLiteral)
|
||
|
if !ok {
|
||
|
return nil, errors.New("right operand must be a string literal")
|
||
|
}
|
||
|
|
||
|
mappedLeft, ok := stringLiteralMap[left.Value]
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf("invalid string literal: %v", left)
|
||
|
}
|
||
|
|
||
|
switch expr.Operator {
|
||
|
case search.TokOpEq:
|
||
|
return sq.Eq{mappedLeft: right.Value}, nil
|
||
|
case search.TokOpNotEq:
|
||
|
return sq.NotEq{mappedLeft: right.Value}, nil
|
||
|
case search.TokOpGt:
|
||
|
return sq.Gt{mappedLeft: right.Value}, nil
|
||
|
case search.TokOpLt:
|
||
|
return sq.Lt{mappedLeft: right.Value}, nil
|
||
|
case search.TokOpGtEq:
|
||
|
return sq.GtOrEq{mappedLeft: right.Value}, nil
|
||
|
case search.TokOpLtEq:
|
||
|
return sq.LtOrEq{mappedLeft: right.Value}, nil
|
||
|
case search.TokOpRe:
|
||
|
return sq.Expr(fmt.Sprintf("regexp(?, %v)", mappedLeft), right.Value), nil
|
||
|
case search.TokOpNotRe:
|
||
|
return sq.Expr(fmt.Sprintf("NOT regexp(?, %v)", mappedLeft), right.Value), nil
|
||
|
default:
|
||
|
return nil, errors.New("unsupported operator")
|
||
|
}
|
||
|
}
|