Skip to content

Commit a81e8a2

Browse files
crud: support noreturn option
`noreturn` option was introduced in crud 1.2.0 [1]. 1. tarantool/crud@af0ce90
1 parent be8ba74 commit a81e8a2

File tree

4 files changed

+250
-8
lines changed

4 files changed

+250
-8
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
1818
- Support password and password file to decrypt private SSL key file (#319)
1919
- Support `operation_data` in `crud.Error` (#330)
2020
- Support `fetch_latest_metadata` option for crud requests with metadata (#335)
21+
- Support `noreturn` option for data change crud requests (#335)
2122

2223
### Changed
2324

crud/example_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,33 @@ func ExampleResult_many() {
187187
// [[2010 45 bla] [2011 4 bla]]
188188
}
189189

190+
// ExampleResult_noreturn demonstrates noreturn request: a data change
191+
// request where you don't need to retrieve the result, just want to know
192+
// whether it was successful or not.
193+
func ExampleResult_noreturn() {
194+
conn := exampleConnect()
195+
req := crud.MakeReplaceManyRequest(exampleSpace).
196+
Tuples([]crud.Tuple{
197+
[]interface{}{uint(2010), nil, "bla"},
198+
[]interface{}{uint(2011), nil, "bla"},
199+
}).
200+
Opts(crud.ReplaceManyOpts{
201+
Noreturn: crud.MakeOptBool(true),
202+
})
203+
204+
ret := crud.Result{}
205+
if err := conn.Do(req).GetTyped(&ret); err != nil {
206+
fmt.Printf("Failed to execute request: %s", err)
207+
return
208+
}
209+
210+
fmt.Println(ret.Metadata)
211+
fmt.Println(ret.Rows)
212+
// Output:
213+
// []
214+
// <nil>
215+
}
216+
190217
// ExampleResult_error demonstrates how to use a helper type Result
191218
// to handle a crud error.
192219
func ExampleResult_error() {

crud/options.go

+27-8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const (
2222
afterOptName = "after"
2323
batchSizeOptName = "batch_size"
2424
fetchLatestMetadataOptName = "fetch_latest_metadata"
25+
noreturnOptName = "noreturn"
2526
)
2627

2728
// OptUint is an optional uint.
@@ -156,21 +157,26 @@ type SimpleOperationOpts struct {
156157
// the latest migration of the data format. Performance overhead is up to 15%.
157158
// Disabled by default.
158159
FetchLatestMetadata OptBool
160+
// Noreturn suppresses successfully processed data (first return value is `nil`).
161+
// Disabled by default.
162+
Noreturn OptBool
159163
}
160164

161165
// EncodeMsgpack provides custom msgpack encoder.
162166
func (opts SimpleOperationOpts) EncodeMsgpack(enc *msgpack.Encoder) error {
163-
const optsCnt = 5
167+
const optsCnt = 6
164168

165169
names := [optsCnt]string{timeoutOptName, vshardRouterOptName,
166-
fieldsOptName, bucketIdOptName, fetchLatestMetadataOptName}
170+
fieldsOptName, bucketIdOptName, fetchLatestMetadataOptName,
171+
noreturnOptName}
167172
values := [optsCnt]interface{}{}
168173
exists := [optsCnt]bool{}
169174
values[0], exists[0] = opts.Timeout.Get()
170175
values[1], exists[1] = opts.VshardRouter.Get()
171176
values[2], exists[2] = opts.Fields.Get()
172177
values[3], exists[3] = opts.BucketId.Get()
173178
values[4], exists[4] = opts.FetchLatestMetadata.Get()
179+
values[5], exists[5] = opts.Noreturn.Get()
174180

175181
return encodeOptions(enc, names[:], values[:], exists[:])
176182
}
@@ -196,15 +202,18 @@ type SimpleOperationObjectOpts struct {
196202
// the latest migration of the data format. Performance overhead is up to 15%.
197203
// Disabled by default.
198204
FetchLatestMetadata OptBool
205+
// Noreturn suppresses successfully processed data (first return value is `nil`).
206+
// Disabled by default.
207+
Noreturn OptBool
199208
}
200209

201210
// EncodeMsgpack provides custom msgpack encoder.
202211
func (opts SimpleOperationObjectOpts) EncodeMsgpack(enc *msgpack.Encoder) error {
203-
const optsCnt = 6
212+
const optsCnt = 7
204213

205214
names := [optsCnt]string{timeoutOptName, vshardRouterOptName,
206215
fieldsOptName, bucketIdOptName, skipNullabilityCheckOnFlattenOptName,
207-
fetchLatestMetadataOptName}
216+
fetchLatestMetadataOptName, noreturnOptName}
208217
values := [optsCnt]interface{}{}
209218
exists := [optsCnt]bool{}
210219
values[0], exists[0] = opts.Timeout.Get()
@@ -213,6 +222,7 @@ func (opts SimpleOperationObjectOpts) EncodeMsgpack(enc *msgpack.Encoder) error
213222
values[3], exists[3] = opts.BucketId.Get()
214223
values[4], exists[4] = opts.SkipNullabilityCheckOnFlatten.Get()
215224
values[5], exists[5] = opts.FetchLatestMetadata.Get()
225+
values[6], exists[6] = opts.Noreturn.Get()
216226

217227
return encodeOptions(enc, names[:], values[:], exists[:])
218228
}
@@ -240,15 +250,18 @@ type OperationManyOpts struct {
240250
// the latest migration of the data format. Performance overhead is up to 15%.
241251
// Disabled by default.
242252
FetchLatestMetadata OptBool
253+
// Noreturn suppresses successfully processed data (first return value is `nil`).
254+
// Disabled by default.
255+
Noreturn OptBool
243256
}
244257

245258
// EncodeMsgpack provides custom msgpack encoder.
246259
func (opts OperationManyOpts) EncodeMsgpack(enc *msgpack.Encoder) error {
247-
const optsCnt = 6
260+
const optsCnt = 7
248261

249262
names := [optsCnt]string{timeoutOptName, vshardRouterOptName,
250263
fieldsOptName, stopOnErrorOptName, rollbackOnErrorOptName,
251-
fetchLatestMetadataOptName}
264+
fetchLatestMetadataOptName, noreturnOptName}
252265
values := [optsCnt]interface{}{}
253266
exists := [optsCnt]bool{}
254267
values[0], exists[0] = opts.Timeout.Get()
@@ -257,6 +270,7 @@ func (opts OperationManyOpts) EncodeMsgpack(enc *msgpack.Encoder) error {
257270
values[3], exists[3] = opts.StopOnError.Get()
258271
values[4], exists[4] = opts.RollbackOnError.Get()
259272
values[5], exists[5] = opts.FetchLatestMetadata.Get()
273+
values[6], exists[6] = opts.Noreturn.Get()
260274

261275
return encodeOptions(enc, names[:], values[:], exists[:])
262276
}
@@ -287,15 +301,19 @@ type OperationObjectManyOpts struct {
287301
// the latest migration of the data format. Performance overhead is up to 15%.
288302
// Disabled by default.
289303
FetchLatestMetadata OptBool
304+
// Noreturn suppresses successfully processed data (first return value is `nil`).
305+
// Disabled by default.
306+
Noreturn OptBool
290307
}
291308

292309
// EncodeMsgpack provides custom msgpack encoder.
293310
func (opts OperationObjectManyOpts) EncodeMsgpack(enc *msgpack.Encoder) error {
294-
const optsCnt = 7
311+
const optsCnt = 8
295312

296313
names := [optsCnt]string{timeoutOptName, vshardRouterOptName,
297314
fieldsOptName, stopOnErrorOptName, rollbackOnErrorOptName,
298-
skipNullabilityCheckOnFlattenOptName, fetchLatestMetadataOptName}
315+
skipNullabilityCheckOnFlattenOptName, fetchLatestMetadataOptName,
316+
noreturnOptName}
299317
values := [optsCnt]interface{}{}
300318
exists := [optsCnt]bool{}
301319
values[0], exists[0] = opts.Timeout.Get()
@@ -305,6 +323,7 @@ func (opts OperationObjectManyOpts) EncodeMsgpack(enc *msgpack.Encoder) error {
305323
values[4], exists[4] = opts.RollbackOnError.Get()
306324
values[5], exists[5] = opts.SkipNullabilityCheckOnFlatten.Get()
307325
values[6], exists[6] = opts.FetchLatestMetadata.Get()
326+
values[7], exists[7] = opts.Noreturn.Get()
308327

309328
return encodeOptions(enc, names[:], values[:], exists[:])
310329
}

crud/tarantool_test.go

+195
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,201 @@ func TestFetchLatestMetadataOption(t *testing.T) {
10121012
}
10131013
}
10141014

1015+
var testNoreturnCases = []struct {
1016+
name string
1017+
req tarantool.Request
1018+
}{
1019+
{
1020+
"Insert",
1021+
crud.MakeInsertRequest(spaceName).
1022+
Tuple(tuple).
1023+
Opts(crud.InsertOpts{
1024+
Noreturn: crud.MakeOptBool(true),
1025+
}),
1026+
},
1027+
{
1028+
"InsertObject",
1029+
crud.MakeInsertObjectRequest(spaceName).
1030+
Object(object).
1031+
Opts(crud.InsertObjectOpts{
1032+
Noreturn: crud.MakeOptBool(true),
1033+
}),
1034+
},
1035+
{
1036+
"InsertMany",
1037+
crud.MakeInsertManyRequest(spaceName).
1038+
Tuples(tuples).
1039+
Opts(crud.InsertManyOpts{
1040+
Noreturn: crud.MakeOptBool(true),
1041+
}),
1042+
},
1043+
{
1044+
"InsertObjectMany",
1045+
crud.MakeInsertObjectManyRequest(spaceName).
1046+
Objects(objects).
1047+
Opts(crud.InsertObjectManyOpts{
1048+
Noreturn: crud.MakeOptBool(true),
1049+
}),
1050+
},
1051+
{
1052+
"Replace",
1053+
crud.MakeReplaceRequest(spaceName).
1054+
Tuple(tuple).
1055+
Opts(crud.ReplaceOpts{
1056+
Noreturn: crud.MakeOptBool(true),
1057+
}),
1058+
},
1059+
{
1060+
"ReplaceObject",
1061+
crud.MakeReplaceObjectRequest(spaceName).
1062+
Object(object).
1063+
Opts(crud.ReplaceObjectOpts{
1064+
Noreturn: crud.MakeOptBool(true),
1065+
}),
1066+
},
1067+
{
1068+
"ReplaceMany",
1069+
crud.MakeReplaceManyRequest(spaceName).
1070+
Tuples(tuples).
1071+
Opts(crud.ReplaceManyOpts{
1072+
Noreturn: crud.MakeOptBool(true),
1073+
}),
1074+
},
1075+
{
1076+
"ReplaceObjectMany",
1077+
crud.MakeReplaceObjectManyRequest(spaceName).
1078+
Objects(objects).
1079+
Opts(crud.ReplaceObjectManyOpts{
1080+
Noreturn: crud.MakeOptBool(true),
1081+
}),
1082+
},
1083+
{
1084+
"Upsert",
1085+
crud.MakeUpsertRequest(spaceName).
1086+
Tuple(tuple).
1087+
Operations(operations).
1088+
Opts(crud.UpsertOpts{
1089+
Noreturn: crud.MakeOptBool(true),
1090+
}),
1091+
},
1092+
{
1093+
"UpsertObject",
1094+
crud.MakeUpsertObjectRequest(spaceName).
1095+
Object(object).
1096+
Operations(operations).
1097+
Opts(crud.UpsertObjectOpts{
1098+
Noreturn: crud.MakeOptBool(true),
1099+
}),
1100+
},
1101+
{
1102+
"UpsertMany",
1103+
crud.MakeUpsertManyRequest(spaceName).
1104+
TuplesOperationsData(tuplesOperationsData).
1105+
Opts(crud.UpsertManyOpts{
1106+
Noreturn: crud.MakeOptBool(true),
1107+
}),
1108+
},
1109+
{
1110+
"UpsertObjectMany",
1111+
crud.MakeUpsertObjectManyRequest(spaceName).
1112+
ObjectsOperationsData(objectsOperationData).
1113+
Opts(crud.UpsertObjectManyOpts{
1114+
Noreturn: crud.MakeOptBool(true),
1115+
}),
1116+
},
1117+
{
1118+
"Update",
1119+
crud.MakeUpdateRequest(spaceName).
1120+
Key(key).
1121+
Operations(operations).
1122+
Opts(crud.UpdateOpts{
1123+
Noreturn: crud.MakeOptBool(true),
1124+
}),
1125+
},
1126+
{
1127+
"Delete",
1128+
crud.MakeDeleteRequest(spaceName).
1129+
Key(key).
1130+
Opts(crud.DeleteOpts{
1131+
Noreturn: crud.MakeOptBool(true),
1132+
}),
1133+
},
1134+
}
1135+
1136+
func TestNoreturnOption(t *testing.T) {
1137+
conn := connect(t)
1138+
defer conn.Close()
1139+
1140+
for _, testCase := range testNoreturnCases {
1141+
t.Run(testCase.name, func(t *testing.T) {
1142+
for i := 1010; i < 1020; i++ {
1143+
req := tarantool.NewDeleteRequest(spaceName).
1144+
Key([]interface{}{uint(i)})
1145+
conn.Do(req).Get()
1146+
}
1147+
1148+
resp, err := conn.Do(testCase.req).Get()
1149+
if err != nil {
1150+
t.Fatalf("Failed to Do CRUD request: %s", err)
1151+
}
1152+
1153+
if len(resp.Data) == 0 {
1154+
t.Fatalf("Expected explicit nil")
1155+
}
1156+
1157+
if resp.Data[0] != nil {
1158+
t.Fatalf("Expected nil result, got %v", resp.Data[0])
1159+
}
1160+
1161+
if len(resp.Data) >= 2 && resp.Data[1] != nil {
1162+
t.Fatalf("Expected no returned errors, got %v", resp.Data[1])
1163+
}
1164+
1165+
for i := 1010; i < 1020; i++ {
1166+
req := tarantool.NewDeleteRequest(spaceName).
1167+
Key([]interface{}{uint(i)})
1168+
conn.Do(req).Get()
1169+
}
1170+
})
1171+
}
1172+
}
1173+
1174+
func TestNoreturnOptionTyped(t *testing.T) {
1175+
conn := connect(t)
1176+
defer conn.Close()
1177+
1178+
for _, testCase := range testNoreturnCases {
1179+
t.Run(testCase.name, func(t *testing.T) {
1180+
for i := 1010; i < 1020; i++ {
1181+
req := tarantool.NewDeleteRequest(spaceName).
1182+
Key([]interface{}{uint(i)})
1183+
conn.Do(req).Get()
1184+
}
1185+
1186+
resp := crud.Result{}
1187+
1188+
err := conn.Do(testCase.req).GetTyped(&resp)
1189+
if err != nil {
1190+
t.Fatalf("Failed to Do CRUD request: %s", err)
1191+
}
1192+
1193+
if resp.Rows != nil {
1194+
t.Fatalf("Expected nil rows, got %v", resp.Rows)
1195+
}
1196+
1197+
if len(resp.Metadata) != 0 {
1198+
t.Fatalf("Expected no metadata")
1199+
}
1200+
1201+
for i := 1010; i < 1020; i++ {
1202+
req := tarantool.NewDeleteRequest(spaceName).
1203+
Key([]interface{}{uint(i)})
1204+
conn.Do(req).Get()
1205+
}
1206+
})
1207+
}
1208+
}
1209+
10151210
// runTestMain is a body of TestMain function
10161211
// (see https://pkg.go.dev/testing#hdr-Main).
10171212
// Using defer + os.Exit is not works so TestMain body

0 commit comments

Comments
 (0)