github.com/ravendb/ravendb-go-client@v0.0.0-20240229102137-4474ee7aa0fa/tests/aggregation_test.go (about) 1 package tests 2 3 import ( 4 "testing" 5 "time" 6 7 ravendb "github.com/ravendb/ravendb-go-client" 8 "github.com/stretchr/testify/assert" 9 ) 10 11 func NewOrdersAll() *ravendb.IndexCreationTask { 12 res := ravendb.NewIndexCreationTask("Orders_All") 13 res.Map = `docs.AggOrders.Select(order => new { order.currency, 14 order.product, 15 order.total, 16 order.quantity, 17 order.region, 18 order.at, 19 order.tax })` 20 return res 21 } 22 23 type Currency = string 24 25 // Note: must rename as it conflicts with Order in order_test.go 26 type AggOrder struct { 27 Currency Currency `json:"currency"` 28 Product string `json:"product"` 29 Total float64 `json:"total"` 30 Region int `json:"region"` 31 } 32 33 const ( 34 EUR = "EUR" 35 PLN = "PLN" 36 NIS = "NIS" 37 ) 38 39 func aggregation_canCorrectlyAggregate_Double(t *testing.T, driver *RavenTestDriver) { 40 41 var err error 42 store := driver.getDocumentStoreMust(t) 43 defer store.Close() 44 45 index := NewOrdersAll() 46 err = index.Execute(store, nil, "") 47 assert.NoError(t, err) 48 49 { 50 session := openSessionMust(t, store) 51 obj := &AggOrder{ 52 Currency: EUR, 53 Product: "Milk", 54 Total: 1.1, 55 Region: 1, 56 } 57 58 obj2 := &AggOrder{ 59 Currency: EUR, 60 Product: "Milk", 61 Total: 1, 62 Region: 1, 63 } 64 err = session.Store(obj) 65 assert.NoError(t, err) 66 err = session.Store(obj2) 67 assert.NoError(t, err) 68 69 err = session.SaveChanges() 70 assert.NoError(t, err) 71 72 session.Close() 73 } 74 75 err = driver.waitForIndexing(store, "", 0) 76 assert.NoError(t, err) 77 78 { 79 session := openSessionMust(t, store) 80 81 q := session.QueryIndex(index.IndexName) 82 f := ravendb.NewFacetBuilder() 83 f.ByField("region").MaxOn("total").MinOn("total") 84 q2 := q.AggregateByFacet(f.GetFacet()) 85 result, err := q2.Execute() 86 assert.NoError(t, err) 87 88 facetResult := result["region"] 89 90 values := facetResult.Values 91 val := values[0] 92 assert.Equal(t, val.Count, 2) 93 assert.Equal(t, *val.Min, float64(1)) 94 assert.Equal(t, *val.Max, float64(1.1)) 95 96 n := 0 97 for _, x := range values { 98 if x.Range == "1" { 99 n++ 100 } 101 } 102 assert.Equal(t, n, 1) 103 104 session.Close() 105 } 106 } 107 108 func getFirstFacetValueOfRange(values []*ravendb.FacetValue, rang string) *ravendb.FacetValue { 109 for _, x := range values { 110 if x.Range == rang { 111 return x 112 } 113 } 114 return nil 115 } 116 117 func aggregationCanCorrectlyAggregateMultipleItems(t *testing.T, driver *RavenTestDriver) { 118 var err error 119 store := driver.getDocumentStoreMust(t) 120 defer store.Close() 121 122 index := NewOrdersAll() 123 err = index.Execute(store, nil, "") 124 assert.NoError(t, err) 125 126 { 127 session := openSessionMust(t, store) 128 obj := &AggOrder{ 129 Currency: EUR, 130 Product: "Milk", 131 Total: 3, 132 } 133 134 obj2 := &AggOrder{ 135 Currency: NIS, 136 Product: "Milk", 137 Total: 9, 138 } 139 140 obj3 := &AggOrder{ 141 Currency: EUR, 142 Product: "iPhone", 143 Total: 3333, 144 } 145 146 err = session.Store(obj) 147 assert.NoError(t, err) 148 err = session.Store(obj2) 149 assert.NoError(t, err) 150 err = session.Store(obj3) 151 assert.NoError(t, err) 152 153 err = session.SaveChanges() 154 assert.NoError(t, err) 155 156 session.Close() 157 } 158 159 err = driver.waitForIndexing(store, "", 0) 160 assert.NoError(t, err) 161 162 { 163 session := openSessionMust(t, store) 164 165 q := session.QueryIndex(index.IndexName) 166 f := ravendb.NewFacetBuilder() 167 f.ByField("product").SumOn("total") 168 q2 := q.AggregateByFacet(f.GetFacet()) 169 f = ravendb.NewFacetBuilder() 170 f.ByField("currency").SumOn("total") 171 q2 = q2.AndAggregateByFacet(f.GetFacet()) 172 r, err := q2.Execute() 173 assert.NoError(t, err) 174 175 facetResult := r["product"] 176 177 values := facetResult.Values 178 assert.Equal(t, len(values), 2) 179 180 x := getFirstFacetValueOfRange(values, "milk") 181 assert.Equal(t, *x.Sum, float64(12)) 182 183 x = getFirstFacetValueOfRange(values, "iphone") 184 assert.Equal(t, *x.Sum, float64(3333)) 185 186 facetResult = r["currency"] 187 values = facetResult.Values 188 assert.Equal(t, len(values), 2) 189 190 x = getFirstFacetValueOfRange(values, "eur") 191 assert.Equal(t, *x.Sum, float64(3336)) 192 193 x = getFirstFacetValueOfRange(values, "nis") 194 assert.Equal(t, *x.Sum, float64(9)) 195 196 session.Close() 197 } 198 } 199 200 func aggregationCanCorrectlyAggregateMultipleAggregations(t *testing.T, driver *RavenTestDriver) { 201 var err error 202 store := driver.getDocumentStoreMust(t) 203 defer store.Close() 204 205 index := NewOrdersAll() 206 err = index.Execute(store, nil, "") 207 assert.NoError(t, err) 208 209 { 210 session := openSessionMust(t, store) 211 obj := &AggOrder{ 212 Currency: EUR, 213 Product: "Milk", 214 Total: 3, 215 } 216 217 obj2 := &AggOrder{ 218 Currency: NIS, 219 Product: "Milk", 220 Total: 9, 221 } 222 223 obj3 := &AggOrder{ 224 Currency: EUR, 225 Product: "iPhone", 226 Total: 3333, 227 } 228 229 err = session.Store(obj) 230 assert.NoError(t, err) 231 err = session.Store(obj2) 232 assert.NoError(t, err) 233 err = session.Store(obj3) 234 assert.NoError(t, err) 235 236 err = session.SaveChanges() 237 assert.NoError(t, err) 238 239 session.Close() 240 } 241 242 err = driver.waitForIndexing(store, "", 0) 243 assert.NoError(t, err) 244 245 { 246 session := openSessionMust(t, store) 247 248 q := session.QueryIndex(index.IndexName) 249 f := ravendb.NewFacetBuilder() 250 f.ByField("product").MaxOn("total").MinOn("total") 251 q2 := q.AggregateByFacet(f.GetFacet()) 252 r, err := q2.Execute() 253 assert.NoError(t, err) 254 255 facetResult := r["product"] 256 values := facetResult.Values 257 assert.Equal(t, len(values), 2) 258 259 x := getFirstFacetValueOfRange(values, "milk") 260 assert.Equal(t, *x.Max, float64(9)) 261 assert.Equal(t, *x.Min, float64(3)) 262 263 x = getFirstFacetValueOfRange(values, "iphone") 264 assert.Equal(t, *x.Max, float64(3333)) 265 assert.Equal(t, *x.Min, float64(3333)) 266 267 session.Close() 268 } 269 } 270 271 func aggregationCanCorrectlyAggregateDisplayName(t *testing.T, driver *RavenTestDriver) { 272 var err error 273 store := driver.getDocumentStoreMust(t) 274 defer store.Close() 275 276 index := NewOrdersAll() 277 err = index.Execute(store, nil, "") 278 assert.NoError(t, err) 279 280 { 281 session := openSessionMust(t, store) 282 obj := &AggOrder{ 283 Currency: EUR, 284 Product: "Milk", 285 Total: 3, 286 } 287 288 obj2 := &AggOrder{ 289 Currency: NIS, 290 Product: "Milk", 291 Total: 9, 292 } 293 294 obj3 := &AggOrder{ 295 Currency: EUR, 296 Product: "iPhone", 297 Total: 3333, 298 } 299 300 err = session.Store(obj) 301 assert.NoError(t, err) 302 err = session.Store(obj2) 303 assert.NoError(t, err) 304 err = session.Store(obj3) 305 assert.NoError(t, err) 306 307 err = session.SaveChanges() 308 assert.NoError(t, err) 309 310 session.Close() 311 } 312 313 err = driver.waitForIndexing(store, "", 0) 314 assert.NoError(t, err) 315 316 { 317 session := openSessionMust(t, store) 318 319 q := session.QueryIndex(index.IndexName) 320 f := ravendb.NewFacetBuilder() 321 f.ByField("product").WithDisplayName("productMax").MaxOn("total") 322 q2 := q.AggregateByFacet(f.GetFacet()) 323 f = ravendb.NewFacetBuilder() 324 f.ByField("product").WithDisplayName("productMin") 325 q2 = q2.AndAggregateByFacet(f.GetFacet()) 326 r, err := q2.Execute() 327 assert.NoError(t, err) 328 329 assert.Equal(t, len(r), 2) 330 assert.Equal(t, *r["productMax"].Values[0].Max, float64(3333)) 331 assert.Equal(t, r["productMin"].Values[1].Count, 2) 332 333 session.Close() 334 } 335 } 336 337 func aggregationCanCorrectlyAggregateRanges(t *testing.T, driver *RavenTestDriver) { 338 var err error 339 store := driver.getDocumentStoreMust(t) 340 defer store.Close() 341 342 index := NewOrdersAll() 343 err = index.Execute(store, nil, "") 344 assert.NoError(t, err) 345 346 { 347 session := openSessionMust(t, store) 348 obj := &AggOrder{ 349 Currency: EUR, 350 Product: "Milk", 351 Total: 3, 352 } 353 354 obj2 := &AggOrder{ 355 Currency: NIS, 356 Product: "Milk", 357 Total: 9, 358 } 359 360 obj3 := &AggOrder{ 361 Currency: EUR, 362 Product: "iPhone", 363 Total: 3333, 364 } 365 366 err = session.Store(obj) 367 assert.NoError(t, err) 368 err = session.Store(obj2) 369 assert.NoError(t, err) 370 err = session.Store(obj3) 371 assert.NoError(t, err) 372 373 err = session.SaveChanges() 374 assert.NoError(t, err) 375 376 session.Close() 377 } 378 379 err = driver.waitForIndexing(store, "", 0) 380 assert.NoError(t, err) 381 382 { 383 session := openSessionMust(t, store) 384 _range := ravendb.NewRangeBuilder("total") 385 386 q := session.QueryIndex(index.IndexName) 387 f := ravendb.NewFacetBuilder() 388 f.ByField("product").SumOn("total") 389 q2 := q.AggregateByFacet(f.GetFacet()) 390 f = ravendb.NewFacetBuilder() 391 fop := f.ByRanges( 392 _range.IsLessThan(100), 393 _range.IsGreaterThanOrEqualTo(100).IsLessThan(500), 394 _range.IsGreaterThanOrEqualTo(500).IsLessThan(1500), 395 _range.IsGreaterThanOrEqualTo(1500)) 396 fop.SumOn("total") 397 facet := f.GetFacet() 398 q2 = q2.AndAggregateByFacet(facet) 399 r, err := q2.Execute() 400 assert.NoError(t, err) 401 402 facetResult := r["product"] 403 values := facetResult.Values 404 assert.Equal(t, len(values), 2) 405 406 x := getFirstFacetValueOfRange(values, "milk") 407 assert.Equal(t, *x.Sum, float64(12)) 408 409 x = getFirstFacetValueOfRange(values, "iphone") 410 assert.Equal(t, *x.Sum, float64(3333)) 411 412 facetResult = r["total"] 413 values = facetResult.Values 414 assert.Equal(t, len(values), 4) 415 416 x = getFirstFacetValueOfRange(values, "total < 100") 417 assert.Equal(t, *x.Sum, float64(12)) 418 419 x = getFirstFacetValueOfRange(values, "total >= 1500") 420 assert.Equal(t, *x.Sum, float64(3333)) 421 422 session.Close() 423 } 424 } 425 426 func now() ravendb.Time { 427 return ravendb.Time(time.Now()) 428 } 429 430 func setYears(t2 ravendb.Time, nYear int) ravendb.Time { 431 t := time.Time(t2) 432 diff := nYear - t.Year() 433 t = t.AddDate(diff, 0, 0) 434 return ravendb.Time(t) 435 } 436 437 func addYears(t ravendb.Time, nYears int) ravendb.Time { 438 t2 := time.Time(t) 439 t2 = t2.AddDate(nYears, 0, 0) 440 return ravendb.Time(t2) 441 } 442 443 func addDays(t ravendb.Time, nDays int) ravendb.Time { 444 t2 := time.Time(t) 445 t2 = t2.Add(time.Hour * 24 * time.Duration(nDays)) 446 return ravendb.Time(t2) 447 } 448 449 func addHours(t ravendb.Time, nHours int) ravendb.Time { 450 t2 := time.Time(t) 451 t2 = t2.Add(time.Hour * time.Duration(nHours)) 452 return ravendb.Time(t2) 453 } 454 455 func addMinutes(t ravendb.Time, nMinutes int) ravendb.Time { 456 t2 := time.Time(t) 457 t2 = t2.Add(time.Minute * time.Duration(nMinutes)) 458 return ravendb.Time(t2) 459 } 460 461 func aggregationCanCorrectlyAggregateDateTimeDataTypeWithRangeCounts(t *testing.T, driver *RavenTestDriver) { 462 var err error 463 store := driver.getDocumentStoreMust(t) 464 defer store.Close() 465 466 index := NewItemsOrdersAll() 467 err = index.Execute(store, nil, "") 468 assert.NoError(t, err) 469 470 { 471 session := openSessionMust(t, store) 472 473 item1 := &ItemsOrder{ 474 Items: []string{"first", "second"}, 475 At: now(), 476 } 477 478 item2 := &ItemsOrder{ 479 Items: []string{"first", "second"}, 480 At: addDays(now(), -1), 481 } 482 483 item3 := &ItemsOrder{ 484 Items: []string{"first", "second"}, 485 At: now(), 486 } 487 488 item4 := &ItemsOrder{ 489 Items: []string{"first"}, 490 At: now(), 491 } 492 493 err = session.Store(item1) 494 assert.NoError(t, err) 495 err = session.Store(item2) 496 assert.NoError(t, err) 497 err = session.Store(item3) 498 assert.NoError(t, err) 499 err = session.Store(item4) 500 assert.NoError(t, err) 501 err = session.SaveChanges() 502 assert.NoError(t, err) 503 504 session.Close() 505 } 506 507 minValue := setYears(now(), 1980) 508 509 end0 := addDays(now(), -2) 510 end1 := addDays(now(), -1) 511 end2 := now() 512 513 err = driver.waitForIndexing(store, "", 0) 514 assert.NoError(t, err) 515 516 builder := ravendb.NewRangeBuilder("at") 517 518 { 519 session := openSessionMust(t, store) 520 q := session.QueryIndex(index.IndexName) 521 q = q.WhereGreaterThanOrEqual("at", end0) 522 f := ravendb.NewFacetBuilder() 523 r1 := builder.IsGreaterThanOrEqualTo(minValue) // all - 4 524 r2 := builder.IsGreaterThanOrEqualTo(end0).IsLessThan(end1) // 1 525 r3 := builder.IsGreaterThanOrEqualTo(end1).IsLessThan(end2) // 3 526 f.ByRanges(r1, r2, r3) 527 q2 := q.AggregateByFacet(f.GetFacet()) 528 r, err := q2.Execute() 529 assert.NoError(t, err) 530 531 facetResults := r["at"].Values 532 assert.Equal(t, facetResults[0].Count, 4) 533 534 assert.Equal(t, facetResults[1].Count, 1) 535 assert.Equal(t, facetResults[2].Count, 3) 536 537 session.Close() 538 } 539 } 540 541 // code coverage for RangeBuilder.IsLessThanOrEqualTo and RangeBuilder.IsGreaterThan 542 func goAggregationIsGreaterThanAndIsLessThanOrEqualTo(t *testing.T, driver *RavenTestDriver) { 543 var err error 544 store := driver.getDocumentStoreMust(t) 545 defer store.Close() 546 547 index := NewOrdersAll() 548 err = index.Execute(store, nil, "") 549 assert.NoError(t, err) 550 551 { 552 session := openSessionMust(t, store) 553 data := []struct { 554 currency Currency 555 product string 556 total float64 557 }{ 558 {EUR, "Milk", 3}, 559 {NIS, "Milk", 9}, 560 {EUR, "iPhone", 3333}, 561 } 562 for _, d := range data { 563 obj := &AggOrder{ 564 Currency: d.currency, 565 Product: d.product, 566 Total: d.total, 567 } 568 err = session.Store(obj) 569 assert.NoError(t, err) 570 } 571 572 err = session.SaveChanges() 573 assert.NoError(t, err) 574 575 session.Close() 576 } 577 578 err = driver.waitForIndexing(store, "", 0) 579 assert.NoError(t, err) 580 581 { 582 session := openSessionMust(t, store) 583 584 q := session.QueryIndex(index.IndexName) 585 b := ravendb.NewFacetBuilder() 586 b.ByField("product").SumOn("total") 587 q2 := q.AggregateByFacet(b.GetFacet()) 588 b = ravendb.NewFacetBuilder() 589 rng := ravendb.NewRangeBuilder("total") 590 fop := b.ByRanges( 591 rng.IsGreaterThan(1), 592 rng.IsGreaterThanOrEqualTo(100).IsLessThanOrEqualTo(499), 593 rng.IsGreaterThanOrEqualTo(500).IsLessThanOrEqualTo(1499), 594 rng.IsGreaterThanOrEqualTo(1500)) 595 fop.SumOn("total") 596 facet := b.GetFacet() 597 q2 = q2.AndAggregateByFacet(facet) 598 r, err := q2.Execute() 599 assert.NoError(t, err) 600 601 facetResult := r["product"] 602 values := facetResult.Values 603 assert.Equal(t, len(values), 2) 604 605 x := getFirstFacetValueOfRange(values, "milk") 606 assert.Equal(t, *x.Sum, float64(12)) 607 608 x = getFirstFacetValueOfRange(values, "iphone") 609 assert.Equal(t, *x.Sum, float64(3333)) 610 611 facetResult = r["total"] 612 values = facetResult.Values 613 assert.Equal(t, len(values), 4) 614 615 x = getFirstFacetValueOfRange(values, "total > 1") 616 assert.Equal(t, *x.Sum, float64(3345)) 617 618 x = getFirstFacetValueOfRange(values, "total >= 1500") 619 assert.Equal(t, *x.Sum, float64(3333)) 620 621 session.Close() 622 } 623 } 624 625 type ItemsOrder struct { 626 Items []string `json:"items"` 627 At ravendb.Time `json:"at"` 628 } 629 630 func NewItemsOrdersAll() *ravendb.IndexCreationTask { 631 res := ravendb.NewIndexCreationTask("ItemsOrders_All") 632 res.Map = "docs.ItemsOrders.Select(order => new { order.at,\n" + 633 " order.items })" 634 return res 635 } 636 637 func TestAggregation(t *testing.T) { 638 driver := createTestDriver(t) 639 destroy := func() { destroyDriver(t, driver) } 640 defer recoverTest(t, destroy) 641 642 // matches order of Java tests 643 aggregation_canCorrectlyAggregate_Double(t, driver) 644 aggregationCanCorrectlyAggregateRanges(t, driver) 645 aggregationCanCorrectlyAggregateMultipleItems(t, driver) 646 aggregationCanCorrectlyAggregateMultipleAggregations(t, driver) 647 aggregationCanCorrectlyAggregateDateTimeDataTypeWithRangeCounts(t, driver) 648 aggregationCanCorrectlyAggregateDisplayName(t, driver) 649 650 // tests unique to go 651 goAggregationIsGreaterThanAndIsLessThanOrEqualTo(t, driver) 652 }