| 1 | -- Basic SQL driver |
| 2 | -- This driver stores data as simple key-values |
| 3 | |
| 4 | local ser = require "util.serialization".serialize; |
| 5 | local deser = function(data) |
| 6 | module:log("debug", "deser: %s", tostring(data)); |
| 7 | if not data then return nil; end |
| 8 | local f = loadstring("return "..data); |
| 9 | if not f then return nil; end |
| 10 | setfenv(f, {}); |
| 11 | local s, d = pcall(f); |
| 12 | if not s then return nil; end |
| 13 | return d; |
| 14 | end; |
| 15 | |
| 16 | local driver = {}; |
| 17 | driver.__index = driver; |
| 18 | |
| 19 | driver.item_table = "item"; |
| 20 | driver.list_table = "list"; |
| 21 | |
| 22 | function driver:prepare(sql) |
| 23 | module:log("debug", "query: %s", sql); |
| 24 | local err; |
| 25 | if not self.sqlcache then self.sqlcache = {}; end |
| 26 | local r = self.sqlcache[sql]; |
| 27 | if r then return r; end |
| 28 | r, err = self.connection:prepare(sql); |
| 29 | if not r then error("Unable to prepare SQL statement: "..err); end |
| 30 | self.sqlcache[sql] = r; |
| 31 | return r; |
| 32 | end |
| 33 | |
| 34 | function driver:load(username, host, datastore) |
| 35 | local select = self:prepare("select data from "..self.item_table.." where username=? and host=? and datastore=?"); |
| 36 | select:execute(username, host, datastore); |
| 37 | local row = select:fetch(); |
| 38 | return row and deser(row[1]) or nil; |
| 39 | end |
| 40 | |
| 41 | function driver:store(username, host, datastore, data) |
| 42 | if not data or next(data) == nil then |
| 43 | local delete = self:prepare("delete from "..self.item_table.." where username=? and host=? and datastore=?"); |
| 44 | delete:execute(username, host, datastore); |
| 45 | return true; |
| 46 | else |
| 47 | local d = self:load(username, host, datastore); |
| 48 | if d then -- update |
| 49 | local update = self:prepare("update "..self.item_table.." set data=? where username=? and host=? and datastore=?"); |
| 50 | return update:execute(ser(data), username, host, datastore); |
| 51 | else -- insert |
| 52 | local insert = self:prepare("insert into "..self.item_table.." values (?, ?, ?, ?)"); |
| 53 | return insert:execute(username, host, datastore, ser(data)); |
| 54 | end |
| 55 | end |
| 56 | end |
| 57 | |
| 58 | function driver:list_append(username, host, datastore, data) |
| 59 | if not data then return; end |
| 60 | local insert = self:prepare("insert into "..self.list_table.." values (?, ?, ?, ?)"); |
| 61 | return insert:execute(username, host, datastore, ser(data)); |
| 62 | end |
| 63 | |
| 64 | function driver:list_store(username, host, datastore, data) |
| 65 | -- remove existing data |
| 66 | local delete = self:prepare("delete from "..self.list_table.." where username=? and host=? and datastore=?"); |
| 67 | delete:execute(username, host, datastore); |
| 68 | if data and next(data) ~= nil then |
| 69 | -- add data |
| 70 | for _, d in ipairs(data) do |
| 71 | self:list_append(username, host, datastore, ser(d)); |
| 72 | end |
| 73 | end |
| 74 | return true; |
| 75 | end |
| 76 | |
| 77 | function driver:list_load(username, host, datastore) |
| 78 | local select = self:prepare("select data from "..self.list_table.." where username=? and host=? and datastore=?"); |
| 79 | select:execute(username, host, datastore); |
| 80 | local r = {}; |
| 81 | for row in select:rows() do |
| 82 | table.insert(r, deser(row[1])); |
| 83 | end |
| 84 | return r; |
| 85 | end |
| 86 | |
| 87 | local _M = {}; |
| 88 | function _M.new(dbtype, dbname, ...) |
| 89 | local d = {}; |
| 90 | setmetatable(d, driver); |
| 91 | local dbh = get_database(dbtype, dbname, ...); |
| 92 | --d:set_connection(dbh); |
| 93 | d.connection = dbh; |
| 94 | return d; |
| 95 | end |
| 96 | return _M; |