diff --git a/builder/filter/filter_test.go b/builder/filter/filter_test.go index deaafc3..15613c8 100644 --- a/builder/filter/filter_test.go +++ b/builder/filter/filter_test.go @@ -1,9 +1,12 @@ package filter import ( - "testing" - + "encoding/json" + "github.com/grafadruid/go-druid/builder" + "github.com/grafadruid/go-druid/builder/intervals" "github.com/stretchr/testify/assert" + "testing" + "time" ) func TestLoadUnsupportedType(t *testing.T) { @@ -11,7 +14,67 @@ func TestLoadUnsupportedType(t *testing.T) { f, err := Load([]byte("{\"type\": \"blahblahType\"}")) - assert.Nil(f, "filter should be nil") - assert.NotNil(err, "error should not be nil") - assert.Error(err, "unsupported filter type") + assert.Nil(f, + "filter should be nil") + assert.NotNil(err, + "error should not be nil") + assert.Error(err, + "unsupported filter type") +} + +func TestNewInterval(t *testing.T) { + location, _ := time.LoadLocation("UTC") + start, _ := time.ParseInLocation(time.RFC3339Nano, + "2022-06-16T08:28:53.33441Z", + location) + end, _ := time.ParseInLocation(time.RFC3339Nano, + "2022-06-16T15:28:53.33441Z", + location) + // simple interval + i := intervals.NewInterval().SetInterval(start, + end) + filter1 := NewSelector().SetDimension("countryName").SetValue("France") + filterInterval := NewInterval().SetIntervals([]*intervals.Interval{i}).SetDimension("__time") + filters := NewOr().SetFields([]builder.Filter{filter1, filterInterval}) + + t.Run("marshal filter with interval", + func(t *testing.T) { + f, err := json.Marshal(filters) + assert.Nil(t, + err) + + assert.Nil(t, + err) + assert.Equal(t, + `{"type":"or","fields":[{"type":"selector","dimension":"countryName","value":"France"},{"type":"interval","dimension":"__time","intervals":["2022-06-16T08:28:53.33441Z/2022-06-16T15:28:53.33441Z"]}]}`, + string(f), + "filter with time interval") + }) + + t.Run("marshal load marshal filter with interval", + func(t *testing.T) { + f, err := json.Marshal(filters) + assert.Nil(t, + err) + + filterWithIntervalObj, err := Load(f) + assert.Nil(t, + err) + assert.NotNil(t, + filterWithIntervalObj) + assert.Equal(t, + filters, + filterWithIntervalObj) + + fJson, err := json.Marshal(filterWithIntervalObj) + assert.Nil(t, + err) + + assert.Nil(t, + err) + assert.Equal(t, + `{"type":"or","fields":[{"type":"selector","dimension":"countryName","value":"France"},{"type":"interval","dimension":"__time","intervals":["2022-06-16T08:28:53.33441Z/2022-06-16T15:28:53.33441Z"]}]}`, + string(fJson), + "filter with time interval") + }) } diff --git a/builder/filter/interval.go b/builder/filter/interval.go index f31f221..1b2bcd3 100644 --- a/builder/filter/interval.go +++ b/builder/filter/interval.go @@ -10,10 +10,10 @@ import ( type Interval struct { Base - Dimension string `json:"dimension,omitempty"` - Intervals builder.Intervals `json:"intervals,omitempty"` - ExtractionFn builder.ExtractionFn `json:"extractionFn,omitempty"` - FilterTuning *FilterTuning `json:"filterTuning,omitempty"` + Dimension string `json:"dimension,omitempty"` + Intervals []*intervals.Interval `json:"intervals,omitempty"` + ExtractionFn builder.ExtractionFn `json:"extractionFn,omitempty"` + FilterTuning *FilterTuning `json:"filterTuning,omitempty"` } func NewInterval() *Interval { @@ -27,7 +27,7 @@ func (i *Interval) SetDimension(dimension string) *Interval { return i } -func (i *Interval) SetIntervals(intervals builder.Intervals) *Interval { +func (i *Interval) SetIntervals(intervals []*intervals.Interval) *Interval { i.Intervals = intervals return i } @@ -51,7 +51,8 @@ func (i *Interval) UnmarshalJSON(data []byte) error { ExtractionFn json.RawMessage `json:"extractionFn,omitempty"` FilterTuning *FilterTuning `json:"filterTuning,omitempty"` } - if err = json.Unmarshal(data, &tmp); err != nil { + if err = json.Unmarshal(data, + &tmp); err != nil { return err } var e builder.ExtractionFn @@ -61,9 +62,10 @@ func (i *Interval) UnmarshalJSON(data []byte) error { return err } } - var ii builder.Intervals + var ii []*intervals.Interval if tmp.Intervals != nil { - ii, err = intervals.Load(tmp.Intervals) + err = json.Unmarshal(tmp.Intervals, + &ii) if err != nil { return err } diff --git a/builder/intervals/default.go b/builder/intervals/default.go index 1257152..d0cb1a2 100644 --- a/builder/intervals/default.go +++ b/builder/intervals/default.go @@ -1,7 +1,5 @@ package intervals -import "encoding/json" - type Intervals struct { Base Intervals []*Interval `json:"intervals,omitempty"` @@ -17,7 +15,3 @@ func (i *Intervals) SetIntervals(intervals []*Interval) *Intervals { i.Intervals = intervals return i } - -func (i *Intervals) MarshalJSON() ([]byte, error) { - return json.Marshal(i.Intervals) -} diff --git a/builder/intervals/intervals_test.go b/builder/intervals/intervals_test.go index 91511aa..5353b77 100644 --- a/builder/intervals/intervals_test.go +++ b/builder/intervals/intervals_test.go @@ -1,17 +1,103 @@ package intervals import ( + "encoding/json" + "fmt" "testing" + "time" "github.com/stretchr/testify/assert" ) -func TestLoadUnsupportedType(t *testing.T) { +func TestIntervals_Load(t *testing.T) { assert := assert.New(t) + t.Run("test unsupported type", + func(t *testing.T) { + f, err := Load([]byte("{\"type\": \"blahblahType\"}")) - f, err := Load([]byte("{\"type\": \"blahblahType\"}")) + assert.Nil(f, + "filter should be nil") + assert.NotNil(err, + "error should not be nil") + assert.Error(err, + "unsupported intervals type") + }) - assert.Nil(f, "filter should be nil") - assert.NotNil(err, "error should not be nil") - assert.Error(err, "unsupported intervals type") + t.Run("simple interval not supported", + func(t *testing.T) { + f, err := Load([]byte(`"2022-06-16T08:28:53.33441Z/2022-06-16T15:28:53.33441Z"`)) + + assert.Nil(f, + "filter should be nil") + assert.NotNil(err, + "error should not be nil") + assert.Error(err, + "unsupported intervals type") + }) + + t.Run("complex interval supported", + func(t *testing.T) { + f, err := Load([]byte(`{"type":"intervals","intervals":["2022-06-16T08:28:53.33441Z/2022-06-16T15:28:53.33441Z"]}`)) + location, _ := time.LoadLocation("UTC") + start, _ := time.ParseInLocation(time.RFC3339Nano, + "2022-06-16T08:28:53.33441Z", + location) + end, _ := time.ParseInLocation(time.RFC3339Nano, + "2022-06-16T15:28:53.33441Z", + location) + // simple interval + interval := NewInterval().SetInterval(start, + end) + // complex intervals + intervals := NewIntervals().SetIntervals([]*Interval{interval}) + + assert.Nil(err, + "error should be nil") + assert.Equal(intervals, + f, + "loaded intervals match the built intervals") + }) +} + +func TestIntervals_MarshalJSON(t *testing.T) { + location, _ := time.LoadLocation("UTC") + start, _ := time.ParseInLocation(time.RFC3339Nano, + "2022-06-16T08:28:53.33441Z", + location) + end, _ := time.ParseInLocation(time.RFC3339Nano, + "2022-06-16T15:28:53.33441Z", + location) + // simple interval + interval := NewInterval().SetInterval(start, + end) + // complex intervals + intervals := NewIntervals().SetIntervals([]*Interval{interval}) + + t.Run("simple interval returns a string", + func(t *testing.T) { + f, err := json.Marshal(interval) + if err != nil { + fmt.Println(err.Error()) + } + assert.Nil(t, + err) + assert.Equal(t, + `"2022-06-16T08:28:53.33441Z/2022-06-16T15:28:53.33441Z"`, + string(f), + "simple interval returns a string") + }) + + t.Run("marshal generates complex interval type", + func(t *testing.T) { + f, err := json.Marshal(intervals) + if err != nil { + fmt.Println(err.Error()) + } + assert.Nil(t, + err) + assert.Equal(t, + `{"type":"intervals","intervals":["2022-06-16T08:28:53.33441Z/2022-06-16T15:28:53.33441Z"]}`, + string(f), + "complex interval returns a struct") + }) }