diff --git a/changelogs/unreleased/gh-10005-tuple-get-format.md b/changelogs/unreleased/gh-10005-tuple-get-format.md new file mode 100644 index 0000000000000000000000000000000000000000..674d1494a1286e13aae3c7639b8350090926cc57 --- /dev/null +++ b/changelogs/unreleased/gh-10005-tuple-get-format.md @@ -0,0 +1,3 @@ +## feature/box + +* Added the `tuple:format` method to get a format of a tuple (gh-10005). diff --git a/src/box/lua/tuple.c b/src/box/lua/tuple.c index 5eedde8721c779c92bc8745d4b896a661336b5fd..30d6b64e6835ef4d3ae2e79245f9c2ac2af0b3b9 100644 --- a/src/box/lua/tuple.c +++ b/src/box/lua/tuple.c @@ -757,6 +757,23 @@ lbox_tuple_info(lua_State *L) return 1; } +/** + * Push to Lua stack an array with the information about a format of a tuple. + * Elements of the array are maps + * {'name' = 'field_name', 'type' = 'field_type'}. + */ +static int +lbox_tuple_get_format(lua_State *L) +{ + int argc = lua_gettop(L); + if (argc != 1) + luaL_error(L, "Usage: tuple:format()"); + + struct tuple *tuple = luaT_checktuple(L, 1); + struct tuple_format *format = tuple_format(tuple); + return box_tuple_format_serialize_impl(L, format); +} + static const struct luaL_Reg lbox_tuple_meta[] = { {"__gc", lbox_tuple_gc}, {"tostring", lbox_tuple_to_string}, @@ -766,6 +783,7 @@ static const struct luaL_Reg lbox_tuple_meta[] = { {"tuple_field_by_path", lbox_tuple_field_by_path}, {"new", lbox_tuple_new}, {"info", lbox_tuple_info}, + {"tuple_get_format", lbox_tuple_get_format}, {NULL, NULL} }; diff --git a/src/box/lua/tuple.lua b/src/box/lua/tuple.lua index ffe3294148360d15c743d91c0447e17f977b976e..416c66fe9e55c4f432742d941be0ddfc3fc0d782 100644 --- a/src/box/lua/tuple.lua +++ b/src/box/lua/tuple.lua @@ -332,6 +332,7 @@ local methods = { ["update"] = tuple_update; ["upsert"] = tuple_upsert; ["bsize"] = tuple_bsize; + ["format"] = box.tuple.format; ["tomap"] = internal.tuple.tuple_to_map; ["info"] = internal.tuple.info; } diff --git a/src/box/lua/tuple_format.c b/src/box/lua/tuple_format.c index 3b5d8e7b463d23ad4bdf3dcffb131ff2db57ad0b..eedc92be9aa83b43e58ad3eac0170d971d2e87c9 100644 --- a/src/box/lua/tuple_format.c +++ b/src/box/lua/tuple_format.c @@ -106,17 +106,15 @@ lbox_tuple_format_tostring(struct lua_State *L) return 1; } -/* - * Returns the format clause with which this tuple format was created. - */ -static int -lbox_tuple_format_serialize(struct lua_State *L) +int +box_tuple_format_serialize_impl(struct lua_State *L, + struct tuple_format *format) { - struct tuple_format *format = luaT_check_tuple_format(L, 1); if (format->data == NULL) { lua_createtable(L, 0, 0); return 1; } + const char *data = format->data; luamp_decode(L, luaL_msgpack_default, &data); luaL_findtable(L, LUA_GLOBALSINDEX, "box.internal.space", 1); @@ -127,6 +125,16 @@ lbox_tuple_format_serialize(struct lua_State *L) return 1; } +/* + * Returns the format clause with which this tuple format was created. + */ +static int +lbox_tuple_format_serialize(struct lua_State *L) +{ + struct tuple_format *format = luaT_check_tuple_format(L, 1); + return box_tuple_format_serialize_impl(L, format); +} + /* * Simply returns `ipairs(format:totable())`. */ diff --git a/src/box/lua/tuple_format.h b/src/box/lua/tuple_format.h index 66a35d5b0b7fc1279921979692d12fcdd8671683..9c0b9ca993b2fcd22363be65158c959edd35c475 100644 --- a/src/box/lua/tuple_format.h +++ b/src/box/lua/tuple_format.h @@ -28,6 +28,13 @@ luaT_check_tuple_format(struct lua_State *L, int narg); void box_lua_tuple_format_init(struct lua_State *L); +/** + * Returns the clause for the given format. + */ +int +box_tuple_format_serialize_impl(struct lua_State *L, + struct tuple_format *format); + #if defined(__cplusplus) } /* extern "C" */ #endif /* defined(__cplusplus) */ diff --git a/src/box/lua/tuple_format.lua b/src/box/lua/tuple_format.lua index 31c6fd108c7c9b3b5c81f32c7baced8f6f9b1815..35ea98797b77b4d8434e62ec3970f0bc625472b0 100644 --- a/src/box/lua/tuple_format.lua +++ b/src/box/lua/tuple_format.lua @@ -1,5 +1,7 @@ local utils = require('internal.utils') +local internal = box.internal + -- new() needs a wrapper in Lua, because format normalization needs to be done -- in Lua. box.tuple.format.new = function(format) @@ -7,3 +9,9 @@ box.tuple.format.new = function(format) format = box.internal.space.normalize_format(nil, nil, format, 2) return box.internal.tuple_format.new(format) end + +setmetatable(box.tuple.format, { + __call = function(_, t) + return internal.tuple.tuple_get_format(t) + end, +}) diff --git a/test/app-luatest/gh_10005_tuple_get_format_test.lua b/test/app-luatest/gh_10005_tuple_get_format_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..b2d42d4a44e0b0f4c5410247b12a4a0bed314300 --- /dev/null +++ b/test/app-luatest/gh_10005_tuple_get_format_test.lua @@ -0,0 +1,50 @@ +local server = require('luatest.server') +local t = require('luatest') + +local g = t.group() + +g.before_all(function(cg) + cg.server = server:new() + cg.server:start() +end) + +g.after_all(function(cg) + cg.server:drop() +end) + +-- Checks that `tuple:format` works as expected. +g.test_tuple_format = function() + local f = box.tuple.format.new({{'id', 'number'}, {'name', 'string'}}) + local tuple = box.tuple.new({1, 'Flint'}, {format = f}) + t.assert_equals(type(tuple:format()), 'table') + t.assert_equals(tuple:format(), f:totable()) + + tuple = box.tuple.new({1, 'Flint', true}, {format = f}) + t.assert_equals(type(tuple:format()), 'table') + t.assert_equals(tuple:format(), f:totable()) +end + +-- Checks that `box.tuple.format` works as expected. +g.test_box_tuple_format = function() + local f = box.tuple.format.new({{'id', 'number'}, {'name', 'string'}}) + local tuple = box.tuple.new({1, 'Flint'}, {format = f}) + t.assert_equals(type(box.tuple.format(tuple)), 'table') + t.assert_equals(box.tuple.format(tuple), f:totable()) + t.assert_equals(box.tuple.format(tuple), tuple:format()) + + tuple = box.tuple.new({1, 'Flint', true}, {format = f}) + t.assert_equals(type(box.tuple.format(tuple)), 'table') + t.assert_equals(box.tuple.format(tuple), f:totable()) + t.assert_equals(box.tuple.format(tuple), tuple:format()) +end + +-- Checks that `tuple:format` and `box.tuple.format` work as expected +-- without set format. +g.test_tuple_format_with_no_format = function() + local tuple = box.tuple.new({1, 'Flint'}) + t.assert_equals(type(tuple:format()), 'table') + t.assert_equals(tuple:format(), {}) + + t.assert_equals(type(box.tuple.format(tuple)), 'table') + t.assert_equals(box.tuple.format(tuple), {}) +end