| rev | 
   line source | 
| 
jbe/bsw@0
 | 
     1 #!/usr/bin/env lua
 | 
| 
jbe/bsw@0
 | 
     2 
 | 
| 
jbe/bsw@0
 | 
     3 local _G             = _G
 | 
| 
jbe/bsw@0
 | 
     4 local _VERSION       = _VERSION
 | 
| 
jbe/bsw@0
 | 
     5 local assert         = assert
 | 
| 
jbe/bsw@0
 | 
     6 local error          = error
 | 
| 
jbe/bsw@0
 | 
     7 local getmetatable   = getmetatable
 | 
| 
jbe/bsw@0
 | 
     8 local ipairs         = ipairs
 | 
| 
jbe/bsw@0
 | 
     9 local next           = next
 | 
| 
jbe/bsw@0
 | 
    10 local pairs          = pairs
 | 
| 
jbe/bsw@0
 | 
    11 local print          = print
 | 
| 
jbe/bsw@0
 | 
    12 local rawequal       = rawequal
 | 
| 
jbe/bsw@0
 | 
    13 local rawget         = rawget
 | 
| 
jbe@64
 | 
    14 local rawlen         = rawlen
 | 
| 
jbe/bsw@0
 | 
    15 local rawset         = rawset
 | 
| 
jbe/bsw@0
 | 
    16 local select         = select
 | 
| 
jbe/bsw@0
 | 
    17 local setmetatable   = setmetatable
 | 
| 
jbe/bsw@0
 | 
    18 local tonumber       = tonumber
 | 
| 
jbe/bsw@0
 | 
    19 local tostring       = tostring
 | 
| 
jbe/bsw@0
 | 
    20 local type           = type
 | 
| 
jbe/bsw@0
 | 
    21 
 | 
| 
jbe/bsw@0
 | 
    22 local math      = math
 | 
| 
jbe/bsw@0
 | 
    23 local string    = string
 | 
| 
jbe@64
 | 
    24 local table     = table
 | 
| 
jbe/bsw@0
 | 
    25 
 | 
| 
jbe/bsw@0
 | 
    26 local mondelefant = require("mondelefant")
 | 
| 
jbe/bsw@0
 | 
    27 local atom        = require("atom")
 | 
| 
jbe@177
 | 
    28 local json        = require("json")
 | 
| 
jbe/bsw@0
 | 
    29 
 | 
| 
jbe@64
 | 
    30 local _M = {}
 | 
| 
jbe@64
 | 
    31 if _ENV then
 | 
| 
jbe@64
 | 
    32   _ENV = _M
 | 
| 
jbe@64
 | 
    33 else
 | 
| 
jbe@64
 | 
    34   _G[...] = _M
 | 
| 
jbe@64
 | 
    35   setfenv(1, _M)
 | 
| 
jbe@64
 | 
    36 end
 | 
| 
jbe/bsw@0
 | 
    37 
 | 
| 
jbe/bsw@0
 | 
    38 
 | 
| 
jbe/bsw@0
 | 
    39 input_converters = setmetatable({}, { __mode = "k" })
 | 
| 
jbe/bsw@0
 | 
    40 
 | 
| 
jbe/bsw@0
 | 
    41 input_converters["boolean"] = function(conn, value)
 | 
| 
jbe/bsw@0
 | 
    42   if value then return "TRUE" else return "FALSE" end
 | 
| 
jbe/bsw@0
 | 
    43 end
 | 
| 
jbe/bsw@0
 | 
    44 
 | 
| 
jbe/bsw@0
 | 
    45 input_converters["number"] = function(conn, value)
 | 
| 
jbe@490
 | 
    46   if _VERSION == "Lua 5.2" then
 | 
| 
jbe@490
 | 
    47     -- TODO: remove following compatibility hack to allow large integers (e.g. 1e14) in Lua 5.2
 | 
| 
jbe@490
 | 
    48     local integer_string = string.format("%i", value)
 | 
| 
jbe@490
 | 
    49     if tonumber(integer_string) == value then
 | 
| 
jbe@490
 | 
    50       return integer_string
 | 
| 
jbe@419
 | 
    51     else
 | 
| 
jbe@490
 | 
    52       local number_string = tostring(value)
 | 
| 
jbe@490
 | 
    53       if string.find(number_string, "^[0-9.e+-]+$") then
 | 
| 
jbe@490
 | 
    54         return number_string
 | 
| 
jbe@490
 | 
    55       else
 | 
