github.com/tobgu/qframe@v0.4.0/filter_test.go (about) 1 package qframe_test 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/tobgu/qframe" 8 ) 9 10 func f(column string, comparator string, arg interface{}) qframe.Filter { 11 return qframe.Filter{Column: column, Comparator: comparator, Arg: arg} 12 } 13 14 func notf(column string, comparator string, arg interface{}) qframe.Filter { 15 filter := f(column, comparator, arg) 16 filter.Inverse = true 17 return filter 18 } 19 20 func and(clauses ...qframe.FilterClause) qframe.AndClause { 21 return qframe.And(clauses...) 22 } 23 24 func or(clauses ...qframe.FilterClause) qframe.OrClause { 25 return qframe.Or(clauses...) 26 } 27 28 func not(clause qframe.FilterClause) qframe.NotClause { 29 return qframe.Not(clause) 30 } 31 32 func TestFilter_Success(t *testing.T) { 33 input := qframe.New(map[string]interface{}{ 34 "COL1": []int{1, 2, 3, 4, 5}, 35 }) 36 37 eq := func(x int) qframe.FilterClause { 38 return f("COL1", "=", x) 39 } 40 41 table := []struct { 42 name string 43 clause qframe.FilterClause 44 expected []int 45 }{ 46 { 47 "Single filter", 48 f("COL1", ">", 3), 49 []int{4, 5}, 50 }, 51 { 52 "Simple or", 53 or(f("COL1", ">", 3), f("COL1", "<", 2)), 54 []int{1, 4, 5}, 55 }, 56 { 57 "Simple and", 58 and(f("COL1", "<", 3), f("COL1", ">", 1)), 59 []int{2}, 60 }, 61 { 62 "Or with nested and", 63 or( 64 and(f("COL1", "<", 3), f("COL1", ">", 1)), 65 eq(5)), 66 []int{2, 5}, 67 }, 68 { 69 "Or with nested and, reverse clause", 70 or(eq(5), 71 and(f("COL1", "<", 3), f("COL1", ">", 1))), 72 []int{2, 5}, 73 }, 74 { 75 "Or with mixed nested or and clause", 76 or(eq(1), or(eq(3), eq(4)), eq(5)), 77 []int{1, 3, 4, 5}, 78 }, 79 { 80 "Nested single clause", 81 or(and(eq(4))), 82 []int{4}, 83 }, 84 { 85 "Not start", 86 not(or(eq(1), eq(2))), 87 []int{3, 4, 5}, 88 }, 89 { 90 "Not end", 91 not(or(eq(4), eq(5))), 92 []int{1, 2, 3}, 93 }, 94 { 95 "Not mixed", 96 not(or(eq(4), eq(2))), 97 []int{1, 3, 5}, 98 }, 99 { 100 "Not empty", 101 not(eq(6)), 102 []int{1, 2, 3, 4, 5}, 103 }, 104 { 105 "Not full", 106 not(f("COL1", "<", 6)), 107 []int{}, 108 }, 109 } 110 111 for _, tc := range table { 112 t.Run(fmt.Sprintf("Filter %s", tc.name), func(t *testing.T) { 113 assertNotErr(t, tc.clause.Err()) 114 out := input.Filter(tc.clause) 115 assertNotErr(t, out.Err) 116 assertEquals(t, qframe.New(map[string]interface{}{"COL1": tc.expected}), out) 117 }) 118 } 119 } 120 121 func TestFilter_ErrorColumnDoesNotExist(t *testing.T) { 122 input := qframe.New(map[string]interface{}{ 123 "COL1": []int{1, 2, 3, 4, 5}, 124 }) 125 126 colGt3 := f("COL", ">", 3) 127 col1Gt3 := f("COL1", ">", 3) 128 129 table := []qframe.FilterClause{ 130 colGt3, 131 or(col1Gt3, colGt3), 132 and(col1Gt3, colGt3), 133 and(col1Gt3, and(col1Gt3, colGt3)), 134 or(and(col1Gt3, colGt3), col1Gt3), 135 or(and(col1Gt3, col1Gt3), colGt3), 136 } 137 138 for i, c := range table { 139 t.Run(fmt.Sprintf("Filter %d", i), func(t *testing.T) { 140 out := input.Filter(c) 141 assertErr(t, out.Err, "unknown column") 142 }) 143 } 144 } 145 146 func TestFilter_String(t *testing.T) { 147 table := []struct { 148 clause qframe.FilterClause 149 expected string 150 }{ 151 {f("COL1", ">", 3), `[">", "COL1", 3]`}, 152 {f("COL1", ">", "3"), `[">", "COL1", "3"]`}, 153 {not(f("COL1", ">", 3)), `["!", [">", "COL1", 3]]`}, 154 {notf("COL1", ">", 3), `["!", [">", "COL1", 3]]`}, 155 {and(f("COL1", ">", 3)), `["and", [">", "COL1", 3]]`}, 156 {or(f("COL1", ">", 3)), `["or", [">", "COL1", 3]]`}, 157 { 158 and(f("COL1", ">", 3), f("COL2", ">", 3)), 159 `["and", [">", "COL1", 3], [">", "COL2", 3]]`, 160 }, 161 { 162 or(f("COL1", ">", 3), f("COL2", ">", 3)), 163 `["or", [">", "COL1", 3], [">", "COL2", 3]]`, 164 }, 165 } 166 167 for _, tc := range table { 168 t.Run(fmt.Sprintf("String %s", tc.expected), func(t *testing.T) { 169 assertNotErr(t, tc.clause.Err()) 170 if tc.expected != tc.clause.String() { 171 t.Errorf("%s != %s", tc.expected, tc.clause.String()) 172 } 173 }) 174 } 175 }