featurebase/client/orm_test.go
reesporte 48aef0c8a4 add copyright notice back in
```bash
for file in `cat diffys`; do
   printf '%s\n%s\n' "// Copyright 2021 Molecula Corp. All rights reserved." "$(cat $file)" >$file;
done
```
2021-12-10 11:01:04 -06:00

1197 lines
34 KiB
Go

// Copyright 2021 Molecula Corp. All rights reserved.
// package ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
import (
"fmt"
"math"
"reflect"
"sort"
"strings"
"testing"
"time"
pilosa "github.com/molecula/featurebase/v2"
"github.com/molecula/featurebase/v2/pql"
"github.com/pkg/errors"
)
func TestORM(t *testing.T) {
var schema = NewSchema()
var sampleIndex = schema.Index("sample-index")
var sampleField = sampleIndex.Field("sample-field")
var projectIndex = schema.Index("project-index")
var collabField = projectIndex.Field("collaboration")
var b1 = sampleField.Row(10)
var b2 = sampleField.Row(20)
var b3 = sampleField.Row(42)
var b4 = collabField.Row(2)
t.Run("SchemaDiff", func(t *testing.T) {
schema1 := NewSchema()
index11 := schema1.Index("diff-index1")
index11.Field("field1-1")
index11.Field("field1-2")
index12 := schema1.Index("diff-index2", OptIndexKeys(true), OptIndexTrackExistence(false))
index12.Field("field2-1")
schema2 := NewSchema()
index21 := schema2.Index("diff-index1")
index21.Field("another-field")
targetDiff12 := NewSchema()
targetIndex1 := targetDiff12.Index("diff-index1", OptIndexTrackExistence(false))
targetIndex1.Field("field1-1")
targetIndex1.Field("field1-2")
targetIndex2 := targetDiff12.Index("diff-index2", OptIndexKeys(true), OptIndexTrackExistence(false))
targetIndex2.Field("field2-1")
targetIndex1.options = &IndexOptions{}
diff12 := schema1.diff(schema2)
strTargetDiff12 := fmt.Sprintf("%+v", targetDiff12.indexes)
strDiff12 := fmt.Sprintf("%+v", diff12.indexes)
if strDiff12 != strTargetDiff12 {
t.Fatalf("The diff must be correctly calculated, but exp/got\n%s\n%s", strTargetDiff12, strDiff12)
}
})
t.Run("SchemaIndexes", func(t *testing.T) {
schema1 := NewSchema()
index11 := schema1.Index("diff-index1")
index12 := schema1.Index("diff-index2")
indexes := schema1.Indexes()
target := map[string]*Index{
"diff-index1": index11,
"diff-index2": index12,
}
if !reflect.DeepEqual(target, indexes) {
t.Fatalf("calling schema.Indexes should return indexes")
}
})
t.Run("SchemaToString", func(t *testing.T) {
schema1 := NewSchema()
_ = schema1.Index("test-index")
target := `map[test-index:{name: "test-index", options: "{"options":{}}", fields: map[_exists:{name: "_exists", index: "test-index", options: "{"options":{"type":"set"}}"}], shardWidth: 0}]`
if target != schema1.String() {
t.Fatalf("%s != %s", target, schema1.String())
}
})
t.Run("NewIndex", func(t *testing.T) {
index1 := schema.Index("index-name")
if index1.Name() != "index-name" {
t.Fatalf("index name was not set")
}
// calling schema.Index again should return the same index
index2 := schema.Index("index-name")
if index1 != index2 {
t.Fatalf("calling schema.Index again should return the same index")
}
if !schema.HasIndex("index-name") {
t.Fatalf("HasIndex should return true")
}
if schema.HasIndex("index-x") {
t.Fatalf("HasIndex should return false")
}
})
t.Run("NewIndexCopy", func(t *testing.T) {
index := schema.Index("my-index-4copy", OptIndexKeys(true))
index.Field("my-field-4copy", OptFieldTypeTime(TimeQuantumDayHour))
copiedIndex := index.copy()
if !reflect.DeepEqual(index, copiedIndex) {
t.Fatalf("copied index should be equivalent")
}
})
t.Run("NewIndexOptions", func(t *testing.T) {
schemal := NewSchema()
// test the defaults
index := schemal.Index("index-default-options")
target := `{"options":{}}`
if target != index.options.String() {
t.Fatalf("%s != %s", target, index.options.String())
}
index = schemal.Index("index-keys", OptIndexKeys(true))
if true != index.Opts().Keys() {
t.Fatalf("index keys %v != %v", true, index.Opts().Keys())
}
target = `{"options":{"keys":true}}`
if target != index.options.String() {
t.Fatalf("%s != %s", target, index.options.String())
}
index = schemal.Index("index-trackexistence", OptIndexTrackExistence(false))
if false != index.Opts().TrackExistence() {
t.Fatalf("index trackExistene %v != %v", true, index.Opts().TrackExistence())
}
target = `{"options":{"trackExistence":false}}`
if target != index.options.String() {
t.Fatalf("%s != %s", target, index.options.String())
}
})
t.Run("NilIndexOption", func(t *testing.T) {
schema.Index("index-with-nil-option", nil)
})
t.Run("IndexFields", func(t *testing.T) {
schema1 := NewSchema()
index11 := schema1.Index("diff-index1", OptIndexTrackExistence(false))
field11 := index11.Field("field1-1")
field12 := index11.Field("field1-2")
fields := index11.Fields()
target := map[string]*Field{
"field1-1": field11,
"field1-2": field12,
}
if !reflect.DeepEqual(target, fields) {
t.Fatalf("calling index.Fields should return fields")
}
if !index11.HasField("field1-1") {
t.Fatalf("HasField should return true")
}
if index11.HasField("field-x") {
t.Fatalf("HasField should return false")
}
})
t.Run("IndexToString", func(t *testing.T) {
schema1 := NewSchema()
index := schema1.Index("test-index")
target := `{name: "test-index", options: "{"options":{}}", fields: map[_exists:{name: "_exists", index: "test-index", options: "{"options":{"type":"set"}}"}], shardWidth: 0}`
if target != index.String() {
t.Fatalf("indexes not equal exp/got:\n%s\n%s", target, index.String())
}
})
t.Run("Field", func(t *testing.T) {
field1 := sampleIndex.Field("nonexistent-field")
field2 := sampleIndex.Field("nonexistent-field")
if field1 != field2 {
t.Fatalf("calling index.Field again should return the same field")
}
if field1.Name() != "nonexistent-field" {
t.Fatalf("calling field.Name should return field's name")
}
})
t.Run("FieldCopy", func(t *testing.T) {
field := sampleIndex.Field("my-field-4copy", OptFieldTypeSet(CacheTypeRanked, 123456))
copiedField := field.copy()
if !reflect.DeepEqual(field, copiedField) {
t.Fatalf("copied field should be equivalent")
}
})
t.Run("FieldToString", func(t *testing.T) {
schema1 := NewSchema()
index := schema1.Index("test-index")
field := index.Field("test-field")
target := `{name: "test-field", index: "test-index", options: "{"options":{"type":"set"}}"}`
if target != field.String() {
t.Fatalf("%s != %s", target, field.String())
}
})
t.Run("NilFieldOption", func(t *testing.T) {
schema1 := NewSchema()
index := schema1.Index("test-index")
index.Field("test-field-with-nil-option", nil)
})
t.Run("FieldSetType", func(t *testing.T) {
schema1 := NewSchema()
index := schema1.Index("test-index")
field := index.Field("test-set-field", OptFieldTypeSet(CacheTypeLRU, 1000), OptFieldKeys(true))
target := `{"options":{"type":"set","cacheType":"lru","cacheSize":1000,"keys":true}}`
if sortedString(target) != sortedString(field.options.String()) {
t.Fatalf("%s != %s", target, field.options.String())
}
field = index.Field("test-set-field2", OptFieldTypeSet(CacheTypeLRU, -10), OptFieldKeys(true))
target = `{"options":{"type":"set","cacheType":"lru","keys":true}}`
if sortedString(target) != sortedString(field.options.String()) {
t.Fatalf("%s != %s", target, field.options.String())
}
})
t.Run("Row", func(t *testing.T) {
comparePQL(t,
"Row(collaboration=5)",
collabField.Row(5))
comparePQL(t,
"Row(collaboration='b7feb014-8ea7-49a8-9cd8-19709161ab63')",
collabField.Row("b7feb014-8ea7-49a8-9cd8-19709161ab63"))
q := collabField.Row(nil)
if q.err == nil {
t.Fatalf("should have failed")
}
})
t.Run("Set", func(t *testing.T) {
comparePQL(t,
"Set(10,collaboration=5)",
collabField.Set(5, 10))
comparePQL(t,
`Set('some_id',collaboration='b7feb014-8ea7-49a8-9cd8-19709161ab63')`,
collabField.Set("b7feb014-8ea7-49a8-9cd8-19709161ab63", "some_id"))
q := collabField.Set(nil, 10)
if q.err == nil {
t.Fatalf("should have failed")
}
q = collabField.Set(5, false)
if q.err == nil {
t.Fatalf("should have failed")
}
})
t.Run("Timestamp", func(t *testing.T) {
timestamp := time.Date(2017, time.April, 24, 12, 14, 0, 0, time.UTC)
comparePQL(t,
"Set(20,collaboration=10,2017-04-24T12:14)",
collabField.SetTimestamp(10, 20, timestamp))
comparePQL(t,
"Set('mycol',collaboration='myrow',2017-04-24T12:14)",
collabField.SetTimestamp("myrow", "mycol", timestamp))
q := collabField.SetTimestamp(nil, 20, timestamp)
if q.err == nil {
t.Fatalf("should have failed")
}
})
t.Run("Clear", func(t *testing.T) {
comparePQL(t,
"Clear(10,collaboration=5)",
collabField.Clear(5, 10))
comparePQL(t,
"Clear('some_id',collaboration='b7feb014-8ea7-49a8-9cd8-19709161ab63')",
collabField.Clear("b7feb014-8ea7-49a8-9cd8-19709161ab63", "some_id"))
comparePQL(t,
`Clear('bill\'s',collaboration='will\'s')`,
collabField.Clear("will's", "bill's"))
q := collabField.Clear(nil, 10)
if q.err == nil {
t.Fatalf("should have failed")
}
q = collabField.Clear(5, false)
if q.err == nil {
t.Fatalf("should have failed")
}
})
t.Run("ClearRow", func(t *testing.T) {
comparePQL(t,
"ClearRow(collaboration=5)",
collabField.ClearRow(5))
comparePQL(t,
"ClearRow(collaboration='five')",
collabField.ClearRow("five"))
comparePQL(t,
"ClearRow(collaboration=true)",
collabField.ClearRow(true))
q := collabField.ClearRow(nil)
if q.err == nil {
t.Fatalf("should have failed")
}
})
t.Run("Union", func(t *testing.T) {
comparePQL(t,
"Union(Row(sample-field=10),Row(sample-field=20))",
sampleIndex.Union(b1, b2))
comparePQL(t,
"Union(Row(sample-field=10),Row(sample-field=20),Row(sample-field=42))",
sampleIndex.Union(b1, b2, b3))
comparePQL(t,
"Union(Row(sample-field=10),Row(collaboration=2))",
sampleIndex.Union(b1, b4))
comparePQL(t,
"Union(Row(sample-field=10))",
sampleIndex.Union(b1))
comparePQL(t,
"Union()",
sampleIndex.Union())
})
t.Run("Intersect", func(t *testing.T) {
comparePQL(t,
"Intersect(Row(sample-field=10),Row(sample-field=20))",
sampleIndex.Intersect(b1, b2))
comparePQL(t,
"Intersect(Row(sample-field=10),Row(sample-field=20),Row(sample-field=42))",
sampleIndex.Intersect(b1, b2, b3))
comparePQL(t,
"Intersect(Row(sample-field=10),Row(collaboration=2))",
sampleIndex.Intersect(b1, b4))
comparePQL(t,
"Intersect(Row(sample-field=10))",
sampleIndex.Intersect(b1))
})
t.Run("Difference", func(t *testing.T) {
comparePQL(t,
"Difference(Row(sample-field=10),Row(sample-field=20))",
sampleIndex.Difference(b1, b2))
comparePQL(t,
"Difference(Row(sample-field=10),Row(sample-field=20),Row(sample-field=42))",
sampleIndex.Difference(b1, b2, b3))
comparePQL(t,
"Difference(Row(sample-field=10),Row(collaboration=2))",
sampleIndex.Difference(b1, b4))
comparePQL(t,
"Difference(Row(sample-field=10))",
sampleIndex.Difference(b1))
})
t.Run("Xor", func(t *testing.T) {
comparePQL(t,
"Xor(Row(sample-field=10),Row(sample-field=20))",
sampleIndex.Xor(b1, b2))
comparePQL(t,
"Xor(Row(sample-field=10),Row(sample-field=20),Row(sample-field=42))",
sampleIndex.Xor(b1, b2, b3))
comparePQL(t,
"Xor(Row(sample-field=10),Row(collaboration=2))",
sampleIndex.Xor(b1, b4))
})
t.Run("Not", func(t *testing.T) {
comparePQL(t,
"Not(Row(sample-field=10))",
sampleIndex.Not(sampleField.Row(10)))
})
t.Run("TopN", func(t *testing.T) {
comparePQL(t,
"TopN(collaboration,n=27)",
collabField.TopN(27))
comparePQL(t,
"TopN(collaboration,Row(collaboration=3),n=10)",
collabField.RowTopN(10, collabField.Row(3)))
})
t.Run("FieldLT", func(t *testing.T) {
comparePQL(t,
"Row(collaboration < 10)",
collabField.LT(10))
comparePQL(t,
"Row(collaboration < 10.12300000)",
collabField.LT(10.123))
})
t.Run("FieldLTE", func(t *testing.T) {
comparePQL(t,
"Row(collaboration <= 10)",
collabField.LTE(10))
comparePQL(t,
"Row(collaboration <= 10.12300000)",
collabField.LTE(10.123))
})
t.Run("FieldGT", func(t *testing.T) {
comparePQL(t,
"Row(collaboration > 10)",
collabField.GT(10))
comparePQL(t,
"Row(collaboration > 10.12300000)",
collabField.GT(10.123))
})
t.Run("FieldGTE", func(t *testing.T) {
comparePQL(t,
"Row(collaboration >= 10)",
collabField.GTE(10))
comparePQL(t,
"Row(collaboration >= 10.12300000)",
collabField.GTE(10.123))
})
t.Run("FieldEQ", func(t *testing.T) {
comparePQL(t,
"Row(collaboration == 10)",
collabField.Equals(10))
comparePQL(t,
"Row(collaboration == 10.12300000)",
collabField.Equals(10.123))
})
t.Run("FieldNEQ", func(t *testing.T) {
comparePQL(t,
"Row(collaboration != 10)",
collabField.NotEquals(10))
comparePQL(t,
"Row(collaboration != 10.12300000)",
collabField.NotEquals(10.123))
})
t.Run("FieldNotNull", func(t *testing.T) {
comparePQL(t,
"Row(collaboration != null)",
collabField.NotNull())
})
t.Run("FieldBetween", func(t *testing.T) {
comparePQL(t,
"Row(collaboration >< [10,20])",
collabField.Between(10, 20))
comparePQL(t,
"Row(collaboration >< [10.12300000,20.45600000])",
collabField.Between(10.123, 20.456))
})
t.Run("FieldSum", func(t *testing.T) {
comparePQL(t,
"Sum(Row(collaboration=10),field='collaboration')",
collabField.Sum(collabField.Row(10)))
comparePQL(t,
"Sum(field='collaboration')",
collabField.Sum(nil))
})
t.Run("FieldMinRow", func(t *testing.T) {
comparePQL(t,
"MinRow(field='sample-field')",
sampleField.MinRow())
})
t.Run("FieldMaxRow", func(t *testing.T) {
comparePQL(t,
"MaxRow(field='sample-field')",
sampleField.MaxRow())
})
t.Run("FieldSetValue", func(t *testing.T) {
comparePQL(t,
"Set(50, collaboration=15)",
collabField.SetIntValue(50, 15))
comparePQL(t,
"Set('mycol', sample-field=22)",
sampleField.SetIntValue("mycol", 22))
q := sampleField.SetIntValue(false, 22)
if q.err == nil {
t.Fatalf("should have failed")
}
})
t.Run("RowOperationInvalidArg", func(t *testing.T) {
invalid := NewPQLRowQuery("", sampleIndex, errors.New("invalid"))
// invalid argument in pos 1
q := sampleIndex.Union(invalid, b1)
if q.Error() == nil {
t.Fatalf("should have failed")
}
// invalid argument in pos 2
q = sampleIndex.Intersect(b1, invalid)
if q.Error() == nil {
t.Fatalf("should have failed")
}
// invalid argument in pos 3
q = sampleIndex.Intersect(b1, b2, invalid)
if q.Error() == nil {
t.Fatalf("should have failed")
}
// not enough rows supplied
q = sampleIndex.Difference()
if q.Error() == nil {
t.Fatalf("should have failed")
}
// not enough rows supplied
q = sampleIndex.Intersect()
if q.Error() == nil {
t.Fatalf("should have failed")
}
// not enough rows supplied
q = sampleIndex.Xor(b1)
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("Store", func(t *testing.T) {
comparePQL(t,
"Store(Row(collaboration=5),sample-field=10)",
sampleField.Store(collabField.Row(5), 10))
q := sampleField.Store(collabField.Row(5), nil)
if q.Error() == nil {
t.Fatalf("query error should be not nil")
}
})
t.Run("Options", func(t *testing.T) {
comparePQL(t,
"Options(Row(collaboration=5),shards=[1,3])",
sampleIndex.Options(collabField.Row(5),
OptOptionsShards(1, 3),
))
})
t.Run("BatchQuery", func(t *testing.T) {
q := sampleIndex.BatchQuery()
if q.Index() != sampleIndex {
t.Fatalf("The correct index should be assigned")
}
q.Add(sampleField.Row(44))
q.Add(sampleField.Row(10101))
if q.Error() != nil {
t.Fatalf("Error should be nil")
}
comparePQL(t, "Row(sample-field=44)Row(sample-field=10101)", q)
q2 := sampleField.Row(nil)
if q2.err == nil {
t.Fatalf("should have failed")
}
})
t.Run("BatchQueryWithError", func(t *testing.T) {
q := sampleIndex.BatchQuery()
q.Add(NewPQLBaseQuery("", nil, errors.New("invalid")))
if q.Error() == nil {
t.Fatalf("The error must be set")
}
})
t.Run("Count", func(t *testing.T) {
q := projectIndex.Count(collabField.Row(42))
comparePQL(t, "Count(Row(collaboration=42))", q)
})
t.Run("Range", func(t *testing.T) {
start := time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2000, time.February, 2, 3, 4, 0, 0, time.UTC)
comparePQL(t,
"Range(collaboration=10,1970-01-01T00:00,2000-02-02T03:04)",
collabField.Range(10, start, end))
comparePQL(t,
"Range(collaboration='foo',1970-01-01T00:00,2000-02-02T03:04)",
collabField.Range("foo", start, end))
q := collabField.Range(nil, start, end)
if q.err == nil {
t.Fatalf("should have failed")
}
})
t.Run("RowRange", func(t *testing.T) {
start := time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2000, time.February, 2, 3, 4, 0, 0, time.UTC)
comparePQL(t,
"Row(collaboration=10,from='1970-01-01T00:00',to='2000-02-02T03:04')",
collabField.RowRange(10, start, end))
comparePQL(t,
"Row(collaboration='foo',from='1970-01-01T00:00',to='2000-02-02T03:04')",
collabField.RowRange("foo", start, end))
comparePQL(t,
`Row(collaboration='bill\'s',from='1970-01-01T00:00',to='2000-02-02T03:04')`,
collabField.RowRange("bill's", start, end))
q := collabField.RowRange(nil, start, end)
if q.err == nil {
t.Fatalf("should have failed")
}
})
t.Run("Rows", func(t *testing.T) {
comparePQL(t,
"Rows(field='collaboration')",
collabField.Rows())
})
t.Run("UnionRows", func(t *testing.T) {
comparePQL(t,
"UnionRows(Rows(field='collaboration'))",
collabField.Rows().Union())
})
t.Run("Like", func(t *testing.T) {
comparePQL(t,
"Rows(field='collaboration',like='_')",
collabField.Like("_"))
comparePQL(t,
`Rows(field='collaboration',like='_\\')`,
collabField.Like(`_\`))
comparePQL(t,
`Rows(field='collaboration',like='_\'')`,
collabField.Like(`_'`))
})
t.Run("RowPrevious", func(t *testing.T) {
comparePQL(t,
"Rows(field='collaboration',previous=42)",
collabField.RowsPrevious(42))
comparePQL(t,
"Rows(field='collaboration',previous='forty-two')",
collabField.RowsPrevious("forty-two"))
comparePQL(t,
`Rows(field='collaboration',previous='bill\'s')`,
collabField.RowsPrevious("bill's"))
q := collabField.RowsPrevious(1.2)
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("RowLimit", func(t *testing.T) {
comparePQL(t,
"Rows(field='collaboration',limit=10)",
collabField.RowsLimit(10))
q := collabField.RowsLimit(-1)
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("RowsColumn", func(t *testing.T) {
comparePQL(t,
"Rows(field='collaboration',column=1000)",
collabField.RowsColumn(1000))
comparePQL(t,
"Rows(field='collaboration',column='one-thousand')",
collabField.RowsColumn("one-thousand"))
q := collabField.RowsColumn(1.2)
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("RowsPreviousLimit", func(t *testing.T) {
comparePQL(t,
"Rows(field='collaboration',previous=42,limit=10)",
collabField.RowsPreviousLimit(42, 10))
comparePQL(t,
"Rows(field='collaboration',previous='forty-two',limit=10)",
collabField.RowsPreviousLimit("forty-two", 10))
q := collabField.RowsPreviousLimit(1.2, 10)
if q.Error() == nil {
t.Fatalf("should have failed")
}
q = collabField.RowsPreviousLimit("forty-two", -1)
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("RowsPreviousColumn", func(t *testing.T) {
comparePQL(t,
"Rows(field='collaboration',previous=42,column=1000)",
collabField.RowsPreviousColumn(42, 1000))
comparePQL(t,
"Rows(field='collaboration',previous='forty-two',column='one-thousand')",
collabField.RowsPreviousColumn("forty-two", "one-thousand"))
q := collabField.RowsPreviousColumn(1.2, 1000)
if q.Error() == nil {
t.Fatalf("should have failed")
}
q = collabField.RowsPreviousColumn("forty-two", 1.2)
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("All", func(t *testing.T) {
comparePQL(t,
"All()",
projectIndex.All())
})
t.Run("Distinct", func(t *testing.T) {
comparePQL(t,
"Distinct(Row(collaboration!=null),index='project-index',field='collaboration')",
collabField.Distinct())
})
t.Run("RowDistinct", func(t *testing.T) {
comparePQL(t,
"Distinct(Row(sample-field=44),index='project-index',field='collaboration')",
collabField.RowDistinct(sampleField.Row(44)))
})
t.Run("RowLimitColumn", func(t *testing.T) {
comparePQL(t,
"Rows(field='collaboration',limit=10,column=1000)",
collabField.RowsLimitColumn(10, 1000))
comparePQL(t,
"Rows(field='collaboration',limit=10,column='one-thousand')",
collabField.RowsLimitColumn(10, "one-thousand"))
q := collabField.RowsLimitColumn(10, 1.2)
if q.Error() == nil {
t.Fatalf("should have failed")
}
q = collabField.RowsLimitColumn(-1, 1000)
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("RowsPreviousLimitColumn", func(t *testing.T) {
comparePQL(t,
"Rows(field='collaboration',previous=42,limit=10,column=1000)",
collabField.RowsPreviousLimitColumn(42, 10, 1000))
comparePQL(t,
"Rows(field='collaboration',previous='forty-two',limit=10,column='one-thousand')",
collabField.RowsPreviousLimitColumn("forty-two", 10, "one-thousand"))
q := collabField.RowsPreviousLimitColumn(1.2, 10, 1000)
if q.Error() == nil {
t.Fatalf("should have failed")
}
q = collabField.RowsPreviousLimitColumn(42, -1, 1000)
if q.Error() == nil {
t.Fatalf("should have failed")
}
q = collabField.RowsPreviousLimitColumn(42, 10, 1.2)
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("GroupBy", func(t *testing.T) {
field := sampleIndex.Field("test")
comparePQL(t,
"GroupBy(Rows(field='collaboration'))",
sampleIndex.GroupBy(collabField.Rows()))
comparePQL(t,
"GroupBy(Rows(field='collaboration'),Rows(field='test'))",
sampleIndex.GroupBy(collabField.Rows(), field.Rows()))
q := sampleIndex.GroupBy()
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("GroupByLimit", func(t *testing.T) {
field := sampleIndex.Field("test")
comparePQL(t,
"GroupBy(Rows(field='collaboration'),limit=10)",
sampleIndex.GroupByLimit(10, collabField.Rows()))
comparePQL(t,
"GroupBy(Rows(field='collaboration'),Rows(field='test'),limit=10)",
sampleIndex.GroupByLimit(10, collabField.Rows(), field.Rows()))
q := sampleIndex.GroupByLimit(10)
if q.Error() == nil {
t.Fatalf("should have failed")
}
q = sampleIndex.GroupByLimit(-1, collabField.Rows())
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("GroupByFilter", func(t *testing.T) {
field := sampleIndex.Field("test")
comparePQL(t,
"GroupBy(Rows(field='collaboration'),filter=Row(test=5))",
sampleIndex.GroupByFilter(field.Row(5), collabField.Rows()))
comparePQL(t,
"GroupBy(Rows(field='collaboration'),Rows(field='test'),filter=Row(test=5))",
sampleIndex.GroupByFilter(field.Row(5), collabField.Rows(), field.Rows()))
q := sampleIndex.GroupByFilter(field.Row(5))
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("GroupByLimitFilter", func(t *testing.T) {
field := sampleIndex.Field("test")
comparePQL(t,
"GroupBy(Rows(field='collaboration'),limit=10,filter=Row(test=5))",
sampleIndex.GroupByLimitFilter(10, field.Row(5), collabField.Rows()))
comparePQL(t,
"GroupBy(Rows(field='collaboration'),Rows(field='test'),limit=10,filter=Row(test=5))",
sampleIndex.GroupByLimitFilter(10, field.Row(5), collabField.Rows(), field.Rows()))
q := sampleIndex.GroupByLimitFilter(10, field.Row(5))
if q.Error() == nil {
t.Fatalf("should have failed")
}
q = sampleIndex.GroupByLimitFilter(-1, field.Row(5), collabField.Rows())
if q.Error() == nil {
t.Fatalf("should have failed")
}
})
t.Run("GroupByBase", func(t *testing.T) {
field := sampleIndex.Field("test")
comparePQL(t,
"GroupBy(Rows(field='collaboration'))",
sampleIndex.GroupByBase(
OptGroupByBuilderRows(collabField.Rows()),
),
)
comparePQL(t,
"GroupBy(Rows(field='collaboration'),Rows(field='test'))",
sampleIndex.GroupByBase(
OptGroupByBuilderRows(collabField.Rows(), field.Rows()),
),
)
comparePQL(t,
"GroupBy(Rows(field='collaboration'),limit=10)",
sampleIndex.GroupByBase(
OptGroupByBuilderLimit(10),
OptGroupByBuilderRows(collabField.Rows()),
),
)
comparePQL(t,
"GroupBy(Rows(field='collaboration'),Rows(field='test'),limit=10)",
sampleIndex.GroupByBase(
OptGroupByBuilderLimit(10),
OptGroupByBuilderRows(collabField.Rows(), field.Rows()),
),
)
comparePQL(t,
"GroupBy(Rows(field='collaboration'),filter=Row(test=5))",
sampleIndex.GroupByBase(
OptGroupByBuilderFilter(field.Row(5)),
OptGroupByBuilderRows(collabField.Rows()),
),
)
comparePQL(t,
"GroupBy(Rows(field='collaboration'),Rows(field='test'),filter=Row(test=5))",
sampleIndex.GroupByBase(
OptGroupByBuilderFilter(field.Row(5)),
OptGroupByBuilderRows(collabField.Rows(), field.Rows()),
),
)
comparePQL(t,
"GroupBy(Rows(field='collaboration'),limit=10,filter=Row(test=5))",
sampleIndex.GroupByBase(
OptGroupByBuilderLimit(10),
OptGroupByBuilderFilter(field.Row(5)),
OptGroupByBuilderRows(collabField.Rows()),
),
)
comparePQL(t,
"GroupBy(Rows(field='collaboration'),Rows(field='test'),limit=10,filter=Row(test=5))",
sampleIndex.GroupByBase(
OptGroupByBuilderLimit(10),
OptGroupByBuilderFilter(field.Row(5)),
OptGroupByBuilderRows(collabField.Rows(), field.Rows()),
),
)
field2 := sampleIndex.Field("age")
comparePQL(t,
"GroupBy(Rows(field='collaboration'),Rows(field='test'),aggregate=Sum(Row(age=20),field='age'))",
sampleIndex.GroupByBase(
OptGroupByBuilderRows(collabField.Rows(), field.Rows()),
OptGroupByBuilderAggregate(field2.Sum(field2.Row(20))),
),
)
})
t.Run("FieldOptions", func(t *testing.T) {
field := sampleIndex.Field("foo", OptFieldKeys(true))
if true != field.Opts().Keys() {
t.Fatalf("field keys: %v != %v", true, field.Opts().Keys())
}
})
t.Run("SetFieldOptions", func(t *testing.T) {
field := sampleIndex.Field("set-field", OptFieldTypeSet(CacheTypeRanked, 9999))
jsonString := field.options.String()
targetString := `{"options":{"type":"set","cacheType":"ranked","cacheSize":9999}}`
if sortedString(targetString) != sortedString(jsonString) {
t.Fatalf("`%s` != `%s`", targetString, jsonString)
}
compareFieldOptions(t,
field.Options(),
FieldTypeSet,
TimeQuantumNone,
CacheTypeRanked,
9999,
pql.NewDecimal(0, 0),
pql.NewDecimal(0, 0),
"",
"")
})
t.Run("IntFieldOptions", func(t *testing.T) {
field := sampleIndex.Field("int-field", OptFieldTypeInt(-10, 100))
jsonString := field.options.String()
targetString := `{"options":{"type":"int","min":-10,"max":100}}`
if sortedString(targetString) != sortedString(jsonString) {
t.Fatalf("`%s` != `%s`", targetString, jsonString)
}
compareFieldOptions(t,
field.Options(),
FieldTypeInt,
TimeQuantumNone,
CacheTypeDefault,
0,
pql.NewDecimal(-10, 0),
pql.NewDecimal(100, 0),
"",
"")
field = sampleIndex.Field("int-field2", OptFieldTypeInt(-10))
jsonString = field.options.String()
targetString = fmt.Sprintf(`{"options":{"type":"int","min":-10,"max":%d}}`, math.MaxInt64)
if sortedString(targetString) != sortedString(jsonString) {
t.Fatalf("`%s` != `%s`", targetString, jsonString)
}
compareFieldOptions(t,
field.Options(),
FieldTypeInt,
TimeQuantumNone,
CacheTypeDefault,
0,
pql.NewDecimal(-10, 0),
pql.NewDecimal(math.MaxInt64, 0),
"",
"")
field = sampleIndex.Field("int-field3", OptFieldTypeInt())
jsonString = field.options.String()
targetString = fmt.Sprintf(`{"options":{"type":"int","min":%d,"max":%d}}`, math.MinInt64, math.MaxInt64)
if sortedString(targetString) != sortedString(jsonString) {
t.Fatalf("`%s` != `%s`", targetString, jsonString)
}
compareFieldOptions(t,
field.Options(),
FieldTypeInt,
TimeQuantumNone,
CacheTypeDefault,
0,
pql.NewDecimal(math.MinInt64, 0),
pql.NewDecimal(math.MaxInt64, 0),
"",
"")
field = sampleIndex.Field("int-field4", OptFieldTypeInt(), OptFieldForeignIndex("blerg"))
jsonString = field.options.String()
targetString = fmt.Sprintf(`{"options":{"type":"int","min":%d,"max":%d,"foreignIndex":"blerg"}}`, math.MinInt64, math.MaxInt64)
if sortedString(targetString) != sortedString(jsonString) {
t.Fatalf("`%s` != `%s`", targetString, jsonString)
}
compareFieldOptions(t,
field.Options(),
FieldTypeInt,
TimeQuantumNone,
CacheTypeDefault,
0,
pql.NewDecimal(math.MinInt64, 0),
pql.NewDecimal(math.MaxInt64, 0),
"blerg",
"")
})
t.Run("TimeFieldOptions", func(t *testing.T) {
field := sampleIndex.Field("time-field", OptFieldTypeTime(TimeQuantumDayHour, true))
if true != field.Opts().NoStandardView() {
t.Fatalf("field noStandardView %v != %v", true, field.Opts().NoStandardView())
}
jsonString := field.options.String()
targetString := `{"options":{"noStandardView":true,"type":"time","timeQuantum":"DH"}}`
if sortedString(targetString) != sortedString(jsonString) {
t.Fatalf("`%s` != `%s`", targetString, jsonString)
}
compareFieldOptions(t,
field.Options(),
FieldTypeTime,
TimeQuantumDayHour,
CacheTypeDefault,
0,
pql.NewDecimal(0, 0),
pql.NewDecimal(0, 0),
"",
"")
})
t.Run("MutexFieldOptions", func(t *testing.T) {
field := sampleIndex.Field("mutex-field", OptFieldTypeMutex(CacheTypeRanked, 9999))
jsonString := field.options.String()
targetString := `{"options":{"type":"mutex","cacheType":"ranked","cacheSize":9999}}`
if sortedString(targetString) != sortedString(jsonString) {
t.Fatalf("`%s` != `%s`", targetString, jsonString)
}
compareFieldOptions(t,
field.Options(),
FieldTypeMutex,
TimeQuantumNone,
CacheTypeRanked,
9999,
pql.NewDecimal(0, 0),
pql.NewDecimal(0, 0),
"",
"")
})
t.Run("BoolFieldOptions", func(t *testing.T) {
field := sampleIndex.Field("bool-field", OptFieldTypeBool())
jsonString := field.options.String()
targetString := `{"options":{"type":"bool"}}`
if sortedString(targetString) != sortedString(jsonString) {
t.Fatalf("`%s` != `%s`", targetString, jsonString)
}
compareFieldOptions(t,
field.Options(),
FieldTypeBool,
TimeQuantumNone,
CacheTypeDefault,
0,
pql.NewDecimal(0, 0),
pql.NewDecimal(0, 0),
"",
"")
})
t.Run("DecimalFieldOptions", func(t *testing.T) {
field := sampleIndex.Field("decimal-field", OptFieldTypeDecimal(3, pql.NewDecimal(7, 3), pql.NewDecimal(999, 3)))
jsonString := field.options.String()
targetString := `{"options":{"type":"decimal","scale":3,"max":0.999,"min":0.007}}`
if sortedString(targetString) != sortedString(jsonString) {
t.Fatalf("`%s` != `%s`", targetString, jsonString)
}
compareFieldOptions(t,
field.Options(),
FieldTypeDecimal,
TimeQuantumNone,
CacheTypeDefault,
0,
pql.NewDecimal(7, 3),
pql.NewDecimal(999, 3),
"",
"")
})
t.Run("DecimalFieldOptions", func(t *testing.T) {
field := sampleIndex.Field("decimal-field", OptFieldTypeDecimal(3, pql.NewDecimal(7, 3), pql.NewDecimal(999, 3)))
jsonString := field.options.String()
targetString := `{"options":{"type":"decimal","scale":3,"max":0.999,"min":0.007}}`
if sortedString(targetString) != sortedString(jsonString) {
t.Fatalf("`%s` != `%s`", targetString, jsonString)
}
compareFieldOptions(t,
field.Options(),
FieldTypeDecimal,
TimeQuantumNone,
CacheTypeDefault,
0,
pql.NewDecimal(7, 3),
pql.NewDecimal(999, 3),
"",
"")
})
t.Run("TimestampFieldOptions", func(t *testing.T) {
field := sampleIndex.Field("timestamp-field", OptFieldTypeTimestamp(pilosa.DefaultEpoch, pilosa.TimeUnitSeconds))
/*jsonString := field.options.String()
targetString := `{"options":{"type":"timestamp","timeUnit":"s","max":5000,"min":2}}`
if sortedString(targetString) != sortedString(jsonString) {
t.Fatalf("`%s` != `%s`", targetString, jsonString)
}
*/
compareFieldOptions(t,
field.Options(),
FieldTypeTimestamp,
TimeQuantumNone,
CacheTypeDefault,
0,
pql.NewDecimal(MinTimestamp.UnixNano()/TimeUnitNanos(pilosa.TimeUnitSeconds), 0),
pql.NewDecimal(MaxTimestamp.UnixNano()/TimeUnitNanos(pilosa.TimeUnitSeconds), 0),
"",
pilosa.TimeUnitSeconds)
})
t.Run("EncodeMapPanicsOnMarshalFailure", func(t *testing.T) {
defer func() {
_ = recover()
}()
m := map[string]interface{}{
"foo": func() {},
}
encodeMap(m)
t.Fatal("Should have panicked")
})
t.Run("FormatIDKey", func(t *testing.T) {
testCase := [][]interface{}{
{uint(42), "42", nil},
{uint32(42), "42", nil},
{uint64(42), "42", nil},
{42, "42", nil},
{int32(42), "42", nil},
{int64(42), "42", nil},
{"foo", `'foo'`, nil},
{false, "", errors.New("error")},
}
for i, item := range testCase {
s, err := formatIDKey(item[0])
if item[2] != nil {
if err == nil {
t.Fatalf("Should have failed: %d", i)
}
continue
}
if item[1] != s {
t.Fatalf("%s != %s", item[1], s)
}
}
})
}
func comparePQL(t *testing.T, target string, q PQLQuery) {
t.Helper()
pql := q.Serialize().String()
if target != pql {
t.Fatalf("%s != %s", target, pql)
}
}
func compareFieldOptions(t *testing.T, opts *FieldOptions, fieldType FieldType, timeQuantum TimeQuantum, cacheType CacheType, cacheSize int, min pql.Decimal, max pql.Decimal, foreignIndex string, timeUnit string) {
if fieldType != opts.Type() {
t.Fatalf("%s != %s", fieldType, opts.Type())
}
if timeQuantum != opts.TimeQuantum() {
t.Fatalf("%s != %s", timeQuantum, opts.TimeQuantum())
}
if cacheType != opts.CacheType() {
t.Fatalf("%s != %s", cacheType, opts.CacheType())
}
if cacheSize != opts.CacheSize() {
t.Fatalf("%d != %d", cacheSize, opts.CacheSize())
}
if min != opts.Min() {
t.Fatalf("%d != %d", min, opts.Min())
}
if max != opts.Max() {
t.Fatalf("%d != %d", max, opts.Max())
}
if foreignIndex != opts.ForeignIndex() {
t.Fatalf("%s != %s", foreignIndex, opts.ForeignIndex())
}
if timeUnit != opts.TimeUnit() {
t.Fatalf("%s != %s", timeUnit, opts.TimeUnit())
}
}
func sortedString(s string) string {
arr := strings.Split(s, "")
sort.Strings(arr)
return strings.Join(arr, "")
}