Skip to content

Commit

Permalink
Fix opts table damaging by CRUD methods (#200)
Browse files Browse the repository at this point in the history
If we have `opts` variable and we pass it to some crud method
(`upsert_object` for example) and then use `opts` variable again
for crud method (`get` for example) we receive an error because
`*_object` method damages `opts` variable adding
`add_space_schema_hash` parameter to `opts` variable.
  • Loading branch information
AnaNek authored Oct 12, 2021
1 parent 66113b7 commit d13fe63
Show file tree
Hide file tree
Showing 11 changed files with 330 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
versions (< 1.10.8) anymore.
* Names of errors generated by CRUD operations have been unified.

### Fixed

* Damaging of opts table by CRUD methods.

### Added

* Added integration with service coveralls.io.
Expand Down
10 changes: 10 additions & 0 deletions crud/common/utils.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
local errors = require('errors')
local ffi = require('ffi')
local vshard = require('vshard')
local fun = require('fun')

local schema = require('crud.common.schema')
local dev_checks = require('crud.common.dev_checks')
Expand Down Expand Up @@ -524,4 +525,13 @@ function utils.flatten_obj_reload(space_name, obj)
return schema.wrap_func_reload(flatten_obj, space_name, obj)
end

-- Merge two options map.
--
-- `opts_a` and/or `opts_b` can be `nil`.
--
-- If `opts_a.foo` and `opts_b.foo` exists, prefer `opts_b.foo`.
function utils.merge_options(opts_a, opts_b)
return fun.chain(opts_a or {}, opts_b or {}):tomap()
end

return utils
4 changes: 1 addition & 3 deletions crud/insert.lua
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,8 @@ end
function insert.object(space_name, obj, opts)
checks('string', 'table', '?table')

opts = opts or {}

-- insert can fail if router uses outdated schema to flatten object
opts.add_space_schema_hash = true
opts = utils.merge_options(opts, {add_space_schema_hash = true})

local tuple, err = utils.flatten_obj_reload(space_name, obj)
if err ~= nil then
Expand Down
4 changes: 1 addition & 3 deletions crud/replace.lua
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,8 @@ end
function replace.object(space_name, obj, opts)
checks('string', 'table', '?table')

opts = opts or {}

-- replace can fail if router uses outdated schema to flatten object
opts.add_space_schema_hash = true
opts = utils.merge_options(opts, {add_space_schema_hash = true})

local tuple, err = utils.flatten_obj_reload(space_name, obj)
if err ~= nil then
Expand Down
4 changes: 1 addition & 3 deletions crud/upsert.lua
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,8 @@ end
function upsert.object(space_name, obj, user_operations, opts)
checks('string', 'table', 'table', '?table')

opts = opts or {}

-- upsert can fail if router uses outdated schema to flatten object
opts.add_space_schema_hash = true
opts = utils.merge_options(opts, {add_space_schema_hash = true})

local tuple, err = utils.flatten_obj_reload(space_name, obj)
if err ~= nil then
Expand Down
48 changes: 48 additions & 0 deletions test/integration/borders_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,51 @@ pgroup.test_equal_secondary_keys = function(g)
local objects = crud.unflatten_rows(result.rows, result.metadata)
t.assert_equals(objects, helpers.get_objects_by_idxs(customers, {2}))
end

pgroup.test_opts_not_damaged = function(g)
helpers.insert_objects(g, 'customers', {
{
id = 1, name = "Elizabeth", last_name = "Jackson",
age = 21, city = "New York",
}, {
id = 2, name = "Mary", last_name = "Brown",
age = 33, city = "Los Angeles",
}, {
id = 3, name = "David", last_name = "Smith",
age = 12, city = "Los Angeles",
}, {
id = 4, name = "William", last_name = "White",
age = 8, city = "Chicago",
},
})

-- min
local min_opts = {timeout = 1, fields = {'name', 'age'}}
local new_min_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local min_opts = ...
local _, err = crud.min('customers', nil, min_opts)
return min_opts, err
]], {min_opts})

