diff --git a/api/proto b/api/proto index f3a62a298..96cb7e86f 160000 --- a/api/proto +++ b/api/proto @@ -1 +1 @@ -Subproject commit f3a62a29837bb6eb6f7e42c91cba92c91103a643 +Subproject commit 96cb7e86f3c21a7bbfe02310ce5561207aafe92f diff --git a/server/services/v1/query_runner.go b/server/services/v1/query_runner.go index dc45e7815..c1ae9f0b0 100644 --- a/server/services/v1/query_runner.go +++ b/server/services/v1/query_runner.go @@ -493,6 +493,10 @@ func (runner *UpdateQueryRunner) Run(ctx context.Context, tx transaction.Tx, ten runner.queryMetrics.SetWriteType("non-pkey") } + var limit = int32(0) + if runner.req.Options != nil { + limit = int32(runner.req.Options.Limit) + } modifiedCount := int32(0) var row Row for iterator.Next(&row) { @@ -515,6 +519,9 @@ func (runner *UpdateQueryRunner) Run(ctx context.Context, tx transaction.Tx, ten return nil, ctx, err } modifiedCount++ + if limit > 0 && modifiedCount == limit { + break + } } ctx = metrics.UpdateSpanTags(ctx, runner.queryMetrics) @@ -592,6 +599,10 @@ func (runner *DeleteQueryRunner) Run(ctx context.Context, tx transaction.Tx, ten return nil, ctx, err } + var limit = int32(0) + if runner.req.Options != nil { + limit = int32(runner.req.Options.Limit) + } modifiedCount := int32(0) var row Row for iterator.Next(&row) { @@ -605,6 +616,9 @@ func (runner *DeleteQueryRunner) Run(ctx context.Context, tx transaction.Tx, ten } modifiedCount++ + if limit > 0 && modifiedCount == limit { + break + } } ctx = metrics.UpdateSpanTags(ctx, runner.queryMetrics) diff --git a/test/v1/server/document_test.go b/test/v1/server/document_test.go index 5b4edcaca..20c84d308 100644 --- a/test/v1/server/document_test.go +++ b/test/v1/server/document_test.go @@ -1267,6 +1267,93 @@ func TestUpdate_MultipleRows(t *testing.T) { outDocument) } +func TestUpdate_Limit(t *testing.T) { + db, coll := setupTests(t) + defer cleanupTests(t, db) + + inputDocument := []Doc{ + { + "pkey_int": 110, + "int_value": 1000, + "string_value": "simple_insert110", + "bool_value": true, + "double_value": 1000.000001, + "bytes_value": []byte(`"simple_insert110"`), + }, + { + "pkey_int": 120, + "int_value": 2000, + "string_value": "simple_insert120", + "bool_value": false, + "double_value": 2000.22221, + "bytes_value": []byte(`"simple_insert120"`), + }, + { + "pkey_int": 130, + "int_value": 3000, + "string_value": "simple_insert130", + "bool_value": true, + "double_value": 3000.999999, + "bytes_value": []byte(`"simple_insert130"`), + }, + } + + // should always succeed with mustNotExists as false + insertDocuments(t, db, coll, inputDocument, false). + Status(http.StatusOK) + + readFilter := Map{ + "$or": []Doc{ + {"pkey_int": 110}, + {"pkey_int": 120}, + {"pkey_int": 130}, + }, + } + readAndValidate(t, + db, + coll, + readFilter, + nil, + inputDocument) + + filter := Map{ + "filter": Map{ + "$or": []Doc{ + {"pkey_int": 110}, + {"pkey_int": 120}, + {"pkey_int": 130}, + }, + }, + } + fields := Map{ + "fields": Map{ + "$set": Map{ + "int_value": 12345, + }, + }, + } + + payload := make(Map) + for key, value := range filter { + payload[key] = value + } + for key, value := range fields { + payload[key] = value + } + payload["options"] = Map{ + "limit": 1, + } + + e := expect(t) + e.PUT(getDocumentURL(db, coll, "update")). + WithJSON(payload). + Expect(). + Status(http.StatusOK). + JSON(). + Object(). + ValueEqual("modified_count", 1) +} + func TestUpdate_UsingCollation(t *testing.T) { db, coll := setupTests(t) defer cleanupTests(t, db)