From 6d5f1db5433b61dcca2ef78dbc53ff5d989a1e2a Mon Sep 17 00:00:00 2001 From: DerekBum <alextruewestern@gmail.com> Date: Fri, 31 May 2024 19:43:58 +0300 Subject: [PATCH] box: feature `tuple:format` to get a format of a tuple This patch adds `tuple:format()` method to get a format of a tuple. Closes #10005 @TarantoolBot document Title: New `format` method for `box.tuple` Product: Tarantool Since: 3.2 The `tuple:format` method returns a format of a tuple. --- .../unreleased/gh-10005-tuple-get-format.md | 3 ++ src/box/lua/tuple.c | 18 +++++++ src/box/lua/tuple.lua | 1 + src/box/lua/tuple_format.c | 20 +++++--- src/box/lua/tuple_format.h | 7 +++ src/box/lua/tuple_format.lua | 8 +++ .../gh_10005_tuple_get_format_test.lua | 50 +++++++++++++++++++ 7 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 changelogs/unreleased/gh-10005-tuple-get-format.md create mode 100644 test/app-luatest/gh_10005_tuple_get_format_test.lua 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 0000000000..674d1494a1 --- /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 5eedde8721..30d6b64e68 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 ffe3294148..416c66fe9e 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 3b5d8e7b46..eedc92be9a 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 66a35d5b0b..9c0b9ca993 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 31c6fd108c..35ea98797b 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 0000000000..b2d42d4a44 --- /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 -- GitLab