@@ -40,7 +40,7 @@ func TestCost(t *testing.T) {
40
40
nestedMap := types .NewMapType (types .StringType , allMap )
41
41
42
42
zeroCost := CostEstimate {}
43
- oneCost := CostEstimate { Min : 1 , Max : 1 }
43
+ oneCost := FixedCostEstimate ( 1 )
44
44
cases := []struct {
45
45
name string
46
46
expr string
@@ -255,6 +255,11 @@ func TestCost(t *testing.T) {
255
255
expr : `size("123")` ,
256
256
wanted : oneCost ,
257
257
},
258
+ {
259
+ name : "bytes size" ,
260
+ expr : `size(b"123")` ,
261
+ wanted : oneCost ,
262
+ },
258
263
{
259
264
name : "bytes to string conversion" ,
260
265
vars : []* decls.VariableDecl {decls .NewVariable ("input" , types .BytesType )},
@@ -462,6 +467,36 @@ func TestCost(t *testing.T) {
462
467
},
463
468
wanted : CostEstimate {Min : 5 , Max : 5 },
464
469
},
470
+ {
471
+ name : "list size from concat" ,
472
+ expr : `([x, y] + list1 + list2).size()` ,
473
+ vars : []* decls.VariableDecl {
474
+ decls .NewVariable ("x" , types .IntType ),
475
+ decls .NewVariable ("y" , types .IntType ),
476
+ decls .NewVariable ("list1" , types .NewListType (types .IntType )),
477
+ decls .NewVariable ("list2" , types .NewListType (types .IntType )),
478
+ },
479
+ hints : map [string ]uint64 {
480
+ "list1" : 10 ,
481
+ "list2" : 20 ,
482
+ },
483
+ wanted : CostEstimate {Min : 17 , Max : 17 },
484
+ },
485
+ {
486
+ name : "list cost tracking through comprehension" ,
487
+ expr : `[list1, list2].exists(l, l.exists(v, v.startsWith('hi')))` ,
488
+ vars : []* decls.VariableDecl {
489
+ decls .NewVariable ("list1" , types .NewListType (types .StringType )),
490
+ decls .NewVariable ("list2" , types .NewListType (types .StringType )),
491
+ },
492
+ hints : map [string ]uint64 {
493
+ "list1" : 10 ,
494
+ "list1.@items" : 64 ,
495
+ "list2" : 20 ,
496
+ "list2.@items" : 128 ,
497
+ },
498
+ wanted : CostEstimate {Min : 21 , Max : 265 },
499
+ },
465
500
{
466
501
name : "str endsWith equality" ,
467
502
expr : `str1.endsWith("abcdefghijklmnopqrstuvwxyz") == str2.endsWith("abcdefghijklmnopqrstuvwxyz")` ,
@@ -539,27 +574,37 @@ func TestCost(t *testing.T) {
539
574
wanted : CostEstimate {Min : 61 , Max : 61 },
540
575
},
541
576
{
542
- name : "nested array selection" ,
577
+ name : "nested map selection" ,
543
578
expr : `{'a': [1,2], 'b': [1,2], 'c': [1,2], 'd': [1,2], 'e': [1,2]}.b` ,
544
579
wanted : CostEstimate {Min : 81 , Max : 81 },
545
580
},
546
581
{
547
- // Estimated cost does not track the sizes of nested aggregate types
548
- // (lists, maps, ...) and so assumes a worst case cost when an
549
- // expression applies a comprehension to a nested aggregated type,
550
- // even if the size information is available.
551
- // TODO: This should be fixed.
552
582
name : "comprehension on nested list" ,
583
+ expr : `[[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]].all(y, y.all(y, y == 1))` ,
584
+ wanted : CostEstimate {Min : 76 , Max : 136 },
585
+ },
586
+ {
587
+ name : "comprehension on transformed nested list" ,
553
588
expr : `[1,2,3,4,5].map(x, [x, x]).all(y, y.all(y, y == 1))` ,
554
- wanted : CostEstimate {Min : 157 , Max : 18446744073709551615 },
589
+ wanted : CostEstimate {Min : 157 , Max : 217 },
555
590
},
556
591
{
557
- // Make sure we're accounting for not just the iteration range size,
558
- // but also the overall comprehension size. The chained map calls
559
- // will treat the result of one map as the iteration range of the other,
560
- // so they're planned in reverse; however, the `+` should verify that
561
- // the comprehension result has a size.
562
- name : "comprehension size" ,
592
+ name : "comprehension on nested literal list" ,
593
+ expr : `["a", "ab", "abc", "abcd", "abcde"].map(x, [x, x]).all(y, y.all(y, y.startsWith('a')))` ,
594
+ wanted : CostEstimate {Min : 157 , Max : 217 },
595
+ },
596
+ {
597
+ name : "comprehension on nested variable list" ,
598
+ expr : `input.map(x, [x, x]).all(y, y.all(y, y.startsWith('a')))` ,
599
+ vars : []* decls.VariableDecl {decls .NewVariable ("input" , types .NewListType (types .StringType ))},
600
+ hints : map [string ]uint64 {
601
+ "input" : 5 ,
602
+ "input.@items" : 10 ,
603
+ },
604
+ wanted : CostEstimate {Min : 13 , Max : 208 },
605
+ },
606
+ {
607
+ name : "comprehension chaining with concat" ,
563
608
expr : `[1,2,3,4,5].map(x, x).map(x, x) + [1]` ,
564
609
wanted : CostEstimate {Min : 173 , Max : 173 },
565
610
},
@@ -568,9 +613,25 @@ func TestCost(t *testing.T) {
568
613
expr : `[1,2,3].all(i, i in [1,2,3].map(j, j + j))` ,
569
614
wanted : CostEstimate {Min : 20 , Max : 230 },
570
615
},
616
+ {
617
+ name : "nested dyn comprehension" ,
618
+ expr : `dyn([1,2,3]).all(i, i in dyn([1,2,3]).map(j, j + j))` ,
619
+ wanted : CostEstimate {Min : 21 , Max : 234 },
620
+ },
621
+ {
622
+ name : "literal map access" ,
623
+ expr : `{'hello': 'hi'}['hello'] != {'hello': 'bye'}['hello']` ,
624
+ wanted : CostEstimate {Min : 63 , Max : 63 },
625
+ },
626
+ {
627
+ name : "literal list access" ,
628
+ expr : `['hello', 'hi'][0] != ['hello', 'bye'][1]` ,
629
+ wanted : CostEstimate {Min : 23 , Max : 23 },
630
+ },
571
631
}
572
632
573
- for _ , tc := range cases {
633
+ for _ , tst := range cases {
634
+ tc := tst
574
635
t .Run (tc .name , func (t * testing.T ) {
575
636
if tc .hints == nil {
576
637
tc .hints = map [string ]uint64 {}
0 commit comments