• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / crud / 6317266567

26 Sep 2023 07:11PM UTC coverage: 89.553% (-3.5%) from 93.065%
6317266567

push

github

better0fdead
crud: add readview support

Added readview support for select and pairs.

Closes #343

241 of 241 new or added lines in 6 files covered. (100.0%)

4586 of 5121 relevant lines covered (89.55%)

17047.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.29
/crud/select/executor.lua
1
local errors = require('errors')
409✔
2
local fiber = require('fiber')
409✔
3
local fun = require('fun')
409✔
4

5
local dev_checks = require('crud.common.dev_checks')
409✔
6
local select_comparators = require('crud.compare.comparators')
409✔
7
local compat = require('crud.common.compat')
409✔
8
local has_keydef = compat.exists('tuple.keydef', 'key_def')
409✔
9

10
local keydef_lib
11
if has_keydef then
409✔
12
    keydef_lib = compat.require('tuple.keydef', 'key_def')
818✔
13
end
14

15
local utils = require('crud.common.utils')
409✔
16

17
local ExecuteSelectError = errors.new_class('ExecuteSelectError')
409✔
18

19
local executor = {}
409✔
20

21
local function scroll_to_after_tuple(gen, space, scan_index, tarantool_iter, after_tuple, yield_every)
22
    local primary_index = space.index[0]
13,588✔
23

24
    local scroll_key_parts = utils.merge_primary_key_parts(scan_index.parts, primary_index.parts)
13,588✔
25

26
    local cmp_operator = select_comparators.get_cmp_operator(tarantool_iter)
13,588✔
27
    local scroll_comparator = select_comparators.gen_tuples_comparator(cmp_operator, scroll_key_parts)
13,588✔
28

29
    local looked_up_tuples = 0
13,588✔
30
    while true do
31
        local tuple
32
        gen.state, tuple = gen(gen.param, gen.state)
176,794✔
33
        looked_up_tuples = looked_up_tuples + 1
88,397✔
34

35
        if yield_every ~= nil and looked_up_tuples % yield_every == 0 then
88,397✔
36
            fiber.yield()
×
37
        end
38

39
        if tuple == nil then
88,397✔
40
            return nil
209✔
41
        end
42

43
        if scroll_comparator(tuple, after_tuple) then
176,376✔
44
            return tuple
13,379✔
45
        end
46
    end
47
end
48

49
local generate_value
50

51
if has_keydef then
409✔
52
    generate_value = function(after_tuple, scan_value, index_parts, tarantool_iter)
53
        local key_def = keydef_lib.new(index_parts)
1,303✔
54
        if #scan_value == 0 and after_tuple ~= nil then
1,303✔
55
            return key_def:extract_key(after_tuple)
164✔
56
        end
57
        local cmp_operator = select_comparators.get_cmp_operator(tarantool_iter)
1,221✔
58
        local cmp = key_def:compare_with_key(after_tuple, scan_value)
2,442✔
59
        if (cmp_operator == '<' and cmp < 0) or (cmp_operator == '>' and cmp > 0) then
1,221✔
60
            return key_def:extract_key(after_tuple)
2,216✔
61
        end
62
    end
63
else
64
    generate_value = function(after_tuple, scan_value, index_parts, tarantool_iter)
65
        local after_tuple_key = utils.extract_key(after_tuple, index_parts)
×
66
        if #scan_value == 0 and after_tuple ~= nil then
×
67
            return after_tuple_key
×
68
        end
69
        local cmp_operator = select_comparators.get_cmp_operator(tarantool_iter)
×
70
        local scan_comparator = select_comparators.gen_tuples_comparator(cmp_operator, index_parts)
×
71
        if scan_comparator(after_tuple_key, scan_value) then
×
72
            return after_tuple_key
×
73
        end
74
    end
75
end
76

77
function executor.execute(space, index, filter_func, opts)
409✔
78
    dev_checks('table', 'table', 'function', {
79,953✔
79
        scan_value = 'table',
80
        after_tuple = '?table',
81
        tarantool_iter = 'number',
82
        limit = '?number',
83
        yield_every = '?number',
84
        readview = '?boolean',
85
        readview_index = '?table'
86
    })
87

88
    opts = opts or {}
79,953✔
89

90
    local resp = { tuples_fetched = 0, tuples_lookup = 0, tuples = {} }
