2016-02-19 15:03:45 +01:00
|
|
|
---
|
2016-03-11 14:21:52 +01:00
|
|
|
-- @usage
|
2016-02-19 15:03:45 +01:00
|
|
|
-- -- Use default backend
|
|
|
|
|
-- dbh = Database.new("system")
|
|
|
|
|
-- .....
|
|
|
|
|
--
|
2016-03-11 14:21:52 +01:00
|
|
|
-- @usage
|
2016-02-19 15:03:45 +01:00
|
|
|
-- -- Use LuaSQL backend
|
|
|
|
|
-- dbh = Database.backend.luasql("system")
|
|
|
|
|
-- .....
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
require 'resources.functions.config'
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
local log = require "resources.functions.log".database
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2016-03-25 08:04:48 +01:00
|
|
|
local BACKEND = database and database.backend
|
|
|
|
|
if type(BACKEND) ~= 'table' then BACKEND = {main = BACKEND} end
|
|
|
|
|
BACKEND.main = BACKEND.main or 'native'
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2016-02-20 13:22:28 +01:00
|
|
|
local unpack = unpack or table.unpack
|
|
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
-----------------------------------------------------------
|
|
|
|
|
local installed_classes = {}
|
|
|
|
|
local default_backend = FsDatabase
|
2016-03-25 08:04:48 +01:00
|
|
|
local function new_database(backend, backend_name)
|
2016-02-19 15:03:45 +01:00
|
|
|
local class = installed_classes[backend]
|
|
|
|
|
if class then return class end
|
|
|
|
|
|
|
|
|
|
local Database = {} do
|
|
|
|
|
Database.__index = Database
|
|
|
|
|
Database.__base = backend or default_backend
|
|
|
|
|
Database = setmetatable(Database, Database.__base)
|
|
|
|
|
|
|
|
|
|
function Database.new(...)
|
|
|
|
|
local self = Database.__base.new(...)
|
|
|
|
|
setmetatable(self, Database)
|
|
|
|
|
return self
|
|
|
|
|
end
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2016-03-25 08:04:48 +01:00
|
|
|
function Database:backend_name()
|
|
|
|
|
return backend_name
|
|
|
|
|
end
|
|
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
function Database:first_row(sql)
|
|
|
|
|
local result
|
|
|
|
|
local ok, err = self:query(sql, function(row)
|
|
|
|
|
result = row
|
|
|
|
|
return 1
|
2015-11-18 14:27:55 +01:00
|
|
|
end)
|
2016-02-19 15:03:45 +01:00
|
|
|
if not ok then return nil, err end
|
|
|
|
|
return result
|
2015-11-18 14:27:55 +01:00
|
|
|
end
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
function Database:first_value(sql)
|
|
|
|
|
local result, err = self:first_row(sql)
|
|
|
|
|
if not result then return nil, err end
|
|
|
|
|
local k, v = next(result)
|
|
|
|
|
return v
|
|
|
|
|
end
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
function Database:first(sql, ...)
|
|
|
|
|
local result, err = self:first_row(sql)
|
|
|
|
|
if not result then return nil, err end
|
|
|
|
|
local t, n = {}, select('#', ...)
|
|
|
|
|
for i = 1, n do
|
|
|
|
|
t[i] = result[(select(i, ...))]
|
|
|
|
|
end
|
|
|
|
|
return unpack(t, 1, n)
|
2015-11-18 14:27:55 +01:00
|
|
|
end
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
function Database:fetch_all(sql)
|
|
|
|
|
local result = {}
|
|
|
|
|
local ok, err = self:query(sql, function(row)
|
|
|
|
|
result[#result + 1] = row
|
|
|
|
|
end)
|
|
|
|
|
if (not ok) and err then return nil, err end
|
|
|
|
|
return result
|
|
|
|
|
end
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2016-06-24 18:32:19 +02:00
|
|
|
function Database:escape(str)
|
|
|
|
|
return (string.gsub(str, "'", "''"))
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Database:quote(str)
|
|
|
|
|
return "'" .. self:escape(str) .. "'"
|
|
|
|
|
end
|
|
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
function Database.__self_test__(...)
|
|
|
|
|
log.info('self_test Database - ' .. Database._backend_name)
|
|
|
|
|
local db = Database.new(...)
|
2015-11-18 14:27:55 +01:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
assert(db:connected())
|
2015-11-18 14:27:55 +01:00
|
|
|
|
2016-02-26 11:52:27 +01:00
|
|
|
do local x = 0
|
|
|
|
|
db:query("select 1 as v union all select 2 as v", function(row)
|
|
|
|
|
x = x + 1
|
|
|
|
|
return 1
|
|
|
|
|
end)
|
|
|
|
|
assert(x == 1, ("Got %d expected %d"):format(x, 1))
|
|
|
|
|
end
|
|
|
|
|
|
2016-02-26 11:57:05 +01:00
|
|
|
do local x = 0
|
|
|
|
|
db:query("select 1 as v union all select 2 as v", function(row)
|
|
|
|
|
x = x + 1
|
|
|
|
|
return -1
|
|
|
|
|
end)
|
|
|
|
|
assert(x == 1, ("Got %d expected %d"):format(x, 1))
|
|
|
|
|
end
|
|
|
|
|
|
2016-02-26 11:52:27 +01:00
|
|
|
do local x = 0
|
|
|
|
|
db:query("select 1 as v union all select 2 as v", function(row)
|
|
|
|
|
x = x + 1
|
|
|
|
|
return 0
|
|
|
|
|
end)
|
|
|
|
|
assert(x == 2, ("Got %d expected %d"):format(x, 2))
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
do local x = 0
|
|
|
|
|
db:query("select 1 as v union all select 2 as v", function(row)
|
|
|
|
|
x = x + 1
|
|
|
|
|
return true
|
|
|
|
|
end)
|
|
|
|
|
assert(x == 2, ("Got %d expected %d"):format(x, 2))
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
do local x = 0
|
|
|
|
|
db:query("select 1 as v union all select 2 as v", function(row)
|
|
|
|
|
x = x + 1
|
|
|
|
|
return false
|
|
|
|
|
end)
|
|
|
|
|
assert(x == 2, ("Got %d expected %d"):format(x, 2))
|
|
|
|
|
end
|
|
|
|
|
|
2016-02-26 12:17:28 +01:00
|
|
|
do local x = 0
|
|
|
|
|
db:query("select 1 as v union all select 2 as v", function(row)
|
|
|
|
|
x = x + 1
|
|
|
|
|
return "1"
|
|
|
|
|
end)
|
|
|
|
|
assert(x == 1, ("Got %d expected %d"):format(x, 2))
|
|
|
|
|
end
|
|
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
assert("1" == db:first_value("select 1 as v union all select 2 as v"))
|
2015-11-18 14:27:55 +01:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
local t = assert(db:first_row("select '1' as v union all select '2' as v"))
|
|
|
|
|
assert(t.v == "1")
|
2015-11-18 14:27:55 +01:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
t = assert(db:fetch_all("select '1' as v union all select '2' as v"))
|
|
|
|
|
assert(#t == 2)
|
|
|
|
|
assert(t[1].v == "1")
|
|
|
|
|
assert(t[2].v == "2")
|
2015-11-18 14:27:55 +01:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
local a, b = assert(db:first("select '1' as b, '2' as a", 'a', 'b'))
|
|
|
|
|
assert(a == "2")
|
|
|
|
|
assert(b == "1")
|
2015-11-18 14:27:55 +01:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
-- assert(nil == db:first_value("some non sql query"))
|
2015-11-18 14:27:55 +01:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
-- select NULL
|
|
|
|
|
local a = assert(db:first_value("select NULL as a"))
|
|
|
|
|
assert(a == "")
|
2015-11-18 14:27:55 +01:00
|
|
|
|
2016-06-24 18:32:19 +02:00
|
|
|
-- escape
|
|
|
|
|
local values = {"hello';select 'world", "hello'"}
|
|
|
|
|
for _, value in ipairs(values) do
|
|
|
|
|
local a = assert(db:first_value(
|
|
|
|
|
string.format("select '%s' as a", db:escape(value))
|
|
|
|
|
))
|
|
|
|
|
assert(a == value)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- close
|
2016-02-19 15:03:45 +01:00
|
|
|
db:release()
|
|
|
|
|
assert(not db:connected())
|
2016-02-26 11:52:27 +01:00
|
|
|
|
|
|
|
|
-- second close
|
|
|
|
|
db:release()
|
|
|
|
|
assert(not db:connected())
|
|
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
log.info('self_test Database - pass')
|
2015-11-18 14:27:55 +01:00
|
|
|
end
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2015-11-18 14:27:55 +01:00
|
|
|
end
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
installed_classes[backend] = Database
|
|
|
|
|
return Database
|
2015-11-18 14:27:55 +01:00
|
|
|
end
|
|
|
|
|
-----------------------------------------------------------
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2015-11-18 14:27:55 +01:00
|
|
|
-----------------------------------------------------------
|
2016-03-11 14:21:52 +01:00
|
|
|
local Database = {} do
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
local backend_loader = setmetatable({}, {__index = function(self, backend)
|
|
|
|
|
local class = require("resources.functions.database." .. backend)
|
2016-03-25 08:04:48 +01:00
|
|
|
local database = new_database(class, backend)
|
2016-02-19 15:03:45 +01:00
|
|
|
self[backend] = function(...)
|
|
|
|
|
return database.new(...)
|
2015-11-18 14:27:55 +01:00
|
|
|
end
|
2016-02-19 15:03:45 +01:00
|
|
|
return self[backend]
|
|
|
|
|
end})
|
2015-11-18 14:27:55 +01:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
Database.backend = backend_loader
|
2015-11-18 14:27:55 +01:00
|
|
|
|
2016-03-25 08:04:48 +01:00
|
|
|
function Database.new(dbname, role)
|
|
|
|
|
local backend = role and BACKEND[role] or BACKEND.main
|
|
|
|
|
return Database.backend[backend](dbname)
|
|
|
|
|
end
|
2015-11-18 14:27:55 +01:00
|
|
|
|
2016-02-19 15:03:45 +01:00
|
|
|
Database.__self_test__ = function(backends, ...)
|
|
|
|
|
for _, backend in ipairs(backends) do
|
|
|
|
|
local t = Database.backend[backend]
|
|
|
|
|
t(...).__self_test__(...)
|
|
|
|
|
end
|
|
|
|
|
end;
|
2015-09-25 13:30:57 +02:00
|
|
|
|
2015-11-18 14:27:55 +01:00
|
|
|
end
|
|
|
|
|
-----------------------------------------------------------
|
2015-09-25 13:30:57 +02:00
|
|
|
|
|
|
|
|
return Database
|