From 492340f6f7036d8bb8af9965dabcd0fbf5d38337 Mon Sep 17 00:00:00 2001 From: fschade Date: Tue, 29 Jul 2025 14:31:06 +0200 Subject: [PATCH] enhancement(search): implement engine docCount --- .../dsl_query_term_level_term_test.go | 4 +- services/search/pkg/opensearch/engine.go | 43 ++++++++++++++++--- services/search/pkg/opensearch/engine_test.go | 36 +++++++++++++++- .../search/pkg/opensearch/internal/test/os.go | 22 ++++++++++ services/search/pkg/opensearch/opensearch.go | 2 + 5 files changed, 98 insertions(+), 9 deletions(-) diff --git a/services/search/pkg/opensearch/dsl_query_term_level_term_test.go b/services/search/pkg/opensearch/dsl_query_term_level_term_test.go index 8e5ad5c483..cc899ea644 100644 --- a/services/search/pkg/opensearch/dsl_query_term_level_term_test.go +++ b/services/search/pkg/opensearch/dsl_query_term_level_term_test.go @@ -17,11 +17,11 @@ func TestTermQuery(t *testing.T) { }, { name: "naked", - got: opensearch.NewTermQuery[bool]("deleted").Value(true), + got: opensearch.NewTermQuery[bool]("deleted").Value(false), want: map[string]any{ "term": map[string]any{ "deleted": map[string]any{ - "value": true, + "value": false, }, }, }, diff --git a/services/search/pkg/opensearch/engine.go b/services/search/pkg/opensearch/engine.go index 3ecaea9156..f912caad18 100644 --- a/services/search/pkg/opensearch/engine.go +++ b/services/search/pkg/opensearch/engine.go @@ -48,10 +48,19 @@ func (e *Engine) Move(id string, parentID string, target string) error { } func (e *Engine) Delete(id string) error { - _, err := e.client.Update(context.Background(), opensearchgoAPI.UpdateReq{ + body, err := json.Marshal(map[string]any{ + "doc": map[string]bool{ + "Deleted": true, + }, + }) + if err != nil { + return fmt.Errorf("failed to marshal body: %w", err) + } + + _, err = e.client.Update(context.Background(), opensearchgoAPI.UpdateReq{ Index: e.index, DocumentID: id, - Body: bytes.NewReader([]byte(`{"doc": {"Deleted": true}}`)), + Body: bytes.NewReader(body), }) if err != nil { return fmt.Errorf("failed to mark document as deleted: %w", err) @@ -61,10 +70,19 @@ func (e *Engine) Delete(id string) error { } func (e *Engine) Restore(id string) error { - _, err := e.client.Update(context.Background(), opensearchgoAPI.UpdateReq{ + body, err := json.Marshal(map[string]any{ + "doc": map[string]bool{ + "Deleted": false, + }, + }) + if err != nil { + return fmt.Errorf("failed to marshal body: %w", err) + } + + _, err = e.client.Update(context.Background(), opensearchgoAPI.UpdateReq{ Index: e.index, DocumentID: id, - Body: bytes.NewReader([]byte(`{"doc": {"Deleted": false}}`)), + Body: bytes.NewReader(body), }) if err != nil { return fmt.Errorf("failed to mark document as deleted: %w", err) @@ -86,5 +104,20 @@ func (e *Engine) Purge(id string) error { } func (e *Engine) DocCount() (uint64, error) { - return 0, nil + body, err := NewRootQuery( + NewTermQuery[bool]("Deleted").Value(false), + ).MarshalJSON() + if err != nil { + return 0, fmt.Errorf("failed to marshal query: %w", err) + } + + resp, err := e.client.Indices.Count(context.Background(), &opensearchgoAPI.IndicesCountReq{ + Indices: []string{e.index}, + Body: bytes.NewReader(body), + }) + if err != nil { + return 0, fmt.Errorf("failed to count documents: %w", err) + } + + return uint64(resp.Count), nil } diff --git a/services/search/pkg/opensearch/engine_test.go b/services/search/pkg/opensearch/engine_test.go index 8b1be51a87..e267729871 100644 --- a/services/search/pkg/opensearch/engine_test.go +++ b/services/search/pkg/opensearch/engine_test.go @@ -58,7 +58,7 @@ func TestEngine_Delete(t *testing.T) { } func TestEngine_Restore(t *testing.T) { - index := "test-engine-delete" + index := "test-engine-restore" tc := ostest.NewDefaultTestClient(t) tc.Require.IndicesReset([]string{index}) tc.Require.IndicesCount([]string{index}, "", 0) @@ -107,4 +107,36 @@ func TestEngine_Purge(t *testing.T) { }) } -func TestEngine_DocCount(t *testing.T) {} +func TestEngine_DocCount(t *testing.T) { + index := "test-engine-doc-count" + tc := ostest.NewDefaultTestClient(t) + tc.Require.IndicesReset([]string{index}) + tc.Require.IndicesCount([]string{index}, "", 0) + + defer tc.Require.IndicesDelete([]string{index}) + + engine, err := opensearch.NewEngine(index, tc.Client()) + assert.NoError(t, err) + + t.Run("ignore deleted documents", func(t *testing.T) { + document := ostest.Testdata.Resources.Full + tc.Require.DocumentCreate(index, document.ID, toJSON(t, document)) + tc.Require.IndicesCount([]string{index}, "", 1) + + count, err := engine.DocCount() + assert.NoError(t, err) + assert.Equal(t, uint64(1), count) + + tc.Require.Update(index, document.ID, toJSON(t, map[string]any{ + "doc": map[string]any{ + "Deleted": true, + }, + })) + + tc.Require.IndicesCount([]string{index}, "", 1) + + count, err = engine.DocCount() + assert.NoError(t, err) + assert.Equal(t, uint64(0), count) + }) +} diff --git a/services/search/pkg/opensearch/internal/test/os.go b/services/search/pkg/opensearch/internal/test/os.go index 8162e0d58a..126dae1ea3 100644 --- a/services/search/pkg/opensearch/internal/test/os.go +++ b/services/search/pkg/opensearch/internal/test/os.go @@ -145,6 +145,24 @@ func (tc *TestClient) DocumentCreate(ctx context.Context, index string, id, body } } +func (tc *TestClient) Update(ctx context.Context, index string, id, body string) error { + if err := tc.IndicesRefresh(ctx, []string{index}, []int{404}); err != nil { + return err + } + + _, err := tc.c.Update(ctx, opensearchgoAPI.UpdateReq{ + Index: index, + DocumentID: id, + Body: strings.NewReader(body), + }) + switch { + case err != nil: + return fmt.Errorf("failed to update document in index %s: %w", index, err) + default: + return nil + } +} + type testRequireClient struct { tc *TestClient t *testing.T @@ -177,3 +195,7 @@ func (trc *testRequireClient) IndicesCount(indices []string, body string, expect func (trc *testRequireClient) DocumentCreate(index string, id, body string) { require.NoError(trc.t, trc.tc.DocumentCreate(trc.t.Context(), index, id, body)) } + +func (trc *testRequireClient) Update(index string, id, body string) { + require.NoError(trc.t, trc.tc.Update(trc.t.Context(), index, id, body)) +} diff --git a/services/search/pkg/opensearch/opensearch.go b/services/search/pkg/opensearch/opensearch.go index 0d4a626a52..7111b82d42 100644 --- a/services/search/pkg/opensearch/opensearch.go +++ b/services/search/pkg/opensearch/opensearch.go @@ -11,6 +11,8 @@ func isEmpty(x any) bool { switch { case x == nil: return true + case reflect.ValueOf(x).Kind() == reflect.Bool: + return false case reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface()): return true case reflect.ValueOf(x).Kind() == reflect.Map && reflect.ValueOf(x).Len() == 0: