add timestamp features, fix sqlite positional parameters
This commit is contained in:
parent
bf8ce59b73
commit
cf38b947e1
@ -55,6 +55,9 @@ var renderLuaCode string
|
|||||||
//go:embed lua/session.lua
|
//go:embed lua/session.lua
|
||||||
var sessionLuaCode string
|
var sessionLuaCode string
|
||||||
|
|
||||||
|
//go:embed lua/timestamp.lua
|
||||||
|
var timestampLuaCode string
|
||||||
|
|
||||||
// Module represents a Lua module to load
|
// Module represents a Lua module to load
|
||||||
type Module struct {
|
type Module struct {
|
||||||
name string
|
name string
|
||||||
@ -78,6 +81,7 @@ var modules = []Module{
|
|||||||
{"time", timeLuaCode, false},
|
{"time", timeLuaCode, false},
|
||||||
{"math", mathLuaCode, false},
|
{"math", mathLuaCode, false},
|
||||||
{"env", envLuaCode, true},
|
{"env", envLuaCode, true},
|
||||||
|
{"timestamp", timestampLuaCode, false},
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadModule loads a single module into the Lua state
|
// loadModule loads a single module into the Lua state
|
||||||
|
@ -18,7 +18,7 @@ function cookie_set(name, value, options)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function cookie_get(name)
|
function cookie_get(name)
|
||||||
return __ctx._request_cookies and __ctx._request_cookies[name]
|
return __ctx.cookies and __ctx.cookies[name]
|
||||||
end
|
end
|
||||||
|
|
||||||
function cookie_delete(name, path, domain)
|
function cookie_delete(name, path, domain)
|
||||||
|
93
runner/lua/timestamp.lua
Normal file
93
runner/lua/timestamp.lua
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
-- timestamp.lua
|
||||||
|
local timestamp = {}
|
||||||
|
|
||||||
|
-- Standard format presets using Lua format codes
|
||||||
|
local FORMATS = {
|
||||||
|
iso = "%Y-%m-%dT%H:%M:%SZ",
|
||||||
|
datetime = "%Y-%m-%d %H:%M:%S",
|
||||||
|
us_date = "%m/%d/%Y",
|
||||||
|
us_datetime = "%m/%d/%Y %I:%M:%S %p",
|
||||||
|
date = "%Y-%m-%d",
|
||||||
|
time = "%H:%M:%S",
|
||||||
|
time12 = "%I:%M:%S %p",
|
||||||
|
readable = "%B %d, %Y %I:%M:%S %p",
|
||||||
|
compact = "%Y%m%d_%H%M%S"
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Parse input to unix timestamp and microseconds
|
||||||
|
local function parse_input(input)
|
||||||
|
local unix_time, micros = 0, 0
|
||||||
|
|
||||||
|
if type(input) == "string" then
|
||||||
|
local frac, secs = input:match("^(0%.%d+)%s+(%d+)$")
|
||||||
|
if frac and secs then
|
||||||
|
unix_time = tonumber(secs)
|
||||||
|
micros = math.floor((tonumber(frac) * 1000000) + 0.5)
|
||||||
|
else
|
||||||
|
unix_time = tonumber(input) or 0
|
||||||
|
end
|
||||||
|
elseif type(input) == "number" then
|
||||||
|
unix_time = math.floor(input)
|
||||||
|
micros = math.floor(((input - unix_time) * 1000000) + 0.5)
|
||||||
|
end
|
||||||
|
|
||||||
|
return unix_time, micros
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove leading zeros from number string
|
||||||
|
local function no_leading_zero(s)
|
||||||
|
return s:gsub("^0+", "") or "0"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Main format function
|
||||||
|
function timestamp.format(input, fmt)
|
||||||
|
fmt = fmt or "datetime"
|
||||||
|
local format_str = FORMATS[fmt] or fmt
|
||||||
|
local unix_time, micros = parse_input(input)
|
||||||
|
local result = os.date(format_str, unix_time)
|
||||||
|
|
||||||
|
-- Handle microseconds if format contains dot
|
||||||
|
if format_str:find("%.") then
|
||||||
|
result = result .. string.format(".%06d", micros)
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- US date/time with no leading zeros
|
||||||
|
function timestamp.us_datetime_no_zero(input)
|
||||||
|
local unix_time, micros = parse_input(input)
|
||||||
|
local month = no_leading_zero(os.date("%m", unix_time))
|
||||||
|
local day = no_leading_zero(os.date("%d", unix_time))
|
||||||
|
local year = os.date("%Y", unix_time)
|
||||||
|
local hour = no_leading_zero(os.date("%I", unix_time))
|
||||||
|
local min = os.date("%M", unix_time)
|
||||||
|
local sec = os.date("%S", unix_time)
|
||||||
|
local ampm = os.date("%p", unix_time)
|
||||||
|
|
||||||
|
return string.format("%s/%s/%s %s:%s:%s %s", month, day, year, hour, min, sec, ampm)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Quick preset functions
|
||||||
|
function timestamp.iso(input) return timestamp.format(input, "iso") end
|
||||||
|
function timestamp.datetime(input) return timestamp.format(input, "datetime") end
|
||||||
|
function timestamp.us_date(input) return timestamp.format(input, "us_date") end
|
||||||
|
function timestamp.us_datetime(input) return timestamp.us_datetime_no_zero(input) end
|
||||||
|
function timestamp.date(input) return timestamp.format(input, "date") end
|
||||||
|
function timestamp.time(input) return timestamp.format(input, "time") end
|
||||||
|
function timestamp.time12(input) return timestamp.format(input, "time12") end
|
||||||
|
function timestamp.readable(input) return timestamp.format(input, "readable") end
|
||||||
|
|
||||||
|
-- Microsecond precision variants
|
||||||
|
function timestamp.datetime_micro(input)
|
||||||
|
return timestamp.format(input, "%Y-%m-%d %H:%M:%S.") .. string.format("%06d", select(2, parse_input(input)))
|
||||||
|
end
|
||||||
|
|
||||||
|
function timestamp.iso_micro(input)
|
||||||
|
return timestamp.format(input, "%Y-%m-%dT%H:%M:%S.") .. string.format("%06dZ", select(2, parse_input(input)))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Register global convenience function
|
||||||
|
_G.format_time = timestamp.format
|
||||||
|
|
||||||
|
return timestamp
|
@ -244,6 +244,28 @@ func setupParams(state *luajit.State, paramIndex int, execOpts *sqlitex.ExecOpti
|
|||||||
return fmt.Errorf("invalid parameters: %w", err)
|
return fmt.Errorf("invalid parameters: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle direct array types
|
||||||
|
if arrParams, ok := paramsAny.([]any); ok {
|
||||||
|
execOpts.Args = arrParams
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if strArr, ok := paramsAny.([]string); ok {
|
||||||
|
args := make([]any, len(strArr))
|
||||||
|
for i, v := range strArr {
|
||||||
|
args[i] = v
|
||||||
|
}
|
||||||
|
execOpts.Args = args
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if floatArr, ok := paramsAny.([]float64); ok {
|
||||||
|
args := make([]any, len(floatArr))
|
||||||
|
for i, v := range floatArr {
|
||||||
|
args[i] = v
|
||||||
|
}
|
||||||
|
execOpts.Args = args
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
params, ok := paramsAny.(map[string]any)
|
params, ok := paramsAny.(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unsupported parameter type: %T", paramsAny)
|
return fmt.Errorf("unsupported parameter type: %T", paramsAny)
|
||||||
|
@ -140,6 +140,13 @@ func (r *Runner) buildHTTPContext(ctx *fasthttp.RequestCtx, params *router.Param
|
|||||||
})
|
})
|
||||||
luaCtx.Set("headers", headers)
|
luaCtx.Set("headers", headers)
|
||||||
|
|
||||||
|
// Cookies
|
||||||
|
cookies := r.ctxPool.Get().(map[string]any)
|
||||||
|
ctx.Request.Header.VisitAllCookie(func(key, value []byte) {
|
||||||
|
cookies[string(key)] = string(value)
|
||||||
|
})
|
||||||
|
luaCtx.Set("cookies", cookies)
|
||||||
|
|
||||||
// Route parameters
|
// Route parameters
|
||||||
if params != nil && len(params.Keys) > 0 {
|
if params != nil && len(params.Keys) > 0 {
|
||||||
paramMap := r.paramsPool.Get().(map[string]any)
|
paramMap := r.paramsPool.Get().(map[string]any)
|
||||||
@ -187,8 +194,8 @@ func (r *Runner) buildHTTPContext(ctx *fasthttp.RequestCtx, params *router.Param
|
|||||||
return luaCtx
|
return luaCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Releases the HTTP context's maps back to their pool
|
||||||
func (r *Runner) releaseHTTPContext(luaCtx *Context) {
|
func (r *Runner) releaseHTTPContext(luaCtx *Context) {
|
||||||
// Return pooled maps
|
|
||||||
if headers, ok := luaCtx.Get("headers").(map[string]any); ok {
|
if headers, ok := luaCtx.Get("headers").(map[string]any); ok {
|
||||||
for k := range headers {
|
for k := range headers {
|
||||||
delete(headers, k)
|
delete(headers, k)
|
||||||
@ -196,6 +203,13 @@ func (r *Runner) releaseHTTPContext(luaCtx *Context) {
|
|||||||
r.ctxPool.Put(headers)
|
r.ctxPool.Put(headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cookies, ok := luaCtx.Get("cookies").(map[string]any); ok {
|
||||||
|
for k := range cookies {
|
||||||
|
delete(cookies, k)
|
||||||
|
}
|
||||||
|
r.ctxPool.Put(cookies)
|
||||||
|
}
|
||||||
|
|
||||||
if params, ok := luaCtx.Get("params").(map[string]any); ok && len(params) > 0 {
|
if params, ok := luaCtx.Get("params").(map[string]any); ok && len(params) > 0 {
|
||||||
for k := range params {
|
for k := range params {
|
||||||
delete(params, k)
|
delete(params, k)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user