Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
To: tarantool-patches@freelists.org
Cc: vdavydov.dev@gmail.com, aleclarson <alec.stanford.larson@gmail.com>
Subject: [PATCH 1/2] schema: expose space_mt and index_mt on `box.schema` table
Date: Fri, 23 Mar 2018 16:07:08 +0300	[thread overview]
Message-ID: <39d1b0b99479563fadd0d9701702ae7c782b18db.1521810303.git.v.shpilevoy@tarantool.org> (raw)
In-Reply-To: <cover.1521810303.git.v.shpilevoy@tarantool.org>
In-Reply-To: <cover.1521810303.git.v.shpilevoy@tarantool.org>

From: aleclarson <alec.stanford.larson@gmail.com>

This commit allows userland to extend the space and index metatables
with their own functions or even metamethods. Reducing barriers for
this kind of experimentation is vital for user contribution toward
the improvement of Tarantool's API.

Also, this commit reuses functions between all spaces/indexes.

The metatables are exposed on `box` to make them simple to discover.
The suggested alternatives were `box.internal` and `box.schema`.

In a future commit, we should look into "freezing" the built-in
methods so the user cannot accidentally override them. This is
especially important when updating Tarantool.

Closes #3204
---
 src/box/lua/schema.lua          | 639 ++++++++++++++++++++--------------------
 test/box-tap/schema_mt.test.lua |  74 +++++
 2 files changed, 398 insertions(+), 315 deletions(-)
 create mode 100755 test/box-tap/schema_mt.test.lua

diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index 5a0f71559..3fb626efd 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -1074,218 +1074,348 @@ end
 
 internal.check_iterator_type = check_iterator_type -- export for net.box
 
-function box.schema.space.bless(space)
-    local index_mt = {}
-    -- __len and __index
-    index_mt.len = function(index)
-        check_index_arg(index, 'len')
-        local ret = builtin.box_index_len(index.space_id, index.id)
-        if ret == -1 then
-            box.error()
-        end
-        return tonumber(ret)
-    end
-    -- index.bsize
-    index_mt.bsize = function(index)
-        check_index_arg(index, 'bsize')
-        local ret = builtin.box_index_bsize(index.space_id, index.id)
-        if ret == -1 then
-            box.error()
-        end
-        return tonumber(ret)
-    end
-    index_mt.__len = index_mt.len -- Lua 5.2 compatibility
-    index_mt.__newindex = function(table, index)
-        return error('Attempt to modify a read-only table') end
-    index_mt.__index = index_mt
-    -- min and max
-    index_mt.min_ffi = function(index, key)
-        check_index_arg(index, 'min')
-        local pkey, pkey_end = tuple_encode(key)
-        if builtin.box_index_min(index.space_id, index.id,
-                                 pkey, pkey_end, ptuple) ~= 0 then
-            box.error() -- error
-        elseif ptuple[0] ~= nil then
-            return tuple_bless(ptuple[0])
-        else
-            return
-        end
-    end
-    index_mt.min_luac = function(index, key)
-        check_index_arg(index, 'min')
-        key = keify(key)
-        return internal.min(index.space_id, index.id, key);
+local space_mt = {}
+space_mt.__index = space_mt
+box.schema.space_mt = space_mt
+
+space_mt.len = function(space)
+    check_space_arg(space, 'len')
+    local pk = space.index[0]
+    if pk == nil then
+        return 0 -- empty space without indexes, return 0
     end
-    index_mt.max_ffi = function(index, key)
-        check_index_arg(index, 'max')
-        local pkey, pkey_end = tuple_encode(key)
-        if builtin.box_index_max(index.space_id, index.id,
-                                 pkey, pkey_end, ptuple) ~= 0 then
-            box.error() -- error
-        elseif ptuple[0] ~= nil then
-            return tuple_bless(ptuple[0])
-        else
-            return
-        end
+    return space.index[0]:len()
+end
+space_mt.count = function(space, key, opts)
+    check_space_arg(space, 'count')
+    local pk = space.index[0]
+    if pk == nil then
+        return 0 -- empty space without indexes, return 0
     end
