Skip to content

Commit

Permalink
Adds support to openresty internal MySQL API.
Browse files Browse the repository at this point in the history
If you are using openresty + mysql it is no longer necessary to install luasql-mysql. Sailor will now use internal resty's API, which is non-blocking.
  • Loading branch information
Etiene committed Oct 7, 2015
1 parent 77c8f84 commit 7e0bd06
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 116 deletions.
2 changes: 1 addition & 1 deletion src/remy/nginx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function M.init()
r.method = ngx.var.request_method
r.args = remy.splitstring(ngx.var.request_uri,'?')
r.banner = M.mode.."/"..ngx.var.nginx_version
r.basic_auth_pw = pass
r.basic_auth_pw = pass
r.canonical_filename = filename
r.context_document_root = ngx.var.document_root
r.document_root = r.context_document_root
Expand Down
2 changes: 1 addition & 1 deletion src/sailor.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ local sailor = {
conf = conf.sailor,
_COPYRIGHT = "Copyright (C) 2014-2015 Etiene Dalcol",
_DESCRIPTION = "Sailor is a framework for creating MVC web applications.",
_VERSION = "Sailor 0.4",
_VERSION = "Sailor 0.4.11",
}

local lp = require "web_utils.lp_ex"
Expand Down
80 changes: 7 additions & 73 deletions src/sailor/db.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--------------------------------------------------------------------------------
-- db.lua, v0.2.1: DB module for connecting and querying through LuaSQL
-- db.lua, v0.3: DB module for connecting and querying through different DB modules
-- This file is a part of Sailor project
-- Copyright (c) 2014 Etiene Dalcol <[email protected]>
-- License: MIT
Expand All @@ -8,80 +8,14 @@

local main_conf = require "conf.conf"
local conf = main_conf.db[main_conf.sailor.environment]
local luasql = require("luasql."..conf.driver)
local db = {}
local remy = require "remy"

-- Creates the connection of the instance
function db.connect()
db.env = assert (luasql[conf.driver]())
db.con = assert (db.env:connect(conf.dbname,conf.user,conf.pass,conf.host))
end

-- Closes the connection of the instance
function db.close()
db.con:close()
db.env:close()
end

-- Runs a query
-- @param query string: the query to be executed
-- @return table: a cursor
function db.query(query)
local cur = assert(db.con:execute(query))
return cur
end

-- Escapes a string or a table (its values). Should be used before concatenating strings on a query.
-- @param q string or table: the string or table to be escaped
-- @return string or nil: if q is a string, returns the new escaped string. If q is a table
-- it simply returns, since it already escaped the table's values
function db.escape(q)
if type(q) == "string" then
q = db.con:escape(q)
return q
elseif type(q) == "table" then
for k,v in pairs(q) do
q[k] = db.con:escape(v)
end
return
end
return q
end


--- Runs two queries and returns the result of the second query.
-- It is no longer in use. It was used by sailor.model to insert and obtain the last id.
-- It is now replaced by query_insert but it's still a valid method that could be used again.
-- @param q1 string: first query to be executed
-- @param q2 string: second query to be executed
-- return table: the result of the second execution
--[[function db.query_query(q1,q2)
local res
local rows = assert(db.con:execute(q1))
if rows == 0 then
res = 0
else
res = assert(db.con:execute(q2))
end
return res
end]]

--- Runs a query and returns the id of the last inserted row. Used for saving
-- a model and obtaining the model id.
-- @param query string: the query to be executed
-- return number or string: the id of the last inserted row.
function db.query_insert(query)
local id
if conf.driver == "postgresql" then
query = query .. "RETURNING uid; "
id = assert(db.con:execute(query))
else
query = query .. "; "
assert(db.con:execute(query))
id = db.con:getlastautoid()
end
local db

return id
if remy.detect() == remy.MODE_NGINX and conf.driver == "mysql" then
db = require "sailor.db.resty_mysql"
else
db = require "sailor.db.luasql"
end

return db
115 changes: 115 additions & 0 deletions src/sailor/db/luasql.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
--------------------------------------------------------------------------------
-- luasql.lua, v0.2.1: DB module for connecting and querying through LuaSQL
-- This file is a part of Sailor project
-- Copyright (c) 2014 Etiene Dalcol <[email protected]>
-- License: MIT
-- http://sailorproject.org
--------------------------------------------------------------------------------

local main_conf = require "conf.conf"
local conf = main_conf.db[main_conf.sailor.environment]
local luasql = require("luasql."..conf.driver)
local db = {}

-- Creates the connection of the instance
function db.connect()
db.env = assert (luasql[conf.driver]())
db.con = assert (db.env:connect(conf.dbname,conf.user,conf.pass,conf.host))
end

-- Closes the connection of the instance
function db.close()
db.con:close()
db.env:close()
end

-- Runs a query
-- @param query string: the query to be executed
-- @return table: a cursor
function db.query(query)
local cur = assert(db.con:execute(query))
if type(cur) == 'number' then
return cur
end
return db.fetch_row(cur)
end

