index and return parentid in search report

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
Jörn Friedrich Dreyer
2022-10-07 09:35:24 +00:00
parent c4b09b0e02
commit 1bb7d57caf
17 changed files with 117 additions and 450 deletions
+3 -1
View File
@@ -24,7 +24,9 @@ docs-generate: config-docs-generate
include ../../.make/generate.mk
.PHONY: ci-go-generate
ci-go-generate: # CI runs ci-node-generate automatically before this target
ci-go-generate: $(MOCKERY) # CI runs ci-node-generate automatically before this target
$(MOCKERY) --dir pkg/search --output pkg/search/mocks --case underscore --name IndexClient
$(MOCKERY) --dir pkg/search --output pkg/search/mocks --case underscore --name ProviderClient
.PHONY: ci-node-generate
ci-node-generate:
+15 -4
View File
@@ -44,9 +44,10 @@ import (
)
type indexDocument struct {
RootID string
Path string
ID string
RootID string
Path string
ID string
ParentID string
Name string
Size uint64
@@ -170,7 +171,7 @@ func (i *Index) Purge(id *sprovider.ResourceId) error {
}
// Move update the path of an entry and all its children
func (i *Index) Move(id *sprovider.ResourceId, fullPath string) error {
func (i *Index) Move(id, newParentID *sprovider.ResourceId, fullPath string) error {
bleveId := idToBleveId(id)
doc, err := i.getEntity(bleveId)
if err != nil {
@@ -182,6 +183,7 @@ func (i *Index) Move(id *sprovider.ResourceId, fullPath string) error {
doc, err = i.updateEntity(bleveId, func(doc *indexDocument) {
doc.Path = newName
doc.Name = path.Base(newName)
doc.ParentID = idToBleveId(newParentID)
})
if err != nil {
return err
@@ -284,6 +286,7 @@ func toEntity(ref *sprovider.Reference, ri *sprovider.ResourceInfo) *indexDocume
RootID: idToBleveId(ref.ResourceId),
Path: ref.Path,
ID: idToBleveId(ri.Id),
ParentID: idToBleveId(ri.ParentId),
Name: ri.Path,
Size: ri.Size,
MimeType: ri.MimeType,
@@ -303,6 +306,7 @@ func fieldsToEntity(fields map[string]interface{}) *indexDocument {
RootID: fields["RootID"].(string),
Path: fields["Path"].(string),
ID: fields["ID"].(string),
ParentID: fields["ParentID"].(string),
Name: fields["Name"].(string),
Size: uint64(fields["Size"].(float64)),
Mtime: fields["Mtime"].(string),
@@ -338,6 +342,13 @@ func fromDocumentMatch(hit *search.DocumentMatch) (*searchmsg.Match, error) {
Deleted: hit.Fields["Deleted"].(bool),
},
}
if hit.Fields["ParentID"] != nil && hit.Fields["ParentID"] != "" {
parentID, err := storagespace.ParseID(hit.Fields["ParentID"].(string))
if err != nil {
return nil, err
}
match.Entity.ParentId = resourceIDtoSearchID(parentID)
}
if mtime, err := time.Parse(time.RFC3339, hit.Fields["Mtime"].(string)); err == nil {
match.Entity.LastModifiedTime = &timestamppb.Timestamp{Seconds: mtime.Unix(), Nanos: int32(mtime.Nanosecond())}
+35 -2
View File
@@ -38,6 +38,11 @@ var _ = Describe("Index", func() {
SpaceId: "spaceid",
OpaqueId: "parentopaqueid",
},
ParentId: &sprovider.ResourceId{
StorageId: "provider-1",
SpaceId: "spaceid",
OpaqueId: "myopaqueid",
},
Path: "sub d!r",
Size: 12345,
Type: sprovider.ResourceType_RESOURCE_TYPE_CONTAINER,
@@ -370,20 +375,48 @@ var _ = Describe("Index", func() {
})
Describe("Move", func() {
It("moves the parent and its child resources", func() {
It("renames the parent and its child resources", func() {
err := i.Add(parentRef, parentRi)
Expect(err).ToNot(HaveOccurred())
err = i.Add(childRef, childRi)
Expect(err).ToNot(HaveOccurred())
parentRi.Path = "newname"
err = i.Move(parentRi.Id, "./somewhere/else/newname")
err = i.Move(parentRi.Id, parentRi.ParentId, "./my/newname")
Expect(err).ToNot(HaveOccurred())
assertDocCount(rootId, `sub\ d!r`, 0)
matches := assertDocCount(rootId, "Name:child.pdf", 1)
Expect(matches[0].Entity.ParentId.OpaqueId).To(Equal("parentopaqueid"))
Expect(matches[0].Entity.Ref.Path).To(Equal("./my/newname/child.pdf"))
})
It("moves the parent and its child resources", func() {
err := i.Add(parentRef, parentRi)
Expect(err).ToNot(HaveOccurred())
err = i.Add(childRef, childRi)
Expect(err).ToNot(HaveOccurred())
parentRi.Path = " "
parentRi.ParentId = &sprovider.ResourceId{
StorageId: "provider-1",
SpaceId: "spaceid",
OpaqueId: "somewhereopaqueid",
}
err = i.Move(parentRi.Id, parentRi.ParentId, "./somewhere/else/newname")
Expect(err).ToNot(HaveOccurred())
assertDocCount(rootId, `sub\ d!r`, 0)
matches := assertDocCount(rootId, "Name:child.pdf", 1)
Expect(matches[0].Entity.ParentId.OpaqueId).To(Equal("parentopaqueid"))
Expect(matches[0].Entity.Ref.Path).To(Equal("./somewhere/else/newname/child.pdf"))
matches = assertDocCount(rootId, `newname`, 1)
Expect(matches[0].Entity.ParentId.OpaqueId).To(Equal("somewhereopaqueid"))
Expect(matches[0].Entity.Ref.Path).To(Equal("./somewhere/else/newname"))
})
})
})
@@ -1,415 +0,0 @@
// Code generated by mockery v2.10.0. DO NOT EDIT.
package mocks
import (
context "context"
bleve "github.com/blevesearch/bleve/v2"
index "github.com/blevesearch/bleve_index_api"
mapping "github.com/blevesearch/bleve/v2/mapping"
mock "github.com/stretchr/testify/mock"
)
// BleveIndex is an autogenerated mock type for the BleveIndex type
type BleveIndex struct {
mock.Mock
}
// Advanced provides a mock function with given fields:
func (_m *BleveIndex) Advanced() (index.Index, error) {
ret := _m.Called()
var r0 index.Index
if rf, ok := ret.Get(0).(func() index.Index); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(index.Index)
}
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Batch provides a mock function with given fields: b
func (_m *BleveIndex) Batch(b *bleve.Batch) error {
ret := _m.Called(b)
var r0 error
if rf, ok := ret.Get(0).(func(*bleve.Batch) error); ok {
r0 = rf(b)
} else {
r0 = ret.Error(0)
}
return r0
}
// Close provides a mock function with given fields:
func (_m *BleveIndex) Close() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// Delete provides a mock function with given fields: id
func (_m *BleveIndex) Delete(id string) error {
ret := _m.Called(id)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(id)
} else {
r0 = ret.Error(0)
}
return r0
}
// DeleteInternal provides a mock function with given fields: key
func (_m *BleveIndex) DeleteInternal(key []byte) error {
ret := _m.Called(key)
var r0 error
if rf, ok := ret.Get(0).(func([]byte) error); ok {
r0 = rf(key)
} else {
r0 = ret.Error(0)
}
return r0
}
// DocCount provides a mock function with given fields:
func (_m *BleveIndex) DocCount() (uint64, error) {
ret := _m.Called()
var r0 uint64
if rf, ok := ret.Get(0).(func() uint64); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(uint64)
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Document provides a mock function with given fields: id
func (_m *BleveIndex) Document(id string) (index.Document, error) {
ret := _m.Called(id)
var r0 index.Document
if rf, ok := ret.Get(0).(func(string) index.Document); ok {
r0 = rf(id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(index.Document)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// FieldDict provides a mock function with given fields: field
func (_m *BleveIndex) FieldDict(field string) (index.FieldDict, error) {
ret := _m.Called(field)
var r0 index.FieldDict
if rf, ok := ret.Get(0).(func(string) index.FieldDict); ok {
r0 = rf(field)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(index.FieldDict)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(field)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// FieldDictPrefix provides a mock function with given fields: field, termPrefix
func (_m *BleveIndex) FieldDictPrefix(field string, termPrefix []byte) (index.FieldDict, error) {
ret := _m.Called(field, termPrefix)
var r0 index.FieldDict
if rf, ok := ret.Get(0).(func(string, []byte) index.FieldDict); ok {
r0 = rf(field, termPrefix)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(index.FieldDict)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string, []byte) error); ok {
r1 = rf(field, termPrefix)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// FieldDictRange provides a mock function with given fields: field, startTerm, endTerm
func (_m *BleveIndex) FieldDictRange(field string, startTerm []byte, endTerm []byte) (index.FieldDict, error) {
ret := _m.Called(field, startTerm, endTerm)
var r0 index.FieldDict
if rf, ok := ret.Get(0).(func(string, []byte, []byte) index.FieldDict); ok {
r0 = rf(field, startTerm, endTerm)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(index.FieldDict)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string, []byte, []byte) error); ok {
r1 = rf(field, startTerm, endTerm)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Fields provides a mock function with given fields:
func (_m *BleveIndex) Fields() ([]string, error) {
ret := _m.Called()
var r0 []string
if rf, ok := ret.Get(0).(func() []string); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]string)
}
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetInternal provides a mock function with given fields: key
func (_m *BleveIndex) GetInternal(key []byte) ([]byte, error) {
ret := _m.Called(key)
var r0 []byte
if rf, ok := ret.Get(0).(func([]byte) []byte); ok {
r0 = rf(key)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
var r1 error
if rf, ok := ret.Get(1).(func([]byte) error); ok {
r1 = rf(key)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Index provides a mock function with given fields: id, data
func (_m *BleveIndex) Index(id string, data interface{}) error {
ret := _m.Called(id, data)
var r0 error
if rf, ok := ret.Get(0).(func(string, interface{}) error); ok {
r0 = rf(id, data)
} else {
r0 = ret.Error(0)
}
return r0
}
// Mapping provides a mock function with given fields:
func (_m *BleveIndex) Mapping() mapping.IndexMapping {
ret := _m.Called()
var r0 mapping.IndexMapping
if rf, ok := ret.Get(0).(func() mapping.IndexMapping); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(mapping.IndexMapping)
}
}
return r0
}
// Name provides a mock function with given fields:
func (_m *BleveIndex) Name() string {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
// NewBatch provides a mock function with given fields:
func (_m *BleveIndex) NewBatch() *bleve.Batch {
ret := _m.Called()
var r0 *bleve.Batch
if rf, ok := ret.Get(0).(func() *bleve.Batch); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*bleve.Batch)
}
}
return r0
}
// Search provides a mock function with given fields: req
func (_m *BleveIndex) Search(req *bleve.SearchRequest) (*bleve.SearchResult, error) {
ret := _m.Called(req)
var r0 *bleve.SearchResult
if rf, ok := ret.Get(0).(func(*bleve.SearchRequest) *bleve.SearchResult); ok {
r0 = rf(req)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*bleve.SearchResult)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(*bleve.SearchRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// SearchInContext provides a mock function with given fields: ctx, req
func (_m *BleveIndex) SearchInContext(ctx context.Context, req *bleve.SearchRequest) (*bleve.SearchResult, error) {
ret := _m.Called(ctx, req)
var r0 *bleve.SearchResult
if rf, ok := ret.Get(0).(func(context.Context, *bleve.SearchRequest) *bleve.SearchResult); ok {
r0 = rf(ctx, req)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*bleve.SearchResult)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *bleve.SearchRequest) error); ok {
r1 = rf(ctx, req)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// SetInternal provides a mock function with given fields: key, val
func (_m *BleveIndex) SetInternal(key []byte, val []byte) error {
ret := _m.Called(key, val)
var r0 error
if rf, ok := ret.Get(0).(func([]byte, []byte) error); ok {
r0 = rf(key, val)
} else {
r0 = ret.Error(0)
}
return r0
}
// SetName provides a mock function with given fields: _a0
func (_m *BleveIndex) SetName(_a0 string) {
_m.Called(_a0)
}
// Stats provides a mock function with given fields:
func (_m *BleveIndex) Stats() *bleve.IndexStat {
ret := _m.Called()
var r0 *bleve.IndexStat
if rf, ok := ret.Get(0).(func() *bleve.IndexStat); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*bleve.IndexStat)
}
}
return r0
}
// StatsMap provides a mock function with given fields:
func (_m *BleveIndex) StatsMap() map[string]interface{} {
ret := _m.Called()
var r0 map[string]interface{}
if rf, ok := ret.Get(0).(func() map[string]interface{}); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(map[string]interface{})
}
}
return r0
}
@@ -1,4 +1,4 @@
// Code generated by mockery v2.10.0. DO NOT EDIT.
// Code generated by mockery v2.10.4. DO NOT EDIT.
package mocks
@@ -65,13 +65,13 @@ func (_m *IndexClient) DocCount() (uint64, error) {
return r0, r1
}
// Move provides a mock function with given fields: id, fullPath
func (_m *IndexClient) Move(id *providerv1beta1.ResourceId, fullPath string) error {
ret := _m.Called(id, fullPath)
// Move provides a mock function with given fields: id, parentID, fullPath
func (_m *IndexClient) Move(id *providerv1beta1.ResourceId, parentID *providerv1beta1.ResourceId, fullPath string) error {
ret := _m.Called(id, parentID, fullPath)
var r0 error
if rf, ok := ret.Get(0).(func(*providerv1beta1.ResourceId, string) error); ok {
r0 = rf(id, fullPath)
if rf, ok := ret.Get(0).(func(*providerv1beta1.ResourceId, *providerv1beta1.ResourceId, string) error); ok {
r0 = rf(id, parentID, fullPath)
} else {
r0 = ret.Error(0)
}
@@ -1,4 +1,4 @@
// Code generated by mockery v2.10.0. DO NOT EDIT.
// Code generated by mockery v2.10.4. DO NOT EDIT.
package mocks
@@ -99,7 +99,7 @@ func (p *Provider) handleEvent(ev interface{}) {
return
}
err = p.indexClient.Move(statRes.Info.Id, gpRes.Path)
err = p.indexClient.Move(statRes.GetInfo().GetId(), statRes.GetInfo().GetParentId(), gpRes.Path)
if err != nil {
p.logger.Error().Err(err).Msg("failed to move the changed resource in the index")
}
@@ -188,7 +188,7 @@ var _ = Describe("Searchprovider", func() {
}, nil)
indexClient.On("Move", mock.MatchedBy(func(id *sprovider.ResourceId) bool {
return id.OpaqueId == ri.Id.OpaqueId
}), "./new/path.pdf").Return(nil).Run(func(args mock.Arguments) {
}), mock.Anything, "./new/path.pdf").Return(nil).Run(func(args mock.Arguments) {
called = true
})
ref.Path = "./new/path.pdf"
+1 -1
View File
@@ -38,7 +38,7 @@ type ProviderClient interface {
type IndexClient interface {
Search(ctx context.Context, req *searchsvc.SearchIndexRequest) (*searchsvc.SearchIndexResponse, error)
Add(ref *providerv1beta1.Reference, ri *providerv1beta1.ResourceInfo) error
Move(id *providerv1beta1.ResourceId, fullPath string) error
Move(id, parentID *providerv1beta1.ResourceId, fullPath string) error
Delete(id *providerv1beta1.ResourceId) error
Restore(id *providerv1beta1.ResourceId) error
Purge(id *providerv1beta1.ResourceId) error
+7
View File
@@ -171,6 +171,13 @@ func matchToPropResponse(ctx context.Context, match *searchmsg.Match) (*propfind
SpaceId: match.Entity.Id.SpaceId,
OpaqueId: match.Entity.Id.OpaqueId,
})))
if match.Entity.ParentId != nil {
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:file-parent", storagespace.FormatResourceID(provider.ResourceId{
StorageId: match.Entity.ParentId.StorageId,
SpaceId: match.Entity.ParentId.SpaceId,
OpaqueId: match.Entity.ParentId.OpaqueId,
})))
}
if match.Entity.Ref.ResourceId.StorageId == utils.ShareStorageProviderID {
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:shareid", match.Entity.Ref.ResourceId.OpaqueId))
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:shareroot", match.Entity.ShareRootName))