github.com/MontFerret/ferret@v0.18.0/pkg/compiler/compiler_filter_test.go (about) 1 package compiler_test 2 3 import ( 4 "context" 5 "testing" 6 7 . "github.com/smartystreets/goconvey/convey" 8 9 "github.com/MontFerret/ferret/pkg/compiler" 10 "github.com/MontFerret/ferret/pkg/runtime/core" 11 "github.com/MontFerret/ferret/pkg/runtime/values" 12 ) 13 14 func TestForFilter(t *testing.T) { 15 Convey("Should compile query with FILTER i > 2", t, func() { 16 c := compiler.New() 17 18 p, err := c.Compile(` 19 FOR i IN [ 1, 2, 3, 4, 1, 3 ] 20 FILTER i > 2 21 RETURN i 22 `) 23 24 So(err, ShouldBeNil) 25 26 out, err := p.Run(context.Background()) 27 28 So(err, ShouldBeNil) 29 30 So(string(out), ShouldEqual, `[3,4,3]`) 31 }) 32 33 Convey("Should compile query with FILTER i > 1 AND i < 3", t, func() { 34 c := compiler.New() 35 36 p, err := c.Compile(` 37 FOR i IN [ 1, 2, 3, 4, 1, 3 ] 38 FILTER i > 1 AND i < 4 39 RETURN i 40 `) 41 42 So(err, ShouldBeNil) 43 44 out, err := p.Run(context.Background()) 45 46 So(err, ShouldBeNil) 47 48 So(string(out), ShouldEqual, `[2,3,3]`) 49 }) 50 51 Convey("Should compile query with a regexp FILTER statement", t, func() { 52 c := compiler.New() 53 54 p, err := c.Compile(` 55 LET users = [ 56 { 57 age: 31, 58 gender: "m", 59 name: "Josh" 60 }, 61 { 62 age: 29, 63 gender: "f", 64 name: "Mary" 65 }, 66 { 67 age: 36, 68 gender: "m", 69 name: "Peter" 70 } 71 ] 72 FOR u IN users 73 FILTER u.name =~ "r" 74 RETURN u 75 `) 76 77 So(err, ShouldBeNil) 78 79 out, err := p.Run(context.Background()) 80 81 So(err, ShouldBeNil) 82 83 So(string(out), ShouldEqual, `[{"age":29,"gender":"f","name":"Mary"},{"age":36,"gender":"m","name":"Peter"}]`) 84 }) 85 86 Convey("Should compile query with multiple FILTER statements", t, func() { 87 c := compiler.New() 88 89 p, err := c.Compile(` 90 LET users = [ 91 { 92 active: true, 93 age: 31, 94 gender: "m" 95 }, 96 { 97 active: true, 98 age: 29, 99 gender: "f" 100 }, 101 { 102 active: true, 103 age: 36, 104 gender: "m" 105 } 106 ] 107 FOR u IN users 108 FILTER u.active == true 109 FILTER u.age < 35 110 RETURN u 111 `) 112 113 So(err, ShouldBeNil) 114 115 out, err := p.Run(context.Background()) 116 117 So(err, ShouldBeNil) 118 119 So(string(out), ShouldEqual, `[{"active":true,"age":31,"gender":"m"},{"active":true,"age":29,"gender":"f"}]`) 120 }) 121 122 Convey("Should compile query with multiple FILTER statements", t, func() { 123 c := compiler.New() 124 125 p, err := c.Compile(` 126 LET users = [ 127 { 128 active: true, 129 age: 31, 130 gender: "m" 131 }, 132 { 133 active: true, 134 age: 29, 135 gender: "f" 136 }, 137 { 138 active: true, 139 age: 36, 140 gender: "m" 141 }, 142 { 143 active: false, 144 age: 69, 145 gender: "m" 146 } 147 ] 148 FOR u IN users 149 FILTER u.active == true 150 LIMIT 2 151 FILTER u.gender == "m" 152 RETURN u 153 `) 154 155 So(err, ShouldBeNil) 156 157 out, err := p.Run(context.Background()) 158 159 So(err, ShouldBeNil) 160 161 So(string(out), ShouldEqual, `[{"active":true,"age":31,"gender":"m"}]`) 162 }) 163 164 Convey("Should compile query with left side expression", t, func() { 165 c := compiler.New() 166 167 p, err := c.Compile(` 168 LET users = [ 169 { 170 active: true, 171 age: 31, 172 gender: "m" 173 }, 174 { 175 active: true, 176 age: 29, 177 gender: "f" 178 }, 179 { 180 active: true, 181 age: 36, 182 gender: "m" 183 }, 184 { 185 active: false, 186 age: 69, 187 gender: "m" 188 } 189 ] 190 FOR u IN users 191 FILTER u.active 192 RETURN u 193 `) 194 195 So(err, ShouldBeNil) 196 197 out, err := p.Run(context.Background()) 198 199 So(err, ShouldBeNil) 200 201 So(string(out), ShouldEqual, `[{"active":true,"age":31,"gender":"m"},{"active":true,"age":29,"gender":"f"},{"active":true,"age":36,"gender":"m"}]`) 202 }) 203 204 Convey("Should compile query with multiple left side expression", t, func() { 205 c := compiler.New() 206 207 p, err := c.Compile(` 208 LET users = [ 209 { 210 active: true, 211 married: true, 212 age: 31, 213 gender: "m" 214 }, 215 { 216 active: true, 217 married: false, 218 age: 25, 219 gender: "f" 220 }, 221 { 222 active: true, 223 married: false, 224 age: 36, 225 gender: "m" 226 }, 227 { 228 active: false, 229 married: true, 230 age: 69, 231 gender: "m" 232 }, 233 { 234 active: true, 235 married: true, 236 age: 45, 237 gender: "f" 238 } 239 ] 240 FOR u IN users 241 FILTER u.active AND u.married 242 RETURN u 243 `) 244 245 So(err, ShouldBeNil) 246 247 out, err := p.Run(context.Background()) 248 249 So(err, ShouldBeNil) 250 251 So(string(out), ShouldEqual, `[{"active":true,"age":31,"gender":"m","married":true},{"active":true,"age":45,"gender":"f","married":true}]`) 252 }) 253 254 Convey("Should compile query with multiple left side expression and with binary operator", t, func() { 255 c := compiler.New() 256 257 p, err := c.Compile(` 258 LET users = [ 259 { 260 active: true, 261 married: true, 262 age: 31, 263 gender: "m" 264 }, 265 { 266 active: true, 267 married: false, 268 age: 25, 269 gender: "f" 270 }, 271 { 272 active: true, 273 married: false, 274 age: 36, 275 gender: "m" 276 }, 277 { 278 active: false, 279 married: true, 280 age: 69, 281 gender: "m" 282 }, 283 { 284 active: true, 285 married: true, 286 age: 45, 287 gender: "f" 288 } 289 ] 290 FOR u IN users 291 FILTER !u.active AND u.married 292 RETURN u 293 `) 294 295 So(err, ShouldBeNil) 296 297 out, err := p.Run(context.Background()) 298 299 So(err, ShouldBeNil) 300 301 So(string(out), ShouldEqual, `[{"active":false,"age":69,"gender":"m","married":true}]`) 302 }) 303 304 Convey("Should compile query with multiple left side expression and with binary operator 2", t, func() { 305 c := compiler.New() 306 307 p, err := c.Compile(` 308 LET users = [ 309 { 310 active: true, 311 married: true, 312 age: 31, 313 gender: "m" 314 }, 315 { 316 active: true, 317 married: false, 318 age: 25, 319 gender: "f" 320 }, 321 { 322 active: true, 323 married: false, 324 age: 36, 325 gender: "m" 326 }, 327 { 328 active: false, 329 married: true, 330 age: 69, 331 gender: "m" 332 }, 333 { 334 active: true, 335 married: true, 336 age: 45, 337 gender: "f" 338 } 339 ] 340 FOR u IN users 341 FILTER !u.active AND !u.married 342 RETURN u 343 `) 344 345 So(err, ShouldBeNil) 346 347 out, err := p.Run(context.Background()) 348 349 So(err, ShouldBeNil) 350 351 So(string(out), ShouldEqual, `[]`) 352 }) 353 354 Convey("Should define variables", t, func() { 355 c := compiler.New() 356 357 p, err := c.Compile(` 358 FOR i IN [ 1, 2, 3, 4, 1, 3 ] 359 LET x = 2 360 FILTER i > x 361 RETURN i + x 362 `) 363 364 So(err, ShouldBeNil) 365 366 out, err := p.Run(context.Background()) 367 368 So(err, ShouldBeNil) 369 370 So(string(out), ShouldEqual, `[5,6,5]`) 371 }) 372 373 Convey("Should call functions", t, func() { 374 c := compiler.New() 375 counterA := 0 376 counterB := 0 377 c.RegisterFunction("COUNT_A", func(ctx context.Context, args ...core.Value) (core.Value, error) { 378 counterA++ 379 380 return values.None, nil 381 }) 382 383 c.RegisterFunction("COUNT_B", func(ctx context.Context, args ...core.Value) (core.Value, error) { 384 counterB++ 385 386 return values.None, nil 387 }) 388 389 p, err := c.Compile(` 390 FOR i IN [ 1, 2, 3, 4, 1, 3 ] 391 LET x = 2 392 COUNT_A() 393 FILTER i > x 394 COUNT_B() 395 RETURN i + x 396 `) 397 398 So(err, ShouldBeNil) 399 400 out, err := p.Run(context.Background()) 401 402 So(err, ShouldBeNil) 403 So(counterA, ShouldEqual, 6) 404 So(counterB, ShouldEqual, 3) 405 So(string(out), ShouldEqual, `[5,6,5]`) 406 }) 407 } 408 409 func BenchmarkFilter(b *testing.B) { 410 p := compiler.New().MustCompile(` 411 LET users = [ 412 { 413 active: true, 414 age: 31, 415 gender: "m" 416 }, 417 { 418 active: true, 419 age: 29, 420 gender: "f" 421 }, 422 { 423 active: true, 424 age: 36, 425 gender: "m" 426 }, 427 { 428 active: false, 429 age: 69, 430 gender: "m" 431 } 432 ] 433 FOR u IN users 434 FILTER u.age < 35 435 RETURN u 436 `) 437 438 for n := 0; n < b.N; n++ { 439 p.Run(context.Background()) 440 } 441 } 442 443 func BenchmarkFilter2(b *testing.B) { 444 p := compiler.New().MustCompile(` 445 LET users = [ 446 { 447 active: true, 448 age: 31, 449 gender: "m" 450 }, 451 { 452 active: true, 453 age: 29, 454 gender: "f" 455 }, 456 { 457 active: true, 458 age: 36, 459 gender: "m" 460 }, 461 { 462 active: false, 463 age: 69, 464 gender: "m" 465 } 466 ] 467 FOR u IN users 468 FILTER u.active == true 469 FILTER u.age < 35 470 RETURN u 471 `) 472 473 for n := 0; n < b.N; n++ { 474 p.Run(context.Background()) 475 } 476 } 477 478 func BenchmarkFilter3(b *testing.B) { 479 p := compiler.New().MustCompile(` 480 LET users = [ 481 { 482 active: true, 483 age: 31, 484 gender: "m" 485 }, 486 { 487 active: true, 488 age: 29, 489 gender: "f" 490 }, 491 { 492 active: true, 493 age: 36, 494 gender: "m" 495 }, 496 { 497 active: false, 498 age: 69, 499 gender: "m" 500 } 501 ] 502 FOR u IN users 503 FILTER u.active == true 504 LIMIT 2 505 FILTER u.gender == "m" 506 RETURN u 507 `) 508 509 for n := 0; n < b.N; n++ { 510 p.Run(context.Background()) 511 } 512 } 513 514 func BenchmarkFilter4(b *testing.B) { 515 p := compiler.New().MustCompile(` 516 LET users = [ 517 { 518 active: true, 519 married: true, 520 age: 31, 521 gender: "m" 522 }, 523 { 524 active: true, 525 married: false, 526 age: 25, 527 gender: "f" 528 }, 529 { 530 active: true, 531 married: false, 532 age: 36, 533 gender: "m" 534 }, 535 { 536 active: false, 537 married: true, 538 age: 69, 539 gender: "m" 540 }, 541 { 542 active: true, 543 married: true, 544 age: 45, 545 gender: "f" 546 } 547 ] 548 FOR u IN users 549 FILTER !u.active AND u.married 550 LIMIT 2 551 RETURN u 552 `) 553 554 for n := 0; n < b.N; n++ { 555 p.Run(context.Background()) 556 } 557 }