dbrest lua脚本模板以及样例

Posted by Henry on 10-18,2020

本系列其他文章

dbrest v1.1公测版发布
dbrest配置说明
dbrestapi调用说明含样例代码
dbrest lua脚本模板
dbrest小试牛刀
dbrest压测结果

dbrest v1.1.0以上版本支持

lua脚本模板文件

--JSON = (loadfile "json.lua")() 
--local g = require("clr")

--[[
该函数在主程序执行Insert之前触发,可以在此函数中对client提交的body进行修改
函数签名不得修改,即函数名称,参数以及返回类型
objArray: table类型, 存放json对象数组(client 提交到服务端的json object),该参数为引用类型(Pass By Reference)
return: 返回bool值true或者false,仅在返回值为true时,脚本中的修改才有效,否则忽略脚本中的修改
--]]
function beforeInsert(objArray)
  --todo modify objArray
  return true
end


--[[
该函数在主程序执行Insert后触发。
函数签名不得修改,即函数名称,参数以及返回类型
t: table类型,存放client提交到服务端的json数组,以及主程序执行insert后数据库返回自动增长ID数组
t.objArray: table类型,入参, 存放json对象数组(client 提交到服务端的json对象数组)
t.idArray: table类型, 入参,存放json整型数组,(自动增长ID)
t.sqlAndArgs: table类型,出参,可以往此table中添加要执行的sql语句及其参数值args,如果sql语句为非参数化sql,args可以忽略
样例:
t.sqlAndArgs[1] = {sql="INSERT INTO students_log (id,name,gender,age,class,remark) select id,name,gender,age,class,remark from students where id=?", args={1}}
t.sqlAndArgs[2] = {sql="INSERT INTO students_log (id,name,gender,age,class,remark) select id,name,gender,age,class,remark from students where id=100"}
t.sqlAndArgs[3] = {sql=string.format("INSERT INTO tab1(name, remark) VALUES('%s', '%s');",string.gsub(t.objArray[i]["tabs"][j]["name"],"'","''"), t.idArray[i])}
t.sqlAndArgs[4] = {sql="INSERT INTO tab1(name, remark) VALUES(?, ?);", args ={t.objArray[i]["tabs"][j]["name"], t.idArray[i]}}
--请注意mysql不支持以下命名参数形式
t.sqlAndArgs[5] = {sql="INSERT INTO tab1(name, remark) VALUES(:name, :remark);", args ={name=t.objArray[i]["tabs"][j]["name"], remark=t.idArray[i]}}
t.sqlAndArgs[6] = {sql="INSERT INTO tab1(name, remark) VALUES($name, $remark);", args ={name=t.objArray[i]["tabs"][j]["name"], remark=t.idArray[i]}}

return: 返回bool值true或者false,仅在返回值为true时,脚本中生成的sql语句才会执行

--]]
function afterInsert_buildSql(t) 
  --todo build sql
  return true
end

--[[
该函数在主程序更新数据前触发
函数签名不得修改,即函数名称,参数以及返回类型
t: table类型,存放update语句的where语句以及其参数以及客户端提交的json object,可以往此table中写入需要在执行update前先执行的sql
t.where: string类型, 存放update语句的where字句(参数化的where子句)
t.args: 数组类型,存放update语句的where子句的参数值
t.obj: table类型, 存放json对象(client 提交到服务端的json object)
t.sqlAndArgs:table类型,可以往此table中添加要执行的sql语句及其参数值args,如果sql语句为非参数化sql,args可以忽略

例如参数化:  t.sqlAndArgs[1] = {sql="update tab1 set remark='lua备注一下'"..t.where, args=args}
例如非参数化:t.sqlAndArgs[2] = {sql="update tab1 set remark='所有记录的备注都被修改了'"}
例子:update前,先将要更新的记录insert至该表的日志表中
t.sqlAndArgs[1] = {sql="INSERT INTO students_log (id,name,gender,age,class,remark) select id,name,gender,age,class,remark from students "..t.where, args=args}

return: 返回bool值true或者false,仅在返回值为true时,脚本中生成的sql语句才会执行
--]]
function beforeUpdate_buildSql(t)
  --todo build sql 
  return true
end

