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  }