From 3d3ee2c855c4596d5370e1b2867386457d6596b3 Mon Sep 17 00:00:00 2001 From: CascadingRadium Date: Tue, 5 Sep 2023 20:20:09 +0530 Subject: [PATCH 1/4] retain layout --- index_impl.go | 4 +- search.go | 25 +++--- search/facet/facet_builder_datetime.go | 18 ++-- search_test.go | 120 +++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 19 deletions(-) diff --git a/index_impl.go b/index_impl.go index 592b3c694..601427b5a 100644 --- a/index_impl.go +++ b/index_impl.go @@ -532,8 +532,8 @@ func (i *indexImpl) SearchInContext(ctx context.Context, req *SearchRequest) (sr facetBuilder := facet.NewDateTimeFacetBuilder(facetRequest.Field, facetRequest.Size) dateTimeParser := i.m.DateTimeParserNamed("") for _, dr := range facetRequest.DateTimeRanges { - start, end := dr.ParseDates(dateTimeParser) - facetBuilder.AddRange(dr.Name, start, end) + start, end, startLayout, endLayout := dr.ParseDates(dateTimeParser) + facetBuilder.AddRange(dr.Name, start, end, startLayout, endLayout) } facetsBuilder.Add(facetName, facetBuilder) } else { diff --git a/search.go b/search.go index db5ced3f4..4445f9e22 100644 --- a/search.go +++ b/search.go @@ -52,29 +52,34 @@ type numericRange struct { } type dateTimeRange struct { - Name string `json:"name,omitempty"` - Start time.Time `json:"start,omitempty"` - End time.Time `json:"end,omitempty"` - startString *string - endString *string + Name string `json:"name,omitempty"` + Start time.Time `json:"start,omitempty"` + End time.Time `json:"end,omitempty"` + DateTimeParser string `json:"date_time_parser,omitempty"` + startString *string + endString *string } -func (dr *dateTimeRange) ParseDates(dateTimeParser analysis.DateTimeParser) (start, end time.Time) { +func (dr *dateTimeRange) ParseDates(dateTimeParser analysis.DateTimeParser) (start, end time.Time, startLayout, endLayout string) { start = dr.Start + startLayout = time.RFC3339Nano if dr.Start.IsZero() && dr.startString != nil { - s, _, err := dateTimeParser.ParseDateTime(*dr.startString) + s, layout, err := dateTimeParser.ParseDateTime(*dr.startString) if err == nil { start = s + startLayout = layout } } end = dr.End + endLayout = time.RFC3339Nano if dr.End.IsZero() && dr.endString != nil { - e, _, err := dateTimeParser.ParseDateTime(*dr.endString) + e, layout, err := dateTimeParser.ParseDateTime(*dr.endString) if err == nil { end = e + endLayout = layout } } - return start, end + return start, end, startLayout, endLayout } func (dr *dateTimeRange) UnmarshalJSON(input []byte) error { @@ -155,7 +160,7 @@ func (fr *FacetRequest) Validate() error { return fmt.Errorf("date ranges contains duplicate name '%s'", dr.Name) } drNames[dr.Name] = struct{}{} - start, end := dr.ParseDates(dateTimeParser) + start, end, _, _ := dr.ParseDates(dateTimeParser) if start.IsZero() && end.IsZero() { return fmt.Errorf("date range query must specify either start, end or both for range name '%s'", dr.Name) } diff --git a/search/facet/facet_builder_datetime.go b/search/facet/facet_builder_datetime.go index ff5167f21..450d562f4 100644 --- a/search/facet/facet_builder_datetime.go +++ b/search/facet/facet_builder_datetime.go @@ -35,8 +35,10 @@ func init() { } type dateTimeRange struct { - start time.Time - end time.Time + start time.Time + end time.Time + startLayout string + endLayout string } type DateTimeFacetBuilder struct { @@ -75,10 +77,12 @@ func (fb *DateTimeFacetBuilder) Size() int { return sizeInBytes } -func (fb *DateTimeFacetBuilder) AddRange(name string, start, end time.Time) { +func (fb *DateTimeFacetBuilder) AddRange(name string, start, end time.Time, startLayout string, endLayout string) { r := dateTimeRange{ - start: start, - end: end, + start: start, + end: end, + startLayout: startLayout, + endLayout: endLayout, } fb.ranges[name] = &r } @@ -134,11 +138,11 @@ func (fb *DateTimeFacetBuilder) Result() *search.FacetResult { Count: count, } if !dateRange.start.IsZero() { - start := dateRange.start.Format(time.RFC3339Nano) + start := dateRange.start.Format(dateRange.startLayout) tf.Start = &start } if !dateRange.end.IsZero() { - end := dateRange.end.Format(time.RFC3339Nano) + end := dateRange.end.Format(dateRange.endLayout) tf.End = &end } rv.DateRanges = append(rv.DateRanges, tf) diff --git a/search_test.go b/search_test.go index 414c907c8..3b98c42b6 100644 --- a/search_test.go +++ b/search_test.go @@ -2473,3 +2473,123 @@ func TestCustomDateTimeParserLayoutValidation(t *testing.T) { } } } + +func TestDateRangeFaceQueriesWithCustomDateTimeParser(t *testing.T) { + idxMapping := NewIndexMapping() + + err := idxMapping.AddCustomDateTimeParser("customDT", map[string]interface{}{ + "type": sanitized.Name, + "layouts": []interface{}{ + "02/01/2006 15:04:05", + "2006/01/02 3:04PM", + }, + }) + + if err != nil { + t.Fatal(err) + } + + err = idxMapping.AddCustomDateTimeParser("queryDT", map[string]interface{}{ + "type": sanitized.Name, + "layouts": []interface{}{ + "02/01/2006 3:04PM", + }, + }) + + if err != nil { + t.Fatal(err) + } + + dtmap := NewDateTimeFieldMapping() + dtmap.DateFormat = "customDT" + idxMapping.DefaultMapping.AddFieldMappingsAt("date", dtmap) + + tmpIndexPath := createTmpIndexPath(t) + defer cleanupTmpIndexPath(t, tmpIndexPath) + + idx, err := New(tmpIndexPath, idxMapping) + if err != nil { + t.Fatal(err) + } + defer func() { + err = idx.Close() + if err != nil { + t.Fatal(err) + } + }() + documents := map[string]map[string]interface{}{ + "doc1": { + "date": "2001/08/20 6:00PM", + }, + "doc2": { + "date": "20/08/2001 18:00:20", + }, + "doc3": { + "date": "20/08/2001 18:10:00", + }, + "doc4": { + "date": "2001/08/20 6:15PM", + }, + "doc5": { + "date": "22/08/2001 18:20:00", + }, + } + + batch := idx.NewBatch() + for docID, doc := range documents { + err := batch.Index(docID, doc) + if err != nil { + t.Fatal(err) + } + } + err = idx.Batch(batch) + if err != nil { + t.Fatal(err) + } + + query := NewMatchAllQuery() + + type testResult struct { + name string + start string + end string + } + + type testStruct struct { + name string + start string + end string + count int + } + + tests := []testStruct{ + { + name: "test1", + start: "2001-08-20", + end: "2001-08-21", + }, + } + + for _, test := range tests { + searchRequest := NewSearchRequest(query) + + fr := NewFacetRequest("dateFacet", 100) + fr.Field = "date" + fr.AddDateTimeRangeString(test.name, &test.start, &test.end) + searchRequest.AddFacet("dateFacet", fr) + + searchResults, err := idx.Search(searchRequest) + if err != nil { + t.Fatal(err) + } + t.Log(searchResults) + for _, facetResult := range searchResults.Facets { + for _, dateRange := range facetResult.DateRanges { + t.Log(dateRange.Name) + t.Log(*dateRange.Start) + t.Log(*dateRange.End) + t.Log(dateRange.Count) + } + } + } +} From 833f787021303e93f8e7ce77755cc170744aebec Mon Sep 17 00:00:00 2001 From: CascadingRadium Date: Wed, 6 Sep 2023 04:13:03 +0530 Subject: [PATCH 2/4] query override --- index_impl.go | 17 +++++++-- search.go | 63 ++++++++++++++++++++++++-------- search_test.go | 97 +++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 141 insertions(+), 36 deletions(-) diff --git a/index_impl.go b/index_impl.go index 601427b5a..5779a98d3 100644 --- a/index_impl.go +++ b/index_impl.go @@ -530,9 +530,22 @@ func (i *indexImpl) SearchInContext(ctx context.Context, req *SearchRequest) (sr } else if facetRequest.DateTimeRanges != nil { // build date range facet facetBuilder := facet.NewDateTimeFacetBuilder(facetRequest.Field, facetRequest.Size) - dateTimeParser := i.m.DateTimeParserNamed("") + dateTimeParserName := defaultDateTimeParser for _, dr := range facetRequest.DateTimeRanges { - start, end, startLayout, endLayout := dr.ParseDates(dateTimeParser) + if dr.DateTimeParser != "" { + dateTimeParserName = dr.DateTimeParser + } + dateTimeParser := i.m.DateTimeParserNamed(dateTimeParserName) + if dateTimeParser == nil { + return nil, fmt.Errorf("no date time parser named `%s` registered", dateTimeParserName) + } + start, end, startLayout, endLayout, err := dr.ParseDates(dateTimeParser) + if err != nil { + return nil, err + } + if start.IsZero() && end.IsZero() { + return nil, fmt.Errorf("date range query must specify either start, end or both for range name '%s'", dr.Name) + } facetBuilder.AddRange(dr.Name, start, end, startLayout, endLayout) } facetsBuilder.Add(facetName, facetBuilder) diff --git a/search.go b/search.go index 4445f9e22..5003821c0 100644 --- a/search.go +++ b/search.go @@ -55,12 +55,12 @@ type dateTimeRange struct { Name string `json:"name,omitempty"` Start time.Time `json:"start,omitempty"` End time.Time `json:"end,omitempty"` - DateTimeParser string `json:"date_time_parser,omitempty"` + DateTimeParser string `json:"datetime_parser,omitempty"` startString *string endString *string } -func (dr *dateTimeRange) ParseDates(dateTimeParser analysis.DateTimeParser) (start, end time.Time, startLayout, endLayout string) { +func (dr *dateTimeRange) ParseDates(dateTimeParser analysis.DateTimeParser) (start, end time.Time, startLayout, endLayout string, err error) { start = dr.Start startLayout = time.RFC3339Nano if dr.Start.IsZero() && dr.startString != nil { @@ -68,6 +68,8 @@ func (dr *dateTimeRange) ParseDates(dateTimeParser analysis.DateTimeParser) (sta if err == nil { start = s startLayout = layout + } else { + err = fmt.Errorf("error parsing start date '%s' for range '%s': %v", *dr.startString, dr.Name, err) } } end = dr.End @@ -77,16 +79,19 @@ func (dr *dateTimeRange) ParseDates(dateTimeParser analysis.DateTimeParser) (sta if err == nil { end = e endLayout = layout + } else { + err = fmt.Errorf("error parsing start date '%s' for range '%s': %v", *dr.startString, dr.Name, err) } } - return start, end, startLayout, endLayout + return start, end, startLayout, endLayout, err } func (dr *dateTimeRange) UnmarshalJSON(input []byte) error { var temp struct { - Name string `json:"name,omitempty"` - Start *string `json:"start,omitempty"` - End *string `json:"end,omitempty"` + Name string `json:"name,omitempty"` + Start *string `json:"start,omitempty"` + End *string `json:"end,omitempty"` + DateTimeParser string `json:"datetime_parser,omitempty"` } err := json.Unmarshal(input, &temp) @@ -101,22 +106,33 @@ func (dr *dateTimeRange) UnmarshalJSON(input []byte) error { if temp.End != nil { dr.endString = temp.End } + if temp.DateTimeParser != "" { + dr.DateTimeParser = temp.DateTimeParser + } return nil } func (dr *dateTimeRange) MarshalJSON() ([]byte, error) { rv := map[string]interface{}{ - "name": dr.Name, - "start": dr.Start, - "end": dr.End, + "name": dr.Name, } - if dr.Start.IsZero() && dr.startString != nil { + + if !dr.Start.IsZero() { + rv["start"] = dr.Start + } else if dr.startString != nil { rv["start"] = dr.startString } - if dr.End.IsZero() && dr.endString != nil { + + if !dr.End.IsZero() { + rv["end"] = dr.End + } else if dr.endString != nil { rv["end"] = dr.endString } + + if dr.DateTimeParser != "" { + rv["datetime_parser"] = dr.DateTimeParser + } return json.Marshal(rv) } @@ -134,7 +150,7 @@ func (fr *FacetRequest) Validate() error { nrCount := len(fr.NumericRanges) drCount := len(fr.DateTimeRanges) if nrCount > 0 && drCount > 0 { - return fmt.Errorf("facet can only conain numeric ranges or date ranges, not both") + return fmt.Errorf("facet can only contain numeric ranges or date ranges, not both") } if nrCount > 0 { @@ -160,10 +176,18 @@ func (fr *FacetRequest) Validate() error { return fmt.Errorf("date ranges contains duplicate name '%s'", dr.Name) } drNames[dr.Name] = struct{}{} - start, end, _, _ := dr.ParseDates(dateTimeParser) + if dr.DateTimeParser != "" { + // cannot parse the date range dates as the defaultDateTimeParser is overridden + // so perform this validation at query time + continue + } + start, end, _, _, err := dr.ParseDates(dateTimeParser) if start.IsZero() && end.IsZero() { return fmt.Errorf("date range query must specify either start, end or both for range name '%s'", dr.Name) } + if err != nil { + return err + } } } return nil @@ -191,7 +215,7 @@ func (fr *FacetRequest) AddDateTimeRange(name string, start, end time.Time) { } // AddDateTimeRangeString adds a bucket to a field -// containing date values. +// containing date values. Uses defaultDateTimeParser to parse the date strings. func (fr *FacetRequest) AddDateTimeRangeString(name string, start, end *string) { if fr.DateTimeRanges == nil { fr.DateTimeRanges = make([]*dateTimeRange, 0, 1) @@ -200,6 +224,17 @@ func (fr *FacetRequest) AddDateTimeRangeString(name string, start, end *string) &dateTimeRange{Name: name, startString: start, endString: end}) } +// AddDateTimeRangeString adds a bucket to a field +// containing date values. Uses the specified parser to parse the date strings. +// provided the parser is registered in the index mapping. +func (fr *FacetRequest) AddDateTimeRangeStringWithParser(name string, start, end *string, parser string) { + if fr.DateTimeRanges == nil { + fr.DateTimeRanges = make([]*dateTimeRange, 0, 1) + } + fr.DateTimeRanges = append(fr.DateTimeRanges, + &dateTimeRange{Name: name, startString: start, endString: end, DateTimeParser: parser}) +} + // AddNumericRange adds a bucket to a field // containing numeric values. Documents with a // numeric value falling into this range are diff --git a/search_test.go b/search_test.go index 3b98c42b6..ddceff3b7 100644 --- a/search_test.go +++ b/search_test.go @@ -2531,7 +2531,7 @@ func TestDateRangeFaceQueriesWithCustomDateTimeParser(t *testing.T) { "date": "2001/08/20 6:15PM", }, "doc5": { - "date": "22/08/2001 18:20:00", + "date": "20/08/2001 18:20:00", }, } @@ -2549,46 +2549,103 @@ func TestDateRangeFaceQueriesWithCustomDateTimeParser(t *testing.T) { query := NewMatchAllQuery() - type testResult struct { + type testFacetResult struct { name string start string end string + count int } - type testStruct struct { - name string - start string - end string - count int + type testFacetRequest struct { + name string + start string + end string + parser string + result testFacetResult } - tests := []testStruct{ + tests := []testFacetRequest{ { - name: "test1", - start: "2001-08-20", - end: "2001-08-21", + // Test without a query time override of the parser (use default parser) + name: "test", + start: "2001-08-20 18:00:00", + end: "2001-08-20 18:10:00", + result: testFacetResult{ + name: "test", + start: "2001-08-20 18:00:00", + end: "2001-08-20 18:10:00", + count: 2, + }, + }, + { + name: "test", + start: "20/08/2001 6:00PM", + end: "20/08/2001 6:10PM", + parser: "queryDT", + result: testFacetResult{ + name: "test", + start: "20/08/2001 6:00PM", + end: "20/08/2001 6:10PM", + count: 2, + }, + }, + { + name: "test", + start: "20/08/2001 15:00:00", + end: "2001/08/20 6:10PM", + parser: "customDT", + result: testFacetResult{ + name: "test", + start: "20/08/2001 15:00:00", + end: "2001/08/20 6:10PM", + count: 2, + }, + }, + { + name: "test", + end: "2001/08/20 6:15PM", + parser: "customDT", + result: testFacetResult{ + name: "test", + end: "2001/08/20 6:15PM", + count: 3, + }, }, } for _, test := range tests { searchRequest := NewSearchRequest(query) - fr := NewFacetRequest("dateFacet", 100) - fr.Field = "date" - fr.AddDateTimeRangeString(test.name, &test.start, &test.end) + fr := NewFacetRequest("date", 100) + fr.AddDateTimeRangeStringWithParser(test.name, &test.start, &test.end, test.parser) searchRequest.AddFacet("dateFacet", fr) searchResults, err := idx.Search(searchRequest) if err != nil { t.Fatal(err) } - t.Log(searchResults) for _, facetResult := range searchResults.Facets { - for _, dateRange := range facetResult.DateRanges { - t.Log(dateRange.Name) - t.Log(*dateRange.Start) - t.Log(*dateRange.End) - t.Log(dateRange.Count) + if len(facetResult.DateRanges) != 1 { + t.Fatal("Expected 1 date range facet") + } + result := facetResult.DateRanges[0] + if result.Name != test.result.name { + t.Fatalf("Expected name %s, got %s", test.result.name, result.Name) + } + if result.Start != nil && *result.Start != test.result.start { + t.Fatalf("Expected start %s, got %s", test.result.start, *result.Start) + } + if result.End != nil && *result.End != test.result.end { + t.Fatalf("Expected end %s, got %s", test.result.end, *result.End) + } + if result.Start == nil && test.result.start != "" { + t.Fatalf("Expected start %s, got nil", test.result.start) + } + if result.End == nil && test.result.end != "" { + t.Fatalf("Expected end %s, got nil", test.result.end) + } + if result.Count != test.result.count { + t.Fatalf("Expected count %d, got %d", test.result.count, result.Count) } } } From 988b1339ed6280b1d35ebb46051e4d416cc56eb9 Mon Sep 17 00:00:00 2001 From: CascadingRadium Date: Wed, 6 Sep 2023 10:43:57 +0530 Subject: [PATCH 3/4] unit test cases --- index_impl.go | 4 +- search.go | 39 +++++++++--------- search/facet/facet_builder_datetime.go | 17 +++++++- search_test.go | 56 ++++++++++++++++++++++++-- test/tests/facet/searches.json | 4 +- 5 files changed, 90 insertions(+), 30 deletions(-) diff --git a/index_impl.go b/index_impl.go index 5779a98d3..df11c851b 100644 --- a/index_impl.go +++ b/index_impl.go @@ -541,10 +541,10 @@ func (i *indexImpl) SearchInContext(ctx context.Context, req *SearchRequest) (sr } start, end, startLayout, endLayout, err := dr.ParseDates(dateTimeParser) if err != nil { - return nil, err + return nil, fmt.Errorf("ParseDates err: %v, using date time parser named %s", err, dateTimeParserName) } if start.IsZero() && end.IsZero() { - return nil, fmt.Errorf("date range query must specify either start, end or both for range name '%s'", dr.Name) + return nil, fmt.Errorf("date range query must specify either start, end or both for date range name '%s'", dr.Name) } facetBuilder.AddRange(dr.Name, start, end, startLayout, endLayout) } diff --git a/search.go b/search.go index 5003821c0..74b79e85b 100644 --- a/search.go +++ b/search.go @@ -64,24 +64,22 @@ func (dr *dateTimeRange) ParseDates(dateTimeParser analysis.DateTimeParser) (sta start = dr.Start startLayout = time.RFC3339Nano if dr.Start.IsZero() && dr.startString != nil { - s, layout, err := dateTimeParser.ParseDateTime(*dr.startString) - if err == nil { - start = s - startLayout = layout - } else { - err = fmt.Errorf("error parsing start date '%s' for range '%s': %v", *dr.startString, dr.Name, err) + s, layout, parseError := dateTimeParser.ParseDateTime(*dr.startString) + if parseError != nil { + return start, end, startLayout, endLayout, fmt.Errorf("error parsing start date '%s' for date range name '%s': %v", *dr.startString, dr.Name, parseError) } + start = s + startLayout = layout } end = dr.End endLayout = time.RFC3339Nano if dr.End.IsZero() && dr.endString != nil { - e, layout, err := dateTimeParser.ParseDateTime(*dr.endString) - if err == nil { - end = e - endLayout = layout - } else { - err = fmt.Errorf("error parsing start date '%s' for range '%s': %v", *dr.startString, dr.Name, err) + e, layout, parseError := dateTimeParser.ParseDateTime(*dr.endString) + if parseError != nil { + return start, end, startLayout, endLayout, fmt.Errorf("error parsing end date '%s' for date range name '%s': %v", *dr.endString, dr.Name, parseError) } + end = e + endLayout = layout } return start, end, startLayout, endLayout, err } @@ -176,17 +174,16 @@ func (fr *FacetRequest) Validate() error { return fmt.Errorf("date ranges contains duplicate name '%s'", dr.Name) } drNames[dr.Name] = struct{}{} - if dr.DateTimeParser != "" { + if dr.DateTimeParser == "" { // cannot parse the date range dates as the defaultDateTimeParser is overridden // so perform this validation at query time - continue - } - start, end, _, _, err := dr.ParseDates(dateTimeParser) - if start.IsZero() && end.IsZero() { - return fmt.Errorf("date range query must specify either start, end or both for range name '%s'", dr.Name) - } - if err != nil { - return err + start, end, _, _, err := dr.ParseDates(dateTimeParser) + if err != nil { + return fmt.Errorf("ParseDates err: %v, using date time parser named %s", err, defaultDateTimeParser) + } + if start.IsZero() && end.IsZero() { + return fmt.Errorf("date range query must specify either start, end or both for range name '%s'", dr.Name) + } } } } diff --git a/search/facet/facet_builder_datetime.go b/search/facet/facet_builder_datetime.go index 450d562f4..c272396b7 100644 --- a/search/facet/facet_builder_datetime.go +++ b/search/facet/facet_builder_datetime.go @@ -17,6 +17,7 @@ package facet import ( "reflect" "sort" + "strconv" "time" "github.com/blevesearch/bleve/v2/numeric" @@ -138,11 +139,23 @@ func (fb *DateTimeFacetBuilder) Result() *search.FacetResult { Count: count, } if !dateRange.start.IsZero() { - start := dateRange.start.Format(dateRange.startLayout) + var start string + if dateRange.startLayout == "" { + // layout not set probably means it is probably a timestamp + start = strconv.FormatInt(dateRange.start.UnixNano(), 10) + } else { + start = dateRange.start.Format(dateRange.startLayout) + } tf.Start = &start } if !dateRange.end.IsZero() { - end := dateRange.end.Format(dateRange.endLayout) + var end string + if dateRange.endLayout == "" { + // layout not set probably means it is probably a timestamp + end = strconv.FormatInt(dateRange.end.UnixNano(), 10) + } else { + end = dateRange.end.Format(dateRange.endLayout) + } tf.End = &end } rv.DateRanges = append(rv.DateRanges, tf) diff --git a/search_test.go b/search_test.go index ddceff3b7..040cc63fc 100644 --- a/search_test.go +++ b/search_test.go @@ -282,7 +282,7 @@ func TestUnmarshalingSearchResult(t *testing.T) { func TestFacetNumericDateRangeRequests(t *testing.T) { var drMissingErr = fmt.Errorf("date range query must specify either start, end or both for range name 'testName'") var nrMissingErr = fmt.Errorf("numeric range query must specify either min, max or both for range name 'testName'") - var drNrErr = fmt.Errorf("facet can only conain numeric ranges or date ranges, not both") + var drNrErr = fmt.Errorf("facet can only contain numeric ranges or date ranges, not both") var drNameDupErr = fmt.Errorf("date ranges contains duplicate name 'testName'") var nrNameDupErr = fmt.Errorf("numeric ranges contains duplicate name 'testName'") value := float64(5) @@ -2554,6 +2554,7 @@ func TestDateRangeFaceQueriesWithCustomDateTimeParser(t *testing.T) { start string end string count int + err error } type testFacetRequest struct { @@ -2575,6 +2576,7 @@ func TestDateRangeFaceQueriesWithCustomDateTimeParser(t *testing.T) { start: "2001-08-20 18:00:00", end: "2001-08-20 18:10:00", count: 2, + err: nil, }, }, { @@ -2587,6 +2589,7 @@ func TestDateRangeFaceQueriesWithCustomDateTimeParser(t *testing.T) { start: "20/08/2001 6:00PM", end: "20/08/2001 6:10PM", count: 2, + err: nil, }, }, { @@ -2599,6 +2602,7 @@ func TestDateRangeFaceQueriesWithCustomDateTimeParser(t *testing.T) { start: "20/08/2001 15:00:00", end: "2001/08/20 6:10PM", count: 2, + err: nil, }, }, { @@ -2609,6 +2613,37 @@ func TestDateRangeFaceQueriesWithCustomDateTimeParser(t *testing.T) { name: "test", end: "2001/08/20 6:15PM", count: 3, + err: nil, + }, + }, + { + name: "test", + start: "20/08/2001 6:15PM", + parser: "queryDT", + result: testFacetResult{ + name: "test", + start: "20/08/2001 6:15PM", + count: 2, + err: nil, + }, + }, + // some error cases + { + name: "test", + parser: "queryDT", + result: testFacetResult{ + name: "test", + err: fmt.Errorf("date range query must specify either start, end or both for date range name 'test'"), + }, + }, + { + // default parser is used for the query, but the start time is not in the correct format (RFC3339), + // so it should throw an error + name: "test", + start: "20/08/2001 6:15PM", + result: testFacetResult{ + name: "test", + err: fmt.Errorf("ParseDates err: error parsing start date '20/08/2001 6:15PM' for date range name 'test': unable to parse datetime with any of the layouts, using date time parser named dateTimeOptional"), }, }, } @@ -2617,12 +2652,27 @@ func TestDateRangeFaceQueriesWithCustomDateTimeParser(t *testing.T) { searchRequest := NewSearchRequest(query) fr := NewFacetRequest("date", 100) - fr.AddDateTimeRangeStringWithParser(test.name, &test.start, &test.end, test.parser) + start := &test.start + if test.start == "" { + start = nil + } + end := &test.end + if test.end == "" { + end = nil + } + + fr.AddDateTimeRangeStringWithParser(test.name, start, end, test.parser) searchRequest.AddFacet("dateFacet", fr) searchResults, err := idx.Search(searchRequest) if err != nil { - t.Fatal(err) + if test.result.err == nil { + t.Fatalf("Unexpected error: %v", err) + } + if err.Error() != test.result.err.Error() { + t.Fatalf("Expected error %v, got %v", test.result.err, err) + } + continue } for _, facetResult := range searchResults.Facets { if len(facetResult.DateRanges) != 1 { diff --git a/test/tests/facet/searches.json b/test/tests/facet/searches.json index 6752282a4..33ac39775 100644 --- a/test/tests/facet/searches.json +++ b/test/tests/facet/searches.json @@ -129,12 +129,12 @@ { "name": "new", "count": 9, - "start": "2012-01-01T00:00:00Z" + "start": "2012-01-01" }, { "name": "old", "count": 1, - "end": "2012-01-01T00:00:00Z" + "end": "2012-01-01" } ] } From 12041113fe53f91f8114f0fd1bcc245b639ffeeb Mon Sep 17 00:00:00 2001 From: CascadingRadium Date: Thu, 7 Sep 2023 22:54:05 +0530 Subject: [PATCH 4/4] fix bug --- index_impl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index_impl.go b/index_impl.go index df11c851b..6c47872d2 100644 --- a/index_impl.go +++ b/index_impl.go @@ -530,8 +530,8 @@ func (i *indexImpl) SearchInContext(ctx context.Context, req *SearchRequest) (sr } else if facetRequest.DateTimeRanges != nil { // build date range facet facetBuilder := facet.NewDateTimeFacetBuilder(facetRequest.Field, facetRequest.Size) - dateTimeParserName := defaultDateTimeParser for _, dr := range facetRequest.DateTimeRanges { + dateTimeParserName := defaultDateTimeParser if dr.DateTimeParser != "" { dateTimeParserName = dr.DateTimeParser }