t.assert_equals(err, nil)
t.assert_equals(new_min_opts, min_opts)

-- max
local max_opts = {timeout = 1, fields = {'name', 'age'}}
local new_max_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local max_opts = ...
local _, err = crud.max('customers', nil, max_opts)
return max_opts, err
]], {min_opts})

t.assert_equals(err, nil)
t.assert_equals(new_max_opts, max_opts)
end
16 changes: 16 additions & 0 deletions test/integration/len_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,19 @@ pgroup.test_len_empty_space = function(g)
t.assert_equals(err, nil)
t.assert_equals(result, 0)
end

pgroup.test_opts_not_damaged = function(g)
local len_opts = {timeout = 1}
local new_len_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local len_opts = ...
local _, err = crud.len('customers', len_opts)
return len_opts, err
]], {len_opts})

t.assert_equals(err, nil)
t.assert_equals(new_len_opts, len_opts)
end
51 changes: 51 additions & 0 deletions test/integration/pairs_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -754,3 +754,54 @@ pgroup.test_pairs_timeout = function(g)
]])
t.assert_equals(objects, raw_rows)
end

pgroup.test_opts_not_damaged = function(g)
local customers = helpers.insert_objects(g, 'customers', {
{
id = 1, name = "Elizabeth", last_name = "Jackson",
age = 12, city = "Los Angeles",
}, {
id = 2, name = "Mary", last_name = "Brown",
age = 46, city = "London",
}, {
id = 3, name = "David", last_name = "Smith",
age = 33, city = "Los Angeles",
}, {
id = 4, name = "William", last_name = "White",
age = 46, city = "Chicago",
},
})

table.sort(customers, function(obj1, obj2) return obj1.id < obj2.id end)

local expected_customers = {
{id = 3, name = "David", age = 33},
{id = 4, name = "William", age = 46},
}

-- after tuple should be in `fields` format + primary key
local fields = {'name', 'age'}
local after = {"Mary", 46, 2}

local pairs_opts = {
timeout = 1, bucket_id = 1161,
batch_size = 105, first = 2, after = after,
fields = fields, mode = 'read', prefer_replica = false,
balance = false, force_map_call = false, use_tomap = true,
}
local new_pairs_opts, objects = g.cluster.main_server:eval([[
local crud = require('crud')
local pairs_opts = ...
local objects = {}
for _, object in crud.pairs('customers', nil, pairs_opts) do
table.insert(objects, object)
end
return pairs_opts, objects
]], {pairs_opts})

t.assert_equals(objects, expected_customers)
t.assert_equals(new_pairs_opts, pairs_opts)
end
43 changes: 43 additions & 0 deletions test/integration/select_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1538,3 +1538,46 @@ pgroup.test_select_timeout = function(g)
{4, 1161, "William", "White", 81, "Chicago"},
})
end

pgroup.test_opts_not_damaged = function(g)
local customers = helpers.insert_objects(g, 'customers', {
{
id = 1, name = "Elizabeth", last_name = "Jackson",
age = 12, city = "Los Angeles",
}, {
id = 2, name = "Mary", last_name = "Brown",
age = 46, city = "London",
}, {
id = 3, name = "David", last_name = "Smith",
age = 33, city = "Los Angeles",
}, {
id = 4, name = "William", last_name = "White",
age = 46, city = "Chicago",
},
})

table.sort(customers, function(obj1, obj2) return obj1.id < obj2.id end)

-- after tuple should be in `fields` format + primary key
local fields = {'name', 'age'}
local after = {"Mary", 46, 2}

local select_opts = {
timeout = 1, bucket_id = 1161,
batch_size = 105, first = 2, after = after,
fields = fields, mode = 'read', prefer_replica = false,
balance = false, force_map_call = false,
}
local new_select_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local select_opts = ...
local _, err = crud.select('customers', nil, select_opts)
return select_opts, err
]], {select_opts})

