local lpeg = require('lpeg') local etlua = require('etlua') local config = require("config") local args = {...} lpeg.locale(lpeg) local V,P,C,S,B,Cs = lpeg.V,lpeg.P,lpeg.C,lpeg.S,lpeg.B,lpeg.Cs --Identity function local ident = function(a) return a end --Lowercase and capitalize first letter local function capitalize(str) return string.lower(str):gsub("^(.)",string.upper) end --Trim whitespace local function trim(str) return str:match("^%s*(.-)%s*$") end --SQL like match anywhere local function like(str) return "%" .. str .. "%" end --Tags are always trimed of whitepsace, lowercase with first letter capitalized local function tag_fmt(str) return capitalize(trim(str)) end --Title match local function title_fmt(str) return like(trim(str)) end --Author names are all lowercase alphanumeric, max 30 characters local function author_fmt(str) return like(string.lower(trim(str))) end local fieldnames = { title = {name="title",type="string",fmt=title_fmt}, author = {name="author",type="string",fmt=author_fmt}, date = {name="date",type="number",fmt=tonumber}, hits = {name="hits",type="number",fmt=tonumber}, tags = {name="tag",type="string",fmt=tag_fmt}, } local field_default = "tag" local fields local grammar = P{ "chunk"; whitespace = S" \t\n"^0, itm = C((P(1 - (P" " * S"+-")))^0), --go until the next '+' or '-' likefield = C(P"title" + P"author") * V"whitespace" * C(P"=") * V"whitespace" * V"itm", rangeop = P"<=" + P">=" + P">" + P"<" + P"=", rangefield = C(P"date" + P"hits") * V"whitespace" * C(V"rangeop") * V"whitespace" * C(V"itm"), field = C(S"+-") * (V"likefield" + V"rangefield" + V"itm") / function(pn,field,expr,value) if expr and value then fields[field] = fields[field] or {} table.insert(fields[field],{pn,expr,value}) else fields.tags = fields.tags or {} table.insert(fields.tags,{pn,"=",field}) end end, chunk = V"field" * (P" " * V"field")^0 } --Grammar --Transpile a sting with + and - into an sql query that searches tags local fname = config.approot .. "pages/search_sql.etlua" local sqltmpl = assert(io.open(fname)) local c = etlua.compile(sqltmpl:read("*a"),fname) sqltmpl:close() local function transpile(str) str = string.lower(str) fields = {tags={}} table.concat({grammar:match(str)}," ") --Sanity perform formatting on data for field,values in pairs(fields) do for _,value in pairs(values) do local pn, expr, val = unpack(value) local nval = fieldnames[field].fmt(val) value[3] = nval end end local ressql = c{ result = fields } return ressql, fields end return transpile