Skip to content

Commit

Permalink
⚡️ ENH: support more parser syntax (#77)
Browse files Browse the repository at this point in the history
* ⚡️ ENH: select to support computed/custom fields `keys/select = { var = julianday("timestamp") }`
* ⚡️ ENH: greater than/less than support in where `where = { date = "> " .. 1000 }/where = { {"date", "> ", 1000} }`
  • Loading branch information
kkharji authored Aug 16, 2021
1 parent 2f87189 commit 47a11e3
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 6 deletions.
37 changes: 31 additions & 6 deletions lua/sql/parser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ local bind = function(o)
k = o.k ~= nil and o.k or k
v = M.sqlvalue(v)
v = o.nonbind and ":" .. k or v
tinsert(res, string.format("%s" .. (o.nonbind and nil or " = ") .. specifier(v, o.nonbind), k, v))
tinsert(res, ("%s" .. (o.nonbind and nil or " = ") .. specifier(v, o.nonbind)):format(k, v))
end
return tconcat(res, o.s)
end
Expand Down Expand Up @@ -145,17 +145,24 @@ local pwhere = function(defs, name, join, contains)
k = join and name .. "." .. k or k

if type(v) ~= "table" then
tinsert(where, bind { v = v, k = k, s = " and " })
if type(v) == "string" and (v:sub(1, 1) == "<" or v:sub(1, 1) == ">") then
tinsert(where, k .. " " .. v)
else
tinsert(where, bind { v = v, k = k, s = " and " })
end
else
tinsert(where, "(" .. bind { kv = v, k = k, s = " or " } .. ")")
if type(k) == "number" then
tinsert(where, table.concat(v, " "))
else
tinsert(where, "(" .. bind { kv = v, k = k, s = " or " } .. ")")
end
end
end
end

if contains then
tinsert(where, pcontains(contains))
end

return ("where %s"):format(tconcat(where, " and "))
end

Expand Down Expand Up @@ -249,15 +256,33 @@ local partial = function(method, tbl, opts)
)
end

local pselect = function(select)
local t = type(select)

if t == "table" and next(select) ~= nil then
local items = {}
for k, v in pairs(select) do
if type(k) == "number" then
tinsert(items, v)
else
tinsert(items, ("%s as %s"):format(v, k))
end
end

return tconcat(items, ", ")
end

return t == "string" and select or "*"
end

---Parse select statement to extracts data from a database
---@param tbl string: table name
---@param opts table: lists of options: valid{ select, join, order_by, limit, where }
---@return string: the select sql statement.
M.select = function(tbl, opts)
opts = opts or {}
local cmd = opts.unique and "select distinct %s" or "select %s"
local t = type(opts.select)
local select = t == "string" and opts.select or (t == "table" and tconcat(opts.select, ", ") or "*")
local select = pselect(opts.select)
local stmt = (cmd .. " from %s"):format(select, tbl)
local method = opts.join and stmt .. " " .. pjoin(opts.join, tbl) or stmt
return partial(method, tbl, opts)
Expand Down
7 changes: 7 additions & 0 deletions test/auto/parser_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ describe("parse", function()
local pselect = p.select(tbl, { where = where })
eq(eselect, pselect, "It should be identical")
end)
it("concat list and pass it as query", function()
local where = { { "date", "<", 2021 } }
local where = { date = "< 2021" }
local eselect = [[select * from todo where date < 2021]]
local pselect = p.select(tbl, { where = where })
eq(eselect, pselect)
end)
end)

describe("[set]", function()
Expand Down

0 comments on commit 47a11e3

Please sign in to comment.