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