--[[
该函数在主程序更新数据后触发
t: table类型,存放update语句的where语句以及其参数以及客户端提交的json object,可以往此table中写入需要在执行update后执行的sql
t.where: string类型, 存放update语句的where字句(参数化的where子句)
t.args: 数组类型,存放update语句的where子句的参数值
t.obj: table类型, 存放json对象(client 提交到服务端的json object)
t.sqlAndArgs:table类型,可以往此table中添加要执行的sql语句及其参数值args,如果sql语句为非参数化sql,args可以忽略

例如参数化:  t.sqlAndArgs[1] = {sql="update tab1 set remark='lua备注一下'"..t.where, args=args}
例如非参数化:t.sqlAndArgs[2] = {sql="update tab1 set remark='所有记录的备注都被修改了'"}
例子:update订单明细表(order_items)后,汇总产品数量更新到订单主表(orders)中,(假设主表与明细表用order_id列关联)
t.sqlAndArgs[1] = {sql=string.format("update a set  a.total_qty=b.sum_qty from orders as a inner join (select order_id, sum(qty) as sum_qty from order_items %s group by order_id) as b on a.order_id=b.order_id", t.where), args=args}

return: 返回bool值true或者false,仅在返回值为true时,脚本中生成的sql语句才会执行
--]]
function afterUpdate_buildSql(t)
   --todo build sql 
   return true
end

 --[[
该函数在主程序删除数据前触发
t: table类型,存放delete语句的where语句以及其参数,可以往此table中写入需要在执行delete前先执行的sql
t.where: string类型, 存放delete语句的where字句(参数化的where子句)
t.args: 数组类型,存放delete语句的where子句的参数值
t.sqlAndArgs:table类型,可以往此table中添加要执行的sql语句及其参数值args,如果sql语句为非参数化sql,args可以忽略
例如删除前,先将要删除的记录insert至该表的日志表中
t.sqlAndArgs[1] = {sql="INSERT INTO students_log (id,name,gender,age,class,remark) select id,name,gender,age,class,remark from students "..t.where, args=args}
return: 返回bool值true或者false,仅在返回值为true时,脚本中生成的sql语句才会执行
--]]
function beforeDelete_buildSql(t)
  --todo build sql 
  return true
end

- lua脚本样例

JSON = (loadfile "json.lua")() 
--"json.lua" 模块说明
--string JSON:encode(object) --lua对象序列化为json字符串
--object JSON:decode(encode) --json字符串反序列化为lua对象
local g = require("clr")
--[[
    "clr" 模块是dbrest内部提供的lua扩展模块
    lua print函数被clr重写,等同于clr模块中的log函数
    clr 函数清单:
    void log(...args)  --打印日志
    void print(...args) --控制台打印
    string getCurrentPath() --返回main process当前路径
    bool pathExists(string) --返回指定路径是否存在
    bool isDir(string)  --返回指定路径是否是目录
    string encode(object) --lua对象序列化为json字符串
    object decode(string) --json字符串反序列化为lua对象
    string md5(string) --md5函数
    string base64Encode(string) --base64编码
    string base64Decode(string) --base64解码
    string guid() --guid,uuid生成函数
    (int status, string body, string error) requests(string method, string url, string queryParams, string headers, string data) --http请求函数
    --[[
      参数说明:
      1)method: http method,样例:GET,POST,PUT,PATCH,DELETE
      2)url: 请求地址,样例:http://wwww.baidu.com
      3)queryParams: json格式查询参数,样例:{"name":"zhangsan","age":20}; 
      url配合queryParams构成完整url:http://www.baidu.com?name=zhangsan&age=20
      4)headers: json格式,样例:{"Authorization": "Basic Y2xpZW50MTphYmNkZQ==","Content-Type": "application/json"}
      5)data:http 请求的body部分。
      返回值说明:
      1)status:http status code
      2)body: http response body
      3)error: 错误信息

    调用demo:
    g.log("记录一行日志")
    g.log(1)
    g.log(true)
    g.print("控制台显示的msg")
    str = g.getCurrentPath()
    g.print("当前路径:"..tostring(str))

    g.print(g.pathExists("f:\abc\def"))

    fruits = {"banana","orange","apple"}
    jsonStr = g.encode(fruits)
    g.print(jsonStr)

    jsonStr = '[{"name":"Tom","gender":"男","age":20,"class":"一班","logondate":"2020-09-02"},{"name":"Jack","gender":"男","age":20,"class":"一班","logondate":"2020-09-02"}]'
    persons = g.decode(jsonStr)
    g.print("数组长度"..#persons)
    g.print(persons[1]["name"]) 
    g.print(persons[2]["name"]) 

    g.print(g.md5("hello,world!"))
    g.print(g.guid())
    str1 = g.base64Encode("hello,world!")
    g.print(str1)
    g.print(g.base64Decode(str1))

    status,body,error=g.requests("GET","https://www.baidu.com","","","")
    g.print(status)
    g.print(body)
    g.print(error)

    status,body,error=g.requests("GET","https://www.infoswap.cn/api/students",'{"id":"lt.20"}',"","")
    g.print(status)
    g.print(body)
    g.print(error)
--]]