| 
jbe@490
 | 
    56         return "'NaN'"
 | 
| 
jbe@490
 | 
    57       end
 | 
| 
jbe@419
 | 
    58     end
 | 
| 
jbe/bsw@0
 | 
    59   end
 | 
| 
jbe@490
 | 
    60   local integer = math.tointeger(value)
 | 
| 
jbe@490
 | 
    61   if integer then
 | 
| 
jbe@490
 | 
    62     return tostring(integer)
 | 
| 
jbe@490
 | 
    63   end
 | 
| 
jbe@490
 | 
    64   local str = tostring(value)
 | 
| 
jbe@490
 | 
    65   if string.find(str, "^[0-9.e+-]+$") then
 | 
| 
jbe@490
 | 
    66     return str
 | 
| 
jbe@490
 | 
    67   end
 | 
| 
jbe@490
 | 
    68   return "'NaN'"
 | 
| 
jbe/bsw@0
 | 
    69 end
 | 
| 
jbe/bsw@0
 | 
    70 
 | 
| 
jbe/bsw@0
 | 
    71 input_converters[atom.fraction] = function(conn, value)
 | 
| 
jbe/bsw@0
 | 
    72   if value.invalid then
 | 
| 
jbe/bsw@0
 | 
    73     return "'NaN'"
 | 
| 
jbe/bsw@0
 | 
    74   else
 | 
| 
jbe/bsw@0
 | 
    75     local n, d = tostring(value.numerator), tostring(value.denominator)
 | 
| 
jbe/bsw@0
 | 
    76     if string.find(n, "^%-?[0-9]+$") and string.find(d, "^%-?[0-9]+$") then
 | 
| 
jbe/bsw@0
 | 
    77       return "(" .. n .. "::numeric / " .. d .. "::numeric)"
 | 
| 
jbe/bsw@0
 | 
    78     else
 | 
| 
jbe/bsw@0
 | 
    79       return "'NaN'"
 | 
| 
jbe/bsw@0
 | 
    80     end
 | 
| 
jbe/bsw@0
 | 
    81   end
 | 
| 
jbe/bsw@0
 | 
    82 end
 | 
| 
jbe/bsw@0
 | 
    83 
 | 
| 
jbe/bsw@0
 | 
    84 input_converters[atom.date] = function(conn, value)
 | 
| 
jbe/bsw@0
 | 
    85   return conn:quote_string(tostring(value)) .. "::date"
 | 
| 
jbe/bsw@0
 | 
    86 end
 | 
| 
jbe/bsw@0
 | 
    87 
 | 
| 
jbe/bsw@0
 | 
    88 input_converters[atom.timestamp] = function(conn, value)
 | 
| 
jbe/bsw@0
 | 
    89   return conn:quote_string(tostring(value))  -- don't define type
 | 
| 
jbe/bsw@0
 | 
    90 end
 | 
| 
jbe/bsw@0
 | 
    91 
 | 
| 
jbe/bsw@0
 | 
    92 input_converters[atom.time] = function(conn, value)
 | 
| 
jbe/bsw@0
 | 
    93   return conn:quote_string(tostring(value)) .. "::time"
 | 
| 
jbe/bsw@0
 | 
    94 end
 | 
| 
jbe/bsw@0
 | 
    95 
 | 
| 
jbe/bsw@0
 | 
    96 
 | 
| 
jbe/bsw@0
 | 
    97 output_converters = setmetatable({}, { __mode = "k" })
 | 
| 
jbe/bsw@0
 | 
    98 
 | 
| 
jbe/bsw@0
 | 
    99 output_converters.int8 = function(str) return atom.integer:load(str) end
 | 
| 
jbe/bsw@0
 | 
   100 output_converters.int4 = function(str) return atom.integer:load(str) end
 | 
| 
jbe/bsw@0
 | 
   101 output_converters.int2 = function(str) return atom.integer:load(str) end
 | 
| 
jbe/bsw@0
 | 
   102 
 | 
| 
jbe/bsw@0
 | 
   103 output_converters.numeric = function(str) return atom.number:load(str) end
 | 
| 
jbe/bsw@0
 | 
   104 output_converters.float4  = function(str) return atom.number:load(str) end
 | 
| 
jbe/bsw@0
 | 
   105 output_converters.float8  = function(str) return atom.number:load(str) end
 | 
| 
jbe/bsw@0
 | 
   106 
 | 
| 
jbe/bsw@0
 | 
   107 output_converters.bool = function(str) return atom.boolean:load(str) end
 | 
