增加orm相关的文件,有待orm类进行测试

This commit is contained in:
wanglei 2025-10-24 22:29:50 +08:00
parent d22570eaaf
commit 9b1de255d2
7 changed files with 692 additions and 3 deletions

View File

@ -24,6 +24,6 @@ return {
PORT = 5432, -- postgres port
USERNAME = "postgres",
PASSWORD = "1qaz2wsx", -- postgres password
DATABASE = "postgres"
DATABASE = "postgres",
}
}

View File

@ -13,6 +13,25 @@ return {
port = env.POSTGRES.PORT,
user = env.POSTGRES.USERNAME,
password = env.POSTGRES.PASSWORD,
database = env.POSTGRES.DATABASE
database = env.POSTGRES.DATABASE,
write = { -- postgresql write database
host = env.POSTGRES.HOST,
port = env.POSTGRES.PORT,
user = env.POSTGRES.USERNAME,
password = env.POSTGRES.PASSWORD,
database = env.POSTGRES.DATABASE
},
read = { -- postgresql read database
host = env.POSTGRES.HOST,
port = env.POSTGRES.PORT,
user = env.POSTGRES.USERNAME,
password = env.POSTGRES.PASSWORD,
database = env.POSTGRES.DATABASE
},
charset = 'utf8',
pool_timeout = 1000, -- postgresql pool timeout
pool_size = 100, -- postgresql pool size
timeout = 1000, -- postgresql timeout
},
}

5
src/model/user.lua Normal file
View File

@ -0,0 +1,5 @@
local Model = require("util.model")
local User = Model:new('tbl_user')
return User

View File

@ -126,12 +126,14 @@ function _M.updateAccount(id, jsonData)
if ok ~= 0 then
return 0x000001,res
end
--获取数据表中的数据记录值
local num = 0
for _, row in ipairs(res) do
for key, value in pairs(row) do
num = value
end
end
--账号不存在返回错误信息
print("exec result:", num)
if num <= 0 then
return 0x01000C,nil

96
src/util/database.lua Normal file
View File

@ -0,0 +1,96 @@
local pgmoon = require('pgmoon')
local ngx = ngx
local _M = {}
local WRITE = 'WRITE'
local READ = 'READ'
local mt = { __index = _M }
--[[
Get db connection from connection pool
@return bool, db_context, err
--]]
function _M:get_connection()
if ngx.ctx[self.db_type] then
-- if write before read, make sure write read connection the same
if ngx.ctx[WRITE] then
return ngx.ctx[WRITE], nil
end
return ngx.ctx[self.db_type], nil
end
local code = 0
-- 创建一个新的连接
local conn = pgmoon.new({
host = self.host, -- postgres host
port = self.port, -- postgres port
user = self.user,
password = self.password, -- postgres password
database = self.database
});
conn.set_timeout(self.timeout or 1000)
---- 连接到数据库
local ok, err = conn:connect()
if not ok then
print("Connection failed: " .. err)
code = 0x000002
end
--ngx.say("Connection success")
ngx.ctx[self.db_type] = conn
return code,conn
end
--[[
set_keepalive代替close() ,nginx工作进程
@return void
--]]
function _M.close(self)
if ngx.ctx[READ] then
ngx.ctx[READ]:set_keepalive(self.db_pool_timeout, self.db_pool_size)
ngx.ctx[READ] = nil
end
if ngx.ctx[WRITE] then
ngx.ctx[WRITE]:set_keepalive(self.db_pool_timeout, self.db_pool_size)
ngx.ctx[WRITE] = nil
end
end
--[[
@param sql
@return bool, data, err
--]]
function _M.db_query(self, sql)
local db, err = self:get_connection()
if err ~= nil then
return nil, err
end
local res, errcode, sqlstate
res, err, errcode, sqlstate = db:query(sql)
if not res then
ngx.log(ngx.ERR, err, errcode, sqlstate)
return nil, err
end
return res, nil
end
function _M.new(self, opts)
return setmetatable({
host = opts.host or '127.0.0.1',
port = opts.port or 5432,
user = opts.user or 'postgres',
password = opts.password or '',
database = opts.database or 'postgres',
--charset = opts.charset or 'utf8mb4',
--timeout = opts.timeout,
--max_packet_size = 1024 * 1024,
db_pool_timeout = opts.pool_timeout or 1000,
db_pool_size = opts.pool_size or 1000,
db_type = opts.db_type,
}, mt)
end
return _M