--[[
该函数在主程序执行Insert之前触发,可以在此函数中对client提交的body进行修改
函数签名不得修改,即函数名称,参数以及返回类型
function beforeInsert(objArray)
  return true/false
end
objArray: table类型, 存放json对象数组(client 提交到服务端的json object),该参数为引用类型(Pass By Reference)
return: 返回bool值true或者false,仅在返回值为true时,脚本中的修改才有效,否则忽略脚本中的修改
--]]
function beforeInsert(objArray)
  --local objArray = JSON:decode(objArrayStr)
  print(#objArray)
  for i=1, #objArray do
    objArray[i]["remark"] = "lua reamrk"
    if objArray[i]["name"] ~= nil then
      objArray[i]["name"] = string.upper(objArray[i]["name"])
    end
    if  objArray[i]["tabs"] ~= nil and #objArray[i]["tabs"]>0 then
      for j =1, #objArray[i]["tabs"] do
        if  objArray[i]["tabs"][j]["name"] ~= nil then
          objArray[i]["tabs"][j]["name"] = string.upper(objArray[i]["tabs"][j]["name"])
        end
      end
    end
  end
  return true
end


--[[
该函数在主程序执行Insert后触发。
t: table类型,存放client提交到服务端的json数组,以及主程序执行insert后数据库返回自动增长ID数组
t.objArray: table类型,入参, 存放json对象数组(client 提交到服务端的json对象数组)
t.idArray: table类型, 入参,存放json整型数组,(自动增长ID)
t.sqlAndArgs: table类型,出参,可以往此table中添加要执行的sql语句及其参数值args,如果sql语句为非参数化sql,args可以忽略
样例:
t.sqlAndArgs[1] = {sql="INSERT INTO students_log (id,name,gender,age,class,remark) select id,name,gender,age,class,remark from students where id=?", args={1}}
t.sqlAndArgs[2] = {sql="INSERT INTO students_log (id,name,gender,age,class,remark) select id,name,gender,age,class,remark from students where id=100"}
t.sqlAndArgs[3] = {sql=string.format("INSERT INTO tab1(name, remark) VALUES('%s', '%s');",string.gsub(t.objArray[i]["tabs"][j]["name"],"'","''"), t.idArray[i])}
t.sqlAndArgs[4] = {sql="INSERT INTO tab1(name, remark) VALUES(?, ?);", args ={t.objArray[i]["tabs"][j]["name"], t.idArray[i]}}
--请注意mysql不支持以下命名参数形式
t.sqlAndArgs[5] = {sql="INSERT INTO tab1(name, remark) VALUES(:name, :remark);", args ={name=t.objArray[i]["tabs"][j]["name"], remark=t.idArray[i]}}
t.sqlAndArgs[6] = {sql="INSERT INTO tab1(name, remark) VALUES($name, $remark);", args ={name=t.objArray[i]["tabs"][j]["name"], remark=t.idArray[i]}}

return: 返回bool值true或者false,仅在返回值为true时,脚本中生成的sql语句才会执行

--]]
function afterInsert_buildSql(t) 
  index = 1
  for i=1, #t.objArray do
    if  t.objArray[i]["tabs"] ~= nil and #t.objArray[i]["tabs"] > 0 then
      for j =1, #t.objArray[i]["tabs"] do
        --t.sqlAndArgs[index] = {sql=string.format("INSERT INTO tab1(name, remark) VALUES('%s', '%s');",string.gsub(t.objArray[i]["tabs"][j]["name"],"'","''"), t.idArray[i])}
        t.sqlAndArgs[index] = {sql="INSERT INTO tab1(name, remark) VALUES(?, ?);", args ={t.objArray[i]["tabs"][j]["name"], t.idArray[i]}}
        --t.sqlAndArgs[index] = {sql="INSERT INTO tab1(name, remark) VALUES(:name, :remark);", args ={name=t.objArray[i]["tabs"][j]["name"], remark=t.idArray[i]}}
        --t.sqlAndArgs[index] = {sql="INSERT INTO tab1(name, remark) VALUES($name, $remark);", args ={name=t.objArray[i]["tabs"][j]["name"], remark=t.idArray[i]}}
        index = index+1
      end
    end
  end

  return true
end

--clone object
local function clone(obj)
  local result
  if type(obj) == "table" then
      result = {}
      --for k,v in next, obj, nil do
  for k, v in pairs(obj) do
          result[clone(k)] = clone(v)
      end
  else -- number, string, boolean, etc
      result = obj
  end
  return result
end


--[[
该函数在主程序更新数据前触发
t: table类型,存放update语句的where语句以及其参数以及客户端提交的json object,可以往此table中写入需要在执行update前先执行的sql
t.where: string类型, 存放update语句的where字句(参数化的where子句)
t.args: 数组类型,存放update语句的where子句的参数值
t.obj: table类型, 存放json对象(client 提交到服务端的json object)
t.sqlAndArgs:table类型,可以往此table中添加要执行的sql语句及其参数值args,如果sql语句为非参数化sql,args可以忽略

例如参数化:  t.sqlAndArgs[1] = {sql="update tab1 set remark='lua备注一下'"..t.where, args=args}
例如非参数化:t.sqlAndArgs[2] = {sql="update tab1 set remark='所有记录的备注都被修改了'"}
例子:update前,先将要更新的记录insert至该表的日志表中
t.sqlAndArgs[1] = {sql="INSERT INTO students_log (id,name,gender,age,class,remark) select id,name,gender,age,class,remark from students "..t.where, args=args}

return: 返回bool值true或者false,仅在返回值为true时,脚本中生成的sql语句才会执行
--]]
function beforeUpdate_buildSql(t)
  print(t.where)
  print(JSON:encode(t.args))
  print(JSON:encode(t.obj))
  args2=clone(t.args)
  table.insert(args2,1,"lua添加的参数")
  --t.sqlAndArgs[1] = {sql="update tab1 set remark=? "..t.where, args=args2}
  --t.sqlAndArgs[2] = {sql="update tab1 set remark2=getdate() where id=3"}
  t.sqlAndArgs[3] = {sql="INSERT INTO students_log(id,name,gender,age,class,remark) select id,name,gender,age,class,remark from students "..t.where, args=t.args}

  return true
end


 --[[
该函数在主程序删除数据前触发
t: table类型,存放delete语句的where语句以及其参数,可以往此table中写入需要在执行delete前先执行的sql
t.where: string类型, 存放delete语句的where字句(参数化的where子句)
t.args: 数组类型,存放delete语句的where子句的参数值
t.sqlAndArgs:table类型,可以往此table中添加要执行的sql语句及其参数值args,如果sql语句为非参数化sql,args可以忽略
例如删除前,先将要删除的记录insert至该表的日志表中
t.sqlAndArgs[1] = {sql="INSERT INTO students_log (id,name,gender,age,class,remark) select id,name,gender,age,class,remark from students "..t.where, args=args}
return: 返回bool值true或者false,仅在返回值为true时,脚本中生成的sql语句才会执行
--]]
function beforeDelete_buildSql(t)
  print(t.where)
  print(JSON:encode(t.args))
  args2=clone(t.args)
  --table.insert(args2,1,"lua添加的参数")  
  t.sqlAndArgs[1] = {sql=[[INSERT INTO students_log (id,name,gender,age,class,remark,remark2,logondate,createdate,height,weight,delete_flag)
  select id,name,gender,age,class,remark,remark2,logondate,createdate,height,weight,delete_flag from students ]]..t.where, args=args2}

  return true
end