| 
jbe/bsw@0
 | 
   108 
 | 
| 
jbe/bsw@0
 | 
   109 output_converters.date = function(str) return atom.date:load(str) end
 | 
| 
jbe/bsw@0
 | 
   110 
 | 
| 
jbe/bsw@0
 | 
   111 local timestamp_loader_func = function(str)
 | 
| 
jbe@1
 | 
   112   local year, month, day, hour, minute, second = string.match(
 | 
| 
jbe/bsw@0
 | 
   113     str,
 | 
| 
jbe@1
 | 
   114     "^([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
 | 
   115   )
 | 
| 
jbe@1
 | 
   116   if year then
 | 
| 
jbe/bsw@0
 | 
   117     return atom.timestamp{
 | 
| 
jbe@1
 | 
   118       year   = tonumber(year),
 | 
| 
jbe@1
 | 
   119       month  = tonumber(month),
 | 
| 
jbe@1
 | 
   120       day    = tonumber(day),
 | 
| 
jbe/bsw@0
 | 
   121       hour   = tonumber(hour),
 | 
| 
jbe/bsw@0
 | 
   122       minute = tonumber(minute),
 | 
| 
jbe/bsw@0
 | 
   123       second = tonumber(second)
 | 
| 
jbe/bsw@0
 | 
   124     }
 | 
| 
jbe/bsw@0
 | 
   125   else
 | 
| 
jbe/bsw@0
 | 
   126     return atom.timestamp.invalid
 | 
| 
jbe/bsw@0
 | 
   127   end
 | 
| 
jbe/bsw@0
 | 
   128 end
 | 
| 
jbe/bsw@0
 | 
   129 output_converters.timestamp = timestamp_loader_func
 | 
| 
jbe/bsw@0
 | 
   130 output_converters.timestamptz = timestamp_loader_func
 | 
| 
jbe/bsw@0
 | 
   131 
 | 
| 
jbe/bsw@0
 | 
   132 local time_loader_func = function(str)
 | 
| 
jbe@1
 | 
   133   local hour, minute, second = string.match(
 | 
| 
jbe/bsw@0
 | 
   134     str,
 | 
| 
jbe@1
 | 
   135     "^([0-9]?[0-9]):([0-9][0-9]):([0-9][0-9])"
 | 
| 
jbe/bsw@0
 | 
   136   )
 | 
| 
jbe@1
 | 
   137   if hour then
 | 
| 
jbe/bsw@0
 | 
   138     return atom.time{
 | 
| 
jbe/bsw@0
 | 
   139       hour   = tonumber(hour),
 | 
| 
jbe/bsw@0
 | 
   140       minute = tonumber(minute),
 | 
| 
jbe/bsw@0
 | 
   141       second = tonumber(second)
 | 
| 
jbe/bsw@0
 | 
   142     }
 | 
| 
jbe/bsw@0
 | 
   143   else
 | 
| 
jbe/bsw@0
 | 
   144     return atom.time.invalid
 | 
| 
jbe/bsw@0
 | 
   145   end
 | 
| 
jbe/bsw@0
 | 
   146 end
 | 
| 
jbe/bsw@0
 | 
   147 output_converters.time = time_loader_func
 | 
| 
jbe/bsw@0
 | 
   148 output_converters.timetz = time_loader_func
 | 
| 
jbe/bsw@0
 | 
   149 
 | 
| 
jbe@178
 | 
   150 local json_loader_func = function(str)
 | 
| 
jbe@178
 | 
   151   return assert(json.import(str))
 | 
| 
jbe@178
 | 
   152 end
 | 
| 
jbe@178
 | 
   153 output_converters.json = json_loader_func
 | 
| 
jbe@178
 | 
   154 output_converters.jsonb = json_loader_func
 | 
| 
jbe@176
 | 
   155 
 | 
| 
jbe/bsw@0
 | 
   156 mondelefant.postgresql_connection_prototype.type_mappings = {
 | 
| 
jbe/bsw@0
 | 
   157   int8 = atom.integer,
 | 
| 
jbe/bsw@0
 | 
   158   int4 = atom.integer,
 | 
| 
jbe/bsw@0
 | 
   159   int2 = atom.integer,
 | 
| 
jbe/bsw@0
 | 
   160   bool = atom.boolean,
 | 
| 
jbe/bsw@0
 | 
   161   date = atom.date,
 | 
| 
jbe/bsw@0
 | 
   162   timestamp = atom.timestamp,
 | 
| 
jbe/bsw@0
 | 
   163   time = atom.time,
 | 
| 
jbe/bsw@0
 | 
   164   text = atom.string,
 | 
| 
jbe/bsw@0
 | 
   165   varchar = atom.string,
 | 
| 
jbe@176
 | 
   166   json = json,
 | 
| 
jbe@176
 | 
   167   jsonb = json,
 | 
| 
jbe/bsw@0
 | 
   168 }
 | 
