[Tarantool-patches] [PATCH v2] Introduce fselect - formatted select

Aleksandr Lyapunov alyapunov at tarantool.org
Mon Oct 5 19:36:08 MSK 2020


space:fselect and index:fselect fetch data like ordinal select,
but formats the result like mysql does - with columns, column
names etc. fselect converts tuple to strings using json,
extending with spaces and cutting tail if necessary. It is
designed for visual analysis of select result and shouldn't
be used stored procedures.

index:fselect(<key>, <opts>, <fselect_opts>)
space:fselect(<key>, <opts>, <fselect_opts>)

There are some options that can be specified in different ways:
 - among other common options (<opts>) with 'fselect_' prefix.
   (e.g. 'fselect_type=..')
 - in special <fselect_opts> map (with or without prefix).
 - in global variables with 'fselect_' prefix.

The possible options are:
 - type:
    - 'sql' - like mysql result (default).
    - 'gh' (or 'github' or 'markdown') - markdown syntax, for
      copy-pasting to github.
    - 'jira' - jira table syntax (for copy-pasting to jira).
 - widths: array with desired widths of columns.
 - max_width: limit entire length of a row string, longest fields
   will be cut if necessary. Set to 0 (default) to detect and use
   screen width. Set to -1 for no limit.
 - print: (default - false) - print each line instead of adding
   to result.
 - use_nbsp: (default - true) - add invisible spaces to improve
   readability in YAML output. Not applicabble when print=true.

There is also a pair of shortcuts:
index/space:gselect - same as fselect, but with type='gh'.
index/space:jselect - same as fselect, but with type='jira'.

See test/engine/select.test.lua for examples.

Closes #5161
---
 src/box/lua/schema.lua      | 232 ++++++++++++++++++++++++++++++++++++++++++
 test/engine/select.result   | 243 ++++++++++++++++++++++++++++++++++++++++++++
 test/engine/select.test.lua |  37 +++++++
 3 files changed, 512 insertions(+)

diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index 7fe1ea7..1131af7 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -1456,6 +1456,226 @@ base_index_mt.bsize = function(index)
     end
     return tonumber(ret)
 end