t.assert_equals(err, nil)
t.assert_equals(new_select_opts, select_opts)
end
139 changes: 139 additions & 0 deletions test/integration/simple_operations_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1007,3 +1007,142 @@ pgroup.test_partial_result_bad_input = function(g)
t.assert_equals(result, nil)
t.assert_str_contains(err.err, 'Space format doesn\'t contain field named "lastname"')
end

pgroup.test_opts_not_damaged = function(g)
-- insert
local insert_opts = {timeout = 1, bucket_id = 655, fields = {'name', 'age'}}
local new_insert_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local insert_opts = ...
local _, err = crud.insert('customers', {22, box.NULL, 'Elizabeth', 24}, insert_opts)
return insert_opts, err
]], {insert_opts})

t.assert_equals(err, nil)
t.assert_equals(new_insert_opts, insert_opts)

-- insert_object
local insert_opts = {timeout = 1, bucket_id = 477, fields = {'name', 'age'}}
local new_insert_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local insert_opts = ...
local _, err = crud.insert_object('customers', {id = 1, name = 'Fedor', age = 59}, insert_opts)
return insert_opts, err
]], {insert_opts})

t.assert_equals(err, nil)
t.assert_equals(new_insert_opts, insert_opts)

-- upsert
local upsert_opts = {timeout = 1, bucket_id = 907, fields = {'name', 'age'}}
local new_upsert_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local upsert_opts = ...
local _, err = crud.upsert('customers', {33, box.NULL, 'Peter', 35}, {{'+', 'age', 1}}, upsert_opts)
return upsert_opts, err
]], {upsert_opts})

t.assert_equals(err, nil)
t.assert_equals(new_upsert_opts, upsert_opts)

-- upsert_object
local upsert_opts = {timeout = 1, bucket_id = 401, fields = {'name', 'age'}}
local new_upsert_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local upsert_opts = ...
local _, err = crud.upsert_object('customers',
{id = 2, name = 'Alex', age = 30}, {{'+', 'age', 1}},
upsert_opts)
return upsert_opts, err
]], {upsert_opts})

t.assert_equals(err, nil)
t.assert_equals(new_upsert_opts, upsert_opts)

-- get
local get_opts = {timeout = 1, bucket_id = 401, fields = {'name', 'age'}}
local new_get_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local get_opts = ...
local _, err = crud.get('customers', 2, get_opts)
return get_opts, err
]], {get_opts})

t.assert_equals(err, nil)
t.assert_equals(new_get_opts, get_opts)

-- update
local update_opts = {timeout = 1, bucket_id = 401, fields = {'name', 'age'}}
local new_update_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local update_opts = ...
local _, err = crud.update('customers', 2, {{'+', 'age', 10}}, update_opts)
return update_opts, err
]], {update_opts})

t.assert_equals(err, nil)
t.assert_equals(new_update_opts, update_opts)

-- replace
local replace_opts = {timeout = 1, bucket_id = 655, fields = {'name', 'age'}}
local new_replace_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local replace_opts = ...
local _, err = crud.replace('customers', {22, box.NULL, 'Elizabeth', 25}, replace_opts)
return replace_opts, err
]], {replace_opts})

t.assert_equals(err, nil)
t.assert_equals(new_replace_opts, replace_opts)

-- replace_object
local replace_opts = {timeout = 1, bucket_id = 477, fields = {'name', 'age'}}
local new_replace_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local replace_opts = ...
local _, err = crud.replace_object('customers', {id = 1, name = 'Fedor', age = 60}, replace_opts)
return replace_opts, err
]], {replace_opts})

t.assert_equals(err, nil)
t.assert_equals(new_replace_opts, replace_opts)

-- delete
local delete_opts = {timeout = 1, bucket_id = 401, fields = {'name', 'age'}}
local new_delete_opts, err = g.cluster.main_server:eval([[
local crud = require('crud')
local delete_opts = ...
local _, err = crud.delete('customers', 2, delete_opts)
return delete_opts, err
]], {delete_opts})

t.assert_equals(err, nil)
t.assert_equals(new_delete_opts, delete_opts)
end
Loading

0 comments on commit d13fe63

Please sign in to comment.