-    index_mt.max_luac = function(index, key)
-        check_index_arg(index, 'max')
-        key = keify(key)
-        return internal.max(index.space_id, index.id, key);
+    return pk:count(key, opts)
+end
+space_mt.bsize = function(space)
+    check_space_arg(space, 'bsize')
+    local s = builtin.space_by_id(space.id)
+    if s == nil then
+        box.error(box.error.NO_SUCH_SPACE, space.name)
     end
-    index_mt.random_ffi = function(index, rnd)
-        check_index_arg(index, 'random')
-        rnd = rnd or math.random()
-        if builtin.box_index_random(index.space_id, index.id, rnd,
-                                    ptuple) ~= 0 then
-            box.error() -- error
-        elseif ptuple[0] ~= nil then
-            return tuple_bless(ptuple[0])
-        else
-            return
-        end
+    return builtin.space_bsize(s)
+end
+
+space_mt.get = function(space, key)
+    check_space_arg(space, 'get')
+    return check_primary_index(space):get(key)
+end
+space_mt.select = function(space, key, opts)
+    check_space_arg(space, 'select')
+    return check_primary_index(space):select(key, opts)
+end
+space_mt.insert = function(space, tuple)
+    check_space_arg(space, 'insert')
+    return internal.insert(space.id, tuple);
+end
+space_mt.replace = function(space, tuple)
+    check_space_arg(space, 'replace')
+    return internal.replace(space.id, tuple);
+end
+space_mt.put = space_mt.replace; -- put is an alias for replace
+space_mt.update = function(space, key, ops)
+    check_space_arg(space, 'update')
+    return check_primary_index(space):update(key, ops)
+end
+space_mt.upsert = function(space, tuple_key, ops, deprecated)
+    check_space_arg(space, 'upsert')
+    if deprecated ~= nil then
+        local msg = "Error: extra argument in upsert call: "
+        msg = msg .. tostring(deprecated)
+        msg = msg .. ". Usage :upsert(tuple, operations)"
+        box.error(box.error.PROC_LUA, msg)
     end
