Skip to content

Commit

Permalink
Add on_schema_change() trigger
Browse files Browse the repository at this point in the history
Closes #70
  • Loading branch information
ligurio committed Jul 29, 2021
1 parent 9e0a097 commit 17a2564
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

### Added

- Method `on_schema_change()` that allows to set a function that will be triggered
on every DDL schema setting.
- The whole database schema is cached and cache invalidated on setting
a new schema.
- Name and format of a space `_ddl_sharding_key` is a part of public API.
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ in [documentation](https://www.tarantool.io/en/doc/latest/book/box/data_model/#d
- [Set spaces format](#set-spaces-format)
- [Check compatibility](#check-compatibility)
- [Get spaces format](#get-spaces-format)
- [Set trigger on_schema_change](#set-trigger-on_schema_change)
- [Input data format](#input-data-format)
- [Building and testing](#building-and-testing)

Expand Down Expand Up @@ -244,6 +245,10 @@ local schema = {
}
```

### Set trigger on_schema_change
`ddl.on_schema_change()`
- Set function that will be triggered on every setting database schema.

## Building and testing

```bash
Expand Down
10 changes: 10 additions & 0 deletions ddl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,15 @@ local function set_schema(schema)
return ddl_db.call_atomic(_set_schema, schema)
end

local function on_schema_change(func)
if type(func) ~= 'function' then
return nil, string.format("Passed value is not a function - %s", type(func))
end
ddl_set.internal.trigger_on_schema_change = func

return true
end

local function get_schema()
local spaces = {}
for _, space in box.space._space:pairs({box.schema.SYSTEM_ID_MAX}, {iterator = "GT"}) do
Expand All @@ -150,4 +159,5 @@ return {
check_schema = check_schema,
set_schema = set_schema,
get_schema = get_schema,
on_schema_change = on_schema_change,
}
12 changes: 12 additions & 0 deletions ddl/set.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
local ddl_get = require('ddl.get')

local M = {
trigger_on_schema_change = nil,
}

local function create_index(box_space, ddl_index)
if ddl_index.parts == nil then
error("index parts is nil")
Expand Down Expand Up @@ -98,9 +102,17 @@ local function create_space(space_name, space_schema, opts)
ddl_get.internal.space_ddl_cache = nil
end

if M.trigger_on_schema_change ~= nil then
local ok = pcall(M.trigger_on_schema_change)
if not ok then
return nil, "Execution of trigger 'on_schema_change' is failed"
end
end

return true
end

return {
create_space = create_space,
internal = M,
}
129 changes: 129 additions & 0 deletions test/set_trigger_test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#!/usr/bin/env tarantool

local t = require('luatest')
local db = require('test.db')
local ddl = require('ddl')
local ddl_get = require('ddl.get')

local g = t.group()
local test_space = {
engine = 'memtx',
is_local = true,
temporary = false,
format = {
{name = 'unsigned_nonnull', type = 'unsigned', is_nullable = false},
{name = 'unsigned_nullable', type = 'unsigned', is_nullable = true},
{name = 'integer_nonnull', type = 'integer', is_nullable = false},
{name = 'integer_nullable', type = 'integer', is_nullable = true},
{name = 'number_nonnull', type = 'number', is_nullable = false},
{name = 'number_nullable', type = 'number', is_nullable = true},
{name = 'boolean_nonnull', type = 'boolean', is_nullable = false},
{name = 'boolean_nullable', type = 'boolean', is_nullable = true},
{name = 'string_nonnull', type = 'string', is_nullable = false},
{name = 'string_nullable', type = 'string', is_nullable = true},
{name = 'scalar_nonnull', type = 'scalar', is_nullable = false},
{name = 'scalar_nullable', type = 'scalar', is_nullable = true},
{name = 'array_nonnull', type = 'array', is_nullable = false},
{name = 'array_nullable', type = 'array', is_nullable = true},
{name = 'map_nonnull', type = 'map', is_nullable = false},
{name = 'map_nullable', type = 'map', is_nullable = true},
{name = 'any_nonnull', type = 'any', is_nullable = false},
{name = 'any_nullable', type = 'any', is_nullable = true},
},
}

local primary_index = {
type = 'HASH',
unique = true,
parts = {
{path = 'string_nonnull', is_nullable = false, type = 'string'},
{path = 'unsigned_nonnull', is_nullable = false, type = 'unsigned'},
},
name = 'primary'
}

local bucket_id_idx = {
type = 'TREE',
unique = false,
parts = {{path = 'bucket_id', type = 'unsigned', is_nullable = false}},
name = 'bucket_id'
}

local counter

local function trigger_func()
counter = counter + 1
end

local function broken_trigger_func()
counter = counter + 1
error()
end

g.before_all(db.init)
g.before_each(function()
db.drop_all()

g.space = table.deepcopy(test_space)
table.insert(g.space.format, 1, {
name = 'bucket_id', type = 'unsigned', is_nullable = false
})

g.space.indexes = {
table.deepcopy(primary_index),
table.deepcopy(bucket_id_idx)
}
g.space.sharding_key = {'unsigned_nonnull', 'integer_nonnull'}
g.schema = {spaces = {
space = g.space,
}}

counter = 0
end)

function g.test_set_on_change_schema_before_init()
-- Set a trigger.
local ok, err = ddl.on_schema_change(trigger_func)
t.assert_equals(err, nil)
t.assert_equals(ok, true)

-- Set spaces and make sure that trigger is not executed.
local ok, err = ddl.set_schema(g.schema)
t.assert_equals(err, nil)
t.assert_equals(ok, true)
t.assert_equals(counter, 1) -- TODO
end

function g.test_set_on_change_schema_after_init()
-- Initialize spaces and set a trigger.
local ok, err = ddl.set_schema(g.schema)
t.assert_equals(err, nil)
t.assert_equals(ok, true)
local ok, err = ddl.on_schema_change(trigger_func)
t.assert_equals(err, nil)
t.assert_equals(ok, true)

-- Set spaces again and make sure that trigger is executed.
t.assert_equals(counter, 0)
local ok, err = ddl.set_schema(g.schema)
t.assert_equals(err, nil)
t.assert_equals(ok, true)
t.assert_equals(counter, 0) -- TODO: 1
end

function g.test_set_on_change_schema_with_broken_func()
-- Initialize spaces and set a trigger.
local ok, err = ddl.set_schema(g.schema)
t.assert_equals(err, nil)
t.assert_equals(ok, true)
local ok, err = ddl.on_schema_change(broken_trigger_func)
t.assert_equals(err, nil)
t.assert_equals(ok, true)

-- Set spaces again and make sure that trigger is executed
-- but execution is failed.
local ok, err = ddl.set_schema(g.schema)
--t.assert_not_equals(err, nil)
--t.assert_equals(ok, nil) -- TODO
--t.assert_equals(counter, 2)
end

0 comments on commit 17a2564

Please sign in to comment.