github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/pkg/database/filter_test.go (about)

     1  // Copyright © 2021 Kaleido, Inc.
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package database
    18  
    19  import (
    20  	"context"
    21  	"database/sql/driver"
    22  	"testing"
    23  
    24  	"github.com/kaleido-io/firefly/pkg/fftypes"
    25  	"github.com/stretchr/testify/assert"
    26  )
    27  
    28  func TestBuildMessageFilter(t *testing.T) {
    29  	fb := MessageQueryFactory.NewFilter(context.Background())
    30  	f, err := fb.And().
    31  		Condition(fb.Eq("namespace", "ns1")).
    32  		Condition(fb.Or().
    33  			Condition(fb.Eq("id", "35c11cba-adff-4a4d-970a-02e3a0858dc8")).
    34  			Condition(fb.Eq("id", "caefb9d1-9fc9-4d6a-a155-514d3139adf7")),
    35  		).
    36  		Condition(fb.Gt("sequence", 12345)).
    37  		Condition(fb.Eq("confirmed", nil)).
    38  		Skip(50).
    39  		Limit(25).
    40  		Sort("namespace").
    41  		Descending().
    42  		Finalize()
    43  
    44  	assert.NoError(t, err)
    45  	assert.Equal(t, "( namespace == 'ns1' ) && ( ( id == '35c11cba-adff-4a4d-970a-02e3a0858dc8' ) || ( id == 'caefb9d1-9fc9-4d6a-a155-514d3139adf7' ) ) && ( sequence > 12345 ) && ( confirmed == null ) sort=namespace descending skip=50 limit=25", f.String())
    46  }
    47  
    48  func TestBuildMessageFilter2(t *testing.T) {
    49  	fb := MessageQueryFactory.NewFilter(context.Background())
    50  	f, err := fb.Gt("sequence", "0").
    51  		Sort("sequence").
    52  		Ascending().
    53  		Finalize()
    54  
    55  	assert.NoError(t, err)
    56  	assert.Equal(t, "sequence > 0 sort=sequence", f.String())
    57  }
    58  
    59  func TestBuildMessageFilter3(t *testing.T) {
    60  	fb := MessageQueryFactory.NewFilter(context.Background())
    61  	f, err := fb.And(
    62  		fb.In("created", []driver.Value{1, 2, 3}),
    63  		fb.NotIn("created", []driver.Value{1, 2, 3}),
    64  		fb.Lt("created", "0"),
    65  		fb.Lte("created", "0"),
    66  		fb.Gte("created", "0"),
    67  		fb.Neq("created", "0"),
    68  		fb.Gt("sequence", 12345),
    69  		fb.Contains("topics", "abc"),
    70  		fb.NotContains("topics", "def"),
    71  		fb.IContains("topics", "ghi"),
    72  		fb.NotIContains("topics", "jkl"),
    73  	).Finalize()
    74  	assert.NoError(t, err)
    75  	assert.Equal(t, "( created IN [1000000000,2000000000,3000000000] ) && ( created NI [1000000000,2000000000,3000000000] ) && ( created < 0 ) && ( created <= 0 ) && ( created >= 0 ) && ( created != 0 ) && ( sequence > 12345 ) && ( topics %= 'abc' ) && ( topics %! 'def' ) && ( topics ^= 'ghi' ) && ( topics ^! 'jkl' )", f.String())
    76  }
    77  
    78  func TestBuildMessageBadInFilterField(t *testing.T) {
    79  	fb := MessageQueryFactory.NewFilter(context.Background())
    80  	_, err := fb.And(
    81  		fb.In("!wrong", []driver.Value{"a", "b", "c"}),
    82  	).Finalize()
    83  	assert.Regexp(t, "FF10148", err)
    84  }
    85  
    86  func TestBuildMessageBadInFilterValue(t *testing.T) {
    87  	fb := MessageQueryFactory.NewFilter(context.Background())
    88  	_, err := fb.And(
    89  		fb.In("sequence", []driver.Value{"!integer"}),
    90  	).Finalize()
    91  	assert.Regexp(t, "FF10149", err)
    92  }
    93  
    94  func TestBuildMessageUUIDConvert(t *testing.T) {
    95  	fb := MessageQueryFactory.NewFilter(context.Background())
    96  	u := fftypes.MustParseUUID("4066ABDC-8BBD-4472-9D29-1A55B467F9B9")
    97  	b32 := fftypes.UUIDBytes(u)
    98  	var nilB32 *fftypes.Bytes32
    99  	f, err := fb.And(
   100  		fb.Eq("id", u),
   101  		fb.Eq("id", *u),
   102  		fb.In("id", []driver.Value{*u}),
   103  		fb.Eq("id", u.String()),
   104  		fb.Neq("id", nil),
   105  		fb.Eq("id", b32),
   106  		fb.Neq("id", *b32),
   107  		fb.Eq("id", ""),
   108  		fb.Eq("id", nilB32),
   109  	).Finalize()
   110  	assert.NoError(t, err)
   111  	assert.Equal(t, "( id == '4066abdc-8bbd-4472-9d29-1a55b467f9b9' ) && ( id == '4066abdc-8bbd-4472-9d29-1a55b467f9b9' ) && ( id IN ['4066abdc-8bbd-4472-9d29-1a55b467f9b9'] ) && ( id == '4066abdc-8bbd-4472-9d29-1a55b467f9b9' ) && ( id != null ) && ( id == '4066abdc-8bbd-4472-9d29-1a55b467f9b9' ) && ( id != '4066abdc-8bbd-4472-9d29-1a55b467f9b9' ) && ( id == null ) && ( id == null )", f.String())
   112  }
   113  
   114  func TestBuildMessageIntConvert(t *testing.T) {
   115  	fb := MessageQueryFactory.NewFilter(context.Background())
   116  	f, err := fb.And(
   117  		fb.Lt("sequence", int(111)),
   118  		fb.Lt("sequence", int32(222)),
   119  		fb.Lt("sequence", int64(333)),
   120  		fb.Lt("sequence", uint(444)),
   121  		fb.Lt("sequence", uint32(555)),
   122  		fb.Lt("sequence", uint64(666)),
   123  	).Finalize()
   124  	assert.NoError(t, err)
   125  	assert.Equal(t, "( sequence < 111 ) && ( sequence < 222 ) && ( sequence < 333 ) && ( sequence < 444 ) && ( sequence < 555 ) && ( sequence < 666 )", f.String())
   126  }
   127  
   128  func TestBuildMessageTimeConvert(t *testing.T) {
   129  	fb := MessageQueryFactory.NewFilter(context.Background())
   130  	f, err := fb.And(
   131  		fb.Gt("created", int64(1621112824)),
   132  		fb.Gt("created", 0),
   133  		fb.Eq("created", "2021-05-15T21:07:54.123456789Z"),
   134  		fb.Eq("created", nil),
   135  		fb.Lt("created", fftypes.UnixTime(1621112824)),
   136  		fb.Lt("created", *fftypes.UnixTime(1621112824)),
   137  	).Finalize()
   138  	assert.NoError(t, err)
   139  	assert.Equal(t, "( created > 1621112824000000000 ) && ( created > 0 ) && ( created == 1621112874123456789 ) && ( created == null ) && ( created < 1621112824000000000 ) && ( created < 1621112824000000000 )", f.String())
   140  }
   141  
   142  func TestBuildMessageStringConvert(t *testing.T) {
   143  	fb := MessageQueryFactory.NewFilter(context.Background())
   144  	u := fftypes.MustParseUUID("3f96e0d5-a10e-47c6-87a0-f2e7604af179")
   145  	b32 := fftypes.UUIDBytes(u)
   146  	f, err := fb.And(
   147  		fb.Lt("namespace", int(111)),
   148  		fb.Lt("namespace", int32(222)),
   149  		fb.Lt("namespace", int64(333)),
   150  		fb.Lt("namespace", uint(444)),
   151  		fb.Lt("namespace", uint32(555)),
   152  		fb.Lt("namespace", uint64(666)),
   153  		fb.Lt("namespace", nil),
   154  		fb.Lt("namespace", *u),
   155  		fb.Lt("namespace", u),
   156  		fb.Lt("namespace", *b32),
   157  		fb.Lt("namespace", b32),
   158  	).Finalize()
   159  	assert.NoError(t, err)
   160  	assert.Equal(t, "( namespace < '111' ) && ( namespace < '222' ) && ( namespace < '333' ) && ( namespace < '444' ) && ( namespace < '555' ) && ( namespace < '666' ) && ( namespace < '' ) && ( namespace < '3f96e0d5-a10e-47c6-87a0-f2e7604af179' ) && ( namespace < '3f96e0d5-a10e-47c6-87a0-f2e7604af179' ) && ( namespace < '3f96e0d5a10e47c687a0f2e7604af17900000000000000000000000000000000' ) && ( namespace < '3f96e0d5a10e47c687a0f2e7604af17900000000000000000000000000000000' )", f.String())
   161  }
   162  
   163  func TestBuildMessageBoolConvert(t *testing.T) {
   164  	fb := PinQueryFactory.NewFilter(context.Background())
   165  	f, err := fb.And(
   166  		fb.Eq("masked", false),
   167  		fb.Eq("masked", true),
   168  		fb.Eq("masked", "false"),
   169  		fb.Eq("masked", "true"),
   170  		fb.Eq("masked", "True"),
   171  		fb.Eq("masked", ""),
   172  		fb.Eq("masked", int(111)),
   173  		fb.Eq("masked", int32(222)),
   174  		fb.Eq("masked", int64(333)),
   175  		fb.Eq("masked", uint(444)),
   176  		fb.Eq("masked", uint32(555)),
   177  		fb.Eq("masked", uint64(666)),
   178  		fb.Eq("masked", nil),
   179  	).Finalize()
   180  	assert.NoError(t, err)
   181  	assert.Equal(t, "( masked == false ) && ( masked == true ) && ( masked == false ) && ( masked == true ) && ( masked == true ) && ( masked == false ) && ( masked == true ) && ( masked == true ) && ( masked == true ) && ( masked == true ) && ( masked == true ) && ( masked == true ) && ( masked == false )", f.String())
   182  }
   183  
   184  func TestBuildMessageJSONConvert(t *testing.T) {
   185  	fb := TransactionQueryFactory.NewFilter(context.Background())
   186  	f, err := fb.And(
   187  		fb.Eq("info", nil),
   188  		fb.Eq("info", `{}`),
   189  		fb.Eq("info", []byte(`{}`)),
   190  		fb.Eq("info", fftypes.JSONObject{"some": "value"}),
   191  	).Finalize()
   192  	assert.NoError(t, err)
   193  	assert.Equal(t, `( info == null ) && ( info == '{}' ) && ( info == '{}' ) && ( info == '{"some":"value"}' )`, f.String())
   194  }
   195  
   196  func TestBuildFFNameArrayConvert(t *testing.T) {
   197  	fb := MessageQueryFactory.NewFilter(context.Background())
   198  	f, err := fb.And(
   199  		fb.Eq("topics", nil),
   200  		fb.Eq("topics", `test1`),
   201  		fb.Eq("topics", []byte(`test2`)),
   202  	).Finalize()
   203  	assert.NoError(t, err)
   204  	assert.Equal(t, `( topics == '' ) && ( topics == 'test1' ) && ( topics == 'test2' )`, f.String())
   205  }
   206  
   207  func TestBuildMessageFailStringConvert(t *testing.T) {
   208  	fb := MessageQueryFactory.NewFilter(context.Background())
   209  	_, err := fb.Lt("namespace", map[bool]bool{true: false}).Finalize()
   210  	assert.Regexp(t, "FF10149.*namespace", err)
   211  }
   212  
   213  func TestBuildMessageFailBoolConvert(t *testing.T) {
   214  	fb := PinQueryFactory.NewFilter(context.Background())
   215  	_, err := fb.Lt("masked", map[bool]bool{true: false}).Finalize()
   216  	assert.Regexp(t, "FF10149.*masked", err)
   217  }
   218  
   219  func TestBuildMessageFailInt64Convert(t *testing.T) {
   220  	fb := MessageQueryFactory.NewFilter(context.Background())
   221  	_, err := fb.Lt("sequence", map[bool]bool{true: false}).Finalize()
   222  	assert.Regexp(t, "FF10149.*sequence", err)
   223  }
   224  
   225  func TestBuildMessageFailTimeConvert(t *testing.T) {
   226  	fb := MessageQueryFactory.NewFilter(context.Background())
   227  	_, err := fb.Lt("created", map[bool]bool{true: false}).Finalize()
   228  	assert.Regexp(t, "FF10149.*created", err)
   229  }
   230  
   231  func TestQueryFactoryBadField(t *testing.T) {
   232  	fb := MessageQueryFactory.NewFilter(context.Background())
   233  	_, err := fb.And(
   234  		fb.Eq("wrong", "ns1"),
   235  	).Finalize()
   236  	assert.Regexp(t, "FF10148.*wrong", err)
   237  }
   238  
   239  func TestQueryFactoryBadValue(t *testing.T) {
   240  	fb := MessageQueryFactory.NewFilter(context.Background())
   241  	_, err := fb.And(
   242  		fb.Eq("sequence", "not an int"),
   243  	).Finalize()
   244  	assert.Regexp(t, "FF10149.*sequence", err)
   245  }
   246  
   247  func TestQueryFactoryBadNestedValue(t *testing.T) {
   248  	fb := MessageQueryFactory.NewFilter(context.Background())
   249  	_, err := fb.And(
   250  		fb.And(
   251  			fb.Eq("sequence", "not an int"),
   252  		),
   253  	).Finalize()
   254  	assert.Regexp(t, "FF10149.*sequence", err)
   255  }
   256  
   257  func TestQueryFactoryGetFields(t *testing.T) {
   258  	fb := MessageQueryFactory.NewFilter(context.Background())
   259  	assert.NotNil(t, fb.Fields())
   260  }
   261  
   262  func TestQueryFactoryGetBuilder(t *testing.T) {
   263  	fb := MessageQueryFactory.NewFilter(context.Background()).Gt("sequence", 0)
   264  	assert.NotNil(t, fb.Builder())
   265  }
   266  
   267  func TestBuildMessageFailJSONConvert(t *testing.T) {
   268  	fb := TransactionQueryFactory.NewFilter(context.Background())
   269  	_, err := fb.Lt("info", map[bool]bool{true: false}).Finalize()
   270  	assert.Regexp(t, "FF10149.*info", err)
   271  }
   272  
   273  func TestStringsForTypes(t *testing.T) {
   274  
   275  	assert.Equal(t, "test", (&stringField{s: "test"}).String())
   276  	assert.Equal(t, "037a025d-681d-4150-a413-05f368729c66", (&uuidField{fftypes.MustParseUUID("037a025d-681d-4150-a413-05f368729c66")}).String())
   277  	assert.Equal(t, "12345", (&int64Field{i: 12345}).String())
   278  	now := fftypes.Now()
   279  	assert.Equal(t, now.String(), (&timeField{t: now}).String())
   280  	assert.Equal(t, `{"some":"value"}`, (&jsonField{b: []byte(`{"some":"value"}`)}).String())
   281  	assert.Equal(t, "t1,t2", (&ffNameArrayField{na: fftypes.FFNameArray{"t1", "t2"}}).String())
   282  	assert.Equal(t, "true", (&boolField{b: true}).String())
   283  }