mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-23 16:27:35 +00:00
3f22fb3a5c
* feat(user/v1): support composite queries * fix: added proper error handling for NotQuery * Added error when there are too many levels of nesting * Add localization keys for english * Update internal/api/grpc/user/query.go
1909 lines
39 KiB
Go
1909 lines
39 KiB
Go
package query
|
|
|
|
import (
|
|
"errors"
|
|
"reflect"
|
|
"testing"
|
|
|
|
sq "github.com/Masterminds/squirrel"
|
|
|
|
"github.com/zitadel/zitadel/internal/domain"
|
|
)
|
|
|
|
var (
|
|
testTable = table{
|
|
name: "test_table",
|
|
instanceIDCol: "instance_id",
|
|
}
|
|
testTableAlias = table{
|
|
name: "test_table",
|
|
alias: "test_alias",
|
|
instanceIDCol: "instance_id",
|
|
}
|
|
testTable2 = table{
|
|
name: "test_table2",
|
|
alias: "test_table2",
|
|
}
|
|
testCol = Column{
|
|
name: "test_col",
|
|
table: testTable,
|
|
}
|
|
testColAlias = Column{
|
|
name: "test_col",
|
|
table: testTableAlias,
|
|
}
|
|
testCol2 = Column{
|
|
name: "test_col2",
|
|
table: testTable2,
|
|
}
|
|
testLowerCol = Column{
|
|
name: "test_lower_col",
|
|
table: testTable,
|
|
isOrderByLower: true,
|
|
}
|
|
testNoCol = Column{
|
|
name: "",
|
|
table: testTable,
|
|
}
|
|
)
|
|
|
|
func TestSearchRequest_ToQuery(t *testing.T) {
|
|
type fields struct {
|
|
Offset uint64
|
|
Limit uint64
|
|
SortingColumn Column
|
|
Asc bool
|
|
}
|
|
type want struct {
|
|
stmtAddition string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "no queries",
|
|
fields: fields{},
|
|
want: want{
|
|
stmtAddition: "",
|
|
},
|
|
},
|
|
{
|
|
name: "offset",
|
|
fields: fields{
|
|
Offset: 5,
|
|
},
|
|
want: want{
|
|
stmtAddition: "OFFSET 5",
|
|
},
|
|
},
|
|
{
|
|
name: "limit",
|
|
fields: fields{
|
|
Limit: 5,
|
|
},
|
|
want: want{
|
|
stmtAddition: "LIMIT 5",
|
|
},
|
|
},
|
|
{
|
|
name: "sort asc",
|
|
fields: fields{
|
|
SortingColumn: testCol,
|
|
Asc: true,
|
|
},
|
|
want: want{
|
|
stmtAddition: "ORDER BY test_table.test_col",
|
|
},
|
|
},
|
|
{
|
|
name: "sort desc",
|
|
fields: fields{
|
|
SortingColumn: testCol,
|
|
},
|
|
want: want{
|
|
stmtAddition: "ORDER BY test_table.test_col DESC",
|
|
},
|
|
},
|
|
{
|
|
name: "sort lower asc",
|
|
fields: fields{
|
|
SortingColumn: testLowerCol,
|
|
Asc: true,
|
|
},
|
|
want: want{
|
|
stmtAddition: "ORDER BY LOWER(test_table.test_lower_col)",
|
|
},
|
|
},
|
|
{
|
|
name: "all",
|
|
fields: fields{
|
|
Offset: 5,
|
|
Limit: 10,
|
|
SortingColumn: testCol,
|
|
Asc: true,
|
|
},
|
|
want: want{
|
|
stmtAddition: "ORDER BY test_table.test_col LIMIT 10 OFFSET 5",
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
req := &SearchRequest{
|
|
Offset: tt.fields.Offset,
|
|
Limit: tt.fields.Limit,
|
|
SortingColumn: tt.fields.SortingColumn,
|
|
Asc: tt.fields.Asc,
|
|
}
|
|
|
|
query := sq.Select((testCol).identifier()).From(testTable.identifier())
|
|
expectedQuery, _, _ := query.ToSql()
|
|
|
|
stmt, _, err := req.toQuery(query).ToSql()
|
|
if len(tt.want.stmtAddition) > 0 {
|
|
expectedQuery += " " + tt.want.stmtAddition
|
|
}
|
|
if expectedQuery != stmt {
|
|
t.Errorf("stmt = %q, want %q", stmt, expectedQuery)
|
|
}
|
|
|
|
if err != nil {
|
|
t.Errorf("no error expected but got %v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewSubSelect(t *testing.T) {
|
|
type args struct {
|
|
column Column
|
|
queries []SearchQuery
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *SubSelect
|
|
wantErr func(error) bool
|
|
}{
|
|
{
|
|
name: "no query nil",
|
|
args: args{
|
|
column: testCol,
|
|
queries: nil,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrNothingSelected)
|
|
},
|
|
},
|
|
{
|
|
name: "no query zero",
|
|
args: args{
|
|
column: testCol,
|
|
queries: []SearchQuery{},
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrNothingSelected)
|
|
},
|
|
},
|
|
{
|
|
name: "no column 1",
|
|
args: args{
|
|
column: Column{},
|
|
queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}},
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "no column name 1",
|
|
args: args{
|
|
column: testNoCol,
|
|
queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}},
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "correct 1",
|
|
args: args{
|
|
column: testCol,
|
|
queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}},
|
|
},
|
|
want: &SubSelect{
|
|
Column: testCol,
|
|
Queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}},
|
|
},
|
|
},
|
|
{
|
|
name: "correct 3",
|
|
args: args{
|
|
column: testCol,
|
|
queries: []SearchQuery{&TextQuery{testCol, "horst1", TextEquals}, &TextQuery{testCol, "horst2", TextEquals}, &TextQuery{testCol, "horst3", TextEquals}},
|
|
},
|
|
want: &SubSelect{
|
|
Column: testCol,
|
|
Queries: []SearchQuery{&TextQuery{testCol, "horst1", TextEquals}, &TextQuery{testCol, "horst2", TextEquals}, &TextQuery{testCol, "horst3", TextEquals}},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := NewSubSelect(tt.args.column, tt.args.queries)
|
|
if err != nil && tt.wantErr == nil {
|
|
t.Errorf("NewTextQuery() no error expected got %v", err)
|
|
return
|
|
} else if tt.wantErr != nil && !tt.wantErr(err) {
|
|
t.Errorf("NewTextQuery() unexpeted error = %v", err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewTextQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSubSelect_comp(t *testing.T) {
|
|
type fields struct {
|
|
Column Column
|
|
Queries []SearchQuery
|
|
}
|
|
type want struct {
|
|
query interface{}
|
|
isNil bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "no queries",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Queries: []SearchQuery{},
|
|
},
|
|
want: want{
|
|
query: sq.Select("test_table.test_col").From("test_table"),
|
|
},
|
|
},
|
|
{
|
|
name: "queries 1",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}},
|
|
},
|
|
want: want{
|
|
query: sq.Select("test_table.test_col").From("test_table").Where(sq.Eq{"test_table.test_col": interface{}("horst")}),
|
|
},
|
|
},
|
|
{
|
|
name: "queries 1 with alias",
|
|
fields: fields{
|
|
Column: testColAlias,
|
|
Queries: []SearchQuery{&TextQuery{testColAlias, "horst", TextEquals}},
|
|
},
|
|
want: want{
|
|
query: sq.Select("test_alias.test_col").From("test_table AS test_alias").Where(sq.Eq{"test_alias.test_col": interface{}("horst")}),
|
|
},
|
|
},
|
|
{
|
|
name: "queries 3",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Queries: []SearchQuery{&TextQuery{testCol, "horst1", TextEquals}, &TextQuery{testCol, "horst2", TextEquals}, &TextQuery{testCol, "horst3", TextEquals}},
|
|
},
|
|
want: want{
|
|
query: sq.Select("test_table.test_col").From("test_table").From("test_table").Where(sq.Eq{"test_table.test_col": "horst1"}).From("test_table").Where(sq.Eq{"test_table.test_col": "horst2"}).From("test_table").Where(sq.Eq{"test_table.test_col": "horst3"}),
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := &SubSelect{
|
|
Column: tt.fields.Column,
|
|
Queries: tt.fields.Queries,
|
|
}
|
|
query := s.comp()
|
|
if query == nil && tt.want.isNil {
|
|
return
|
|
} else if tt.want.isNil && query != nil {
|
|
t.Error("query should not be nil")
|
|
}
|
|
|
|
if !reflect.DeepEqual(query, tt.want.query) {
|
|
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewColumnComparisonQuery(t *testing.T) {
|
|
type args struct {
|
|
column Column
|
|
columnCompare Column
|
|
compare ColumnComparison
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *ColumnComparisonQuery
|
|
wantErr func(error) bool
|
|
}{
|
|
{
|
|
name: "too low compare",
|
|
args: args{
|
|
column: testCol,
|
|
columnCompare: testCol2,
|
|
compare: -1,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrInvalidCompare)
|
|
},
|
|
},
|
|
{
|
|
name: "too high compare",
|
|
args: args{
|
|
column: testCol,
|
|
columnCompare: testCol2,
|
|
compare: columnCompareMax,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrInvalidCompare)
|
|
},
|
|
},
|
|
{
|
|
name: "no column 1",
|
|
args: args{
|
|
column: Column{},
|
|
columnCompare: testCol2,
|
|
compare: ColumnEquals,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "no column 2",
|
|
args: args{
|
|
column: testCol,
|
|
columnCompare: Column{},
|
|
compare: ColumnEquals,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "no column name 1",
|
|
args: args{
|
|
column: testNoCol,
|
|
columnCompare: testCol2,
|
|
compare: ColumnEquals,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "no column name 2",
|
|
args: args{
|
|
column: testCol,
|
|
columnCompare: testNoCol,
|
|
compare: ColumnEquals,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "correct",
|
|
args: args{
|
|
column: testCol,
|
|
columnCompare: testCol2,
|
|
compare: ColumnEquals,
|
|
},
|
|
want: &ColumnComparisonQuery{
|
|
Column1: testCol,
|
|
Column2: testCol2,
|
|
Compare: ColumnEquals,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := NewColumnComparisonQuery(tt.args.column, tt.args.columnCompare, tt.args.compare)
|
|
if err != nil && tt.wantErr == nil {
|
|
t.Errorf("NewTextQuery() no error expected got %v", err)
|
|
return
|
|
} else if tt.wantErr != nil && !tt.wantErr(err) {
|
|
t.Errorf("NewTextQuery() unexpeted error = %v", err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewTextQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestColumnComparisonQuery_comp(t *testing.T) {
|
|
type fields struct {
|
|
Column Column
|
|
ColumnCompare Column
|
|
Compare ColumnComparison
|
|
}
|
|
type want struct {
|
|
query interface{}
|
|
isNil bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "equals",
|
|
fields: fields{
|
|
Column: testCol,
|
|
ColumnCompare: testCol2,
|
|
Compare: ColumnEquals,
|
|
},
|
|
want: want{
|
|
query: sq.Expr("test_table.test_col = test_table2.test_col2"),
|
|
},
|
|
},
|
|
{
|
|
name: "not equals",
|
|
fields: fields{
|
|
Column: testCol,
|
|
ColumnCompare: testCol2,
|
|
Compare: ColumnNotEquals,
|
|
},
|
|
want: want{
|
|
query: sq.Expr("test_table.test_col != test_table2.test_col2"),
|
|
},
|
|
},
|
|
{
|
|
name: "too high comparison",
|
|
fields: fields{
|
|
Column: testCol,
|
|
ColumnCompare: testCol2,
|
|
Compare: columnCompareMax,
|
|
},
|
|
want: want{
|
|
isNil: true,
|
|
},
|
|
},
|
|
{
|
|
name: "too low comparison",
|
|
fields: fields{
|
|
Column: testCol,
|
|
ColumnCompare: testCol2,
|
|
Compare: -1,
|
|
},
|
|
want: want{
|
|
isNil: true,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := &ColumnComparisonQuery{
|
|
Column1: tt.fields.Column,
|
|
Column2: tt.fields.ColumnCompare,
|
|
Compare: tt.fields.Compare,
|
|
}
|
|
query := s.comp()
|
|
if query == nil && tt.want.isNil {
|
|
return
|
|
} else if tt.want.isNil && query != nil {
|
|
t.Error("query should not be nil")
|
|
}
|
|
|
|
if !reflect.DeepEqual(query, tt.want.query) {
|
|
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewListQuery(t *testing.T) {
|
|
type args struct {
|
|
column Column
|
|
data interface{}
|
|
compare ListComparison
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *ListQuery
|
|
wantErr func(error) bool
|
|
}{
|
|
{
|
|
name: "too low compare",
|
|
args: args{
|
|
column: testCol,
|
|
data: []interface{}{"hurst"},
|
|
compare: -1,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrInvalidCompare)
|
|
},
|
|
},
|
|
{
|
|
name: "too high compare",
|
|
args: args{
|
|
column: testCol,
|
|
data: []interface{}{"hurst"},
|
|
compare: listCompareMax,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrInvalidCompare)
|
|
},
|
|
},
|
|
{
|
|
name: "no column",
|
|
args: args{
|
|
column: Column{},
|
|
data: []interface{}{"hurst"},
|
|
compare: ListIn,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "no column name",
|
|
args: args{
|
|
column: testNoCol,
|
|
data: []interface{}{"hurst"},
|
|
compare: ListIn,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "correct slice",
|
|
args: args{
|
|
column: testCol,
|
|
data: []interface{}{"hurst"},
|
|
compare: ListIn,
|
|
},
|
|
want: &ListQuery{
|
|
Column: testCol,
|
|
Data: []interface{}{"hurst"},
|
|
Compare: ListIn,
|
|
},
|
|
},
|
|
{
|
|
name: "correct",
|
|
args: args{
|
|
column: testCol,
|
|
data: &SubSelect{Column: testCol, Queries: []SearchQuery{&TextQuery{testCol, "horst1", TextEquals}}},
|
|
compare: ListIn,
|
|
},
|
|
want: &ListQuery{
|
|
Column: testCol,
|
|
Data: &SubSelect{Column: testCol, Queries: []SearchQuery{&TextQuery{testCol, "horst1", TextEquals}}},
|
|
Compare: ListIn,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := NewListQuery(tt.args.column, tt.args.data, tt.args.compare)
|
|
if err != nil && tt.wantErr == nil {
|
|
t.Errorf("NewTextQuery() no error expected got %v", err)
|
|
return
|
|
} else if tt.wantErr != nil && !tt.wantErr(err) {
|
|
t.Errorf("NewTextQuery() unexpeted error = %v", err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewTextQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestListQuery_comp(t *testing.T) {
|
|
type fields struct {
|
|
Column Column
|
|
Data interface{}
|
|
Compare ListComparison
|
|
}
|
|
type want struct {
|
|
query interface{}
|
|
isNil bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "in list one element",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Data: []interface{}{"hurst"},
|
|
Compare: ListIn,
|
|
},
|
|
want: want{
|
|
query: sq.Eq{"test_table.test_col": []interface{}{"hurst"}},
|
|
},
|
|
},
|
|
{
|
|
name: "in list three elements",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Data: []interface{}{"hurst1", "hurst2", "hurst3"},
|
|
Compare: ListIn,
|
|
},
|
|
want: want{
|
|
query: sq.Eq{"test_table.test_col": []interface{}{"hurst1", "hurst2", "hurst3"}},
|
|
},
|
|
},
|
|
{
|
|
name: "in string list one element",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Data: []string{"hurst"},
|
|
Compare: ListIn,
|
|
},
|
|
want: want{
|
|
query: sq.Eq{"test_table.test_col": []string{"hurst"}},
|
|
},
|
|
},
|
|
{
|
|
name: "in string list three elements",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Data: []string{"hurst1", "hurst2", "hurst3"},
|
|
Compare: ListIn,
|
|
},
|
|
want: want{
|
|
query: sq.Eq{"test_table.test_col": []string{"hurst1", "hurst2", "hurst3"}},
|
|
},
|
|
},
|
|
{
|
|
name: "in int list one element",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Data: []int{1},
|
|
Compare: ListIn,
|
|
},
|
|
want: want{
|
|
query: sq.Eq{"test_table.test_col": []int{1}},
|
|
},
|
|
},
|
|
{
|
|
name: "in int list three elements",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Data: []int{1, 2, 3},
|
|
Compare: ListIn,
|
|
},
|
|
want: want{
|
|
query: sq.Eq{"test_table.test_col": []int{1, 2, 3}},
|
|
},
|
|
},
|
|
{
|
|
name: "in subquery text",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Data: &SubSelect{Column: testCol, Queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}}},
|
|
Compare: ListIn,
|
|
},
|
|
want: want{
|
|
query: sq.Expr("test_table.test_col IN ( SELECT test_table.test_col FROM test_table WHERE test_table.test_col = ? )", "horst"),
|
|
},
|
|
},
|
|
{
|
|
name: "in subquery number",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Data: &SubSelect{Column: testCol, Queries: []SearchQuery{&NumberQuery{testCol, 1, NumberEquals}}},
|
|
Compare: ListIn,
|
|
},
|
|
want: want{
|
|
query: sq.Expr("test_table.test_col IN ( SELECT test_table.test_col FROM test_table WHERE test_table.test_col = ? )", 1),
|
|
},
|
|
},
|
|
{
|
|
name: "in subquery column",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Data: &SubSelect{Column: testCol, Queries: []SearchQuery{&ColumnComparisonQuery{testCol, ColumnEquals, testCol2}}},
|
|
Compare: ListIn,
|
|
},
|
|
want: want{
|
|
query: sq.Expr("test_table.test_col IN ( SELECT test_table.test_col FROM test_table WHERE test_table.test_col = test_table2.test_col2 )"),
|
|
},
|
|
},
|
|
{
|
|
name: "too high comparison",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Data: []interface{}{"hurst"},
|
|
Compare: listCompareMax,
|
|
},
|
|
want: want{
|
|
isNil: true,
|
|
},
|
|
},
|
|
{
|
|
name: "too low comparison",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Data: []interface{}{"hurst"},
|
|
Compare: -1,
|
|
},
|
|
want: want{
|
|
isNil: true,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := &ListQuery{
|
|
Column: tt.fields.Column,
|
|
Data: tt.fields.Data,
|
|
Compare: tt.fields.Compare,
|
|
}
|
|
query := s.comp()
|
|
if query == nil && tt.want.isNil {
|
|
return
|
|
} else if tt.want.isNil && query != nil {
|
|
t.Error("query should not be nil")
|
|
}
|
|
|
|
if !reflect.DeepEqual(query, tt.want.query) {
|
|
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewTextQuery(t *testing.T) {
|
|
type args struct {
|
|
column Column
|
|
value string
|
|
compare TextComparison
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *TextQuery
|
|
wantErr func(error) bool
|
|
}{
|
|
{
|
|
name: "too low compare",
|
|
args: args{
|
|
column: testCol,
|
|
value: "hurst",
|
|
compare: -1,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrInvalidCompare)
|
|
},
|
|
},
|
|
{
|
|
name: "too high compare",
|
|
args: args{
|
|
column: testCol,
|
|
value: "hurst",
|
|
compare: textCompareMax,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrInvalidCompare)
|
|
},
|
|
},
|
|
{
|
|
name: "no column",
|
|
args: args{
|
|
column: Column{},
|
|
value: "hurst",
|
|
compare: TextEquals,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "no column name",
|
|
args: args{
|
|
column: testNoCol,
|
|
value: "hurst",
|
|
compare: TextEquals,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "correct",
|
|
args: args{
|
|
column: testCol,
|
|
value: "hurst",
|
|
compare: TextEquals,
|
|
},
|
|
want: &TextQuery{
|
|
Column: testCol,
|
|
Text: "hurst",
|
|
Compare: TextEquals,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := NewTextQuery(tt.args.column, tt.args.value, tt.args.compare)
|
|
if err != nil && tt.wantErr == nil {
|
|
t.Errorf("NewTextQuery() no error expected got %v", err)
|
|
return
|
|
} else if tt.wantErr != nil && !tt.wantErr(err) {
|
|
t.Errorf("NewTextQuery() unexpeted error = %v", err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewTextQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTextQuery_comp(t *testing.T) {
|
|
type fields struct {
|
|
Column Column
|
|
Text string
|
|
Compare TextComparison
|
|
}
|
|
type want struct {
|
|
query interface{}
|
|
isNil bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "equals",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Text: "Hurst",
|
|
Compare: TextEquals,
|
|
},
|
|
want: want{
|
|
query: sq.Eq{"test_table.test_col": "Hurst"},
|
|
},
|
|
},
|
|
{
|
|
name: "equals ignore case",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Text: "Hurst",
|
|
Compare: TextEqualsIgnoreCase,
|
|
},
|
|
want: want{
|
|
query: sq.ILike{"test_table.test_col": "Hurst"},
|
|
},
|
|
},
|
|
{
|
|
name: "starts with",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Text: "Hurst",
|
|
Compare: TextStartsWith,
|
|
},
|
|
want: want{
|
|
query: sq.Like{"test_table.test_col": "Hurst%"},
|
|
},
|
|
},
|
|
{
|
|
name: "starts with ignore case",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Text: "Hurst",
|
|
Compare: TextStartsWithIgnoreCase,
|
|
},
|
|
want: want{
|
|
query: sq.ILike{"test_table.test_col": "Hurst%"},
|
|
},
|
|
},
|
|
{
|
|
name: "ends with",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Text: "Hurst",
|
|
Compare: TextEndsWith,
|
|
},
|
|
want: want{
|
|
query: sq.Like{"test_table.test_col": "%Hurst"},
|
|
},
|
|
},
|
|
{
|
|
name: "ends with ignore case",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Text: "Hurst",
|
|
Compare: TextEndsWithIgnoreCase,
|
|
},
|
|
want: want{
|
|
query: sq.ILike{"test_table.test_col": "%Hurst"},
|
|
},
|
|
},
|
|
{
|
|
name: "contains",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Text: "Hurst",
|
|
Compare: TextContains,
|
|
},
|
|
want: want{
|
|
query: sq.Like{"test_table.test_col": "%Hurst%"},
|
|
},
|
|
},
|
|
{
|
|
name: "containts ignore case",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Text: "Hurst",
|
|
Compare: TextContainsIgnoreCase,
|
|
},
|
|
want: want{
|
|
query: sq.ILike{"test_table.test_col": "%Hurst%"},
|
|
},
|
|
},
|
|
{
|
|
name: "list containts",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Text: "Hurst",
|
|
Compare: TextListContains,
|
|
},
|
|
want: want{
|
|
query: &listContains{
|
|
col: testCol,
|
|
args: []interface{}{"Hurst"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "too high comparison",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Text: "Hurst",
|
|
Compare: textCompareMax,
|
|
},
|
|
want: want{
|
|
isNil: true,
|
|
},
|
|
},
|
|
{
|
|
name: "too low comparison",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Text: "Hurst",
|
|
Compare: -1,
|
|
},
|
|
want: want{
|
|
isNil: true,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := &TextQuery{
|
|
Column: tt.fields.Column,
|
|
Text: tt.fields.Text,
|
|
Compare: tt.fields.Compare,
|
|
}
|
|
query := s.comp()
|
|
if query == nil && tt.want.isNil {
|
|
return
|
|
} else if tt.want.isNil && query != nil {
|
|
t.Error("query should not be nil")
|
|
}
|
|
|
|
if !reflect.DeepEqual(query, tt.want.query) {
|
|
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTextComparisonFromMethod(t *testing.T) {
|
|
type args struct {
|
|
m domain.SearchMethod
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want TextComparison
|
|
}{
|
|
{
|
|
name: "equals",
|
|
args: args{
|
|
m: domain.SearchMethodEquals,
|
|
},
|
|
want: TextEquals,
|
|
},
|
|
{
|
|
name: "equals ignore case",
|
|
args: args{
|
|
m: domain.SearchMethodEqualsIgnoreCase,
|
|
},
|
|
want: TextEqualsIgnoreCase,
|
|
},
|
|
{
|
|
name: "starts with",
|
|
args: args{
|
|
m: domain.SearchMethodStartsWith,
|
|
},
|
|
want: TextStartsWith,
|
|
},
|
|
{
|
|
name: "starts with ignore case",
|
|
args: args{
|
|
m: domain.SearchMethodStartsWithIgnoreCase,
|
|
},
|
|
want: TextStartsWithIgnoreCase,
|
|
},
|
|
{
|
|
name: "ends with",
|
|
args: args{
|
|
m: domain.SearchMethodEndsWith,
|
|
},
|
|
want: TextEndsWith,
|
|
},
|
|
{
|
|
name: "ends with ignore case",
|
|
args: args{
|
|
m: domain.SearchMethodEndsWithIgnoreCase,
|
|
},
|
|
want: TextEndsWithIgnoreCase,
|
|
},
|
|
{
|
|
name: "contains",
|
|
args: args{
|
|
m: domain.SearchMethodContains,
|
|
},
|
|
want: TextContains,
|
|
},
|
|
{
|
|
name: "list contains",
|
|
args: args{
|
|
m: domain.SearchMethodListContains,
|
|
},
|
|
want: TextListContains,
|
|
},
|
|
{
|
|
name: "containts ignore case",
|
|
args: args{
|
|
m: domain.SearchMethodContainsIgnoreCase,
|
|
},
|
|
want: TextContainsIgnoreCase,
|
|
},
|
|
{
|
|
name: "invalid search method",
|
|
args: args{
|
|
m: -1,
|
|
},
|
|
want: textCompareMax,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := TextComparisonFromMethod(tt.args.m); got != tt.want {
|
|
t.Errorf("TextCompareFromMethod() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewNumberQuery(t *testing.T) {
|
|
type args struct {
|
|
column Column
|
|
value interface{}
|
|
compare NumberComparison
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *NumberQuery
|
|
wantErr func(error) bool
|
|
}{
|
|
{
|
|
name: "too low compare",
|
|
args: args{
|
|
column: testCol,
|
|
value: "hurst",
|
|
compare: -1,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrInvalidCompare)
|
|
},
|
|
},
|
|
{
|
|
name: "too high compare",
|
|
args: args{
|
|
column: testCol,
|
|
value: "hurst",
|
|
compare: numberCompareMax,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrInvalidCompare)
|
|
},
|
|
},
|
|
{
|
|
name: "no column",
|
|
args: args{
|
|
column: Column{},
|
|
value: "hurst",
|
|
compare: NumberEquals,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "no column name",
|
|
args: args{
|
|
column: testNoCol,
|
|
value: "hurst",
|
|
compare: NumberEquals,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "no number",
|
|
args: args{
|
|
column: testCol,
|
|
value: "hurst",
|
|
compare: NumberEquals,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrInvalidNumber)
|
|
},
|
|
},
|
|
{
|
|
name: "correct",
|
|
args: args{
|
|
column: testCol,
|
|
value: 5,
|
|
compare: NumberEquals,
|
|
},
|
|
want: &NumberQuery{
|
|
Column: testCol,
|
|
Number: 5,
|
|
Compare: NumberEquals,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := NewNumberQuery(tt.args.column, tt.args.value, tt.args.compare)
|
|
if err != nil && tt.wantErr == nil {
|
|
t.Errorf("NewNumberQuery() no error expected got %v", err)
|
|
return
|
|
} else if tt.wantErr != nil && !tt.wantErr(err) {
|
|
t.Errorf("NewNumberQuery() unexpeted error = %v", err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewNumberQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNumberQuery_comp(t *testing.T) {
|
|
type fields struct {
|
|
Column Column
|
|
Number interface{}
|
|
Compare NumberComparison
|
|
}
|
|
type want struct {
|
|
query interface{}
|
|
isNil bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "equals",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Number: 42,
|
|
Compare: NumberEquals,
|
|
},
|
|
want: want{
|
|
query: sq.Eq{"test_table.test_col": 42},
|
|
},
|
|
},
|
|
{
|
|
name: "not equals",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Number: 42,
|
|
Compare: NumberNotEquals,
|
|
},
|
|
want: want{
|
|
query: sq.NotEq{"test_table.test_col": 42},
|
|
},
|
|
},
|
|
{
|
|
name: "less",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Number: 42,
|
|
Compare: NumberLess,
|
|
},
|
|
want: want{
|
|
query: sq.Lt{"test_table.test_col": 42},
|
|
},
|
|
},
|
|
{
|
|
name: "greater",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Number: 42,
|
|
Compare: NumberGreater,
|
|
},
|
|
want: want{
|
|
query: sq.Gt{"test_table.test_col": 42},
|
|
},
|
|
},
|
|
{
|
|
name: "list containts",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Number: 42,
|
|
Compare: NumberListContains,
|
|
},
|
|
want: want{
|
|
query: &listContains{
|
|
col: testCol,
|
|
args: []interface{}{42},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "too high comparison",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Number: 42,
|
|
Compare: numberCompareMax,
|
|
},
|
|
want: want{
|
|
isNil: true,
|
|
},
|
|
},
|
|
{
|
|
name: "too low comparison",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Number: 42,
|
|
Compare: -1,
|
|
},
|
|
want: want{
|
|
isNil: true,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := &NumberQuery{
|
|
Column: tt.fields.Column,
|
|
Number: tt.fields.Number,
|
|
Compare: tt.fields.Compare,
|
|
}
|
|
query := s.comp()
|
|
if query == nil && tt.want.isNil {
|
|
return
|
|
} else if tt.want.isNil && query != nil {
|
|
t.Error("query should not be nil")
|
|
}
|
|
|
|
if !reflect.DeepEqual(query, tt.want.query) {
|
|
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNumberComparisonFromMethod(t *testing.T) {
|
|
type args struct {
|
|
m domain.SearchMethod
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want NumberComparison
|
|
}{
|
|
{
|
|
name: "equals",
|
|
args: args{
|
|
m: domain.SearchMethodEquals,
|
|
},
|
|
want: NumberEquals,
|
|
},
|
|
{
|
|
name: "not equals",
|
|
args: args{
|
|
m: domain.SearchMethodNotEquals,
|
|
},
|
|
want: NumberNotEquals,
|
|
},
|
|
{
|
|
name: "less than",
|
|
args: args{
|
|
m: domain.SearchMethodLessThan,
|
|
},
|
|
want: NumberLess,
|
|
},
|
|
{
|
|
name: "greater than",
|
|
args: args{
|
|
m: domain.SearchMethodGreaterThan,
|
|
},
|
|
want: NumberGreater,
|
|
},
|
|
{
|
|
name: "list contains",
|
|
args: args{
|
|
m: domain.SearchMethodListContains,
|
|
},
|
|
want: NumberListContains,
|
|
},
|
|
{
|
|
name: "invalid search method",
|
|
args: args{
|
|
m: -1,
|
|
},
|
|
want: numberCompareMax,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := NumberComparisonFromMethod(tt.args.m); got != tt.want {
|
|
t.Errorf("TextCompareFromMethod() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewOrQuery(t *testing.T) {
|
|
|
|
type args struct {
|
|
queries []SearchQuery
|
|
}
|
|
|
|
singleCorrectQuery, _ := NewTextQuery(testCol, "hello", TextEquals)
|
|
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *OrQuery
|
|
wantErr func(error) bool
|
|
}{
|
|
{
|
|
name: "empty values",
|
|
args: args{
|
|
queries: []SearchQuery{},
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "correct",
|
|
args: args{
|
|
queries: []SearchQuery{singleCorrectQuery},
|
|
},
|
|
want: &OrQuery{
|
|
queries: []SearchQuery{singleCorrectQuery},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := NewOrQuery(tt.args.queries...)
|
|
if err != nil && tt.wantErr == nil {
|
|
t.Errorf("NewOrQuery() no error expected got %v", err)
|
|
return
|
|
} else if tt.wantErr != nil && !tt.wantErr(err) {
|
|
t.Errorf("NewOrQuery() unexpeted error = %v", err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewOrQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
func TestOrQuery_comp(t *testing.T) {
|
|
q1, _ := NewTextQuery(testCol, "hello1", TextEquals)
|
|
q2, _ := NewTextQuery(testCol, "hello2", TextEquals)
|
|
q3, _ := NewTextQuery(testCol2, "world1", TextEquals)
|
|
q4, _ := NewTextQuery(testCol2, "world2", TextEquals)
|
|
orq, _ := NewOrQuery(q3, q4)
|
|
|
|
type fields struct {
|
|
queries []SearchQuery
|
|
}
|
|
type want struct {
|
|
query interface{}
|
|
isNil bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "single input",
|
|
fields: fields{
|
|
queries: []SearchQuery{q1},
|
|
},
|
|
want: want{
|
|
query: sq.Or{sq.Eq{"test_table.test_col": "hello1"}},
|
|
},
|
|
},
|
|
{
|
|
name: "multi input",
|
|
fields: fields{
|
|
queries: []SearchQuery{q1, q2},
|
|
},
|
|
want: want{
|
|
query: sq.Or{sq.Eq{"test_table.test_col": "hello1"}, sq.Eq{"test_table.test_col": "hello2"}},
|
|
},
|
|
},
|
|
{
|
|
name: "nested inputs",
|
|
fields: fields{
|
|
queries: []SearchQuery{q1, orq},
|
|
},
|
|
want: want{
|
|
query: sq.Or{sq.Eq{"test_table.test_col": "hello1"}, sq.Or{sq.Eq{"test_table2.test_col2": "world1"}, sq.Eq{"test_table2.test_col2": "world2"}}},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := &OrQuery{
|
|
queries: tt.fields.queries,
|
|
}
|
|
query := s.comp()
|
|
if query == nil && tt.want.isNil {
|
|
return
|
|
} else if tt.want.isNil && query != nil {
|
|
t.Error("query should not be nil")
|
|
}
|
|
|
|
if !reflect.DeepEqual(query, tt.want.query) {
|
|
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
func TestNewAndQuery(t *testing.T) {
|
|
|
|
type args struct {
|
|
queries []SearchQuery
|
|
}
|
|
|
|
singleCorrectQuery, _ := NewTextQuery(testCol, "hello", TextEquals)
|
|
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *AndQuery
|
|
wantErr func(error) bool
|
|
}{
|
|
{
|
|
name: "empty values",
|
|
args: args{
|
|
queries: []SearchQuery{},
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "correct",
|
|
args: args{
|
|
queries: []SearchQuery{singleCorrectQuery},
|
|
},
|
|
want: &AndQuery{
|
|
queries: []SearchQuery{singleCorrectQuery},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := NewAndQuery(tt.args.queries...)
|
|
if err != nil && tt.wantErr == nil {
|
|
t.Errorf("NewAndQuery() no error expected got %v", err)
|
|
return
|
|
} else if tt.wantErr != nil && !tt.wantErr(err) {
|
|
t.Errorf("NewAndQuery() unexpeted error = %v", err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewAndQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAndQuery_comp(t *testing.T) {
|
|
q1, _ := NewTextQuery(testCol, "hello1", TextEquals)
|
|
q2, _ := NewTextQuery(testCol, "hello2", TextEquals)
|
|
q3, _ := NewTextQuery(testCol2, "world1", TextEquals)
|
|
q4, _ := NewTextQuery(testCol2, "world2", TextEquals)
|
|
andq, _ := NewAndQuery(q3, q4)
|
|
|
|
type fields struct {
|
|
queries []SearchQuery
|
|
}
|
|
type want struct {
|
|
query interface{}
|
|
isNil bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "single input",
|
|
fields: fields{
|
|
queries: []SearchQuery{q1},
|
|
},
|
|
want: want{
|
|
query: sq.And{sq.Eq{"test_table.test_col": "hello1"}},
|
|
},
|
|
},
|
|
{
|
|
name: "multi input",
|
|
fields: fields{
|
|
queries: []SearchQuery{q1, q2},
|
|
},
|
|
want: want{
|
|
query: sq.And{sq.Eq{"test_table.test_col": "hello1"}, sq.Eq{"test_table.test_col": "hello2"}},
|
|
},
|
|
},
|
|
{
|
|
name: "nested inputs",
|
|
fields: fields{
|
|
queries: []SearchQuery{q1, andq},
|
|
},
|
|
want: want{
|
|
query: sq.And{sq.Eq{"test_table.test_col": "hello1"}, sq.And{sq.Eq{"test_table2.test_col2": "world1"}, sq.Eq{"test_table2.test_col2": "world2"}}},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := &AndQuery{
|
|
queries: tt.fields.queries,
|
|
}
|
|
query := s.comp()
|
|
if query == nil && tt.want.isNil {
|
|
return
|
|
} else if tt.want.isNil && query != nil {
|
|
t.Error("query should not be nil")
|
|
}
|
|
|
|
if !reflect.DeepEqual(query, tt.want.query) {
|
|
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewNotQuery(t *testing.T) {
|
|
|
|
type args struct {
|
|
query SearchQuery
|
|
}
|
|
|
|
singleCorrectQuery, _ := NewTextQuery(testCol, "hello", TextEquals)
|
|
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *NotQuery
|
|
wantErr func(error) bool
|
|
}{
|
|
{
|
|
name: "empty query",
|
|
args: args{
|
|
query: nil,
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "correct",
|
|
args: args{
|
|
query: singleCorrectQuery,
|
|
},
|
|
want: &NotQuery{
|
|
query: singleCorrectQuery,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := NewNotQuery(tt.args.query)
|
|
if err != nil && tt.wantErr == nil {
|
|
t.Errorf("NewNotQuery() no error expected got %v", err)
|
|
return
|
|
} else if tt.wantErr != nil && !tt.wantErr(err) {
|
|
t.Errorf("NewNotQuery() unexpeted error = %v", err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewNotQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNotQuery_comp(t *testing.T) {
|
|
q1, _ := NewTextQuery(testCol, "hello1", TextEquals)
|
|
|
|
type fields struct {
|
|
query SearchQuery
|
|
}
|
|
type want struct {
|
|
query interface{}
|
|
isNil bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "single input",
|
|
fields: fields{
|
|
query: q1,
|
|
},
|
|
want: want{
|
|
query: &NotQuery{query: q1},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := &NotQuery{
|
|
query: tt.fields.query,
|
|
}
|
|
query := s.comp()
|
|
if query == nil && tt.want.isNil {
|
|
return
|
|
} else if tt.want.isNil && query != nil {
|
|
t.Error("query should not be nil")
|
|
}
|
|
|
|
if !reflect.DeepEqual(query, tt.want.query) {
|
|
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
func TestNotQuery_ToSql(t *testing.T) {
|
|
q, _ := NewTextQuery(testCol, "hello1", TextEquals)
|
|
type fields struct {
|
|
query SearchQuery
|
|
}
|
|
type want struct {
|
|
query string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "single input",
|
|
fields: fields{
|
|
query: q,
|
|
},
|
|
want: want{
|
|
query: "NOT (test_table.test_col = hello1)",
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := &NotQuery{
|
|
query: tt.fields.query,
|
|
}
|
|
queryStr, _, err := s.ToSql()
|
|
if err != nil {
|
|
t.Error("an error raised ")
|
|
}
|
|
if queryStr == tt.want.query {
|
|
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, queryStr, queryStr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAndOrQueryCombo(t *testing.T) {
|
|
q1, _ := NewTextQuery(testCol, "hello1", TextEquals)
|
|
q2, _ := NewTextQuery(testCol, "hello2", TextEquals)
|
|
q3, _ := NewTextQuery(testCol2, "world1", TextEquals)
|
|
q4, _ := NewTextQuery(testCol2, "world2", TextEquals)
|
|
andq, _ := NewAndQuery(q3, q4)
|
|
orq, _ := NewOrQuery(q1, q2, andq)
|
|
|
|
type fields struct {
|
|
query SearchQuery
|
|
}
|
|
type want struct {
|
|
query interface{}
|
|
isNil bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "OR containing AND query",
|
|
fields: fields{
|
|
query: orq,
|
|
},
|
|
want: want{
|
|
query: sq.Or{sq.Eq{"test_table.test_col": "hello1"}, sq.Eq{"test_table.test_col": "hello2"}, sq.And{sq.Eq{"test_table2.test_col2": "world1"}, sq.Eq{"test_table2.test_col2": "world2"}}},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := tt.fields.query
|
|
query := s.comp()
|
|
if query == nil && tt.want.isNil {
|
|
return
|
|
} else if tt.want.isNil && query != nil {
|
|
t.Error("query should not be nil")
|
|
}
|
|
|
|
if !reflect.DeepEqual(query, tt.want.query) {
|
|
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewInTextQuery(t *testing.T) {
|
|
type args struct {
|
|
column Column
|
|
value []string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *InTextQuery
|
|
wantErr func(error) bool
|
|
}{
|
|
{
|
|
name: "empty values",
|
|
args: args{
|
|
column: testCol,
|
|
value: []string{},
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrEmptyValues)
|
|
},
|
|
},
|
|
{
|
|
name: "no column",
|
|
args: args{
|
|
column: Column{},
|
|
value: []string{"adler", "hurst"},
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "no column name",
|
|
args: args{
|
|
column: testNoCol,
|
|
value: []string{"adler", "hurst"},
|
|
},
|
|
wantErr: func(err error) bool {
|
|
return errors.Is(err, ErrMissingColumn)
|
|
},
|
|
},
|
|
{
|
|
name: "correct",
|
|
args: args{
|
|
column: testCol,
|
|
value: []string{"adler", "hurst"},
|
|
},
|
|
want: &InTextQuery{
|
|
Column: testCol,
|
|
Values: []string{"adler", "hurst"},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := NewInTextQuery(tt.args.column, tt.args.value)
|
|
if err != nil && tt.wantErr == nil {
|
|
t.Errorf("NewTextQuery() no error expected got %v", err)
|
|
return
|
|
} else if tt.wantErr != nil && !tt.wantErr(err) {
|
|
t.Errorf("NewTextQuery() unexpeted error = %v", err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewTextQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestInTextQuery_comp(t *testing.T) {
|
|
type fields struct {
|
|
Column Column
|
|
Values []string
|
|
}
|
|
type want struct {
|
|
query interface{}
|
|
isNil bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
want want
|
|
}{
|
|
{
|
|
name: "equals",
|
|
fields: fields{
|
|
Column: testCol,
|
|
Values: []string{"Adler", "Hurst"},
|
|
},
|
|
want: want{
|
|
query: sq.Eq{"test_table.test_col": []string{"Adler", "Hurst"}},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := &InTextQuery{
|
|
Column: tt.fields.Column,
|
|
Values: tt.fields.Values,
|
|
}
|
|
query := s.comp()
|
|
if query == nil && tt.want.isNil {
|
|
return
|
|
} else if tt.want.isNil && query != nil {
|
|
t.Error("query should not be nil")
|
|
}
|
|
|
|
if !reflect.DeepEqual(query, tt.want.query) {
|
|
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query)
|
|
}
|
|
})
|
|
}
|
|
}
|