+-- index.fselect - formatted select.
+-- Options can be passed through opts, fselect_opts and global variables.
+-- If an option is in opts table or set in global variable - it must have
+-- prefix 'fselect_'. If an option is on fselect_opts table - it may or
+-- may not have the prefix.
+-- Options:
+-- type:
+--   'sql' - like mysql result (default)
+--   'gh' (or 'github' or 'markdown') - markdown syntax, for pasting to github.
+--   'jira' syntax (for pasting to jira)
+-- widths: array with desired widths of columns.
+-- max_width: limit entire length of a row string, longest fields will be cut.
+--  Set to 0 (default) to detect and use screen width. Set to -1 for no limit.
+-- print: (default - false) - print each line instead of adding to result.
+-- use_nbsp: (default - true) - add invisible spaces to improve readability
+--  in YAML output. Not applicabble when print=true.
+base_index_mt.fselect = function(index, key, opts, fselect_opts)
+    -- Options.
+    if type(fselect_opts) ~= 'table' then fselect_opts = {} end
+
+    -- Get global value, like _G[name] but wrapped with pcall for strict mode.
+    local function get_global(name)
+        local function internal() return _G[name] end
+        local success,result = pcall(internal)
+        return success and result or nil
+    end
+    -- Get a value from `opts` table and remove it from the table.
+    local function grab_from_opts(name)
+        if type(opts) ~= 'table' then return nil end
+        local res = opts[name]
+        if res ~= nil then opts[name] = nil end
+        return res
+    end
+    -- Find an option in opts, fselect_opts or _G by given name.
+    -- In opts and _G the value is searched with 'fselect_' prefix;
+    -- In fselect_opts - with or without prefix.
+    local function get_opt(name, default, expected_type)
+        local prefix_name = 'fselect_' .. name
+        local variants = {fselect_opts[prefix_name], fselect_opts[name],
+            grab_from_opts(prefix_name), get_global(prefix_name), default }
+        local min_i = 0
+        local min_v = nil
+        for i,v in pairs(variants) do
+            if (type(v) == expected_type and i < min_i) or min_v == nil then
+                min_i = i
+                min_v = v
+            end
+        end
+        return min_v
+    end
+
+    local fselect_type = get_opt('type', 'sql', 'string')
+    if fselect_type == 'gh' or fselect_type == 'github' then
+        fselect_type = 'markdown'
+    end
+    if fselect_type ~= 'sql' and fselect_type ~= 'markdown' and fselect_type ~= 'jira' then
+        fselect_type = 'sql'
+    end
+    local widths = get_opt('widths', {}, 'table')
+    local default_max_width = 0
+    if #widths > 0 then default_max_width = -1 end
+    local max_width = get_opt('max_width', default_max_width, 'number')
+    local use_print = get_opt('print', false, 'boolean')
+    local use_nbsp = get_opt('use_nbsp', true, 'boolean')
+    local min_col_width = 5
+    local max_col_width = 1000
+    if use_print then use_nbsp = false end
+
+    -- Screen size autodetection.
+    local function detect_width()
+        local ffi = require('ffi')
+        ffi.cdef('void rl_get_screen_size(int *rows, int *cols);')
+        local colsp = ffi.new('int[1]')
+        ffi.C.rl_get_screen_size(nil, colsp)
+        return colsp[0]
+    end
+    if max_width == 0 then
+        max_width = detect_width()
+        -- YAML uses several additinal symbols in output, we should shink line.
+        local waste_size = use_print and 0 or 5
+        if max_width > waste_size then
+            max_width = max_width - waste_size
+        else
+            max_width = fselect_type == 'sql' and 140 or 260
+        end
+    end
+
+    -- select and stringify.
+    local tab = { }
+    local json = require('json')
+    for _,t in index:pairs(key, opts) do
+        local row = { }
+        for _,f in t:pairs() do
+            table.insert(row, json.encode(f))
+        end
+        table.insert(tab, row)
+    end
+
+    local num_rows = #tab
+    local space = box.space[index.space_id]
+    local fmt = space:format()
+    local num_cols = math.max(#fmt, 1)
+    for i = 1,num_rows do
+        num_cols = math.max(num_cols, #tab[i])
+    end
+
+    local names = {}
+    for j = 1,num_cols do
+        table.insert(names, fmt[j] and fmt[j].name or 'col' .. tostring(j))
+    end
+    local real_width = num_cols + 1 -- including '|' symbols
+    for j = 1,num_cols do
+        if type(widths[j]) ~= 'number' then
+            local width = names[j]:len()
+            if fselect_type == 'jira' then
+                width = width + 1
+            end
+            for i = 1,num_rows do
+                if tab[i][j] then
+                    width = math.max(width, tab[i][j]:len())
+                end
+            end
+            widths[j] = width
+        end
+        widths[j] = math.max(widths[j], min_col_width)
+        widths[j] = math.min(widths[j], max_col_width)
+        real_width = real_width + widths[j]
+    end
+
+    -- cut some columns if its width is too big
+    while max_width > 0 and real_width > max_width do
+        local max_j = 1
+        for j = 2,num_cols do
+            if widths[j] >= widths[max_j] then max_j = j end
+        end
+        widths[max_j] = widths[max_j] - 1
+        real_width = real_width - 1
+    end
+
+    -- Yaml wraps all strings that contain spaces with single quotes, and
+    -- does not wrap otherwise. Let's add some invisible spaces to every line
+    -- in order to make them similar in output.
+    local prefix = string.char(0xE2) .. string.char(0x80) .. string.char(0x8B)
+    if not use_nbsp then prefix = '' end
+
+    local header_row_delim = fselect_type == 'jira' and '||' or '|'
+    local result_row_delim = '|'
+    local delim_row_delim = fselect_type == 'sql' and '+' or '|'
+
+    local delim_row = prefix .. delim_row_delim
+    for j = 1,num_cols do
+        delim_row = delim_row .. string.rep('-', widths[j]) .. delim_row_delim
+    end
+
+    -- format string - cut or fill with spaces to make is exactly n symbols.
+    -- also replace spaces with non-break spaces.
+    local fmt_str = function(x, n)
+        if not x then x = '' end
+        local str
+        if x:len() <= n then
+            local add = n - x:len()
+            local addl = math.floor(add/2)
+            local addr = math.ceil(add/2)
+            str = string.rep(' ', addl) .. x .. string.rep(' ', addr)
+        else
+            str = x:sub(1, n)
+        end
+        if use_nbsp then
+            -- replace spaces with &nbsp
+            return str:gsub("%s", string.char(0xC2) .. string.char(0xA0))
+        else
+            return str
+        end
+    end
+
+    local res = {}
+
+    -- insert into res a string with formatted row.
+    local res_insert = function(row, is_header)
+        local delim = is_header and header_row_delim or result_row_delim
+        local str_row = prefix .. delim
+        local shrink = fselect_type == 'jira' and is_header and 1 or 0
+        for j = 1,num_cols do
+            str_row = str_row .. fmt_str(row[j], widths[j] - shrink) .. delim
+        end
+        table.insert(res, str_row)
+    end
+
+    -- format result
+    if fselect_type == 'sql' then
+        table.insert(res, delim_row)
+    end
+    res_insert(names, true)
+    if fselect_type ~= 'jira' then
+        table.insert(res, delim_row)
+    end
+    for i = 1,num_rows do
+        res_insert(tab[i], false)
+    end
+    if fselect_type == 'sql' then
+        table.insert(res, delim_row)
+    end
+    if use_print then
+        for _,line in ipairs(res) do
+            print(line)
+        end
+        return {}
+    end
+    return res
+end
+base_index_mt.gselect = function(index, key, opts, fselect_opts)
+    if type(fselect_opts) ~= 'table' then fselect_opts = {} end
+    fselect_opts['type'] = 'gh'
+    return base_index_mt.fselect(index, key, opts, fselect_opts)
+end
+base_index_mt.jselect = function(index, key, opts, fselect_opts)
+    if type(fselect_opts) ~= 'table' then fselect_opts = {} end
+    fselect_opts['type'] = 'jira'
+    return base_index_mt.fselect(index, key, opts, fselect_opts)
+end
 -- Lua 5.2 compatibility
 base_index_mt.__len = base_index_mt.len
 -- min and max
@@ -1697,6 +1917,18 @@ space_mt.select = function(space, key, opts)
     check_space_arg(space, 'select')
     return check_primary_index(space):select(key, opts)
 end
+space_mt.fselect = function(space, key, opts, fselect_opts)
+    check_space_arg(space, 'select')
+    return check_primary_index(space):fselect(key, opts, fselect_opts)
+end
+space_mt.gselect = function(space, key, opts, fselect_opts)
+    check_space_arg(space, 'select')
+    return check_primary_index(space):gselect(key, opts, fselect_opts)
+end
+space_mt.jselect = function(space, key, opts, fselect_opts)
+    check_space_arg(space, 'select')
+    return check_primary_index(space):jselect(key, opts, fselect_opts)
+end
 space_mt.insert = function(space, tuple)
     check_space_arg(space, 'insert')
     return internal.insert(space.id, tuple);
diff --git a/test/engine/select.result b/test/engine/select.result
index 8f37ac9..1d13f93 100644
--- a/test/engine/select.result
+++ b/test/engine/select.result
@@ -3429,3 +3429,246 @@ index3:select{1235}
 space:drop()
 ---
 ...
+--https://github.com/tarantool/tarantool/issues/5161
+--formatted select
+s = box.schema.space.create('test', { engine = engine })
+---
+...
+i1 = s:create_index('test1')
+---
+...
+i2 = s:create_index('test2', {parts={{2, 'unsigned'}}})
+---
+...
+_ = s:replace{1, 2, 3, 4, box.NULL, 5}
+---
+...
+_ = s:replace{3, 4, true, {1, 2, 3}}
+---
+...
+_ = s:replace{5, 6, false, {1, 2, 3, ['key']='value'}}
+---
+...
+_ = s:replace{3, 4, true, {1, {3, {aa=1,bb=2}}, 3}}
+---
+...
+_ = s:replace{7, 8, 'asdgsdgswegg', 'sdf', 'dsgfsdgsegasges' }
+---
+...
+s:fselect()
+---
+- - ​+-----+-----+--------------+---------------------------------+-----------------+-----+
+  - ​|col1 |col2 |     col3     |              col4               |      col5       |col6 |
+  - ​+-----+-----+--------------+---------------------------------+-----------------+-----+
+  - ​|  1  |  2  |      3       |                4                |      null       |  5  |
+  - ​|  3  |  4  |     true     |    [1,[3,{"aa":1,"bb":2}],3]    |                 |     |
+  - ​|  5  |  6  |    false     |{"1":1,"2":2,"3":3,"key":"value"}|                 |     |
+  - ​|  7  |  8  |"asdgsdgswegg"|              "sdf"              |"dsgfsdgsegasges"|     |
+  - ​+-----+-----+--------------+---------------------------------+-----------------+-----+
+...
+s:fselect({5}, {iterator='le'})
+---
+- - ​+-----+-----+-----+---------------------------------+-----+-----+
+  - ​|col1 |col2 |col3 |              col4               |col5 |col6 |
+  - ​+-----+-----+-----+---------------------------------+-----+-----+
+  - ​|  5  |  6  |false|{"1":1,"2":2,"3":3,"key":"value"}|     |     |
+  - ​|  3  |  4  |true |    [1,[3,{"aa":1,"bb":2}],3]    |     |     |
+  - ​|  1  |  2  |  3  |                4                |null |  5  |
+  - ​+-----+-----+-----+---------------------------------+-----+-----+
+...
+s:fselect({5}, {iterator='le', fselect_max_width=40})
+---
+- - ​+-----+-----+-----+--------+-----+-----+
+  - ​|col1 |col2 |col3 |  col4  |col5 |col6 |
+  - ​+-----+-----+-----+--------+-----+-----+
+  - ​|  5  |  6  |false|{"1":1,"|     |     |
+  - ​|  3  |  4  |true |[1,[3,{"|     |     |
+  - ​|  1  |  2  |  3  |   4    |null |  5  |
+  - ​+-----+-----+-----+--------+-----+-----+
+...
+i1:fselect({3})
+---
+- - ​+-----+-----+-----+-------------------------+
+  - ​|col1 |col2 |col3 |          col4           |
+  - ​+-----+-----+-----+-------------------------+
+  - ​|  3  |  4  |true |[1,[3,{"aa":1,"bb":2}],3]|
+  - ​+-----+-----+-----+-------------------------+
+...
+i2:fselect({6})
+---
+- - ​+-----+-----+-----+---------------------------------+
+  - ​|col1 |col2 |col3 |              col4               |
+  - ​+-----+-----+-----+---------------------------------+
+  - ​|  5  |  6  |false|{"1":1,"2":2,"3":3,"key":"value"}|
+  - ​+-----+-----+-----+---------------------------------+
+...
+i1:fselect({2})
+---
+- - ​+-----+
+  - ​|col1 |
+  - ​+-----+
+  - ​+-----+
+...
+i2:fselect({5})
+---
+- - ​+-----+
+  - ​|col1 |
+  - ​+-----+
+  - ​+-----+
+...
+s:format{{name='name', type='unsigned'}, {name='veeeeeeeery long name', type='unsigned'}}
+---
+...
+s:fselect()
+---
+- - ​+-----+---------------------+--------------+---------------------------------+-----------------+-----+
+  - ​|name |veeeeeeeery long name|     col3     |              col4               |      col5       |col6 |
+  - ​+-----+---------------------+--------------+---------------------------------+-----------------+-----+
+  - ​|  1  |          2          |      3       |                4                |      null       |  5  |
+  - ​|  3  |          4          |     true     |    [1,[3,{"aa":1,"bb":2}],3]    |                 |     |
+  - ​|  5  |          6          |    false     |{"1":1,"2":2,"3":3,"key":"value"}|                 |     |
+  - ​|  7  |          8          |"asdgsdgswegg"|              "sdf"              |"dsgfsdgsegasges"|     |
+  - ​+-----+---------------------+--------------+---------------------------------+-----------------+-----+
+...
+s:fselect({}, nil, {max_width=40})
+---
+- - ​+-----+------+------+------+-----+-----+
+  - ​|name |veeeee| col3 | col4 |col5 |col6 |
+  - ​+-----+------+------+------+-----+-----+
+  - ​|  1  |  2   |  3   |  4   |null |  5  |
+  - ​|  3  |  4   | true |[1,[3,|     |     |
+  - ​|  5  |  6   |false |{"1":1|     |     |
+  - ​|  7  |  8   |"asdgs|"sdf" |"dsgf|     |
+  - ​+-----+------+------+------+-----+-----+
+...
+i1:fselect({3})
+---
+- - ​+-----+---------------------+-----+-------------------------+
+  - ​|name |veeeeeeeery long name|col3 |          col4           |
+  - ​+-----+---------------------+-----+-------------------------+
+  - ​|  3  |          4          |true |[1,[3,{"aa":1,"bb":2}],3]|
+  - ​+-----+---------------------+-----+-------------------------+
+...
+i2:fselect({6})
+---
+- - ​+-----+---------------------+-----+---------------------------------+
+  - ​|name |veeeeeeeery long name|col3 |              col4               |
+  - ​+-----+---------------------+-----+---------------------------------+
+  - ​|  5  |          6          |false|{"1":1,"2":2,"3":3,"key":"value"}|
+  - ​+-----+---------------------+-----+---------------------------------+
+...
+i1:fselect({2})
+---
+- - ​+-----+---------------------+
+  - ​|name |veeeeeeeery long name|
+  - ​+-----+---------------------+
+  - ​+-----+---------------------+
+...
+i2:fselect({5})
+---
+- - ​+-----+---------------------+
+  - ​|name |veeeeeeeery long name|
+  - ​+-----+---------------------+
+  - ​+-----+---------------------+
+...
+s:fselect({}, {fselect_type='gh'})
+---
+- - ​|name |veeeeeeeery long name|     col3     |              col4               |      col5       |col6 |
+  - ​|-----|---------------------|--------------|---------------------------------|-----------------|-----|
+  - ​|  1  |          2          |      3       |                4                |      null       |  5  |
+  - ​|  3  |          4          |     true     |    [1,[3,{"aa":1,"bb":2}],3]    |                 |     |
+  - ​|  5  |          6          |    false     |{"1":1,"2":2,"3":3,"key":"value"}|                 |     |
+  - ​|  7  |          8          |"asdgsdgswegg"|              "sdf"              |"dsgfsdgsegasges"|     |
+...
+s:fselect({}, nil, {type='gh'})
+---
+- - ​|name |veeeeeeeery long name|     col3     |              col4               |      col5       |col6 |
+  - ​|-----|---------------------|--------------|---------------------------------|-----------------|-----|
+  - ​|  1  |          2          |      3       |                4                |      null       |  5  |
+  - ​|  3  |          4          |     true     |    [1,[3,{"aa":1,"bb":2}],3]    |                 |     |
+  - ​|  5  |          6          |    false     |{"1":1,"2":2,"3":3,"key":"value"}|                 |     |
+  - ​|  7  |          8          |"asdgsdgswegg"|              "sdf"              |"dsgfsdgsegasges"|     |
+...
+s:fselect({}, nil, {fselect_type='github'})
+---
+- - ​|name |veeeeeeeery long name|     col3     |              col4               |      col5       |col6 |
+  - ​|-----|---------------------|--------------|---------------------------------|-----------------|-----|
+  - ​|  1  |          2          |      3       |                4                |      null       |  5  |
+  - ​|  3  |          4          |     true     |    [1,[3,{"aa":1,"bb":2}],3]    |                 |     |
+  - ​|  5  |          6          |    false     |{"1":1,"2":2,"3":3,"key":"value"}|                 |     |
+  - ​|  7  |          8          |"asdgsdgswegg"|              "sdf"              |"dsgfsdgsegasges"|     |
+...
+s:gselect{}
+---
+- - ​|name |veeeeeeeery long name|     col3     |              col4               |      col5       |col6 |
+  - ​|-----|---------------------|--------------|---------------------------------|-----------------|-----|
+  - ​|  1  |          2          |      3       |                4                |      null       |  5  |
+  - ​|  3  |          4          |     true     |    [1,[3,{"aa":1,"bb":2}],3]    |                 |     |
+  - ​|  5  |          6          |    false     |{"1":1,"2":2,"3":3,"key":"value"}|                 |     |
+  - ​|  7  |          8          |"asdgsdgswegg"|              "sdf"              |"dsgfsdgsegasges"|     |
+...
+fselect_type = 'gh'
+---
+...
+s:fselect()
+---
+- - ​|name |veeeeeeeery long name|     col3     |              col4               |      col5       |col6 |
+  - ​|-----|---------------------|--------------|---------------------------------|-----------------|-----|
+  - ​|  1  |          2          |      3       |                4                |      null       |  5  |
+  - ​|  3  |          4          |     true     |    [1,[3,{"aa":1,"bb":2}],3]    |                 |     |
+  - ​|  5  |          6          |    false     |{"1":1,"2":2,"3":3,"key":"value"}|                 |     |
+  - ​|  7  |          8          |"asdgsdgswegg"|              "sdf"              |"dsgfsdgsegasges"|     |
+...
+fselect_type = nil
+---
+...
+s:fselect()
+---
+- - ​+-----+---------------------+--------------+---------------------------------+-----------------+-----+
+  - ​|name |veeeeeeeery long name|     col3     |              col4               |      col5       |col6 |
+  - ​+-----+---------------------+--------------+---------------------------------+-----------------+-----+
+  - ​|  1  |          2          |      3       |                4                |      null       |  5  |
+  - ​|  3  |          4          |     true     |    [1,[3,{"aa":1,"bb":2}],3]    |                 |     |
+  - ​|  5  |          6          |    false     |{"1":1,"2":2,"3":3,"key":"value"}|                 |     |
+  - ​|  7  |          8          |"asdgsdgswegg"|              "sdf"              |"dsgfsdgsegasges"|     |
+  - ​+-----+---------------------+--------------+---------------------------------+-----------------+-----+
+...
+s:fselect({}, {fselect_type='jira'})
+---
+- - ​||name||veeeeeeeery long name||    col3     ||              col4              ||      col5      ||col6||
+  - ​|  1  |          2           |      3       |                4                |      null       |  5  |
+  - ​|  3  |          4           |     true     |    [1,[3,{"aa":1,"bb":2}],3]    |                 |     |
+  - ​|  5  |          6           |    false     |{"1":1,"2":2,"3":3,"key":"value"}|                 |     |
+  - ​|  7  |          8           |"asdgsdgswegg"|              "sdf"              |"dsgfsdgsegasges"|     |
+...
+s:jselect()
+---
+- - ​||name||veeeeeeeery long name||    col3     ||              col4              ||      col5      ||col6||
+  - ​|  1  |          2           |      3       |                4                |      null       |  5  |
+  - ​|  3  |          4           |     true     |    [1,[3,{"aa":1,"bb":2}],3]    |                 |     |
+  - ​|  5  |          6           |    false     |{"1":1,"2":2,"3":3,"key":"value"}|                 |     |
+  - ​|  7  |          8           |"asdgsdgswegg"|              "sdf"              |"dsgfsdgsegasges"|     |
+...
+s:fselect({}, {fselect_widths={8, 8, nil, 10}})
+---
+- - ​+--------+--------+--------------+----------+-----------------+-----+
+  - ​|  name  |veeeeeee|     col3     |   col4   |      col5       |col6 |
+  - ​+--------+--------+--------------+----------+-----------------+-----+
+  - ​|   1    |   2    |      3       |    4     |      null       |  5  |
+  - ​|   3    |   4    |     true     |[1,[3,{"aa|                 |     |
+  - ​|   5    |   6    |    false     |{"1":1,"2"|                 |     |
+  - ​|   7    |   8    |"asdgsdgswegg"|  "sdf"   |"dsgfsdgsegasges"|     |
+  - ​+--------+--------+--------------+----------+-----------------+-----+
+...
+s:fselect(nil, {fselect_use_nbsp=false})
+---
+- - +-----+---------------------+--------------+---------------------------------+-----------------+-----+
+  - '|name |veeeeeeeery long name|     col3     |              col4               |      col5       |col6
+    |'
+  - +-----+---------------------+--------------+---------------------------------+-----------------+-----+
+  - '|  1  |          2          |      3       |                4                |      null       |  5  |'
+  - '|  3  |          4          |     true     |    [1,[3,{"aa":1,"bb":2}],3]    |                 |     |'
+  - '|  5  |          6          |    false     |{"1":1,"2":2,"3":3,"key":"value"}|                 |     |'
+  - '|  7  |          8          |"asdgsdgswegg"|              "sdf"              |"dsgfsdgsegasges"|     |'
+  - +-----+---------------------+--------------+---------------------------------+-----------------+-----+
+...
diff --git a/test/engine/select.test.lua b/test/engine/select.test.lua
index 7b34541..0919d49 100644
--- a/test/engine/select.test.lua
+++ b/test/engine/select.test.lua
@@ -111,3 +111,40 @@ index2:get{104}
 index3:get{9}
 index3:select{1235}
 space:drop()
+
+--https://github.com/tarantool/tarantool/issues/5161
+--formatted select
+s = box.schema.space.create('test', { engine = engine })
+i1 = s:create_index('test1')
+i2 = s:create_index('test2', {parts={{2, 'unsigned'}}})
+_ = s:replace{1, 2, 3, 4, box.NULL, 5}
+_ = s:replace{3, 4, true, {1, 2, 3}}
+_ = s:replace{5, 6, false, {1, 2, 3, ['key']='value'}}
+_ = s:replace{3, 4, true, {1, {3, {aa=1,bb=2}}, 3}}
+_ = s:replace{7, 8, 'asdgsdgswegg', 'sdf', 'dsgfsdgsegasges' }
+s:fselect()
+s:fselect({5}, {iterator='le'})
+s:fselect({5}, {iterator='le', fselect_max_width=40})
+i1:fselect({3})
+i2:fselect({6})
+i1:fselect({2})
+i2:fselect({5})
+s:format{{name='name', type='unsigned'}, {name='veeeeeeeery long name', type='unsigned'}}
+s:fselect()
+s:fselect({}, nil, {max_width=40})
+i1:fselect({3})
+i2:fselect({6})
+i1:fselect({2})
+i2:fselect({5})
+s:fselect({}, {fselect_type='gh'})
+s:fselect({}, nil, {type='gh'})
+s:fselect({}, nil, {fselect_type='github'})
+s:gselect{}
+fselect_type = 'gh'
+s:fselect()
+fselect_type = nil
+s:fselect()
+s:fselect({}, {fselect_type='jira'})
+s:jselect()
+s:fselect({}, {fselect_widths={8, 8, nil, 10}})
+s:fselect(nil, {fselect_use_nbsp=false})
-- 
2.7.4



More information about the Tarantool-patches mailing list