416 lines
11 KiB
Lua
416 lines
11 KiB
Lua
|
|
local Database = require('util.database')
|
||
|
|
local dbconf = require("config.database")
|
||
|
|
|
||
|
|
local helpers = require('util.helpers')
|
||
|
|
local implode = helpers.implode
|
||
|
|
local unique = helpers.unique
|
||
|
|
local table_remove = helpers.table_remove
|
||
|
|
|
||
|
|
local _M = {}
|
||
|
|
|
||
|
|
local mt = { __index = _M }
|
||
|
|
|
||
|
|
local WRITE = 'WRITE'
|
||
|
|
local READ = 'READ'
|
||
|
|
|
||
|
|
local database_write = Database:new({
|
||
|
|
host = dbconf.postgres.write.host,
|
||
|
|
port = dbconf.postgres.write.port,
|
||
|
|
user = dbconf.postgres.write.user,
|
||
|
|
password = dbconf.postgres.write.password,
|
||
|
|
database = dbconf.postgres.write.database,
|
||
|
|
--charset = dbconf.postgres.charset,
|
||
|
|
--timeout = dbconf.postgres.timeout,
|
||
|
|
db_pool_timeout = dbconf.postgres.pool_timeout,
|
||
|
|
db_pool_size = dbconf.postgres.pool_size,
|
||
|
|
db_type = WRITE
|
||
|
|
})
|
||
|
|
|
||
|
|
local database_read = Database:new({
|
||
|
|
host = dbconf.postgres.read.host,
|
||
|
|
port = dbconf.postgres.read.port,
|
||
|
|
user = dbconf.postgres.read.user,
|
||
|
|
password = dbconf.postgres.read.password,
|
||
|
|
database = dbconf.postgres.read.database,
|
||
|
|
--charset = dbconf.postgres.charset,
|
||
|
|
--timeout = dbconf.postgres.timeout,
|
||
|
|
db_pool_timeout = dbconf.postgres.pool_timeout,
|
||
|
|
db_pool_size = dbconf.postgres.pool_size,
|
||
|
|
db_type = READ
|
||
|
|
})
|
||
|
|
|
||
|
|
local function transform_value(value)
|
||
|
|
if value == ngx.null then
|
||
|
|
value = ''
|
||
|
|
end
|
||
|
|
value = value or ''
|
||
|
|
if string.lower(value) == 'null' then
|
||
|
|
return 'NULL'
|
||
|
|
end
|
||
|
|
return ngx.quote_sql_str(value)
|
||
|
|
end
|
||
|
|
|
||
|
|
-- return whole relations keys
|
||
|
|
--获取整个关系的键值
|
||
|
|
function _M:get_relation_local_index(parents)
|
||
|
|
local ids = {}
|
||
|
|
for key,parent in pairs(parents) do
|
||
|
|
table.insert( ids, parent[self.relation.local_key] )
|
||
|
|
end
|
||
|
|
return ids
|
||
|
|
end
|
||
|
|
|
||
|
|
-- return whole relation models
|
||
|
|
function _M:retrieve_relations(ids)
|
||
|
|
-- if table is empty
|
||
|
|
if next(ids) == nil then
|
||
|
|
return {}
|
||
|
|
end
|
||
|
|
local ids_str = implode(unique(ids))
|
||
|
|
self.relation_sql = 'select * from '..self.relation.model.table..' where ' .. self.relation.foreign_key .. ' in (' .. ids_str .. ')'
|
||
|
|
return table_remove(self:query(self.relation_sql, READ), self.relation.model:get_hidden())
|
||
|
|
end
|
||
|
|
|
||
|
|
-- return current parent node
|
||
|
|
function _M:merge_one_relation(parent, relations)
|
||
|
|
for _, item in pairs(relations) do
|
||
|
|
if (parent[self.relation.local_key] == item[self.relation.foreign_key]) then
|
||
|
|
parent[self.relation.key_name] = item
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return parent
|
||
|
|
end
|
||
|
|
|
||
|
|
function _M:merge_many_relations(parent, relations)
|
||
|
|
for index, item in pairs(relations) do
|
||
|
|
if (parent[self.relation.local_key] == item[self.relation.foreign_key]) then
|
||
|
|
if not parent[self.relation.key_name] then
|
||
|
|
parent[self.relation.key_name] = {}
|
||
|
|
end
|
||
|
|
table.insert(parent[self.relation.key_name], item)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return parent
|
||
|
|
end
|
||
|
|
|
||
|
|
function _M:make_relations(parents)
|
||
|
|
if self.relation.mode ~= 0 then
|
||
|
|
local relations = self:retrieve_relations(self:get_relation_local_index(parents))
|
||
|
|
for key, parent in pairs(parents) do
|
||
|
|
if self.relation.mode == 1 then
|
||
|
|
-- belongs to
|
||
|
|
if table.getn(relations) > 0 then
|
||
|
|
parents[key] = self:merge_one_relation(parent, relations)
|
||
|
|
else
|
||
|
|
parents[key][self.relation.key_name] = nil
|
||
|
|
end
|
||
|
|
elseif self.relation.mode == 2 then
|
||
|
|
-- has many
|
||
|
|
parents[key] = self:merge_many_relations(parent, relations)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return parents
|
||
|
|
end
|
||
|
|
|
||
|
|
-- function _M:merge_hidden()
|
||
|
|
-- if #self.attributes == 0 then
|
||
|
|
-- return '*'
|
||
|
|
-- else
|
||
|
|
-- local result = table_remove(self.attributes, self.hidden)
|
||
|
|
-- return table.concat(result, ", ")
|
||
|
|
-- end
|
||
|
|
-- end
|
||
|
|
|
||
|
|
function _M:find(id,column)
|
||
|
|
if self.query_sql ~= nil then
|
||
|
|
ngx.log(ngx.ERR, 'cannot use find() with other query sql')
|
||
|
|
return nil
|
||
|
|
end
|
||
|
|
column = column or 'id'
|
||
|
|
id = transform_value(id)
|
||
|
|
local sql = 'select * from '..self.table..' where '..column..'='..id..' limit 1'
|
||
|
|
local res = self:query(sql, READ)
|
||
|
|
if table.getn(res) > 0 then
|
||
|
|
res = self:make_relations(res)
|
||
|
|
return res[1]
|
||
|
|
else
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function _M:all()
|
||
|
|
if self.query_sql ~= nil then
|
||
|
|
ngx.log(ngx.ERR, 'cannot use all() with other query sql ', self.query_sql)
|
||
|
|
return nil
|
||
|
|
end
|
||
|
|
local res = self:query('select * from '..self.table, READ)
|
||
|
|
return self:make_relations(res)
|
||
|
|
end
|
||
|
|
|
||
|
|
--组装sql语句条件为and相关的字段
|
||
|
|
function _M:where(column,operator,value)
|
||
|
|
value = transform_value(value)
|
||
|
|
if not self.query_sql then
|
||
|
|
self.query_sql = 'where '..column.. ' ' .. operator .. ' ' .. value
|
||
|
|
else
|
||
|
|
self.query_sql = self.query_sql..' and '..column..' '..operator..' '..value
|
||
|
|
end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--组装sql语句条件为or相关的字段
|
||
|
|
function _M:orwhere(column,operator,value)
|
||
|
|
value = transform_value(value)
|
||
|
|
if not self.query_sql then
|
||
|
|
return ngx.log(ngx.ERR,'orwhere function need a query_sql prefix')
|
||
|
|
else
|
||
|
|
self.query_sql = self.query_sql..' or '..column..operator..value
|
||
|
|
end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
function _M:orderby(column,operator)
|
||
|
|
local operator = operator or 'asc'
|
||
|
|
if not self.query_sql then
|
||
|
|
self.query_sql = 'order by '.. self.table .. '.' .. column .. ' ' ..operator
|
||
|
|
else
|
||
|
|
if self.has_order_by then
|
||
|
|
self.query_sql = self.query_sql .. ',' .. column.. ' ' ..operator
|
||
|
|
else
|
||
|
|
self.query_sql = self.query_sql .. ' order by ' .. column.. ' ' ..operator
|
||
|
|
end
|
||
|
|
end
|
||
|
|
self.has_order_by = true
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--获取数据表中记录的数量
|
||
|
|
function _M:count()
|
||
|
|
local sql = self.query_sql
|
||
|
|
if not sql then
|
||
|
|
sql = 'select count(*) from '..self.table
|
||
|
|
else
|
||
|
|
sql = 'select count(*) from '..self.table..' '..self.query_sql
|
||
|
|
end
|
||
|
|
local res = self:query(sql, READ)
|
||
|
|
if table.getn(res) > 0 then
|
||
|
|
return tonumber(res[1]['count(*)'])
|
||
|
|
else
|
||
|
|
return 0
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- params: (option)int num
|
||
|
|
-- return: table
|
||
|
|
function _M:get(num)
|
||
|
|
num = num or nil
|
||
|
|
local limit_sql = ''
|
||
|
|
if num ~= nil then
|
||
|
|
limit_sql = 'limit ' .. num
|
||
|
|
end
|
||
|
|
if not self.query_sql then
|
||
|
|
ngx.log(ngx.ERR,'do not have query sql str')
|
||
|
|
return
|
||
|
|
end
|
||
|
|
local sql = 'select * from '..self.table..' '..self.query_sql .. ' ' .. limit_sql
|
||
|
|
local res = self:query(sql, READ)
|
||
|
|
if self.relation.local_key ~= nil then
|
||
|
|
return self:make_relations(res)
|
||
|
|
end
|
||
|
|
return res
|
||
|
|
end
|
||
|
|
|
||
|
|
--根据数据模型中的
|
||
|
|
function _M:paginate(page_num, per_page)
|
||
|
|
page_num = page_num or 1
|
||
|
|
per_page = per_page or config.per_page
|
||
|
|
local sql, count_sql, total
|
||
|
|
local data={
|
||
|
|
data = {},
|
||
|
|
next_page = 1,
|
||
|
|
prev_page = 1,
|
||
|
|
total = 0
|
||
|
|
}
|
||
|
|
if not self.query_sql then
|
||
|
|
sql = 'select * from '..self.table..' limit '..per_page*page_num..','..per_page
|
||
|
|
count_sql = 'select count(*) from '..self.table
|
||
|
|
else
|
||
|
|
sql = 'select * from '..self.table .. ' '..self.query_sql .. ' limit '..per_page*(page_num-1)..','..per_page
|
||
|
|
count_sql = 'select count(*) from '..self.table..' '..self.query_sql
|
||
|
|
end
|
||
|
|
total = self:query(count_sql, READ)
|
||
|
|
if not total then
|
||
|
|
else
|
||
|
|
data['total'] = tonumber(total[1]['count(*)'])
|
||
|
|
data['data'] = self:make_relations(self:query(sql, READ))
|
||
|
|
end
|
||
|
|
if (table.getn(data['data']) + ((page_num - 1)* per_page)) < data['total'] then
|
||
|
|
data['next_page'] = page_num + 1
|
||
|
|
end
|
||
|
|
if tonumber(page_num) ~= 1 then
|
||
|
|
data['prev_page'] = page_num - 1
|
||
|
|
end
|
||
|
|
|
||
|
|
return data
|
||
|
|
end
|
||
|
|
|
||
|
|
--返回数据表中的第一条数据记录
|
||
|
|
function _M:first()
|
||
|
|
if not self.query_sql then
|
||
|
|
ngx.log(ngx.ERR,'do not have query sql str')
|
||
|
|
return
|
||
|
|
end
|
||
|
|
local sql = 'select * from '..self.table..' '..self.query_sql..' limit 1'
|
||
|
|
local res = self:query(sql, READ)
|
||
|
|
if next(res) ~= nil then
|
||
|
|
res = self:make_relations(res)
|
||
|
|
return res[1]
|
||
|
|
else
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--插入数据内容到数据表中
|
||
|
|
function _M:create(data)
|
||
|
|
local columns,values
|
||
|
|
for column,value in pairs(data) do
|
||
|
|
value = transform_value(value)
|
||
|
|
if not columns then
|
||
|
|
columns = column
|
||
|
|
values = value
|
||
|
|
else
|
||
|
|
columns = columns..','..column
|
||
|
|
values = values..','..value
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return self:query('insert into '..self.table..'('..columns..') values('..values..')', WRITE)
|
||
|
|
end
|
||
|
|
|
||
|
|
function _M:with(relation)
|
||
|
|
self.relation.key_name = relation
|
||
|
|
if self[relation] == nil then
|
||
|
|
ngx.log(ngx.ERR, self.table .. ' dont have ' .. relation .. ' function')
|
||
|
|
end
|
||
|
|
return self[relation]()
|
||
|
|
end
|
||
|
|
|
||
|
|
-- 使用数组来存储关系模型
|
||
|
|
function _M:has_many(model, foreign_key, local_key)
|
||
|
|
self.relation.model = model
|
||
|
|
self.relation.local_key = local_key
|
||
|
|
self.relation.foreign_key = foreign_key
|
||
|
|
self.relation.mode = 2
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
function _M:belongs_to(model, foreign_key, local_key)
|
||
|
|
self.relation.model = model
|
||
|
|
self.relation.local_key = local_key
|
||
|
|
self.relation.foreign_key = foreign_key
|
||
|
|
self.relation.mode = 1
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--根据id删除数据库中的数据记录
|
||
|
|
function _M:delete(id)
|
||
|
|
id = id or nil
|
||
|
|
if not id then
|
||
|
|
-- 拼接需要delete的字段
|
||
|
|
if self.query_sql then
|
||
|
|
local sql = 'delete from '..self.table..' '..self.query_sql..' limit 1'
|
||
|
|
return self:query(sql, WRITE)
|
||
|
|
end
|
||
|
|
ngx.log(ngx.ERR,'delete function need prefix sql')
|
||
|
|
ngx.exit(500)
|
||
|
|
else
|
||
|
|
return self:query('delete from '..self.table..' where id=' .. id .. ' limit 1', WRITE)
|
||
|
|
end
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
|
||
|
|
--软删除数据,不从数据表中删除记录,只将定义表中的字段值进行处理
|
||
|
|
--function _M:soft_delete()
|
||
|
|
-- if self.query_sql then
|
||
|
|
-- local sql = 'update '..self.table..' set '..self.soft_delete_column..' = now() '.. self.query_sql ..' limit 1'
|
||
|
|
-- return self:query(sql, WRITE)
|
||
|
|
-- end
|
||
|
|
-- ngx.log(ngx.ERR,'soft_delete function cannot called without restriction')
|
||
|
|
-- ngx.exit(500)
|
||
|
|
-- return false
|
||
|
|
--end
|
||
|
|
|
||
|
|
--更新数据表中的数据记录
|
||
|
|
function _M:update(data)
|
||
|
|
-- 拼接需要update的字段
|
||
|
|
local str = nil
|
||
|
|
for column,value in pairs(data) do
|
||
|
|
clean_value = transform_value(value)
|
||
|
|
if not str then
|
||
|
|
str = column..'='..clean_value
|
||
|
|
else
|
||
|
|
str = str..','..column..'='..clean_value
|
||
|
|
end
|
||
|
|
end
|
||
|
|
-- 判断是模型自身执行update还是数据库where限定执行
|
||
|
|
if self.query_sql then
|
||
|
|
local sql = 'update '..self.table..' set '..str..' '..self.query_sql..' limit 1'
|
||
|
|
return self:query(sql, WRITE)
|
||
|
|
end
|
||
|
|
ngx.log(ngx.ERR,'update function cannot called without restriction')
|
||
|
|
ngx.exit(500)
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
|
||
|
|
--查询数据表中的数据记录
|
||
|
|
function _M:query(sql, type)
|
||
|
|
if not sql then
|
||
|
|
return ngx.log(ngx.ERR,'query() function need sql to query')
|
||
|
|
end
|
||
|
|
self.query_sql = nil
|
||
|
|
self.has_order_by = false
|
||
|
|
if type == READ then
|
||
|
|
local result, err = database_read:db_query(sql)
|
||
|
|
if err ~= nil then
|
||
|
|
ngx.log(ngx.ERR, "read db error. res: " .. (err or "no reason"))
|
||
|
|
ngx.exit(500)
|
||
|
|
return
|
||
|
|
end
|
||
|
|
return result
|
||
|
|
elseif type == WRITE then
|
||
|
|
local result, err = database_write:db_query(sql)
|
||
|
|
if err ~= nil then
|
||
|
|
ngx.log(ngx.ERR, "write db error. res: " .. (err or "no reason"))
|
||
|
|
ngx.exit(500)
|
||
|
|
return
|
||
|
|
end
|
||
|
|
return result.affected_rows
|
||
|
|
else
|
||
|
|
ngx.log(ngx.ERR, 'type invalid, need ' .. READ .. ' or '..WRITE)
|
||
|
|
ngx.exit(500)
|
||
|
|
return
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--获取需要隐藏的列
|
||
|
|
function _M:get_hidden()
|
||
|
|
return self.hidden
|
||
|
|
end
|
||
|
|
|
||
|
|
--初始化数据表中的字段
|
||
|
|
function _M:new(table, attributes, hidden)
|
||
|
|
return setmetatable({
|
||
|
|
table = table,
|
||
|
|
attributes = attributes or {},
|
||
|
|
hidden = hidden or {},
|
||
|
|
query_sql = nil,
|
||
|
|
has_order_by = false,
|
||
|
|
relation = {
|
||
|
|
mode = 0
|
||
|
|
},
|
||
|
|
relation_sql = nil,
|
||
|
|
--soft_delete_column = 'deleted_at'
|
||
|
|
}, mt)
|
||
|
|
end
|
||
|
|
|
||
|
|
return _M
|