diff --git a/CHANGELOG.md b/CHANGELOG.md index b4cdf0012..01d08c408 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release. - Support `operation_data` in `crud.Error` (#330) - Support `fetch_latest_metadata` option for crud requests with metadata (#335) - Support `noreturn` option for data change crud requests (#335) -- Support `crud.schema` request (#336) +- Support `crud.schema` request (#336, #351) - Support `IPROTO_WATCH_ONCE` request type for Tarantool version >= 3.0.0-alpha1 (#337) - Support `yield_every` option for crud select requests (#350) diff --git a/crud/options.go b/crud/options.go index fa5dca2c9..311df522c 100644 --- a/crud/options.go +++ b/crud/options.go @@ -23,7 +23,7 @@ const ( batchSizeOptName = "batch_size" fetchLatestMetadataOptName = "fetch_latest_metadata" noreturnOptName = "noreturn" - yieldEvery = "yield_every" + cachedOptName = "cached" ) // OptUint is an optional uint. diff --git a/crud/request_test.go b/crud/request_test.go index 8a64ab427..9644a19ac 100644 --- a/crud/request_test.go +++ b/crud/request_test.go @@ -194,6 +194,7 @@ func TestRequestsCodes(t *testing.T) { {req: crud.MakeCountRequest(validSpace), rtype: CrudRequestType}, {req: crud.MakeStorageInfoRequest(), rtype: CrudRequestType}, {req: crud.MakeStatsRequest(), rtype: CrudRequestType}, + {req: crud.MakeSchemaRequest(), rtype: CrudRequestType}, } for _, test := range tests { @@ -231,6 +232,7 @@ func TestRequestsAsync(t *testing.T) { {req: crud.MakeCountRequest(validSpace), async: false}, {req: crud.MakeStorageInfoRequest(), async: false}, {req: crud.MakeStatsRequest(), async: false}, + {req: crud.MakeSchemaRequest(), async: false}, } for _, test := range tests { @@ -268,6 +270,7 @@ func TestRequestsCtx_default(t *testing.T) { {req: crud.MakeCountRequest(validSpace), expected: nil}, {req: crud.MakeStorageInfoRequest(), expected: nil}, {req: crud.MakeStatsRequest(), expected: nil}, + {req: crud.MakeSchemaRequest(), expected: nil}, } for _, test := range tests { @@ -306,6 +309,7 @@ func TestRequestsCtx_setter(t *testing.T) { {req: crud.MakeCountRequest(validSpace).Context(ctx), expected: ctx}, {req: crud.MakeStorageInfoRequest().Context(ctx), expected: ctx}, {req: crud.MakeStatsRequest().Context(ctx), expected: ctx}, + {req: crud.MakeSchemaRequest().Context(ctx), expected: ctx}, } for _, test := range tests { @@ -462,6 +466,12 @@ func TestRequestsDefaultValues(t *testing.T) { []interface{}{}), target: crud.MakeStatsRequest(), }, + { + name: "SchemaRequest", + ref: tarantool.NewCall17Request("crud.schema").Args( + []interface{}{nil, map[string]interface{}{}}), + target: crud.MakeSchemaRequest(), + }, } for _, tc := range testCases { @@ -624,6 +634,296 @@ func TestRequestsSetters(t *testing.T) { []interface{}{spaceName}), target: crud.MakeStatsRequest().Space(spaceName), }, + { + name: "SchemaRequest", + ref: tarantool.NewCall17Request("crud.schema").Args( + []interface{}{nil, schemaOpts}, + ), + target: crud.MakeSchemaRequest().Opts(schemaOpts), + }, + { + name: "SchemaRequestWithSpace", + ref: tarantool.NewCall17Request("crud.schema").Args( + []interface{}{spaceName, schemaOpts}, + ), + target: crud.MakeSchemaRequest().Space(spaceName).Opts(schemaOpts), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + assertBodyEqual(t, tc.ref, tc.target) + }) + } +} + +func TestRequestsVshardRouter(t *testing.T) { + testCases := []struct { + name string + ref tarantool.Request + target tarantool.Request + }{ + { + name: "InsertRequest", + ref: tarantool.NewCall17Request("crud.insert").Args([]interface{}{ + validSpace, + []interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeInsertRequest(validSpace).Opts(crud.InsertOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "InsertObjectRequest", + ref: tarantool.NewCall17Request("crud.insert_object").Args([]interface{}{ + validSpace, + map[string]interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeInsertObjectRequest(validSpace).Opts(crud.InsertObjectOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "InsertManyRequest", + ref: tarantool.NewCall17Request("crud.insert_many").Args([]interface{}{ + validSpace, + []interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeInsertManyRequest(validSpace).Opts(crud.InsertManyOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "InsertObjectManyRequest", + ref: tarantool.NewCall17Request("crud.insert_object_many").Args([]interface{}{ + validSpace, + []map[string]interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeInsertObjectManyRequest(validSpace).Opts(crud.InsertObjectManyOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "GetRequest", + ref: tarantool.NewCall17Request("crud.get").Args([]interface{}{ + validSpace, + []interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeGetRequest(validSpace).Opts(crud.GetOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "UpdateRequest", + ref: tarantool.NewCall17Request("crud.update").Args([]interface{}{ + validSpace, + []interface{}{}, + []interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeUpdateRequest(validSpace).Opts(crud.UpdateOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "DeleteRequest", + ref: tarantool.NewCall17Request("crud.delete").Args([]interface{}{ + validSpace, + []interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeDeleteRequest(validSpace).Opts(crud.DeleteOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "ReplaceRequest", + ref: tarantool.NewCall17Request("crud.replace").Args([]interface{}{ + validSpace, + []interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeReplaceRequest(validSpace).Opts(crud.ReplaceOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "ReplaceObjectRequest", + ref: tarantool.NewCall17Request("crud.replace_object").Args([]interface{}{ + validSpace, + map[string]interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeReplaceObjectRequest(validSpace).Opts(crud.ReplaceObjectOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "ReplaceManyRequest", + ref: tarantool.NewCall17Request("crud.replace_many").Args([]interface{}{ + validSpace, + []interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeReplaceManyRequest(validSpace).Opts(crud.ReplaceManyOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "ReplaceObjectManyRequest", + ref: tarantool.NewCall17Request("crud.replace_object_many").Args([]interface{}{ + validSpace, + []map[string]interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeReplaceObjectManyRequest(validSpace).Opts(crud.ReplaceObjectManyOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "UpsertRequest", + ref: tarantool.NewCall17Request("crud.upsert").Args([]interface{}{ + validSpace, + []interface{}{}, + []interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeUpsertRequest(validSpace).Opts(crud.UpsertOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "UpsertObjectRequest", + ref: tarantool.NewCall17Request("crud.upsert_object").Args([]interface{}{ + validSpace, + map[string]interface{}{}, + []interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeUpsertObjectRequest(validSpace).Opts(crud.UpsertObjectOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "UpsertManyRequest", + ref: tarantool.NewCall17Request("crud.upsert_many").Args([]interface{}{ + validSpace, + []interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeUpsertManyRequest(validSpace).Opts(crud.UpsertManyOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "UpsertObjectManyRequest", + ref: tarantool.NewCall17Request("crud.upsert_object_many").Args([]interface{}{ + validSpace, + []interface{}{}, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeUpsertObjectManyRequest(validSpace).Opts(crud.UpsertObjectManyOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "SelectRequest", + ref: tarantool.NewCall17Request("crud.select").Args([]interface{}{ + validSpace, + nil, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeSelectRequest(validSpace).Opts(crud.SelectOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "MinRequest", + ref: tarantool.NewCall17Request("crud.min").Args([]interface{}{ + validSpace, + nil, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeMinRequest(validSpace).Opts(crud.MinOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "MaxRequest", + ref: tarantool.NewCall17Request("crud.max").Args([]interface{}{ + validSpace, + nil, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeMaxRequest(validSpace).Opts(crud.MaxOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "TruncateRequest", + ref: tarantool.NewCall17Request("crud.truncate").Args([]interface{}{ + validSpace, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeTruncateRequest(validSpace).Opts(crud.TruncateOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "LenRequest", + ref: tarantool.NewCall17Request("crud.len").Args([]interface{}{ + validSpace, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeLenRequest(validSpace).Opts(crud.LenOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "CountRequest", + ref: tarantool.NewCall17Request("crud.count").Args([]interface{}{ + validSpace, + nil, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeCountRequest(validSpace).Opts(crud.CountOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "StorageInfoRequest", + ref: tarantool.NewCall17Request("crud.storage_info").Args([]interface{}{ + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeStorageInfoRequest().Opts(crud.StorageInfoOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "SchemaRequest", + ref: tarantool.NewCall17Request("crud.schema").Args([]interface{}{ + nil, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeSchemaRequest().Opts(crud.SchemaOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, + { + name: "SchemaRequestWithSpace", + ref: tarantool.NewCall17Request("crud.schema").Args([]interface{}{ + validSpace, + map[string]interface{}{"vshard_router": "custom_router"}, + }), + target: crud.MakeSchemaRequest().Space(validSpace).Opts(crud.SchemaOpts{ + VshardRouter: crud.MakeOptString("custom_router"), + }), + }, } for _, tc := range testCases { diff --git a/crud/schema.go b/crud/schema.go index 3335a3347..6f3b94a97 100644 --- a/crud/schema.go +++ b/crud/schema.go @@ -14,33 +14,68 @@ func msgpackIsMap(code byte) bool { return code == msgpcode.Map16 || code == msgpcode.Map32 || msgpcode.IsFixedMap(code) } +// SchemaOpts describes options for `crud.schema` method. +type SchemaOpts struct { + // Timeout is a `vshard.call` timeout and vshard + // master discovery timeout (in seconds). + Timeout OptFloat64 + // VshardRouter is cartridge vshard group name or + // vshard router instance. + VshardRouter OptString + // Cached defines whether router should reload storage schema on call. + Cached OptBool +} + +// EncodeMsgpack provides custom msgpack encoder. +func (opts SchemaOpts) EncodeMsgpack(enc *msgpack.Encoder) error { + const optsCnt = 3 + + names := [optsCnt]string{timeoutOptName, vshardRouterOptName, + cachedOptName} + values := [optsCnt]interface{}{} + exists := [optsCnt]bool{} + values[0], exists[0] = opts.Timeout.Get() + values[1], exists[1] = opts.VshardRouter.Get() + values[2], exists[2] = opts.Cached.Get() + + return encodeOptions(enc, names[:], values[:], exists[:]) +} + // SchemaRequest helps you to create request object to call `crud.schema` // for execution by a Connection. type SchemaRequest struct { baseRequest space OptString + opts SchemaOpts } -// MakeSchemaRequest returns a new empty StatsRequest. +// MakeSchemaRequest returns a new empty SchemaRequest. func MakeSchemaRequest() SchemaRequest { req := SchemaRequest{} req.impl = newCall("crud.schema") return req } -// Space sets the space name for the StatsRequest request. +// Space sets the space name for the SchemaRequest request. // Note: default value is nil. func (req SchemaRequest) Space(space string) SchemaRequest { req.space = MakeOptString(space) return req } +// Opts sets the options for the SchemaRequest request. +// Note: default value is nil. +func (req SchemaRequest) Opts(opts SchemaOpts) SchemaRequest { + req.opts = opts + return req +} + // Body fills an encoder with the call request body. func (req SchemaRequest) Body(res tarantool.SchemaResolver, enc *msgpack.Encoder) error { if value, ok := req.space.Get(); ok { - req.impl = req.impl.Args([]interface{}{value}) + req.impl = req.impl.Args([]interface{}{value, req.opts}) } else { - req.impl = req.impl.Args([]interface{}{}) + req.impl = req.impl.Args([]interface{}{nil, req.opts}) } return req.impl.Body(res, enc) diff --git a/crud/tarantool_test.go b/crud/tarantool_test.go index 399b0d48f..529f0201a 100644 --- a/crud/tarantool_test.go +++ b/crud/tarantool_test.go @@ -87,6 +87,11 @@ var opObjManyOpts = crud.OperationObjectManyOpts{ Timeout: crud.MakeOptFloat64(timeout), } +var schemaOpts = crud.SchemaOpts{ + Timeout: crud.MakeOptFloat64(timeout), + Cached: crud.MakeOptBool(false), +} + var conditions = []crud.Condition{ { Operator: crud.Lt, @@ -216,6 +221,11 @@ var testProcessDataCases = []struct { 1, crud.MakeStorageInfoRequest().Opts(baseOpts), }, + { + "Schema", + 1, + crud.MakeSchemaRequest().Opts(schemaOpts), + }, } var testResultWithErrCases = []struct {