View File

@ -4,10 +4,11 @@
--- DateTime: 2025/10/24 11:36
---
local snowflake = require("util.snowflake")
local cjson = require("cjson")
local _M = {}
function _M:getUuid()
local function getUuid()
local workerId = 0 -- 假设当前机器的ID是1范围在[0, 31]之间
local datacenterId = 0 -- 数据中心ID范围在[0, 31]之间
local snow = snowflake.new(workerId, datacenterId)
@ -16,4 +17,154 @@ function _M:getUuid()
return snow.int64_to_string(id)
end
-- here you need use . not :
local function table_reverse(tbl)
for i=1, math.floor(#tbl / 2) do
tbl[i], tbl[#tbl - i + 1] = tbl[#tbl - i + 1], tbl[i]
end
return tbl
end
-- remove item in table
local function table_remove(tab, rm)
local result = tab
for k, v in pairs(rm) do
for a_k, a_v in pairs(result) do
-- array
if type(a_k) == 'number' then
-- object
if type(a_v) == 'table' then
result[a_k][v] = nil
elseif v == a_v then
table.remove(result, a_k)
end
else
-- hash array
if v == a_k then
result[a_k] = nil
end
end
end
end
return result
end
-- unique a array
local function unique(arr)
local hash = {}
local res = {}
for _,v in ipairs(arr) do
if not hash[v] then
hash[v] = true
table.insert(res, v)
end
end
return res
end
-- make up a string from array
local function implode(arr, symbol)
local implode_str = ''
symbol = symbol or ','
for key, value in pairs(arr) do
implode_str = implode_str .. value .. symbol
end
return string.sub(implode_str, 1, #implode_str - 1)
end
-- sort a hashTable by key
local function sort_by_key(tab)
local a = {}
for n in pairs(tab) do
table.insert(a, n)
end
table.sort(a)
local i = 0 -- iterator variable
local iter = function()
-- iterator function
i = i + 1
if a[i] then
return a[i], tab[a[i]]
else
return nil
end
end
return iter
end
local function set_cookie(key, value, expires)
local config = require("config.app")
local cookie, err = require("lib.cookie"):new()
if not cookie then
ngx.log(ngx.ERR, err)
return false, err
end
local cookie_payload = {
key = key,
value = value,
path = '/',
domain = config.app_domain,
httponly = true,
}
if expires ~= nil then
cookie_payload.expires = ngx.cookie_time(expires)
end
local ok, err = cookie:set(cookie_payload)
if not ok then
ngx.log(ngx.ERR, err)
return false, err
end
return true
end
local function get_cookie(key)
local cookie, err = require("lib.cookie"):new()
if not cookie then
ngx.log(ngx.ERR, err)
return false
end
return cookie:get(key)
end
local function get_local_time()
local config = require("config.app")
local time_zone = ngx.re.match(config.time_zone, "[0-9]+")
if time_zone == nil then
local err = "not set time zone or format error, time zone should look like `+8:00` current is: " .. config.time_zone
ngx.log(ngx.ERR, err)
return false, err
end
-- ngx.time() return UTC+0 timestamp
-- time_zone * 60(sec) * 60(min) + UTC+0 time = current time
return time_zone[0] * 3600 + ngx.time()
end
local function trim(str, symbol)
symbol = symbol or '%s' -- %s default match space \t \n etc..
return (string.gsub(string.gsub(str, '^' .. symbol .. '*', ""), symbol .. '*$', ''))
end
-- data not in order
local function log(...)
local args
if #{...}>1 then
args = {...}
else
args = ...
end
ngx.log(ngx.WARN, cjson.encode(args))
end
_M.getUuid = getUuid
_M.log = log
_M.trim = trim
_M.get_cookie = get_cookie
_M.set_cookie = set_cookie
_M.get_local_time = get_local_time
_M.sort_by_key = sort_by_key
_M.implode = implode
_M.unique = unique
_M.table_reverse = table_reverse
_M.table_remove = table_remove
return _M

416
src/util/model.lua Normal file
View File

@ -0,0 +1,416 @@
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