Skip to content

Commit

Permalink
Add Filter string generation (linode#145)
Browse files Browse the repository at this point in the history
add helper functions to generate filter strings based on
https://www.linode.com/docs/api/#filtering-and-sorting
todo: add order-by

Co-authored-by: zdypro <[email protected]>
Co-authored-by: Jacob Riddle <[email protected]>
Co-authored-by: Lena Garber <[email protected]>
  • Loading branch information
4 people authored Sep 16, 2021
1 parent 76e9a77 commit d390dfa
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 0 deletions.
121 changes: 121 additions & 0 deletions comparison.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package linodego

/**
* Pagination and Filtering types and helpers
*/

import (
"fmt"
"strings"
)

type ComparisonOperator int

const (
Eq = iota
Neq

Gt
Gte

Lt
Lte

Contains
)

func (c ComparisonOperator) String() string {
switch c {
case Eq:
return "+eq"
case Neq:
return "+neq"
case Gt:
return "+gt"
case Gte:
return "+gte"
case Lt:
return "+lt"
case Lte:
return "+lte"
case Contains:
return "+contains"
default:
return "Unknown ComparisonOperator"
}
}

type LogicalOperator int

const (
LogicalAnd = iota
LogicalOr
)

func (l LogicalOperator) String() string {
switch l {
case LogicalAnd:
return "+and"
case LogicalOr:
return "+or"
default:
return "Unknown LogicalOperator"
}
}

type FilterNode interface {
GetChildren() []FilterNode
JSON() string
}

type Filter struct {
Operator LogicalOperator
Children []FilterNode
}

func (f *Filter) GetChildren() []FilterNode {
return f.Children
}

func (f *Filter) JSON() string {
children := make([]string, 0, len(f.Children))
for _, c := range f.Children {
children = append(children, c.JSON())
}
return fmt.Sprintf("\"%s\": [%s]", f.Operator, strings.Join(children, ", "))
}

type Comparison struct {
Column string
Operator ComparisonOperator
Value interface{}
}

func (c *Comparison) GetChildren() []FilterNode {
return []FilterNode{}
}

func (c *Comparison) JSON() string {
if c.Operator == Eq {
return fmt.Sprintf("{\"%s\": %s}", c.Column, getJSONValueString(c.Value))
}

return fmt.Sprintf("{\"%s\": {\"%s\": %s}",
c.Column, c.Operator, getJSONValueString(c.Value))
}

func And(nodes ...FilterNode) *Filter {
return &Filter{LogicalAnd, nodes}
}

func Or(nodes ...FilterNode) *Filter {
return &Filter{LogicalOr, nodes}
}

func getJSONValueString(value interface{}) string {
if _, ok := value.(string); ok {
return fmt.Sprintf("\"%s\"", value)
}

return fmt.Sprintf("%v", value)
}
58 changes: 58 additions & 0 deletions comparison_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package linodego

import "testing"

func TestComparisonOperator(t *testing.T) {
var opTests = []struct {
in ComparisonOperator
out string
}{
{Eq, "+eq"},
{Neq, "+neq"},
{Gt, "+gt"},
{Gte, "+gte"},
{Lt, "+lt"},
{Lte, "+lte"},
{Contains, "+contains"},
}
for _, tests := range opTests {
out := tests.in.String()
if out != tests.out {
t.Fatal(out, " doesn't match ", tests.out)
}
}
}

func TestLogicalOperator(t *testing.T) {
var opTests = []struct {
in LogicalOperator
out string
}{
{LogicalOr, "+or"},
{LogicalAnd, "+and"},
}
for _, tests := range opTests {
out := tests.in.String()
if out != tests.out {
t.Fatal(out, " doesn't match ", tests.out)
}
}
}

func TestFilter(t *testing.T) {
expected := `"+and": [{"vcpus": {"+gte": 12}, {"class": "standard"}]`
c1 := &Comparison{
Column: "vcpus",
Operator: Gte,
Value: 12,
}
c2 := &Comparison{
Column: "class",
Operator: Eq,
Value: "standard",
}
out := And(c1, c2)
if out.JSON() != expected {
t.Fatal(out.JSON(), " doesn't match ", expected)
}
}

0 comments on commit d390dfa

Please sign in to comment.