diff --git a/opensearchapi/api_update-params.go b/opensearchapi/api_update-params.go new file mode 100644 index 000000000..ff961e7bb --- /dev/null +++ b/opensearchapi/api_update-params.go @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// The OpenSearch Contributors require contributions made to +// this file be licensed under the Apache-2.0 license or a +// compatible open source license. +// +// Modifications Copyright OpenSearch Contributors. See +// GitHub history for details. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package opensearchapi + +import ( + "strconv" + "strings" + "time" +) + +// UpdateParams represents possible parameters for the UpdateReq +type UpdateParams struct { + IfPrimaryTerm *int + IfSeqNo *int + Lang string + Refresh string + RequireAlias *bool + RetryOnConflict *int + Routing string + Source interface{} + SourceExcludes []string + SourceIncludes []string + Timeout time.Duration + WaitForActiveShards string + + Pretty bool + Human bool + ErrorTrace bool +} + +func (r UpdateParams) get() map[string]string { + params := make(map[string]string) + + if r.IfPrimaryTerm != nil { + params["if_primary_term"] = strconv.FormatInt(int64(*r.IfPrimaryTerm), 10) + } + + if r.IfSeqNo != nil { + params["if_seq_no"] = strconv.FormatInt(int64(*r.IfSeqNo), 10) + } + + if r.Lang != "" { + params["lang"] = r.Lang + } + + if r.Refresh != "" { + params["refresh"] = r.Refresh + } + + if r.RequireAlias != nil { + params["require_alias"] = strconv.FormatBool(*r.RequireAlias) + } + + if r.RetryOnConflict != nil { + params["retry_on_conflict"] = strconv.FormatInt(int64(*r.RetryOnConflict), 10) + } + + if r.Routing != "" { + params["routing"] = r.Routing + } + + if source, ok := r.Source.(bool); ok { + params["_source"] = strconv.FormatBool(source) + } else if source, ok := r.Source.(string); ok && source != "" { + params["_source"] = source + } else if sources, ok := r.Source.([]string); ok && len(sources) > 0 { + params["_source"] = strings.Join(sources, ",") + } + + if len(r.SourceExcludes) > 0 { + params["_source_excludes"] = strings.Join(r.SourceExcludes, ",") + } + + if len(r.SourceIncludes) > 0 { + params["_source_includes"] = strings.Join(r.SourceIncludes, ",") + } + + if r.Timeout != 0 { + params["timeout"] = formatDuration(r.Timeout) + } + + if r.WaitForActiveShards != "" { + params["wait_for_active_shards"] = r.WaitForActiveShards + } + + if r.Pretty { + params["pretty"] = "true" + } + + if r.Human { + params["human"] = "true" + } + + if r.ErrorTrace { + params["error_trace"] = "true" + } + + return params +} diff --git a/opensearchapi/api_update.go b/opensearchapi/api_update.go new file mode 100644 index 000000000..f688c8712 --- /dev/null +++ b/opensearchapi/api_update.go @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// The OpenSearch Contributors require contributions made to +// this file be licensed under the Apache-2.0 license or a +// compatible open source license. +// +// Modifications Copyright OpenSearch Contributors. See +// GitHub history for details. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package opensearchapi + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/opensearch-project/opensearch-go/v2" +) + +// Update executes a /_update request with the optional UpdateReq +func (c Client) Update(ctx context.Context, req UpdateReq) (*UpdateResp, error) { + var ( + data UpdateResp + err error + ) + if data.response, err = c.do(ctx, req, &data); err != nil { + return &data, err + } + + return &data, nil +} + +// UpdateReq represents possible options for the /_update request +type UpdateReq struct { + Index string + DocumentID string + + Body io.Reader + + Header http.Header + Params UpdateParams +} + +// GetRequest returns the *http.Request that gets executed by the client +func (r UpdateReq) GetRequest() (*http.Request, error) { + return opensearch.BuildRequest( + "POST", + fmt.Sprintf("/%s/_update/%s", r.Index, r.DocumentID), + r.Body, + r.Params.get(), + r.Header, + ) +} + +// UpdateResp represents the returned struct of the /_update response +type UpdateResp struct { + Index string `json:"_index"` + ID string `json:"_id"` + Version int `json:"_version"` + Result string `json:"result"` + Shards struct { + Total int `json:"total"` + Successful int `json:"successful"` + Failed int `json:"failed"` + } `json:"_shards"` + SeqNo int `json:"_seq_no"` + PrimaryTerm int `json:"_primary_term"` + response *opensearch.Response +} + +// Inspect returns the Inspect type containing the raw *opensearch.Reponse +func (r UpdateResp) Inspect() Inspect { + return Inspect{Response: r.response} +} diff --git a/opensearchapi/api_update_test.go b/opensearchapi/api_update_test.go new file mode 100644 index 000000000..c8bef3a00 --- /dev/null +++ b/opensearchapi/api_update_test.go @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// The OpenSearch Contributors require contributions made to +// this file be licensed under the Apache-2.0 license or a +// compatible open source license. +// +// Modifications Copyright OpenSearch Contributors. See +// GitHub history for details. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//go:build integration + +package opensearchapi_test + +import ( + "strconv" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/opensearch-project/opensearch-go/v2/opensearchapi" + osapitest "github.com/opensearch-project/opensearch-go/v2/opensearchapi/internal/test" +) + +func TestUpdate(t *testing.T) { + client, err := opensearchapi.NewDefaultClient() + require.Nil(t, err) + + testIndex := "test-update" + t.Cleanup(func() { + client.Indices.Delete(nil, opensearchapi.IndicesDeleteReq{Indices: []string{testIndex}}) + }) + + for i := 1; i <= 2; i++ { + _, err = client.Document.Create( + nil, + opensearchapi.DocumentCreateReq{ + Index: testIndex, + Body: strings.NewReader(`{"foo": "bar", "counter": 1}`), + DocumentID: strconv.Itoa(i), + Params: opensearchapi.DocumentCreateParams{Refresh: "true"}, + }, + ) + require.Nil(t, err) + } + + t.Run("with request", func(t *testing.T) { + resp, err := client.Update( + nil, + opensearchapi.UpdateReq{ + Index: testIndex, + DocumentID: "1", + Body: strings.NewReader(`{"script":{"source":"ctx._source.counter += params.count","lang":"painless","params":{"count":4}}}`), + }, + ) + require.Nil(t, err) + assert.NotEmpty(t, resp) + osapitest.CompareRawJSONwithParsedJSON(t, resp, resp.Inspect().Response) + }) + + t.Run("inspect", func(t *testing.T) { + failingClient, err := osapitest.CreateFailingClient() + require.Nil(t, err) + + res, err := failingClient.Update(nil, opensearchapi.UpdateReq{}) + assert.NotNil(t, err) + assert.NotNil(t, res) + osapitest.VerifyInspect(t, res.Inspect()) + }) +}