Merge pull request #1978 from molecula/decimal-field-fix

[FB-1257] decimal woes
This commit is contained in:
tgruben 2022-03-15 11:35:42 -05:00 committed by GitHub
commit 1906709ce5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 4 deletions

View file

@ -1563,20 +1563,43 @@ func fieldOptionsToFunctionalOpts(opt fieldOptions) []FieldOption {
case FieldTypeSet:
fos = append(fos, OptFieldTypeSet(*opt.CacheType, *opt.CacheSize))
case FieldTypeInt:
if opt.Min == nil {
min := pql.NewDecimal(int64(math.MinInt64), 0)
opt.Min = &min
min, max := pql.MinMax(0)
// ensure the provided bounds are valid
if opt.Max != nil && max.LessThan(*opt.Max) {
opt.Max = &max
}
if opt.Max == nil {
max := pql.NewDecimal(int64(math.MaxInt64), 0)
opt.Max = &max
}
if opt.Min != nil && min.GreaterThan(*opt.Min) {
opt.Min = &min
}
if opt.Min == nil {
opt.Min = &min
}
fos = append(fos, OptFieldTypeInt(opt.Min.ToInt64(0), opt.Max.ToInt64(0)))
case FieldTypeDecimal:
scale := int64(0)
if opt.Scale != nil {
scale = *opt.Scale
min, max := pql.MinMax(scale)
// ensure the provided bounds are valid
if opt.Max != nil && max.LessThan(*opt.Max) {
opt.Max = &max
}
if opt.Max == nil {
opt.Max = &max
}
if opt.Min != nil && min.GreaterThan(*opt.Min) {
opt.Min = &min
}
if opt.Min == nil {
opt.Min = &min
}
}
if opt.Min == nil {
min := pql.NewDecimal(int64(math.MinInt64), scale)
opt.Min = &min

View file

@ -11,6 +11,7 @@ import (
"sync"
"github.com/molecula/featurebase/v3/disco"
"github.com/molecula/featurebase/v3/pql"
"github.com/molecula/featurebase/v3/roaring"
"github.com/molecula/featurebase/v3/stats"
"github.com/molecula/featurebase/v3/testhook"
@ -613,6 +614,27 @@ func (i *Index) CreateFieldIfNotExistsWithOptions(name string, opt *FieldOptions
if f := i.fields[name]; f != nil {
return f, nil
}
// added for backward compatablity with old schemas
if opt != nil && opt.Type == FieldTypeDecimal {
min, max := pql.MinMax(opt.Scale)
// ensure the provided bounds are valid
if max.LessThan(opt.Max) {
opt.Max = max
}
if min.GreaterThan(opt.Min) {
opt.Min = min
}
}
if opt != nil && opt.Type == FieldTypeDecimal {
min, max := pql.MinMax(0)
// ensure the provided bounds are valid
if max.LessThan(opt.Max) {
opt.Max = max
}
if min.GreaterThan(opt.Min) {
opt.Min = min
}
}
cfm := &CreateFieldMessage{
Index: i.name,

View file

@ -886,6 +886,37 @@ func TestHandler_Endpoints(t *testing.T) {
}
}
})
t.Run("Query decimal field scale only", func(t *testing.T) {
w := httptest.NewRecorder()
fieldName := "f-decimal-scale-only"
h.ServeHTTP(w, test.MustNewHTTPRequest("POST", fmt.Sprintf("/index/i0/field/%s", fieldName),
strings.NewReader(`{"options":{"type":"decimal", "scale": 2}}`)))
if w.Code != gohttp.StatusOK {
fmt.Println(w.Body.String())
t.Fatalf("unexpected status code: %d", w.Code)
}
w = httptest.NewRecorder()
h.ServeHTTP(w, test.MustNewHTTPRequest("GET", "/schema", strings.NewReader("")))
if w.Code != gohttp.StatusOK {
t.Fatalf("unexpected status code: %d", w.Code)
}
rsp := getSchemaResponse{}
if err := json.Unmarshal(w.Body.Bytes(), &rsp); err != nil {
t.Fatalf("json decode: %s", err)
}
field := rsp.findField("i0", fieldName)
if field == nil {
t.Fatalf("field not found: %s", fieldName)
}
if field != nil { // happy linter
if !reflect.DeepEqual(pql.NewDecimal(math.MinInt64, 2), field.Options.Min) {
t.Fatalf("field min %d != %d", pql.NewDecimal(math.MinInt64, 1), field.Options.Min)
}
if !reflect.DeepEqual(pql.NewDecimal(math.MaxInt64, 2), field.Options.Max) {
t.Fatalf("field min %d != %d", pql.NewDecimal(math.MaxInt64, 2), field.Options.Max)
}
}
})
// Ensure that decimal fields error when scale is not provided.
t.Run("Query decimal field scale error", func(t *testing.T) {