github.com/altipla-consulting/ravendb-go-client@v0.1.3/tests/aggregation_test.go (about)

     1  package tests
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	ravendb "github.com/altipla-consulting/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  }