Files
teleport/lib/utils/fields.go
T
Zac Bergquist 44a6bb1933 Use pkg slices from the standard library (#35905)
Prefer the stdlib version of the experimental package.
Includes a depguard update to prevent future regressions,
as well as an e-ref update to appease depguard.

Generated with:

    $ gofmt -w -r '"golang.org/x/exp/slices" -> "slices"' . && \
        make fix-imports
2023-12-19 23:06:53 +00:00

158 lines
4.3 KiB
Go

/*
* Teleport
* Copyright (C) 2023 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package utils
import (
"slices"
"time"
"github.com/gravitational/trace"
"github.com/gravitational/teleport/api/types"
)
// Fields represents a generic string-keyed map.
type Fields map[string]interface{}
// GetString returns a string representation of a field.
func (f Fields) GetString(key string) string {
val, found := f[key]
if !found {
return ""
}
return val.(string)
}
// GetStrings returns a slice-of-strings representation of a field.
func (f Fields) GetStrings(key string) []string {
val, found := f[key]
if !found {
return nil
}
strings, ok := val.([]string)
if ok {
return strings
}
slice, _ := val.([]interface{})
res := make([]string, 0, len(slice))
for _, v := range slice {
s, ok := v.(string)
if ok {
res = append(res, s)
}
}
return res
}
// GetInt returns an int representation of a field.
func (f Fields) GetInt(key string) int {
val, found := f[key]
if !found {
return 0
}
v, ok := val.(int)
if !ok {
f, ok := val.(float64)
if ok {
v = int(f)
}
}
return v
}
// GetTime returns a time.Time representation of a field.
func (f Fields) GetTime(key string) time.Time {
val, found := f[key]
if !found {
return time.Time{}
}
v, ok := val.(time.Time)
if !ok {
s := f.GetString(key)
v, _ = time.Parse(time.RFC3339, s)
}
return v
}
// HasField returns true if the field exists.
func (f Fields) HasField(key string) bool {
_, ok := f[key]
return ok
}
// FieldsCondition is a boolean function on Fields.
type FieldsCondition func(Fields) bool
// ToFieldsCondition converts a WhereExpr into a FieldsCondition.
func ToFieldsCondition(expr *types.WhereExpr) (FieldsCondition, error) {
if expr == nil {
return nil, trace.BadParameter("expr is nil")
}
binOp := func(e types.WhereExpr2, op func(a, b bool) bool) (FieldsCondition, error) {
left, err := ToFieldsCondition(e.L)
if err != nil {
return nil, trace.Wrap(err)
}
right, err := ToFieldsCondition(e.R)
if err != nil {
return nil, trace.Wrap(err)
}
return func(f Fields) bool { return op(left(f), right(f)) }, nil
}
if expr, err := binOp(expr.And, func(a, b bool) bool { return a && b }); err == nil {
return expr, nil
}
if expr, err := binOp(expr.Or, func(a, b bool) bool { return a || b }); err == nil {
return expr, nil
}
if inner, err := ToFieldsCondition(expr.Not); err == nil {
return func(f Fields) bool { return !inner(f) }, nil
}
if expr.Equals.L != nil && expr.Equals.R != nil {
left, right := expr.Equals.L, expr.Equals.R
switch {
case left.Field != "" && right.Field != "":
return func(f Fields) bool { return f[left.Field] == f[right.Field] }, nil
case left.Literal != nil && right.Field != "":
return func(f Fields) bool { return left.Literal == f[right.Field] }, nil
case left.Field != "" && right.Literal != nil:
return func(f Fields) bool { return f[left.Field] == right.Literal }, nil
}
}
if expr.Contains.L != nil && expr.Contains.R != nil {
left, right := expr.Contains.L, expr.Contains.R
switch {
case left.Field != "" && right.Field != "":
return func(f Fields) bool { return slices.Contains(f.GetStrings(left.Field), f.GetString(right.Field)) }, nil
case left.Literal != nil && right.Field != "":
if ss, ok := left.Literal.([]string); ok {
return func(f Fields) bool { return slices.Contains(ss, f.GetString(right.Field)) }, nil
}
case left.Field != "" && right.Literal != nil:
if s, ok := right.Literal.(string); ok {
return func(f Fields) bool { return slices.Contains(f.GetStrings(left.Field), s) }, nil
}
}
}
return nil, trace.BadParameter("failed to convert expression %q to FieldsCondition", expr)
}