-- Escapes a string or a table (its values). Should be used before concatenating strings on a query.
-- @param q string or table: the string or table to be escaped
-- @return string or nil: if q is a string, returns the new escaped string. If q is a table
-- it simply returns, since it already escaped the table's values
function db.escape(q)
if type(q) == "string" then
q = db.con:escape(q)
return q
elseif type(q) == "table" then
for k,v in pairs(q) do
q[k] = db.con:escape(v)
end
return
end
return q
end


--- Runs two queries and returns the result of the second query.
-- It is no longer in use. It was used by sailor.model to insert and obtain the last id.
-- It is now replaced by query_insert but it's still a valid method that could be used again.
-- @param q1 string: first query to be executed
-- @param q2 string: second query to be executed
-- return table: the result of the second execution
--[[function db.query_query(q1,q2)
local res
local rows = assert(db.con:execute(q1))
if rows == 0 then
res = 0
else
res = assert(db.con:execute(q2))
end
return res
end]]

--- Runs a query and returns the id of the last inserted row. Used for saving
-- a model and obtaining the model id.
-- @param query string: the query to be executed
-- return number or string: the id of the last inserted row.
function db.query_insert(query)
local id
if conf.driver == "postgresql" then
query = query .. "RETURNING uid; "
id = assert(db.con:execute(query))
else
query = query .. "; "
assert(db.con:execute(query))
id = db.con:getlastautoid()
end

return id
end

-- Reads the cursor information after reading from db and returns a table
function db.fetch_row(cur, res)
res = res or {}
local row = cur:fetch ({}, "a")

if not row then
cur:close()
return false
end

local types = cur:getcoltypes()
local names = cur:getcolnames()

for k,t in pairs(types) do
if t:find('number') then
row[names[k]] = tonumber(row[names[k]])
end
end

table.insert(res,row)
db.fetch_row(cur,res)

return res
end

return db
117 changes: 117 additions & 0 deletions src/sailor/db/resty_mysql.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
--------------------------------------------------------------------------------
-- db.lua, v0.1: DB module for connecting and querying through MySQL on openresty servers
-- This file is a part of Sailor project
-- Copyright (c) 2014 Etiene Dalcol <[email protected]>
-- License: MIT
-- http://sailorproject.org
--------------------------------------------------------------------------------

local main_conf = require "conf.conf"
local conf = main_conf.db[main_conf.sailor.environment]
local mysql = require "resty.mysql"

local db = {instance = nil}

local luasql = require("luasql."..conf.driver)

function db.instantiate()
if not db.instance then
local instance, err = mysql:new()
if not instance then
error("Failed to instantiate mysql: ".. err)
end
db.instance = instance
end
end
-- Creates the connection of the instance
function db.connect()
db.instantiate()
conf.host = string.gsub(conf.host, "localhost", "127.0.0.1")

local ok, err, errno, sqlstate = db.instance:connect{
host = conf.host,
port = 3306,
database = conf.dbname,
user = conf.user,
password = conf.pass,
max_packet_size = 1024 * 1024
}
if not ok then
error("Failed to connect to database: ".. err ..": ".. (errno or '') .." "..(sqlstate or ''))
end
end

-- Closes the connection of the instance
function db.close()
local ok, err = db.instance:close()
if not ok then
error("Failed to close database connection: ".. err)
end
db.instance = nil
end

-- Runs a query
-- @param query string: the query to be executed
-- @return table: a cursor
function db.query(query)
local res, err, errno, sqlstate = db.instance:query(query)
if not res then
error(query)
error("Bad result: ".. err ..": ".. (errno or '') .." "..(sqlstate or ''))
end
--if #res == 1 then res = res[1] end
return res
end

-- Escapes a string or a table (its values). Should be used before concatenating strings on a query.
-- @param q string or table: the string or table to be escaped
-- @return string or nil: if q is a string, returns the new escaped string. If q is a table
-- it simply returns, since it already escaped the table's values

function escape_string(s)
-- Based on luajson code
-- https://github.com/harningt/luajson/blob/master/lua/json/encode/strings.lua
local matches = {
['\\'] = '\\\\',
["\0"] = '\\0',
["\n"] = '\\n',
["\r"] = '\\r',
["'"] = "\\'",
['"'] = '\\"',
["\x1a"] = '\\Z'
}

for i = 0, 255 do
local c = string.char(i)
if c:match('[%z\1-\031\128-\255]') and not matches[c] then
matches[c] = ('\\x%.2X'):format(i)
end
end

return s:gsub('[\\"/%z\1-\031\128-\255]', matches)
end

function db.escape(q)
if type(q) == "string" then
q = escape_string(q)
return q
elseif type(q) == "table" then
for k,v in pairs(q) do
q[k] = escape_string(v)
end
return
end
return q
end

--- Runs a query and returns the id of the last inserted row. Used for saving
-- a model and obtaining the model id.
-- @param query string: the query to be executed
-- return number or string: the id of the last inserted row.
function db.query_insert(query)
local res = db.query(query)
return res.insert_id
end

return db

Loading

0 comments on commit 7e0bd06

Please sign in to comment.