417 lines
12 KiB
Lua
417 lines
12 KiB
Lua
local Database = require('share.database')
|
|
local conf = require("config")
|
|
|
|
local helpers = require('share.helpers')
|
|
local implode = helpers.implode
|
|
local unique = helpers.unique
|
|
local table_remove = helpers.table_remove
|
|
|
|
local _M = {}
|
|
|
|
local WRITE = 'WRITE'
|
|
local READ = 'READ'
|
|
|
|
local database_write = Database:new({
|
|
host = conf.POSTGRES.host,
|
|
port = conf.POSTGRES.port,
|
|
user = conf.POSTGRES.user,
|
|
password = conf.POSTGRES.password,
|
|
database = conf.POSTGRES.database,
|
|
--charset = conf.POSTGRES.charset,
|
|
--timeout = conf.POSTGRES.timeout,
|
|
db_pool_timeout = conf.POSTGRES.pool_timeout,
|
|
db_pool_size = conf.POSTGRES.pool_size,
|
|
db_type = WRITE
|
|
})
|
|
|
|
local database_read = Database:new({
|
|
host = conf.POSTGRES.host,
|
|
port = conf.POSTGRES.port,
|
|
user = conf.POSTGRES.user,
|
|
password = conf.POSTGRES.password,
|
|
database = conf.POSTGRES.database,
|
|
--charset = conf.POSTGRES.charset,
|
|
--timeout = conf.POSTGRES.timeout,
|
|
db_pool_timeout = conf.POSTGRES.pool_timeout,
|
|
db_pool_size = conf.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 1, nil
|
|
end
|
|
column = column or 'id'
|
|
id = transform_value(id)
|
|
ngx.log(ngx.INFO, 'table name :' .. self.table)
|
|
local sql = 'select * from \"'..self.table..'\" where '..column..'='..id..' limit 1'
|
|
ngx.log(ngx.INFO, 'query sql:', sql)
|
|
local code, res = self:query(sql, READ)
|
|
if code == 0 then
|
|
if table.getn(res) > 0 then
|
|
ngx.log(ngx.INFO, 'query record count:', table.getn(res))
|
|
res = self:make_relations(res)
|
|
return code, res
|
|
end
|
|
end
|
|
return code, nil
|
|
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 2, nil
|
|
end
|
|
local code, res = self:query('select * from \"'..self.table..'\"', READ)
|
|
return code, 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 = ""
|
|
if self.query_sql ~= nil then
|
|
sql = 'select count(*) from \"'..self.table..'\" '..self.query_sql
|
|
else
|
|
sql = 'select count(*) from \"'..self.table.."\""
|
|
end
|
|
local code, res = self:query(sql, READ)
|
|
if code == 0 then
|
|
if table.getn(res) > 0 then
|
|
return code, tonumber(res[1]['count'])
|
|
end
|
|
end
|
|
return code, nil
|
|
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 2,nil
|
|
end
|
|
local sql = 'select * from \"'..self.table..'\" '..self.query_sql .. ' ' .. limit_sql
|
|
local code,res = self:query(sql, READ)
|
|
if self.relation.local_key ~= nil then
|
|
return code, self:make_relations(res)
|
|
end
|
|
return code, res
|
|
end
|
|
|
|
--根据数据模型中的
|
|
function _M:paginate(pageNum, pageSize)
|
|
ngx.log(ngx.INFO, "pageNum:", tostring(pageNum), " pageSize:", tostring(pageSize))
|
|
pageNum = pageNum or 1
|
|
pageSize = pageSize or 10
|
|
local sql, count_sql, total, code, res
|
|
local data={
|
|
data = {},
|
|
total = 0
|
|
}
|
|
if not self.query_sql then
|
|
sql = 'select * from \"'..self.table..'\" limit '..tostring(pageSize)..' offset '..tostring((pageNum - 1) * pageSize)
|
|
count_sql = 'select count(*) from \"'..self.table..'\"'
|
|
else
|
|
sql = 'select * from \"'..self.table .. '\" '..self.query_sql .. ' limit '..tostring(pageSize)..' offset '..tostring((pageNum - 1) * pageSize)
|
|
count_sql = 'select count(*) from \"'..self.table..'\" '..self.query_sql
|
|
end
|
|
code, total = self:query(count_sql, READ)
|
|
if code == 0 then
|
|
data['total'] = tonumber(total[1]['count'])
|
|
end
|
|
code, res = self:query(sql, READ)
|
|
if code == 0 then
|
|
data['data'] = self:make_relations(res)
|
|
end
|
|
return code, data
|
|
end
|
|
|
|
--返回数据表中的第一条数据记录
|
|
function _M:first()
|
|
if not self.query_sql then
|
|
ngx.log(ngx.ERR,'do not have query sql str')
|
|
return 2,nil
|
|
end
|
|
local sql = 'select * from \"'..self.table..'\" '..self.query_sql..' limit 1'
|
|
local code, res = self:query(sql, READ)
|
|
if next(res) ~= nil then
|
|
res = self:make_relations(res)
|
|
return code, res[1]
|
|
end
|
|
return code, nil
|
|
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
|
|
--postgres 数据库使用delete语句时不支持limit
|
|
--local sql = 'delete from \"'..self.table..'\" '..self.query_sql..' limit 1'
|
|
local sql = 'delete from \"'..self.table..'\" '..self.query_sql
|
|
return self:query(sql, WRITE)
|
|
end
|
|
ngx.log(ngx.ERR,'delete function need prefix sql')
|
|
return 2, nil
|
|
end
|
|
--return self:query('delete from '..self.table..' where id=' .. id .. ' limit 1', WRITE)
|
|
return self:query('delete from \"'..self.table..'\" where id='.. id, WRITE)
|
|
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
|
|
local 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
|
|
--postgres 数据库使用update语句时不支持limit
|
|
--local sql = 'update \"'..self.table..'\" set '..str..' '..self.query_sql..' limit 1'
|
|
local sql = 'update \"'..self.table..'\" set '..str..' '..self.query_sql
|
|
return self:query(sql, WRITE)
|
|
end
|
|
ngx.log(ngx.ERR,'update function cannot called without restriction')
|
|
return 2, nil
|
|
end
|
|
|
|
--查询数据表中的数据记录
|
|
function _M:query(sql, type)
|
|
if not sql then
|
|
ngx.log(ngx.ERR,'query() function need sql to query')
|
|
return 2, nil
|
|
end
|
|
self.query_sql = nil
|
|
self.has_order_by = false
|
|
if type == READ then
|
|
local code, result = database_read:db_query(sql)
|
|
if code ~= 0 then
|
|
ngx.log(ngx.ERR, "read db error. res: " .. tostring(code).." or no reason")
|
|
return code, nil
|
|
end
|
|
return code, result
|
|
elseif type == WRITE then
|
|
local code, result = database_write:db_query(sql)
|
|
if code ~= 0 then
|
|
ngx.log(ngx.ERR, "write db error. res: " .. (code or "no reason"))
|
|
return code, nil
|
|
end
|
|
return code, result
|
|
end
|
|
ngx.log(ngx.ERR, 'type invalid, need ' .. READ .. ' or '..WRITE)
|
|
return 2, nil
|
|
end
|
|
|
|
--获取需要隐藏的列
|
|
function _M:get_hidden()
|
|
return self.hidden
|
|
end
|
|
|
|
function _M:debug()
|
|
ngx.log(ngx.INFO, self.table.." ")
|
|
end
|
|
|
|
--初始化数据表中的字段
|
|
function _M:new(table, attributes, hidden)
|
|
local obj = {
|
|
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'
|
|
}
|
|
setmetatable(obj, {__index = _M})
|
|
return obj
|
|
end
|
|
|
|
return _M |