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 }