diff --git a/services/search/pkg/bleve/mtime_test.go b/services/search/pkg/bleve/mtime_test.go index c29c83d9b8..2118662289 100644 --- a/services/search/pkg/bleve/mtime_test.go +++ b/services/search/pkg/bleve/mtime_test.go @@ -1,6 +1,10 @@ package bleve_test import ( + "time" + + "github.com/opencloud-eu/opencloud/pkg/conversions" + bleveSearch "github.com/blevesearch/bleve/v2" bquery "github.com/blevesearch/bleve/v2/search/query" . "github.com/onsi/ginkgo/v2" @@ -21,7 +25,7 @@ var _ = Describe("Mtime date range", func() { idx, err := bleveSearch.NewMemOnly(m) Expect(err).ToNot(HaveOccurred()) - r := search.Resource{ID: "x", Document: content.Document{Name: "f", Mtime: "2026-03-15T12:00:00.123456789Z"}} + r := search.Resource{ID: "x", Document: content.Document{Name: "f", Mtime: conversions.ToPointer(time.Date(2026, 3, 15, 12, 0, 0, 123456789, time.UTC))}} doc, err := mapping.PrepareForIndex(r, r.SearchFieldOverrides()) Expect(err).ToNot(HaveOccurred()) Expect(idx.Index(r.ID, doc)).To(Succeed()) diff --git a/services/search/pkg/content/basic.go b/services/search/pkg/content/basic.go index 1499258c98..7ba8638a18 100644 --- a/services/search/pkg/content/basic.go +++ b/services/search/pkg/content/basic.go @@ -3,9 +3,9 @@ package content import ( "context" "encoding/json" - "time" storageProvider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/opencloud-eu/opencloud/pkg/conversions" "github.com/opencloud-eu/opencloud/pkg/log" "github.com/opencloud-eu/reva/v2/pkg/tags" "github.com/opencloud-eu/reva/v2/pkg/utils" @@ -54,7 +54,7 @@ func (b Basic) Extract(_ context.Context, ri *storageProvider.ResourceInfo) (Doc } if ri.Mtime != nil { - doc.Mtime = utils.TSToTime(ri.Mtime).UTC().Format(time.RFC3339Nano) + doc.Mtime = conversions.ToPointer(utils.TSToTime(ri.Mtime).UTC()) } return doc, nil diff --git a/services/search/pkg/content/basic_test.go b/services/search/pkg/content/basic_test.go index 86832ed418..709202fc33 100644 --- a/services/search/pkg/content/basic_test.go +++ b/services/search/pkg/content/basic_test.go @@ -1,6 +1,10 @@ package content_test import ( + "time" + + "github.com/opencloud-eu/opencloud/pkg/conversions" + "context" "encoding/json" @@ -69,11 +73,11 @@ var _ = Describe("Basic", func() { It("RFC3339 mtime", func() { for _, data := range []struct { second uint64 - expect string + expect *time.Time }{ - {second: 4000, expect: "1970-01-01T01:06:40Z"}, - {second: 3000, expect: "1970-01-01T00:50:00Z"}, - {expect: ""}, + {second: 4000, expect: conversions.ToPointer(time.Unix(4000, 0).UTC())}, + {second: 3000, expect: conversions.ToPointer(time.Unix(3000, 0).UTC())}, + {}, } { ri := &storageProvider.ResourceInfo{} diff --git a/services/search/pkg/content/content.go b/services/search/pkg/content/content.go index b162ccdcfc..a789847244 100644 --- a/services/search/pkg/content/content.go +++ b/services/search/pkg/content/content.go @@ -2,6 +2,7 @@ package content import ( "strings" + "time" "github.com/bbalet/stopwords" libregraph "github.com/opencloud-eu/libre-graph-api-go" @@ -18,7 +19,7 @@ type Document struct { Name string `json:"Name"` Content string `json:"Content"` Size uint64 `json:"Size"` - Mtime string `json:"Mtime"` + Mtime *time.Time `json:"Mtime"` MimeType string `json:"MimeType"` Tags []string `json:"Tags"` Favorites []string `json:"Favorites"` diff --git a/services/search/pkg/opensearch/backend_test.go b/services/search/pkg/opensearch/backend_test.go index 9ad254f835..2fb55f03b6 100644 --- a/services/search/pkg/opensearch/backend_test.go +++ b/services/search/pkg/opensearch/backend_test.go @@ -91,6 +91,16 @@ func TestEngine_Upsert(t *testing.T) { tc.Require.IndicesCount([]string{indexName}, nil, 1) }) + + t.Run("upsert without mtime", func(t *testing.T) { + // content.Extract leaves Mtime nil when the resource info carries none + document := opensearchtest.Testdata.Resources.File + document.ID = "1$1!4" + document.Mtime = nil + require.NoError(t, backend.Upsert(document.ID, document)) + + tc.Require.IndicesCount([]string{indexName}, nil, 2) + }) } func TestEngine_Move(t *testing.T) { diff --git a/services/search/pkg/opensearch/internal/convert/opensearch.go b/services/search/pkg/opensearch/internal/convert/opensearch.go index 1eef75ac88..01c662096c 100644 --- a/services/search/pkg/opensearch/internal/convert/opensearch.go +++ b/services/search/pkg/opensearch/internal/convert/opensearch.go @@ -3,7 +3,6 @@ package convert import ( "fmt" "strings" - "time" opensearchgoAPI "github.com/opensearch-project/opensearch-go/v4/opensearchapi" "google.golang.org/protobuf/types/known/timestamppb" @@ -86,8 +85,8 @@ func OpenSearchHitToMatch(hit opensearchgoAPI.SearchHit) (*searchMessage.Match, }, } - if mtime, err := time.Parse(time.RFC3339, resource.Mtime); err == nil { - match.Entity.LastModifiedTime = ×tamppb.Timestamp{Seconds: mtime.Unix(), Nanos: int32(mtime.Nanosecond())} + if resource.Mtime != nil { + match.Entity.LastModifiedTime = timestamppb.New(*resource.Mtime) } return match, nil diff --git a/services/search/pkg/search/search.go b/services/search/pkg/search/search.go index a659169672..c0dac8fe99 100644 --- a/services/search/pkg/search/search.go +++ b/services/search/pkg/search/search.go @@ -72,10 +72,6 @@ var resourceFieldOverrides = sync.OnceValue(func() map[string]mapping.FieldOpts "Tags": {Analyzer: "lowercaseKeyword", IncludeInAll: &excludeFromAll}, "Favorites": {Analyzer: "lowercaseKeyword", IncludeInAll: &excludeFromAll}, "location": {Type: mapping.TypeGeopoint}, - // Mtime is stored as an RFC3339 string; type it as a date so mtime:>... - // range queries are chronological on both backends (bleve DateRangeQuery - // / OpenSearch date range), not a lexicographic keyword compare. - "Mtime": {Type: mapping.TypeDatetime}, } })