Lua表作为数据库的前端

时间:2016-02-27 07:03:46

标签: lua redis lua-table

我正在尝试将数据库实现为Lua表。使用元表,此表将为空,并且当在表中请求或修改项时,它将返回或修改数据库中的项。除了请求的部分之外,数据库本身永远不会被加载到内存中。它应该作为一个表与程序进行交互(因为它是一个表)。该表,因为它只是一个“前面”,将修改后的数据保存到数据库中(而不是在表中定义该项)。

在一个没有表格的表格中,这很容易实现。我正在尝试使用无限深度的多层表。 (旁白:我正在考虑的数据库是redis。理想情况下,只需更改基本操作语法就可以为任何数据库或类似数据库的服务器实现。)

由于Lua的元表的行为,__newindex方法仅在顶层修改某些内容时使用(或者,如果您使用代理,则创建)。读取内容时会调用__index方法,即使调用是修改子表中的内容也是如此。因此,我正在尝试编写一个__index方法,当请求表时,返回另一个具有相同行为的伪代理(代理数据库而不是另一个表的表),代理除外用于顶层等中的表/数组/列表,以无限深度。我在挣扎。

我的问题是:

  • 以前是否已实施?
  • 我应该专注于“适当” 阶级制度而不是我现在正在做的事情?

1 个答案:

答案 0 :(得分:1)

当你创建一个表时,只需在假的表中添加一个空表并将其设置为metatable:

local fake = {}
do
   local lookup = {} --Will be using this to avoid using lots of metatables

   local real = {}

   local meta
   meta = {
      __index = function(self,i)
         return rawget(lookup[self], i)
      end,
      __newindex = function(self,i,v)
         rawset(lookup[self], i, v)
         if type(v) == "table" then
             rawset(self, i, setmetatable({},meta))
             lookup[self[i]] = v
         end
      end
   }

   setmetatable(fake, meta)
   lookup[fake] = real
end

fake[1] = "hello"
print(fake[1])
print(rawget(fake, 1))
fake.x = {"hi"}
print(fake.x)
print(rawget(fake, 'x')) --This still prints a table because there actually is one, but in reality it's abiding by our rules
print(fake.x[1])
print(rawget(fake.x, 1))
fake.x.y = "aha"
print(fake.x.y)
print(rawget(fake.x, 'y'))

这种方法唯一需要注意的是他们可以像这样直接修改数据库:

fake.myvalue = {}
fake.myvalue = 5

另一种方法可以是随身包裹:

local fake = {}
do
   local lookup = {} --Will be using this to avoid using lots of metatables
   local cache = {} --will be using to avoid usings tons of new objects

   local real = {}

   local meta
   meta = {
      __index = function(self,i)
         local val = rawget(lookup[self], i)
         if type(val) == "table" then
            if cache[val] then
                return cache[val]
            else
                local faker = {}
                lookup[faker] = val
                cache[val] = faker
                return setmetatable(faker, meta)
             end
         else
            return val
         end
       end,
      __newindex = function(self,i,v)
         rawset(lookup[self], i, v)
      end
   }

   setmetatable(fake, meta)
   lookup[fake] = real
end

fake[1] = "hello"
print(fake[1])
print(rawget(fake, 1))

fake.x = {"hi"}
print(fake.x)
print(rawget(fake, 'x')) --This still prints a table because there actually is one, but in reality it's abiding by our rules
print(fake.x[1])
print(rawget(fake.x, 1))
fake.x.y = "aha"
print(fake.x.y)
print(rawget(fake.x, 'y'))

完全避免直接修改问题