79,953✔
91

92
    if opts.limit == 0 then
79,953✔
93
        return resp
5✔
94
    end
95

96
    local value = opts.scan_value
79,948✔
97
    if opts.after_tuple ~= nil then
79,948✔
98
        local iter = opts.tarantool_iter
13,596✔
99
        if iter == box.index.EQ or iter == box.index.REQ then
13,596✔
100
            -- we need to make sure that the keys are equal
101
            -- the code is correct even if value is a partial key
102
            local parts = {}
12,293✔
103
            for i, _ in ipairs(value) do
24,596✔
104
                -- the code required for tarantool 1.10.6 at least
105
                table.insert(parts, index.parts[i])
12,303✔
106
            end
107

108
            local is_eq = iter == box.index.EQ
12,293✔
109
            local is_after_bigger
110
            if has_keydef then
12,293✔
111
                local key_def = keydef_lib.new(parts)
12,293✔
112
                local cmp = key_def:compare_with_key(opts.after_tuple, value)
24,586✔
113
                is_after_bigger = (is_eq and cmp > 0) or (not is_eq and cmp < 0)
12,293✔
114
            else
115
                local comparator
116
                if is_eq then
×
117
                    comparator = select_comparators.gen_func('<=', parts)
×
118
                else
119
                    comparator = select_comparators.gen_func('>=', parts)
×
120
                end
121
                local after_key = utils.extract_key(opts.after_tuple, parts)
×
122
                is_after_bigger = not comparator(after_key, value)
×
123
            end
124
            if is_after_bigger then
12,293✔
125
                -- it makes no sence to continue
126
                return resp
8✔
127
            end
128
        else
129
            local new_value = generate_value(opts.after_tuple, value, index.parts, iter)
1,303✔
130
            if new_value ~= nil then
1,303✔
131
                value = new_value
1,190✔
132
            end
133
        end
134
    end
135

136
    local tuple
137
    local raw_gen, param, state
138
    if opts.readview then
79,940✔
139
        raw_gen, param, state = opts.readview_index:pairs(value, {iterator = opts.tarantool_iter})
×
140
    else
141
        raw_gen, param, state = index:pairs(value, {iterator = opts.tarantool_iter})
159,848✔
142
    end
143
    local gen = fun.wrap(function(param, state)
159,816✔
144
        local next_state, var = raw_gen(param, state)
327,138✔
145

146
        if var ~= nil then
327,138✔
147
            resp.tuples_lookup = resp.tuples_lookup + 1
270,554✔
148
        end
149

150
        return next_state, var
327,138✔
151
    end, param, state)
79,908✔
152

153
    if opts.after_tuple ~= nil then
79,908✔
154
        local err
155
        tuple, err = scroll_to_after_tuple(gen, space, index, opts.tarantool_iter, opts.after_tuple, opts.yield_every)
27,176✔
156
        if err ~= nil then
13,588✔
157
            return nil, ExecuteSelectError:new("Failed to scroll to the after_tuple: %s", err)
×
158
        end
159

160
        if tuple == nil then
13,588✔
161
            return resp
209✔
162
        end
163
    end
164

165
    if tuple == nil then
79,699✔
166
        gen.state, tuple = gen(gen.param, gen.state)
132,640✔
167
    end
168

169
    local looked_up_tuples = 0
79,699✔
170
    while true do
171
        if tuple == nil then
252,120✔
172
            break
56,375✔
173
        end
174

175
        local matched, early_exit = filter_func(tuple)
195,745✔
176

177
        if matched then
195,745✔
178
            table.insert(resp.tuples, tuple)
195,418✔
179
            resp.tuples_fetched = resp.tuples_fetched + 1
195,418✔
180

181
            if opts.limit ~= nil and resp.tuples_fetched >= opts.limit then
195,418✔
182
                break
23,305✔
183
            end
184
        elseif early_exit then
327✔
185
            break
19✔
186
        end
187

188
        gen.state, tuple = gen(gen.param, gen.state)
344,842✔
189
        looked_up_tuples = looked_up_tuples + 1
172,421✔
190

191
        if opts.yield_every ~= nil and looked_up_tuples % opts.yield_every == 0 then
172,421✔
192
            fiber.yield()
4,000✔
193
        end
194
    end
195

196
    return resp
79,699✔
197
end
198

199
return executor
409✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc