| package models |
|
|
| import ( |
| "encoding/json" |
| "strings" |
|
|
| "github.com/samber/lo" |
|
|
| "github.com/openmeterio/openmeter/pkg/treex" |
| ) |
|
|
| type FieldDescriptor struct { |
| field string |
| exp FieldExpression |
| attrs Attributes |
|
|
| node *treex.Node[*FieldDescriptor] |
| } |
|
|
| func (s FieldDescriptor) Clone() *FieldDescriptor { |
| desc := &FieldDescriptor{ |
| field: s.field, |
| exp: s.exp, |
| attrs: s.attrs.Clone(), |
| node: s.node.ShallowClone(), |
| } |
| desc.node.SetValue(desc) |
|
|
| return desc |
| } |
|
|
| func (s FieldDescriptor) WithExpression(exp FieldExpression) *FieldDescriptor { |
| s.exp = exp |
| s.node = s.node.ShallowClone() |
| s.node.SetValue(&s) |
|
|
| return &s |
| } |
|
|
| func (s FieldDescriptor) WithAttributes(attrs Attributes) *FieldDescriptor { |
| curr := s.attrs |
|
|
| if curr == nil { |
| curr = make(Attributes) |
| } |
|
|
| s.attrs = curr.Merge(attrs) |
| s.node = s.node.ShallowClone() |
| s.node.SetValue(&s) |
|
|
| return &s |
| } |
|
|
| func (p FieldDescriptor) GetAttributes() Attributes { |
| return p.attrs |
| } |
|
|
| func (p FieldDescriptor) WithPrefix(_prefix *FieldDescriptor) *FieldDescriptor { |
| var prefix *FieldDescriptor |
| if _prefix != nil { |
| prefix = _prefix.Clone() |
| } |
|
|
| p.node = p.node.ShallowClone() |
| p.node.SetValue(&p) |
|
|
| if prefix == nil { |
| return NewFieldSelectorGroup(&p) |
| } |
|
|
| return NewFieldSelectorGroup(prefix, &p) |
| } |
|
|
| func (p *FieldDescriptor) MarshalJSON() ([]byte, error) { |
| if p == nil { |
| return json.Marshal("") |
| } |
|
|
| return json.Marshal(p.JSONPath()) |
| } |
|
|
| func (p *FieldDescriptor) String() string { |
| if p == nil { |
| return "" |
| } |
|
|
| b := strings.Builder{} |
|
|
| |
| if err := p.Tree(func(t *FieldDescriptorTree) error { |
| leafCount := 0 |
|
|
| return t.DFS(func(n *treex.Node[*FieldDescriptor]) (bool, error) { |
| |
| if n.IsLeaf() { |
| desc := n.Value() |
|
|
| if leafCount > 0 { |
| b.WriteString(".") |
| } |
|
|
| b.WriteString(n.Value().field) |
|
|
| if desc.exp != nil { |
| if exp := desc.exp.String(); exp != "" { |
| b.WriteString("[") |
| b.WriteString(exp) |
| b.WriteString("]") |
| } |
| } |
|
|
| leafCount++ |
| } |
|
|
| return false, nil |
| }) |
| }); err != nil { |
| return "" |
| } |
|
|
| return b.String() |
| } |
|
|
| func (p *FieldDescriptor) JSONPath() string { |
| if p == nil { |
| return "" |
| } |
|
|
| b := strings.Builder{} |
|
|
| |
| if p.node.IsRoot() { |
| b.WriteString("$") |
| b.WriteString(".") |
| } |
|
|
| if err := p.Tree(func(t *FieldDescriptorTree) error { |
| leafCount := 0 |
|
|
| return t.DFS(func(n *treex.Node[*FieldDescriptor]) (bool, error) { |
| |
| if n.IsLeaf() { |
| desc := n.Value() |
|
|
| if leafCount > 0 { |
| b.WriteString(".") |
| } |
|
|
| b.WriteString(desc.field) |
|
|
| if desc.exp != nil { |
| expOpen := "[" |
| expClose := "]" |
|
|
| if desc.exp.IsCondition() { |
| expOpen = "[?(" |
| expClose = ")]" |
| } |
|
|
| if exp := desc.exp.JSONPathExpression(); exp != "" { |
| b.WriteString(expOpen) |
| b.WriteString(exp) |
| b.WriteString(expClose) |
| } |
| } |
|
|
| leafCount++ |
| } |
|
|
| return false, nil |
| }) |
| }); err != nil { |
| return "" |
| } |
|
|
| return b.String() |
| } |
|
|
| |
| |
| type FieldDescriptorTree struct { |
| *treex.Tree[*FieldDescriptor] |
| } |
|
|
| |
| |
| func (t *FieldDescriptorTree) Swap(old, new *FieldDescriptor) error { |
| return t.Tree.SwapNode(old.node, new.node) |
| } |
|
|
| func (t *FieldDescriptorTree) Leafs() []*FieldDescriptor { |
| return lo.Map(t.Tree.Leafs(), func(n *treex.Node[*FieldDescriptor], _ int) *FieldDescriptor { |
| return n.Value() |
| }) |
| } |
|
|
| |
| func (s FieldDescriptor) Tree(cb func(t *FieldDescriptorTree) error) error { |
| tree, err := treex.NewTree(s.node) |
| if err != nil { |
| return err |
| } |
|
|
| return cb(&FieldDescriptorTree{Tree: tree}) |
| } |
|
|
| func newFieldDescriptor() *FieldDescriptor { |
| desc := &FieldDescriptor{} |
| desc.node = treex.NewNode(desc) |
| return desc |
| } |
|
|
| func NewFieldSelector(field string) *FieldDescriptor { |
| desc := newFieldDescriptor() |
| desc.field = field |
|
|
| return desc |
| } |
|
|
| func NewFieldSelectorGroup(selectors ...*FieldDescriptor) *FieldDescriptor { |
| selectors = lo.Filter(selectors, func(item *FieldDescriptor, _ int) bool { |
| return item != nil |
| }) |
|
|
| if len(selectors) == 0 { |
| return nil |
| } |
|
|
| desc := newFieldDescriptor() |
| for i := range selectors { |
| nd := selectors[i].node |
| desc.node.AddChild(nd) |
| } |
|
|
| return desc |
| } |
|
|