| 
jbe/bsw@0
 | 
   169 
 | 
| 
jbe/bsw@0
 | 
   170 
 | 
| 
jbe/bsw@0
 | 
   171 function mondelefant.postgresql_connection_prototype.input_converter(conn, value, info)
 | 
| 
jbe/bsw@0
 | 
   172   if value == nil then
 | 
| 
jbe/bsw@0
 | 
   173     return "NULL"
 | 
| 
jbe/bsw@0
 | 
   174   else
 | 
| 
jbe/bsw@0
 | 
   175     local converter =
 | 
| 
jbe/bsw@0
 | 
   176       input_converters[getmetatable(value)] or
 | 
| 
jbe/bsw@0
 | 
   177       input_converters[type(value)]
 | 
| 
jbe/bsw@0
 | 
   178     if converter then
 | 
| 
jbe/bsw@0
 | 
   179       return converter(conn, value)
 | 
| 
jbe/bsw@0
 | 
   180     else
 | 
| 
jbe/bsw@0
 | 
   181       return conn:quote_string(tostring(value))
 | 
| 
jbe/bsw@0
 | 
   182     end
 | 
| 
jbe/bsw@0
 | 
   183   end
 | 
| 
jbe/bsw@0
 | 
   184 end
 | 
| 
jbe/bsw@0
 | 
   185 
 | 
| 
jbe/bsw@0
 | 
   186 function mondelefant.postgresql_connection_prototype.output_converter(conn, value, info)
 | 
| 
jbe/bsw@0
 | 
   187   if value == nil then
 | 
| 
jbe/bsw@0
 | 
   188     return nil
 | 
| 
jbe/bsw@0
 | 
   189   else
 | 
| 
jbe/bsw@0
 | 
   190     local converter = output_converters[info.type]
 | 
| 
jbe/bsw@0
 | 
   191     if converter then
 | 
| 
jbe/bsw@0
 | 
   192       return converter(value)
 | 
| 
jbe/bsw@0
 | 
   193     else
 | 
| 
jbe/bsw@0
 | 
   194       return value
 | 
| 
jbe/bsw@0
 | 
   195     end
 | 
| 
jbe/bsw@0
 | 
   196   end
 | 
| 
jbe/bsw@0
 | 
   197 end
 | 
| 
jbe/bsw@0
 | 
   198 
 | 
| 
jbe@374
 | 
   199 
 | 
| 
jbe@374
 | 
   200 function mondelefant.save_mutability_state(value)
 | 
| 
jbe@374
 | 
   201   local jsontype = json.type(value)
 | 
| 
jbe@374
 | 
   202   if jsontype == "object" or jsontype == "array" then
 | 
| 
jbe@374
 | 
   203     return tostring(value)
 | 
| 
jbe@374
 | 
   204   end
 | 
| 
jbe@374
 | 
   205 end
 | 
| 
jbe@374
 | 
   206 
 | 
| 
jbe@374
 | 
   207 function mondelefant.verify_mutability_state(value, state)
 | 
| 
jbe@375
 | 
   208   return tostring(value) ~= state
 | 
| 
jbe@374
 | 
   209 end
 | 
| 
jbe@374
 | 
   210 
 | 
| 
jbe@375
 | 
   211 
 | 
| 
jbe@64
 | 
   212 return _M
 | 
| 
jbe@64
 | 
   213 
 | 
| 
jbe/bsw@0
 | 
   214 
 | 
| 
jbe/bsw@0
 | 
   215 --[[
 | 
| 
jbe/bsw@0
 | 
   216 
 | 
| 
jbe/bsw@0
 | 
   217 db = assert(mondelefant.connect{engine='postgresql', dbname='test'})
 | 
| 
jbe/bsw@0
 | 
   218 result = db:query{'SELECT ? + 1', atom.date{ year=1999, month=12, day=31}}
 | 
| 
jbe/bsw@0
 | 
   219 print(result[1][1].year)
 | 
| 
jbe/bsw@0
 | 
   220 
 | 
| 
jbe/bsw@0
 | 
   221 --]]
 |