-    index_mt.random_luac = function(index, rnd)
-        check_index_arg(index, 'random')
-        rnd = rnd or math.random()
-        return internal.random(index.space_id, index.id, rnd);
-    end
-    -- iteration
-    index_mt.pairs_ffi = function(index, key, opts)
-        check_index_arg(index, 'pairs')
-        local pkey, pkey_end = tuple_encode(key)
-        local itype = check_iterator_type(opts, pkey + 1 >= pkey_end);
-
-        local keybuf = ffi.string(pkey, pkey_end - pkey)
-        local pkeybuf = ffi.cast('const char *', keybuf)
-        local cdata = builtin.box_index_iterator(index.space_id, index.id,
-            itype, pkeybuf, pkeybuf + #keybuf);
-        if cdata == nil then
-            box.error()
-        end
-        return fun.wrap(iterator_gen, keybuf,
-            ffi.gc(cdata, builtin.box_iterator_free))
-    end
-    index_mt.pairs_luac = function(index, key, opts)
-        check_index_arg(index, 'pairs')
-        key = keify(key)
-        local itype = check_iterator_type(opts, #key == 0);
-        local keymp = msgpack.encode(key)
-        local keybuf = ffi.string(keymp, #keymp)
-        local cdata = internal.iterator(index.space_id, index.id, itype, keymp);
-        return fun.wrap(iterator_gen_luac, keybuf,
-            ffi.gc(cdata, builtin.box_iterator_free))
-    end
-
-    -- index subtree size
-    index_mt.count_ffi = function(index, key, opts)
-        check_index_arg(index, 'count')
-        local pkey, pkey_end = tuple_encode(key)
-        local itype = check_iterator_type(opts, pkey + 1 >= pkey_end);
-        local count = builtin.box_index_count(index.space_id, index.id,
-            itype, pkey, pkey_end);
-        if count == -1 then
-            box.error()
-        end
-        return tonumber(count)
-    end
-    index_mt.count_luac = function(index, key, opts)
-        check_index_arg(index, 'count')
-        key = keify(key)
-        local itype = check_iterator_type(opts, #key == 0);
-        return internal.count(index.space_id, index.id, itype, key);
-    end
-
-    index_mt.get_ffi = function(index, key)
-        check_index_arg(index, 'get')
-        local key, key_end = tuple_encode(key)
-        if builtin.box_index_get(index.space_id, index.id,
-                                 key, key_end, ptuple) ~= 0 then
-            return box.error() -- error
-        elseif ptuple[0] ~= nil then
-            return tuple_bless(ptuple[0])
-        else
-            return
-        end
+    return internal.upsert(space.id, tuple_key, ops);
+end
+space_mt.delete = function(space, key)
+    check_space_arg(space, 'delete')
+    return check_primary_index(space):delete(key)
+end
+-- Assumes that spaceno has a TREE (NUM) primary key
+-- inserts a tuple after getting the next value of the
+-- primary key and returns it back to the user
+space_mt.auto_increment = function(space, tuple)
+    check_space_arg(space, 'auto_increment')
+    local max_tuple = check_primary_index(space):max()
+    local max = 0
+    if max_tuple ~= nil then
+        max = max_tuple[1]
     end
-    index_mt.get_luac = function(index, key)
-        check_index_arg(index, 'get')
-        key = keify(key)
-        return internal.get(index.space_id, index.id, key)
+    table.insert(tuple, 1, max + 1)
+    return space:insert(tuple)
+end
+
+space_mt.pairs = function(space, key, opts)
+    check_space_arg(space, 'pairs')
+    local pk = space.index[0]
+    if pk == nil then
+        -- empty space without indexes, return empty iterator
+        return fun.iter({})
+    end
+    return pk:pairs(key, opts)
+end
+space_mt.__pairs = space_mt.pairs -- Lua 5.2 compatibility
+space_mt.__ipairs = space_mt.pairs -- Lua 5.2 compatibility
+space_mt.truncate = function(space)
+    check_space_arg(space, 'truncate')
+    return internal.truncate(space.id)
+end
+space_mt.format = function(space, format)
+    check_space_arg(space, 'format')
+    return box.schema.space.format(space.id, format)
+end
+space_mt.drop = function(space)
+    check_space_arg(space, 'drop')
+    check_space_exists(space)
+    return box.schema.space.drop(space.id, space.name)
+end
+space_mt.rename = function(space, name)
+    check_space_arg(space, 'rename')
+    check_space_exists(space)
+    return box.schema.space.rename(space.id, name)
+end
+space_mt.create_index = function(space, name, options)
+    check_space_arg(space, 'create_index')
+    check_space_exists(space)
+    return box.schema.index.create(space.id, name, options)
+end
+space_mt.run_triggers = function(space, yesno)
+    check_space_arg(space, 'run_triggers')
+    local s = builtin.space_by_id(space.id)
+    if s == nil then
+        box.error(box.error.NO_SUCH_SPACE, space.name)
     end
+    builtin.space_run_triggers(s, yesno)
+end
 
-    local function check_select_opts(opts, key_is_nil)
-        local offset = 0
-        local limit = 4294967295
-        local iterator = check_iterator_type(opts, key_is_nil)
-        if opts ~= nil then
-            if opts.offset ~= nil then
-                offset = opts.offset
-            end
-            if opts.limit ~= nil then
-                limit = opts.limit
-            end
-        end
-        return iterator, offset, limit
+local index_mt = {}
+index_mt.__index = index_mt
+box.schema.index_mt = index_mt
+
+-- __len and __index
+index_mt.len = function(index)
+    check_index_arg(index, 'len')
+    local ret = builtin.box_index_len(index.space_id, index.id)
+    if ret == -1 then
+        box.error()
+    end
+    return tonumber(ret)
+end
+-- index.bsize
+index_mt.bsize = function(index)
+    check_index_arg(index, 'bsize')
+    local ret = builtin.box_index_bsize(index.space_id, index.id)
+    if ret == -1 then
+        box.error()
+    end
+    return tonumber(ret)
+end
+index_mt.__len = index_mt.len -- Lua 5.2 compatibility
+index_mt.__index = index_mt
+-- min and max
+index_mt.min_ffi = function(index, key)
+    check_index_arg(index, 'min')
+    local pkey, pkey_end = tuple_encode(key)
+    if builtin.box_index_min(index.space_id, index.id,
+                             pkey, pkey_end, ptuple) ~= 0 then
+        box.error() -- error
+    elseif ptuple[0] ~= nil then
+        return tuple_bless(ptuple[0])
+    else
+        return
+    end
+end
+index_mt.min_luac = function(index, key)
+    check_index_arg(index, 'min')
+    key = keify(key)
+    return internal.min(index.space_id, index.id, key);
+end
+index_mt.max_ffi = function(index, key)
+    check_index_arg(index, 'max')
+    local pkey, pkey_end = tuple_encode(key)
+    if builtin.box_index_max(index.space_id, index.id,
+                             pkey, pkey_end, ptuple) ~= 0 then
+        box.error() -- error
+    elseif ptuple[0] ~= nil then
+        return tuple_bless(ptuple[0])
+    else
+        return
     end
+end
+index_mt.max_luac = function(index, key)
+    check_index_arg(index, 'max')
+    key = keify(key)
+    return internal.max(index.space_id, index.id, key);
+end
+index_mt.random_ffi = function(index, rnd)
+    check_index_arg(index, 'random')
+    rnd = rnd or math.random()
+    if builtin.box_index_random(index.space_id, index.id, rnd,
+                                ptuple) ~= 0 then
+        box.error() -- error
+    elseif ptuple[0] ~= nil then
+        return tuple_bless(ptuple[0])
+    else
+        return
+    end
+end
+index_mt.random_luac = function(index, rnd)
+    check_index_arg(index, 'random')
+    rnd = rnd or math.random()
+    return internal.random(index.space_id, index.id, rnd);
+end
+-- iteration
+index_mt.pairs_ffi = function(index, key, opts)
+    check_index_arg(index, 'pairs')
+    local pkey, pkey_end = tuple_encode(key)
+    local itype = check_iterator_type(opts, pkey + 1 >= pkey_end);
 
-    index_mt.select_ffi = function(index, key, opts)
-        check_index_arg(index, 'select')
-        local key, key_end = tuple_encode(key)
-        local iterator, offset, limit = check_select_opts(opts, key + 1 >= key_end)
+    local keybuf = ffi.string(pkey, pkey_end - pkey)
+    local pkeybuf = ffi.cast('const char *', keybuf)
+    local cdata = builtin.box_index_iterator(index.space_id, index.id,
+        itype, pkeybuf, pkeybuf + #keybuf);
+    if cdata == nil then
+        box.error()
+    end
+    return fun.wrap(iterator_gen, keybuf,
+        ffi.gc(cdata, builtin.box_iterator_free))
+end
+index_mt.pairs_luac = function(index, key, opts)
+    check_index_arg(index, 'pairs')
+    key = keify(key)
+    local itype = check_iterator_type(opts, #key == 0);
+    local keymp = msgpack.encode(key)
+    local keybuf = ffi.string(keymp, #keymp)
+    local cdata = internal.iterator(index.space_id, index.id, itype, keymp);
+    return fun.wrap(iterator_gen_luac, keybuf,
+        ffi.gc(cdata, builtin.box_iterator_free))
+end
+
+-- index subtree size
+index_mt.count_ffi = function(index, key, opts)
+    check_index_arg(index, 'count')
+    local pkey, pkey_end = tuple_encode(key)
+    local itype = check_iterator_type(opts, pkey + 1 >= pkey_end);
+    local count = builtin.box_index_count(index.space_id, index.id,
+        itype, pkey, pkey_end);
+    if count == -1 then
+        box.error()
+    end
+    return tonumber(count)
+end
+index_mt.count_luac = function(index, key, opts)
+    check_index_arg(index, 'count')
+    key = keify(key)
+    local itype = check_iterator_type(opts, #key == 0);
+    return internal.count(index.space_id, index.id, itype, key);
+end
 
-        local port = ffi.cast('struct port *', port_tuple)
+index_mt.get_ffi = function(index, key)
+    check_index_arg(index, 'get')
+    local key, key_end = tuple_encode(key)
+    if builtin.box_index_get(index.space_id, index.id,
+                             key, key_end, ptuple) ~= 0 then
+        return box.error() -- error
+    elseif ptuple[0] ~= nil then
+        return tuple_bless(ptuple[0])
+    else
+        return
+    end
+end
+index_mt.get_luac = function(index, key)
+    check_index_arg(index, 'get')
+    key = keify(key)
+    return internal.get(index.space_id, index.id, key)
+end
 
-        if builtin.box_select(index.space_id, index.id,
-            iterator, offset, limit, key, key_end, port) ~= 0 then
-            return box.error()
+local function check_select_opts(opts, key_is_nil)
+    local offset = 0
+    local limit = 4294967295
+    local iterator = check_iterator_type(opts, key_is_nil)
+    if opts ~= nil then
+        if opts.offset ~= nil then
+            offset = opts.offset
         end
-
-        local ret = {}
-        local entry = port_tuple.first
-        for i=1,tonumber(port_tuple.size),1 do
-            ret[i] = tuple_bless(entry.tuple)
-            entry = entry.next
+        if opts.limit ~= nil then
+            limit = opts.limit
         end
-        builtin.port_destroy(port);
-        return ret
     end
+    return iterator, offset, limit
+end
 
-    index_mt.select_luac = function(index, key, opts)
-        check_index_arg(index, 'select')
-        local key = keify(key)
-        local iterator, offset, limit = check_select_opts(opts, #key == 0)
-        return internal.select(index.space_id, index.id, iterator,
-            offset, limit, key)
-    end
+index_mt.select_ffi = function(index, key, opts)
+    check_index_arg(index, 'select')
+    local key, key_end = tuple_encode(key)
+    local iterator, offset, limit = check_select_opts(opts, key + 1 >= key_end)
 
-    index_mt.update = function(index, key, ops)
-        check_index_arg(index, 'update')
-        return internal.update(index.space_id, index.id, keify(key), ops);
-    end
-    index_mt.delete = function(index, key)
-        check_index_arg(index, 'delete')
-        return internal.delete(index.space_id, index.id, keify(key));
-    end
+    local port = ffi.cast('struct port *', port_tuple)
 
-    index_mt.info = function(index)
-        return internal.info(index.space_id, index.id);
+    if builtin.box_select(index.space_id, index.id,
+        iterator, offset, limit, key, key_end, port) ~= 0 then
+        return box.error()
     end
 
-    index_mt.drop = function(index)
-        check_index_arg(index, 'drop')
-        return box.schema.index.drop(index.space_id, index.id)
+    local ret = {}
+    local entry = port_tuple.first
+    for i=1,tonumber(port_tuple.size),1 do
+        ret[i] = tuple_bless(entry.tuple)
+        entry = entry.next
     end
-    index_mt.rename = function(index, name)
-        check_index_arg(index, 'rename')
-        return box.schema.index.rename(index.space_id, index.id, name)
+    builtin.port_destroy(port);
+    return ret
+end
+
+index_mt.select_luac = function(index, key, opts)
+    check_index_arg(index, 'select')
+    local key = keify(key)
+    local iterator, offset, limit = check_select_opts(opts, #key == 0)
+    return internal.select(index.space_id, index.id, iterator,
+        offset, limit, key)
+end
+
+index_mt.update = function(index, key, ops)
+    check_index_arg(index, 'update')
+    return internal.update(index.space_id, index.id, keify(key), ops);
+end
+index_mt.delete = function(index, key)
+    check_index_arg(index, 'delete')
+    return internal.delete(index.space_id, index.id, keify(key));
+end
+
+index_mt.info = function(index)
+    return internal.info(index.space_id, index.id);
+end
+
+index_mt.drop = function(index)
+    check_index_arg(index, 'drop')
+    return box.schema.index.drop(index.space_id, index.id)
+end
+index_mt.rename = function(index, name)
+    check_index_arg(index, 'rename')
+    return box.schema.index.rename(index.space_id, index.id, name)
+end
+index_mt.alter = function(index, options)
+    check_index_arg(index, 'alter')
+    if index.id == nil or index.space_id == nil then
+        box.error(box.error.PROC_LUA, "Usage: index:alter{opts}")
     end
-    index_mt.alter = function(index, options)
-        check_index_arg(index, 'alter')
-        if index.id == nil or index.space_id == nil then
-            box.error(box.error.PROC_LUA, "Usage: index:alter{opts}")
-        end
-        return box.schema.index.alter(index.space_id, index.id, options)
+    return box.schema.index.alter(index.space_id, index.id, options)
+end
+
+index_mt.__pairs = index_mt.pairs -- Lua 5.2 compatibility
+index_mt.__ipairs = index_mt.pairs -- Lua 5.2 compatibility
+
+function box.schema.space.bless(space)
+    local index_mt = {}
+    index_mt.__index = function(index, key)
+      return index_mt[key] or box.schema.index_mt[key]
     end
 
     -- true if reading operations may yield
@@ -1294,136 +1424,15 @@ function box.schema.space.bless(space)
     for _, op in ipairs(read_ops) do
         if read_yields then
             -- use Lua/C implmenetation
-            index_mt[op] = index_mt[op .. "_luac"]
+            index_mt[op] = box.schema.index_mt[op .. "_luac"]
         else
             -- use FFI implementation
-            index_mt[op] = index_mt[op .. "_ffi"]
+            index_mt[op] = box.schema.index_mt[op .. "_ffi"]
         end
     end
-    index_mt.__pairs = index_mt.pairs -- Lua 5.2 compatibility
-    index_mt.__ipairs = index_mt.pairs -- Lua 5.2 compatibility
     --
-    local space_mt = {}
-    space_mt.len = function(space)
-        check_space_arg(space, 'len')
-        local pk = space.index[0]
-        if pk == nil then
-            return 0 -- empty space without indexes, return 0
-        end
-        return space.index[0]:len()
-    end
-    space_mt.count = function(space, key, opts)
-        check_space_arg(space, 'count')
-        local pk = space.index[0]
-        if pk == nil then
-            return 0 -- empty space without indexes, return 0
-        end
-        return pk:count(key, opts)
-    end
-    space_mt.bsize = function(space)
-        check_space_arg(space, 'bsize')
-        local s = builtin.space_by_id(space.id)
-        if s == nil then
-            box.error(box.error.NO_SUCH_SPACE, space.name)
-        end
-        return builtin.space_bsize(s)
-    end
-    space_mt.__newindex = index_mt.__newindex
 
-    space_mt.get = function(space, key)
-        check_space_arg(space, 'get')
-        return check_primary_index(space):get(key)
-    end
-    space_mt.select = function(space, key, opts)
-        check_space_arg(space, 'select')
-        return check_primary_index(space):select(key, opts)
-    end
-    space_mt.insert = function(space, tuple)
-        check_space_arg(space, 'insert')
-        return internal.insert(space.id, tuple);
-    end
-    space_mt.replace = function(space, tuple)
-        check_space_arg(space, 'replace')
-        return internal.replace(space.id, tuple);
-    end
-    space_mt.put = space_mt.replace; -- put is an alias for replace
-    space_mt.update = function(space, key, ops)
-        check_space_arg(space, 'update')
-        return check_primary_index(space):update(key, ops)
-    end
-    space_mt.upsert = function(space, tuple_key, ops, deprecated)
-        check_space_arg(space, 'upsert')
-        if deprecated ~= nil then
-            local msg = "Error: extra argument in upsert call: "
-            msg = msg .. tostring(deprecated)
-            msg = msg .. ". Usage :upsert(tuple, operations)"
-            box.error(box.error.PROC_LUA, msg)
-        end
-        return internal.upsert(space.id, tuple_key, ops);
-    end
-    space_mt.delete = function(space, key)
-        check_space_arg(space, 'delete')
-        return check_primary_index(space):delete(key)
-    end
--- Assumes that spaceno has a TREE (NUM) primary key
--- inserts a tuple after getting the next value of the
--- primary key and returns it back to the user
-    space_mt.auto_increment = function(space, tuple)
-        check_space_arg(space, 'auto_increment')
-        local max_tuple = check_primary_index(space):max()
-        local max = 0
-        if max_tuple ~= nil then
-            max = max_tuple[1]
-        end
-        table.insert(tuple, 1, max + 1)
-        return space:insert(tuple)
-    end
-
-    space_mt.pairs = function(space, key, opts)
-        check_space_arg(space, 'pairs')
-        local pk = space.index[0]
-        if pk == nil then
-            -- empty space without indexes, return empty iterator
-            return fun.iter({})
-        end
-        return pk:pairs(key, opts)
-    end
-    space_mt.__pairs = space_mt.pairs -- Lua 5.2 compatibility
-    space_mt.__ipairs = space_mt.pairs -- Lua 5.2 compatibility
-    space_mt.truncate = function(space)
-        check_space_arg(space, 'truncate')
-        return internal.truncate(space.id)
-    end
-    space_mt.format = function(space, format)
-        check_space_arg(space, 'format')
-        return box.schema.space.format(space.id, format)
-    end
-    space_mt.drop = function(space)
-        check_space_arg(space, 'drop')
-        check_space_exists(space)
-        return box.schema.space.drop(space.id, space.name)
-    end
-    space_mt.rename = function(space, name)
-        check_space_arg(space, 'rename')
-        check_space_exists(space)
-        return box.schema.space.rename(space.id, name)
-    end
-    space_mt.create_index = function(space, name, options)
-        check_space_arg(space, 'create_index')
-        check_space_exists(space)
-        return box.schema.index.create(space.id, name, options)
-    end
-    space_mt.run_triggers = function(space, yesno)
-        check_space_arg(space, 'run_triggers')
-        local s = builtin.space_by_id(space.id)
-        if s == nil then
-            box.error(box.error.NO_SUCH_SPACE, space.name)
-        end
-        builtin.space_run_triggers(s, yesno)
-    end
-    space_mt.__index = space_mt
-
-    setmetatable(space, space_mt)
+    setmetatable(space, box.schema.space_mt)
     if type(space.index) == 'table' and space.enabled then
         for j, index in pairs(space.index) do
             if type(j) == 'number' then
diff --git a/test/box-tap/schema_mt.test.lua b/test/box-tap/schema_mt.test.lua
new file mode 100755
index 000000000..7e531dd01
--- /dev/null
+++ b/test/box-tap/schema_mt.test.lua
@@ -0,0 +1,74 @@
+#!/usr/bin/env tarantool
+--
+-- pr-3204: expose space_mt, index_mt into box.schema.
+--
+
+local tap = require('tap')
+local test = tap.test('schema_mt')
+
+test:plan(7)
+
+box.cfg{
+  log="tarantool.log",
+}
+
+local sp1 = box.schema.space.create('test')
+local sp2 = box.schema.space.create('test2')
+
+test:is(
+  getmetatable(sp1),
+  getmetatable(sp2),
+  'all spaces use the same metatable'
+)
+
+local idx1 = sp1:create_index('primary')
+local idx2 = sp2:create_index('primary')
+
+test:isnt(
+  getmetatable(idx1),
+  getmetatable(idx2),
+  'all indexes have their own metatable'
+)
+
+test:is(
+  idx1.get,
+  idx2.get,
+  'memtx indexes share read methods'
+)
+
+local sp3 = box.schema.space.create('test3', {engine='vinyl'})
+local sp4 = box.schema.space.create('test4', {engine='vinyl'})
+
+local idx3 = sp3:create_index('primary')
+local idx4 = sp4:create_index('primary')
+
+test:is(
+  idx3.get,
+  idx4.get,
+  'vinyl indexes share read methods'
+)
+
+test:isnt(
+  idx1.get,
+  idx3.get,
+  'memtx and vinyl indexes have separate read methods'
+)
+
+function box.schema.space_mt.foo() end
+
+test:is(
+  sp1.foo,
+  box.schema.space_mt.foo,
+  'box.schema.space_mt is mutable'
+)
+
+function box.schema.index_mt.foo() end
+
+test:is(
+  idx1.foo,
+  box.schema.index_mt.foo,
+  'box.schema.index_mt is mutable'
+)
+
+test:check()
+os.exit(0)
-- 
2.14.3 (Apple Git-98)

  reply	other threads:[~2018-03-23 13:07 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-23 13:07 [PATCH 0/2] schema: expose space_mt and index_mt on table Vladislav Shpilevoy
2018-03-23 13:07 ` Vladislav Shpilevoy [this message]
2018-03-23 13:07 ` [PATCH 2/2] schema: review fixes for box.schema.space/index metatables Vladislav Shpilevoy
2018-03-29 10:54 ` [PATCH 0/2] schema: expose space_mt and index_mt on table Vladimir Davydov
2018-03-29 14:31   ` [PATCH v2 0/2] schema: expose space_mt and index_mt on box.schema table Vladislav Shpilevoy
2018-03-29 14:31     ` [PATCH v2 1/2] schema: move space_mt and index_mt definition out of space bless Vladislav Shpilevoy
2018-04-01  9:33       ` Vladimir Davydov
2018-04-01 11:02         ` [PATCH 0/2] schema: expose space_mt and index_mt on box.schema table Vladislav Shpilevoy
2018-04-01 11:02           ` [PATCH 1/2] schema: move space_mt and index_mt definition out of space bless Vladislav Shpilevoy
2018-04-01 11:02           ` [PATCH 2/2] schema: expose space_mt and index_mt on `box.schema` table Vladislav Shpilevoy
2018-04-02 11:28             ` Vladimir Davydov
2018-04-03 16:50               ` [PATCH v2 0/3] schema: expose space_mt and index_mt on box.schema table Vladislav Shpilevoy
2018-04-03 16:50                 ` [PATCH v2 1/3] schema: move space_mt and index_mt definition out of space bless Vladislav Shpilevoy
2018-04-03 16:50                 ` [PATCH v2 2/3] schema: inherit vinyl/memtx_index_mt from base index mt Vladislav Shpilevoy
2018-04-03 16:50                 ` [PATCH v2 3/3] schema: expose space_mt and index_mt on box.schema table Vladislav Shpilevoy
2018-05-05 12:47                   ` [tarantool-patches] " Vladislav Shpilevoy
2018-05-08 16:48                     ` Konstantin Osipov
2018-05-08 17:33                       ` Vladislav Shpilevoy
2018-03-29 14:31     ` [PATCH v2 2/2] schema: expose space_mt and index_mt on `box.schema` table Vladislav Shpilevoy
2018-04-01  9:37     ` [PATCH v2 0/2] schema: expose space_mt and index_mt on box.schema table Vladimir Davydov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=39d1b0b99479563fadd0d9701702ae7c782b18db.1521810303.git.v.shpilevoy@tarantool.org \
    --to=v.shpilevoy@tarantool.org \
    --cc=alec.stanford.larson@gmail.com \
    --cc=tarantool-patches@freelists.org \
    --cc=vdavydov.dev@gmail.com \
    --subject='Re: [PATCH 1/2] schema: expose space_mt and index_mt on `box.schema` table' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox