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