jbe/bsw@0: #!/usr/bin/env lua jbe/bsw@0: jbe/bsw@0: local _G = _G jbe/bsw@0: local _VERSION = _VERSION jbe/bsw@0: local assert = assert jbe/bsw@0: local error = error jbe/bsw@0: local getmetatable = getmetatable jbe/bsw@0: local ipairs = ipairs jbe/bsw@0: local next = next jbe/bsw@0: local pairs = pairs jbe/bsw@0: local print = print jbe/bsw@0: local rawequal = rawequal jbe/bsw@0: local rawget = rawget jbe@64: local rawlen = rawlen jbe/bsw@0: local rawset = rawset jbe/bsw@0: local select = select jbe/bsw@0: local setmetatable = setmetatable jbe/bsw@0: local tonumber = tonumber jbe/bsw@0: local tostring = tostring jbe/bsw@0: local type = type jbe/bsw@0: jbe/bsw@0: local math = math jbe/bsw@0: local string = string jbe@64: local table = table jbe/bsw@0: jbe/bsw@0: local mondelefant = require("mondelefant") jbe/bsw@0: local atom = require("atom") jbe/bsw@0: jbe@64: local _M = {} jbe@64: if _ENV then jbe@64: _ENV = _M jbe@64: else jbe@64: _G[...] = _M jbe@64: setfenv(1, _M) jbe@64: end jbe/bsw@0: jbe/bsw@0: jbe/bsw@0: input_converters = setmetatable({}, { __mode = "k" }) jbe/bsw@0: jbe/bsw@0: input_converters["boolean"] = function(conn, value) jbe/bsw@0: if value then return "TRUE" else return "FALSE" end jbe/bsw@0: end jbe/bsw@0: jbe/bsw@0: input_converters["number"] = function(conn, value) jbe/bsw@0: local str = tostring(value) jbe/bsw@0: if string.find(str, "^[0-9%.e%-]+$") then jbe/bsw@0: return str jbe/bsw@0: else jbe/bsw@0: return "'NaN'" jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: jbe/bsw@0: input_converters[atom.fraction] = function(conn, value) jbe/bsw@0: if value.invalid then jbe/bsw@0: return "'NaN'" jbe/bsw@0: else jbe/bsw@0: local n, d = tostring(value.numerator), tostring(value.denominator) jbe/bsw@0: if string.find(n, "^%-?[0-9]+$") and string.find(d, "^%-?[0-9]+$") then jbe/bsw@0: return "(" .. n .. "::numeric / " .. d .. "::numeric)" jbe/bsw@0: else jbe/bsw@0: return "'NaN'" jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: jbe/bsw@0: input_converters[atom.date] = function(conn, value) jbe/bsw@0: return conn:quote_string(tostring(value)) .. "::date" jbe/bsw@0: end jbe/bsw@0: jbe/bsw@0: input_converters[atom.timestamp] = function(conn, value) jbe/bsw@0: return conn:quote_string(tostring(value)) -- don't define type jbe/bsw@0: end jbe/bsw@0: jbe/bsw@0: input_converters[atom.time] = function(conn, value) jbe/bsw@0: return conn:quote_string(tostring(value)) .. "::time" jbe/bsw@0: end jbe/bsw@0: jbe@106: input_converters[atom.interval] = function(conn, value) jbe@106: return ( jbe@106: conn:quote_string( jbe@106: table.concat( jbe@106: { jbe@106: tostring(value.years), "years", jbe@106: tostring(value.months), "months", jbe@106: tostring(value.days), "days", jbe@106: tostring(value.hours), "hours", jbe@106: tostring(value.minutes), "minutes", jbe@106: tostring(value.seconds), "seconds" jbe@106: }, jbe@106: " " jbe@106: ) jbe@106: ) .. "::interval" jbe@106: ) jbe@106: end jbe@106: jbe/bsw@0: jbe/bsw@0: output_converters = setmetatable({}, { __mode = "k" }) jbe/bsw@0: jbe/bsw@0: output_converters.int8 = function(str) return atom.integer:load(str) end jbe/bsw@0: output_converters.int4 = function(str) return atom.integer:load(str) end jbe/bsw@0: output_converters.int2 = function(str) return atom.integer:load(str) end jbe/bsw@0: jbe/bsw@0: output_converters.numeric = function(str) return atom.number:load(str) end jbe/bsw@0: output_converters.float4 = function(str) return atom.number:load(str) end jbe/bsw@0: output_converters.float8 = function(str) return atom.number:load(str) end jbe/bsw@0: jbe/bsw@0: output_converters.bool = function(str) return atom.boolean:load(str) end jbe/bsw@0: jbe/bsw@0: output_converters.date = function(str) return atom.date:load(str) end jbe/bsw@0: jbe/bsw@0: local timestamp_loader_func = function(str) jbe@1: local year, month, day, hour, minute, second = string.match( jbe/bsw@0: str, jbe@1: "^([0-9][0-9][0-9][0-9])%-([0-9][0-9])%-([0-9][0-9]) ([0-9]?[0-9]):([0-9][0-9]):([0-9][0-9])" jbe/bsw@0: ) jbe@1: if year then jbe/bsw@0: return atom.timestamp{ jbe@1: year = tonumber(year), jbe@1: month = tonumber(month), jbe@1: day = tonumber(day), jbe/bsw@0: hour = tonumber(hour), jbe/bsw@0: minute = tonumber(minute), jbe/bsw@0: second = tonumber(second) jbe/bsw@0: } jbe/bsw@0: else jbe/bsw@0: return atom.timestamp.invalid jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: output_converters.timestamp = timestamp_loader_func jbe/bsw@0: output_converters.timestamptz = timestamp_loader_func jbe/bsw@0: jbe/bsw@0: local time_loader_func = function(str) jbe@1: local hour, minute, second = string.match( jbe/bsw@0: str, jbe@1: "^([0-9]?[0-9]):([0-9][0-9]):([0-9][0-9])" jbe/bsw@0: ) jbe@1: if hour then jbe/bsw@0: return atom.time{ jbe/bsw@0: hour = tonumber(hour), jbe/bsw@0: minute = tonumber(minute), jbe/bsw@0: second = tonumber(second) jbe/bsw@0: } jbe/bsw@0: else jbe/bsw@0: return atom.time.invalid jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: output_converters.time = time_loader_func jbe/bsw@0: output_converters.timetz = time_loader_func jbe/bsw@0: jbe@106: output_converters.interval = function(str) jbe@106: local years, months, days, hours, minutes, seconds = 0, 0, 0, 0, 0, 0 jbe@106: local any_match = false jbe@106: for amount, unit in string.gmatch(str, "(%-?[0-9]+)%s*([A-Za-z]+)") do jbe@106: local unit = string.lower(unit) jbe@106: if string.match(unit, "^y") then jbe@106: years = years + tonumber(amount) jbe@106: any_match = true jbe@106: elseif string.match(unit, "^mo") then jbe@106: months = months + tonumber(amount) jbe@106: any_match = true jbe@106: elseif string.match(unit, "^d") then jbe@106: days = days + tonumber(amount) jbe@106: any_match = true jbe@106: elseif string.match(unit, "^h") then jbe@106: hours = hours + tonumber(amount) jbe@106: any_match = true jbe@106: elseif string.match(unit, "^mi") then jbe@106: minutes = minutes + tonumber(amount) jbe@106: any_match = true jbe@106: elseif string.match(unit, "^s") then jbe@106: seconds = seconds + tonumber(amount) jbe@106: any_match = true jbe@106: else jbe@106: return atom.interval.invalid jbe@106: end jbe@106: end jbe@106: local sign, h, m, s = string.match(str, "(%-?)([0-9]+):([0-9]+):([0-9]+)") jbe@106: if h then jbe@106: if sign == "-" then jbe@106: hours = hours - tonumber(h) jbe@106: minutes = minutes - tonumber(m) jbe@106: seconds = seconds - tonumber(s) jbe@106: else jbe@106: hours = hours + tonumber(h) jbe@106: minutes = minutes + tonumber(m) jbe@106: seconds = seconds + tonumber(s) jbe@106: end jbe@106: any_match = true jbe@106: end jbe@106: if not any_match then jbe@106: return atom.interval.invalid jbe@106: end jbe@106: if string.match(str, "%sago%s*$") then jbe@106: years, months, days = -years, -months, -days jbe@106: hours, minutes, seconds = -hours, -minutes, -seconds jbe@106: end jbe@106: return atom.interval:new{ jbe@106: years = years, months = months, days = days, jbe@106: hours = hours, minutes = minutes, seconds = seconds jbe@106: } jbe@106: end jbe@106: jbe/bsw@0: mondelefant.postgresql_connection_prototype.type_mappings = { jbe/bsw@0: int8 = atom.integer, jbe/bsw@0: int4 = atom.integer, jbe/bsw@0: int2 = atom.integer, jbe/bsw@0: bool = atom.boolean, jbe/bsw@0: date = atom.date, jbe/bsw@0: timestamp = atom.timestamp, jbe/bsw@0: time = atom.time, jbe/bsw@0: text = atom.string, jbe/bsw@0: varchar = atom.string, jbe/bsw@0: } jbe/bsw@0: jbe/bsw@0: jbe/bsw@0: function mondelefant.postgresql_connection_prototype.input_converter(conn, value, info) jbe/bsw@0: if value == nil then jbe/bsw@0: return "NULL" jbe/bsw@0: else jbe/bsw@0: local converter = jbe/bsw@0: input_converters[getmetatable(value)] or jbe/bsw@0: input_converters[type(value)] jbe/bsw@0: if converter then jbe/bsw@0: return converter(conn, value) jbe/bsw@0: else jbe/bsw@0: return conn:quote_string(tostring(value)) jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: jbe/bsw@0: function mondelefant.postgresql_connection_prototype.output_converter(conn, value, info) jbe/bsw@0: if value == nil then jbe/bsw@0: return nil jbe/bsw@0: else jbe/bsw@0: local converter = output_converters[info.type] jbe/bsw@0: if converter then jbe/bsw@0: return converter(value) jbe/bsw@0: else jbe/bsw@0: return value jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: jbe@64: return _M jbe@64: jbe/bsw@0: jbe/bsw@0: --[[ jbe/bsw@0: jbe/bsw@0: db = assert(mondelefant.connect{engine='postgresql', dbname='test'}) jbe/bsw@0: result = db:query{'SELECT ? + 1', atom.date{ year=1999, month=12, day=31}} jbe/bsw@0: print(result[1][1].year) jbe/bsw@0: jbe/bsw@0: --]]