diff --git a/src/launchers/orbit b/src/launchers/orbit index fac223e..726c5b7 100755 --- a/src/launchers/orbit +++ b/src/launchers/orbit @@ -56,7 +56,7 @@ if opts.l or opts.log then io.stdout = log io.stderr = log print = function (...) - local nargs = select('#', ...) + local nargs = select("#", ...) for i = 1, nargs-1 do log:write(tostring((select(i, ...)))) log:write("\t") @@ -91,16 +91,15 @@ if not app then app = _G[name:match("(.+)%.")] end if type(app) == "table" then app = app.run end xavante.httpd.handle_request = xavante.vhostshandler { - [""] = xavante.urlhandler { - ["/"] = wsx.makeHandler (app, nil, path, path), - } + [""] = xavante.urlhandler { + ["/"] = wsx.makeHandler (app, nil, path, path), + } } xavante.httpd.register ("*", tonumber(opts.p or opts.port) or 8080, "Xavante 2.0") xavante.start_message(function (ports) - print(string.format("Starting Orbit server at port %s", - table.concat(ports, ", "))) - end) + print(string.format("Starting Orbit server at port %s", table.concat(ports, ", "))) +end) xavante.start() diff --git a/src/orbit.lua b/src/orbit.lua index d445b76..1600a12 100644 --- a/src/orbit.lua +++ b/src/orbit.lua @@ -182,15 +182,17 @@ _M.web_methods = {} local web_methods = _M.web_methods local function flatten(t) - local res = {} - for _, item in ipairs(t) do - if type(item) == "table" then - res[#res + 1] = flatten(item) - else - res[#res + 1] = item - end - end - return table.concat(res) + local res = {} + + for _, item in ipairs(t) do + if type(item) == "table" then + res[#res + 1] = flatten(item) + else + res[#res + 1] = item + end + end + + return table.concat(res) end local function make_tag(name, data, class) @@ -198,8 +200,7 @@ local function make_tag(name, data, class) if not data then return "<" .. name .. class .. "/>" elseif type(data) == "string" then - return "<" .. name .. class .. ">" .. data .. - "" .. name .. ">" + return "<" .. name .. class .. ">" .. data .. "" .. name .. ">" else local attrs = {} for k, v in pairs(data) do @@ -207,77 +208,79 @@ local function make_tag(name, data, class) table.insert(attrs, k .. '="' .. tostring(v) .. '"') end end - local open_tag = "<" .. name .. class .. " " .. - table.concat(attrs, " ") .. ">" + local open_tag = "<" .. name .. class .. " " .. table.concat(attrs, " ") .. ">" local close_tag = "" .. name .. ">" - return open_tag .. flatten(data) .. close_tag - end + return open_tag .. flatten(data) .. close_tag + end end function _M.new(app_module) - if type(app_module) == "string" then - app_module = { _NAME = app_module } - else - app_module = app_module or {} - end - for k, v in pairs(app_module_methods) do - app_module[k] = v - end - app_module.run = function (wsapi_env) - return _M.run(app_module, wsapi_env) - end - app_module.real_path = wsapi.app_path or "." - app_module.mapper = { default = true } - app_module.not_found = function (web) - web.status = "404 Not Found" - return [[ -
Not found!
]] - end - app_module.server_error = function (web, msg) - web.status = "500 Server Error" - return [[ -]] .. msg .. [[]] - end - app_module.reparse = REPARSE - app_module.dispatch_table = { get = {}, post = {}, put = {}, delete = {} } - return app_module + if type(app_module) == "string" then + app_module = { _NAME = app_module } + else + app_module = app_module or {} + end + + for k, v in pairs(app_module_methods) do + app_module[k] = v + end + + app_module.run = function (wsapi_env) + return _M.run(app_module, wsapi_env) + end + + app_module.real_path = wsapi.app_path or "." + app_module.mapper = { default = true } + app_module.not_found = function (web) + web.status = "404 Not Found" + return [[
Not found!
]] + end + + app_module.server_error = function (web, msg) + web.status = "500 Server Error" + return [[]] .. msg .. [[]] + end + + app_module.reparse = REPARSE + app_module.dispatch_table = { + get = {}, + post = {}, + put = {}, + delete = {} + } + + return app_module end local function serve_file(app_module) - return function (web) - local filename = web.real_path .. web.path_info - return app_module:serve_static(web, filename) - end + return function (web) + local filename = web.real_path .. web.path_info + return app_module:serve_static(web, filename) + end end function app_module_methods.dispatch_get(app_module, func, ...) - for _, pat in ipairs{ ... } do - table.insert(app_module.dispatch_table.get, { pattern = pat, - handler = func }) - end + for _, pat in ipairs{ ... } do + table.insert(app_module.dispatch_table.get, { pattern = pat, handler = func }) + end end function app_module_methods.dispatch_post(app_module, func, ...) - for _, pat in ipairs{ ... } do - table.insert(app_module.dispatch_table.post, { pattern = pat, - handler = func }) - end + for _, pat in ipairs{ ... } do + table.insert(app_module.dispatch_table.post, { pattern = pat, handler = func }) + end end function app_module_methods.dispatch_put(app_module, func, ...) - for _, pat in ipairs{ ... } do - table.insert(app_module.dispatch_table.put, { pattern = pat, - handler = func }) - end + for _, pat in ipairs{ ... } do + table.insert(app_module.dispatch_table.put, { pattern = pat, handler = func }) + end end function app_module_methods.dispatch_delete(app_module, func, ...) - for _, pat in ipairs{ ... } do - table.insert(app_module.dispatch_table.delete, { pattern = pat, - handler = func }) - end + for _, pat in ipairs{ ... } do + table.insert(app_module.dispatch_table.delete, { pattern = pat, handler = func }) + end end function app_module_methods.dispatch_wsapi(app_module, func, ...) @@ -289,104 +292,107 @@ function app_module_methods.dispatch_wsapi(app_module, func, ...) end function app_module_methods.dispatch_static(app_module, ...) - app_module:dispatch_get(serve_file(app_module), ...) + app_module:dispatch_get(serve_file(app_module), ...) end function app_module_methods.serve_static(app_module, web, filename) - local ext = string.match(filename, "%.([^%.]+)$") - if app_module.use_xsendfile then - web.headers["Content-Type"] = _M.mime_types[ext] or - "application/octet-stream" - web.headers["X-Sendfile"] = filename - return "xsendfile" - else - local file = io.open(filename, "rb") - if not file then - return app_module.not_found(web) - else - web.headers["Content-Type"] = _M.mime_types[ext] or - "application/octet-stream" - local contents = file:read("*a") - file:close() - return contents - end - end + local ext = string.match(filename, "%.([^%.]+)$") + if app_module.use_xsendfile then + web.headers["Content-Type"] = _M.mime_types[ext] or "application/octet-stream" + web.headers["X-Sendfile"] = filename + return "xsendfile" + else + local file = io.open(filename, "rb") + if not file then + return app_module.not_found(web) + else + web.headers["Content-Type"] = _M.mime_types[ext] or "application/octet-stream" + local contents = file:read("*a") + file:close() + return contents + end + end end local function newtag(name) local tag = {} setmetatable(tag, { - __call = function (_, data) - return make_tag(name, data) - end, - __index = function(_, class) - return function (data) - return make_tag(name, data, class) - end - end - }) + __call = function (_, data) + return make_tag(name, data) + end, + __index = function (_, class) + return function (data) + return make_tag(name, data, class) + end + end + }) return tag end local function htmlify_func(func) local tags = {} - local env = { H = function (name) - local tag = tags[name] - if not tag then - tag = newtag(name) - tags[name] = tag - end - return tag - end - } + + local env = { + H = function (name) + local tag = tags[name] + if not tag then + tag = newtag(name) + tags[name] = tag + end + return tag + end + } + local old_env = getfenv(func) - setmetatable(env, { __index = function (env, name) - if old_env[name] then - return old_env[name] - else - local tag = newtag(name) - rawset(env, name, tag) - return tag - end - end }) + setmetatable(env, { + __index = function (env, name) + if old_env[name] then + return old_env[name] + else + local tag = newtag(name) + rawset(env, name, tag) + return tag + end + end + }) + setfenv(func, env) end function _M.htmlify(app_module, ...) - if type(app_module) == "function" then - htmlify_func(app_module) - for _, func in ipairs{...} do - htmlify_func(func) - end - else - local patterns = { ... } - for _, patt in ipairs(patterns) do - if type(patt) == "function" then - htmlify_func(patt) - else - for name, func in pairs(app_module) do - if string.match(name, "^" .. patt .. "$") and - type(func) == "function" then - htmlify_func(func) - end - end - end + if type(app_module) == "function" then + htmlify_func(app_module) + for _, func in ipairs{...} do + htmlify_func(func) + end + else + local patterns = { ... } + for _, patt in ipairs(patterns) do + if type(patt) == "function" then + htmlify_func(patt) + else + for name, func in pairs(app_module) do + if string.match(name, "^" .. patt .. "$") and type(func) == "function" then + htmlify_func(func) + end + end end - end + end + end end app_module_methods.htmlify = _M.htmlify function app_module_methods.model(app_module, ...) - if app_module.mapper.default then - local table_prefix = (app_module._NAME and app_module._NAME .. "_") or "" - if not orm then - orm = require "orbit.model" - end - app_module.mapper = orm.new(app_module.mapper.table_prefix or table_prefix, - app_module.mapper.conn, app_module.mapper.driver, app_module.mapper.logging) - end - return app_module.mapper:new(...) + if app_module.mapper.default then + local table_prefix = (app_module._NAME and app_module._NAME .. "_") or "" + if not orm then + orm = require "orbit.model" + end + app_module.mapper = orm.new(app_module.mapper.table_prefix or table_prefix, app_module.mapper.conn, app_module.mapper.driver, app_module.mapper.logging) + end + + return app_module.mapper:new(...) end function web_methods:redirect(url) @@ -458,8 +464,8 @@ end for name, func in pairs(wsutil) do web_methods[name] = function (self, ...) - return func(...) - end + return func(...) + end end local function dispatcher(app_module, method, path, index) @@ -471,27 +477,34 @@ local function dispatcher(app_module, method, path, index) local item = app_module.dispatch_table[method][index] local captures if type(item.pattern) == "string" then - captures = { string.match(path, "^" .. item.pattern .. "$") } + captures = { string.match(path, "^" .. item.pattern .. "$") } else - captures = { item.pattern:match(path) } + captures = { item.pattern:match(path) } end if #captures > 0 then - for i = 1, #captures do - if type(captures[i]) == "string" then - captures[i] = wsutil.url_decode(captures[i]) - end - end - return item.handler, captures, item.wsapi, index + for i = 1, #captures do + if type(captures[i]) == "string" then + captures[i] = wsutil.url_decode(captures[i]) + end + end + return item.handler, captures, item.wsapi, index end end end end local function make_web_object(app_module, wsapi_env) - local web = { status = "200 Ok", response = "", - headers = { ["Content-Type"]= "text/html" }, - cookies = {} } + local web = { + status = "200 Ok", + response = "", + headers = { + ["Content-Type"] = "text/html" + }, + cookies = {} + } + setmetatable(web, { __index = web_methods }) + web.vars = wsapi_env web.prefix = app_module.prefix or wsapi_env.SCRIPT_NAME web.suffix = app_module.suffix @@ -504,11 +517,11 @@ local function make_web_object(app_module, wsapi_env) local req = wsreq.new(wsapi_env) local res = wsres.new(web.status, web.headers) web.set_cookie = function (_, name, value) - res:set_cookie(name, value) - end + res:set_cookie(name, value) + end web.delete_cookie = function (_, name, path) - res:delete_cookie(name, path) - end + res:delete_cookie(name, path) + end web.path_info = req.path_info web.path_translated = wsapi_env.PATH_TRANSLATED if web.path_translated == "" then web.path_translated = wsapi_env.SCRIPT_FILENAME end @@ -520,15 +533,14 @@ local function make_web_object(app_module, wsapi_env) end function _M.run(app_module, wsapi_env) - local handler, captures, wsapi_handler, index = dispatcher(app_module, - string.lower(wsapi_env.REQUEST_METHOD), - wsapi_env.PATH_INFO) + local handler, captures, wsapi_handler, index = dispatcher(app_module, string.lower(wsapi_env.REQUEST_METHOD), wsapi_env.PATH_INFO) handler = handler or app_module.not_found captures = captures or {} if wsapi_handler then - local ok, status, headers, res = xpcall(function () - return handler(wsapi_env, unpack(captures)) - end, debug.traceback) + local ok, status, headers, res = xpcall( + function () return handler(wsapi_env, unpack(captures)) end, + debug.traceback + ) if ok then return status, headers, res else @@ -538,25 +550,24 @@ function _M.run(app_module, wsapi_env) local web, res = make_web_object(app_module, wsapi_env) repeat local reparse = false - local ok, response = xpcall(function () - return handler(web, unpack(captures)) - end, function(msg) return debug.traceback(msg) end) + local ok, response = xpcall( + function () return handler(web, unpack(captures)) end, + function (msg) return debug.traceback(msg) end + ) if not ok then res.status = "500 Internal Server Error" res:write(app_module.server_error(web, response)) else if response == REPARSE then - reparse = true - handler, captures, wsapi_handler, index = dispatcher(app_module, - string.lower(wsapi_env.REQUEST_METHOD), - wsapi_env.PATH_INFO, index) - handler, captures = handler or app_module.not_found, captures or {} - if wsapi_handler then - error("cannot reparse to WSAPI handler") - end + reparse = true + handler, captures, wsapi_handler, index = dispatcher(app_module, string.lower(wsapi_env.REQUEST_METHOD), wsapi_env.PATH_INFO, index) + handler, captures = handler or app_module.not_found, captures or {} + if wsapi_handler then + error("Cannot reparse to WSAPI handler") + end else - res.status = web.status - res:write(response) + res.status = web.status + res:write(response) end end until not reparse @@ -564,4 +575,3 @@ function _M.run(app_module, wsapi_env) end return _M - diff --git a/src/orbit/cache.lua b/src/orbit/cache.lua index 83017c2..a9ab85b 100644 --- a/src/orbit/cache.lua +++ b/src/orbit/cache.lua @@ -3,116 +3,120 @@ local lfs = require "lfs" module("orbit.cache", package.seeall) local function pathinfo_to_file(path_info) - local atom = path_info:find("/xml$") - if atom then - path_info = path_info:sub(2, atom - 1) - else - path_info = path_info:sub(2, #path_info) - end - path_info = string.gsub(path_info, "/", "-") - if path_info == "" then path_info = "index" end - if atom then - return path_info .. '.xml' - else - return path_info .. '.html' - end + local atom = path_info:find("/xml$") + if atom then + path_info = path_info:sub(2, atom - 1) + else + path_info = path_info:sub(2, #path_info) + end + path_info = string.gsub(path_info, "/", "-") + if path_info == "" then path_info = "index" end + if atom then + return path_info .. ".xml" + else + return path_info .. ".html" + end end function get(cache, key) if not cache.base_path then - local headers = {} - if key:find("/xml$") then - headers["Content-Type"] = "text/xml" - else - headers["Content-Type"] = "text/html" - end - return cache.values[key], headers + local headers = {} + if key:find("/xml$") then + headers["Content-Type"] = "text/xml" + else + headers["Content-Type"] = "text/html" + end + return cache.values[key], headers else - local filename = cache.base_path .. "/" .. pathinfo_to_file(key) - local web = { headers = {} } - if lfs.attributes(filename, "mode") == "file" then - local response = cache.app:serve_static(web, filename) - return response, web.headers - end + local filename = cache.base_path .. "/" .. pathinfo_to_file(key) + local web = { + headers = {} + } + if lfs.attributes(filename, "mode") == "file" then + local response = cache.app:serve_static(web, filename) + return response, web.headers + end end end local function writefile(filename, contents) local file = assert(io.open(filename, "wb")) if lfs.lock(file, "w") then - file:write(contents) - lfs.unlock(file) - file:close() + file:write(contents) + lfs.unlock(file) + file:close() else - file:close() + file:close() end end function set(cache, key, value) if not cache.base_path then - cache.values[key] = value + cache.values[key] = value else - local filename = cache.base_path .. "/" .. pathinfo_to_file(key) - writefile(filename, value) + local filename = cache.base_path .. "/" .. pathinfo_to_file(key) + writefile(filename, value) end end local function cached(cache, f) return function (web, ...) - local body, headers = cache:get(web.path_info) - if body then - for k, v in pairs(headers) do - web.headers[k] = v - end - return body - else - local key = web.path_info - local body = f(web, ...) - cache:set(key, body) - return body - end - end + local body, headers = cache:get(web.path_info) + if body then + for k, v in pairs(headers) do + web.headers[k] = v + end + return body + else + local key = web.path_info + local body = f(web, ...) + cache:set(key, body) + return body + end + end end function invalidate(cache, ...) - for _, key in ipairs{...} do - if not cache.base_path then - cache.values[key] = nil - else - local filename = cache.base_path .. "/" .. pathinfo_to_file(key) - os.remove(filename) - end - end + for _, key in ipairs{...} do + if not cache.base_path then + cache.values[key] = nil + else + local filename = cache.base_path .. "/" .. pathinfo_to_file(key) + os.remove(filename) + end + end end function nuke(cache) - if not cache.base_path then - cache.values = {} - else - for file in lfs.dir(cache.base_path) do - if file ~= "." and file ~= ".." then - os.remove(cache.base_path .. "/" .. file) - end + if not cache.base_path then + cache.values = {} + else + for file in lfs.dir(cache.base_path) do + if file ~= "." and file ~= ".." then + os.remove(cache.base_path .. "/" .. file) end - end + end + end end function new(app, base_path) - local values - if not base_path then - values = {} - else - local dir = lfs.attributes(base_path, "mode") - if not dir then - assert(lfs.mkdir(base_path)) - elseif dir ~= "directory" then - error("base path of cache " .. base_path .. " not a directory") - end - end - local cache = { app = app, values = values, - base_path = base_path } - setmetatable(cache, { __index = _M, __call = function (tab, f) - return cached(tab, f) - end }) - return cache + local values + if not base_path then + values = {} + else + local dir = lfs.attributes(base_path, "mode") + if not dir then + assert(lfs.mkdir(base_path)) + elseif dir ~= "directory" then + error("base path of cache " .. base_path .. " not a directory") + end + end + local cache = { app = app, values = values, base_path = base_path } + setmetatable(cache, { + __index = _M, + __call = function(tab, f) + return cached(tab, f) + end + }) + return cache end diff --git a/src/orbit/model.lua b/src/orbit/model.lua index 0d86eae..94b8266 100644 --- a/src/orbit/model.lua +++ b/src/orbit/model.lua @@ -79,7 +79,7 @@ function convert.boolean(v, driver) elseif driver == "postgres" then return v == "t" else - error("driver not supported") + error("Driver not supported") end end @@ -90,9 +90,14 @@ end function convert.datetime(v) local year, month, day, hour, min, sec = string.match(v, "(%d+)%-(%d+)%-(%d+) (%d+):(%d+):(%d+)") - return os.time({ year = tonumber(year), month = tonumber(month), - day = tonumber(day), hour = tonumber(hour), - min = tonumber(min), sec = tonumber(sec) }) + return os.time({ + year = tonumber(year), + month = tonumber(month), + day = tonumber(day), + hour = tonumber(hour), + min = tonumber(min), + sec = tonumber(sec) + }) end convert.timestamp = convert.datetime @@ -103,7 +108,7 @@ local function convert_types(row, meta, driver) if conv then row[k] = conv(v, driver) else - error("no conversion for type " .. meta[k].type) + error("No conversion for type " .. meta[k].type) end end end @@ -172,9 +177,9 @@ local function escape_values(row) else local esc = escape[m.type] if esc then - row_escaped[m.name] = esc(row[m.name], row.driver, row.model.conn) + row_escaped[m.name] = esc(row[m.name], row.driver, row.model.conn) else - error("no escape function for type " .. m.type) + error("No escape function for type " .. m.type) end end end @@ -227,7 +232,7 @@ local function parse_condition(dao, condition, args) elseif type(args[j]) == "table" then local values = {} for _, value in ipairs(args[j]) do - values[#values + 1] = escape[dao.meta[part].type](value, dao.driver, dao.model.conn) + values[#values + 1] = escape[dao.meta[part].type](value, dao.driver, dao.model.conn) end parts[i] = part .. " IN (" .. table.concat(values,", ") .. ")" else @@ -242,48 +247,46 @@ end local function build_inject(project, inject, dao) local fields = {} if project then - for i, field in ipairs(project) do - fields[i] = dao.table_name .. "." .. field .. " as " .. field - end + for i, field in ipairs(project) do + fields[i] = dao.table_name .. "." .. field .. " AS " .. field + end else - for i, field in ipairs(dao.meta) do - fields[i] = dao.table_name .. "." .. field.name .. " as " .. field.name - end + for i, field in ipairs(dao.meta) do + fields[i] = dao.table_name .. "." .. field.name .. " AS " .. field.name + end end local inject_fields = {} local model = inject.model for _, field in ipairs(inject.fields) do - inject_fields[model.name .. "_" .. field] = - model.meta[field] - fields[#fields + 1] = model.table_name .. "." .. field .. " as " .. - model.name .. "_" .. field + inject_fields[model.name .. "_" .. field] = model.meta[field] + fields[#fields + 1] = model.table_name .. "." .. field .. " AS " .. model.name .. "_" .. field end setmetatable(dao.meta, { __index = inject_fields }) - return table.concat(fields, ", "), dao.table_name .. ", " .. - model.table_name, model.name .. "_id = " .. model.table_name .. ".id" + return table.concat(fields, ", "), dao.table_name .. ", " .. model.table_name, model.name .. "_id = " .. model.table_name .. ".id" end local function build_query_by(dao, condition, args) local parts = parse_condition(dao, condition, args) local order = "" local field_list, table_list, select, limit - if args.distinct then select = "select distinct " else select = "select " end - if tonumber(args.count) then limit = " limit " .. tonumber(args.count) else limit = "" end - if args.order then order = " order by " .. args.order end + if args.distinct then select = "SELECT DISTINCT " else select = "SELECT " end + if tonumber(args.count) then limit = " LIMIT " .. tonumber(args.count) else limit = "" end + if args.order then order = " ORDER BY " .. args.order end if args.inject then - if #parts > 0 then parts[#parts + 1] = "and" end - field_list, table_list, parts[#parts + 1] = build_inject(args.fields, args.inject, - dao) + if #parts > 0 then + parts[#parts + 1] = "AND" + end + field_list, table_list, parts[#parts + 1] = build_inject(args.fields, args.inject, dao) + else if args.fields then - field_list = table.concat(args.fields, ", ") + field_list = table.concat(args.fields, ", ") else - field_list = "*" + field_list = "*" end table_list = dao.table_name end - local sql = select .. field_list .. " from " .. table_list .. - " where " .. table.concat(parts, " ") .. order .. limit + local sql = select .. field_list .. " FROM " .. table_list .. " WHERE " .. table.concat(pairs, " ") .. order .. limit if dao.model.logging then log_query(sql) end return sql end @@ -315,18 +318,19 @@ end function model_methods:new(name, dao) dao = dao or {} - dao.model, dao.name, dao.table_name, dao.meta, dao.driver = self, name, - self.table_prefix .. name, {}, self.driver + dao.model, dao.name, dao.table_name, dao.meta, dao.driver = self, name, self.table_prefix .. name, {}, self.driver setmetatable(dao, { __index = dao_index }) - local sql = "select * from " .. dao.table_name .. " limit 0" + local sql = "SELECT * FROM " .. dao.table_name .. " LIMIT 0" if self.logging then log_query(sql) end local cursor, err = self.conn:execute(sql) if not cursor then error(err) end local names, types = cursor:getcolnames(), cursor:getcoltypes() cursor:close() for i = 1, #names do - local colinfo = { name = names[i], - type = type_names[self.driver](types[i]) } + local colinfo = { + name = names[i], + type = type_names[self.driver](types[i]) + } dao.meta[i] = colinfo dao.meta[colinfo.name] = colinfo end @@ -337,23 +341,30 @@ function recycle(fresh_conn, timeout) local created_at = os.time() local conn = fresh_conn() timeout = timeout or 20000 - return setmetatable({}, { __index = function (tab, meth) - tab[meth] = function (tab, ...) - if created_at + timeout < os.time() then - created_at = os.time() - pcall(conn.close, conn) - conn = fresh_conn() - end - return conn[meth](conn, ...) - end - return tab[meth] - end - }) + return setmetatable({}, { + __index = function (tab, meth) + tab[meth] = function (tab, ...) + if created_at + timeout < os.time() then + created_at = os.time() + pcall(conn.close, conn) + conn = fresh_conn() + end + return conn[meth](conn, ...) + end + return tab[meth] + end + }) end function new(table_prefix, conn, driver, logging) driver = driver or "sqlite3" - local app_model = { table_prefix = table_prefix or "", conn = conn, driver = driver or "sqlite3", logging = logging, models = {} } + local app_model = { + table_prefix = table_prefix or "", + conn = conn, + driver = driver or "sqlite3", + logging = logging, + models = {} + } setmetatable(app_model, { __index = model_methods }) return app_model end @@ -362,22 +373,20 @@ function dao_methods.find(dao, id, inject) if not type(id) == "number" then error("find error: id must be a number") end - local sql = "select * from " .. dao.table_name .. - " where id=" .. id + local sql = "SELECT * FROM " .. dao.table_name .. " WHERE id=" .. id if dao.logging then log_query(sql) end return fetch_row(dao, sql) end condition_parser = re.compile([[ - top <- {~
Not found!
]] + web.status = 404 + return "Not found!
" end end diff --git a/src/orbit/routes.lua b/src/orbit/routes.lua index f0e597d..3882854 100644 --- a/src/orbit/routes.lua +++ b/src/orbit/routes.lua @@ -6,50 +6,48 @@ local util = require "wsapi.util" local _M = {} -local alpha = lpeg.R('AZ', 'az') -local number = lpeg.R('09') -local asterisk = lpeg.P('*') -local question_mark = lpeg.P('?') -local at_sign = lpeg.P('@') -local colon = lpeg.P(':') -local the_dot = lpeg.P('.') -local underscore = lpeg.P('_') -local forward_slash = lpeg.P('/') +local alpha = lpeg.R("AZ", "az") +local number = lpeg.R("09") +local asterisk = lpeg.P("*") +local question_mark = lpeg.P("?") +local at_sign = lpeg.P("@") +local colon = lpeg.P(":") +local the_dot = lpeg.P(".") +local underscore = lpeg.P("_") +local forward_slash = lpeg.P("/") local slash_or_dot = forward_slash + the_dot local function cap_param(prefix, name, dot) - local inner = (1 - lpeg.S('/' .. (dot or '')))^1 - local close = lpeg.P'/' + (dot or -1) + -1 - return { - cap = lpeg.Carg(1) * slash_or_dot * lpeg.C(inner^1) * #close / function (params, item, delim) params[name] = util.url_decode(item) end, - clean = slash_or_dot * inner^1 * #close, - tag = "param", - name = name, - prefix = prefix - } + local inner = (1 - lpeg.S("/" .. (dot or "")))^1 + local close = lpeg.P"/" + (dot or -1) + -1 + return { + cap = lpeg.Carg(1) * slash_or_dot * lpeg.C(inner^1) * #close / function (params, item, delim) params[name] = util.url_decode(item) end, + clean = slash_or_dot * inner^1 * #close, + tag = "param", + name = name, + prefix = prefix + } end local param_pre = lpeg.C(slash_or_dot) * colon * lpeg.C((alpha + number + underscore)^1) -local param = (param_pre * #(forward_slash + -1) / cap_param) + - (param_pre * #the_dot / function (prefix, name) return cap_param(prefix, name, ".") end) +local param = (param_pre * #(forward_slash + -1) / cap_param) + (param_pre * #the_dot / function (prefix, name) return cap_param(prefix, name, ".") end) local function cap_opt_param(prefix, name, dot) - local inner = (1 - lpeg.S('/' .. (dot or '')))^1 - local close = lpeg.P('/') + lpeg.P(dot or -1) + -1 - return { - cap = (lpeg.Carg(1) * slash_or_dot * lpeg.C(inner) * #close / function (params, item, delim) params[name] = util.url_decode(item) end)^-1, - clean = (slash_or_dot * inner * #lpeg.C(close))^-1, - tag = "opt", - name = name, - prefix = prefix - } + local inner = (1 - lpeg.S("/" .. (dot or "")))^1 + local close = lpeg.P("/") + lpeg.P(dot or -1) + -1 + return { + cap = (lpeg.Carg(1) * slash_or_dot * lpeg.C(inner) * #close / function (params, item, delim) params[name] = util.url_decode(item) end)^-1, + clean = (slash_or_dot * inner * #lpeg.C(close))^-1, + tag = "opt", + name = name, + prefix = prefix + } end local opt_param_pre = lpeg.C(slash_or_dot) * question_mark * colon * lpeg.C((alpha + number + underscore)^1) * question_mark -local opt_param = (opt_param_pre * #(forward_slash + -1) / cap_opt_param) + - (opt_param_pre * #the_dot / function (prefix, name) return cap_opt_param(prefix, name, ".") end) +local opt_param = (opt_param_pre * #(forward_slash + -1) / cap_opt_param) + (opt_param_pre * #the_dot / function (prefix, name) return cap_opt_param(prefix, name, ".") end) local splat = lpeg.P(lpeg.C(forward_slash + the_dot) * asterisk * #(forward_slash + the_dot + -1)) / function (prefix) @@ -73,13 +71,13 @@ local function fold_captures(cap, acc) -- if we have a star match (match everything) if cap.cap == "*" then return { - cap = (lpeg.Carg(1) * (cap.prefix * lpeg.C((1 - acc.clean)^0))^-1 / - function (params, splat) - params.splat = params.splat or {} - if splat and splat ~= "" then - params.splat[#params.splat+1] = util.url_decode(splat) - end - end) * acc.cap, + cap = (lpeg.Carg(1) * (cap.prefix * lpeg.C((1 - acc.clean)^0))^-1 / + function (params, splat) + params.splat = params.splat or {} + if splat and splat ~= "" then + params.splat[#params.splat+1] = util.url_decode(splat) + end + end) * acc.cap, clean = (cap.prefix * (1 - acc.clean)^0)^-1 * acc.clean } end @@ -91,7 +89,7 @@ local function fold_captures(cap, acc) end local function fold_parts(parts, cap) - + if type(cap) == "string" then -- if the capture is a string parts[#parts+1] = { tag = "text", @@ -125,7 +123,7 @@ local function fold_left(t, f, acc) end local route = lpeg.Ct((param + opt_param + splat + rest)^0 * -1) / function (caps) - local forward_slash_at_end = lpeg.P('/')^-1 * -1 + local forward_slash_at_end = lpeg.P("/")^-1 * -1 return fold_right(caps, fold_captures, { cap = forward_slash_at_end, clean = forward_slash_at_end }), fold_left(caps, fold_parts, {}) end @@ -134,17 +132,17 @@ local function build(parts, params) params = params or {} params.splat = params.splat or {} for _, part in ipairs(parts) do - if part.tag == 'param' then - if not params[part.name] then error('route parameter ' .. part.name .. ' does not exist') end - local s = string.gsub (params[part.name], '([^%.@]+)', function (s) return util.url_encode(s) end) + if part.tag == "param" then + if not params[part.name] then error("route parameter " .. part.name .. " does not exist") end + local s = string.gsub (params[part.name], "([^%.@]+)", function (s) return util.url_encode(s) end) res[#res+1] = part.prefix .. s elseif part.tag == "splat" then - local s = string.gsub (params.splat[i] or '', '([^/%.@]+)', function (s) return util.url_encode(s) end) + local s = string.gsub (params.splat[i] or "", "([^/%.@]+)", function (s) return util.url_encode(s) end) res[#res+1] = part.prefix .. s i = i + 1 elseif part.tag == "opt" then if params and params[part.name] then - local s = string.gsub (params[part.name], '([^%.@]+)', function (s) return util.url_encode(s) end) + local s = string.gsub (params[part.name], "([^%.@]+)", function (s) return util.url_encode(s) end) res[#res+1] = part.prefix .. s end else @@ -155,13 +153,13 @@ local function build(parts, params) if #res > 0 then return table.concat(res) end - - return '/' + + return "/" end function _M.R(path) local p, b = route:match(path) - + return setmetatable({ parser = p.cap, parts = b