webmcp

view libraries/mondelefant/mondelefant_atom_connector.lua @ 106:bbfbbddf13ad

Support for intervals
author jbe
date Sun Nov 04 04:55:22 2012 +0100 (2012-11-04)
parents 3d43a5cf17c1
children 6b435d3c0b14
line source
1 #!/usr/bin/env lua
3 local _G = _G
4 local _VERSION = _VERSION
5 local assert = assert
6 local error = error
7 local getmetatable = getmetatable
8 local ipairs = ipairs
9 local next = next
10 local pairs = pairs
11 local print = print
12 local rawequal = rawequal
13 local rawget = rawget
14 local rawlen = rawlen
15 local rawset = rawset
16 local select = select
17 local setmetatable = setmetatable
18 local tonumber = tonumber
19 local tostring = tostring
20 local type = type
22 local math = math
23 local string = string
24 local table = table
26 local mondelefant = require("mondelefant")
27 local atom = require("atom")
29 local _M = {}
30 if _ENV then
31 _ENV = _M
32 else
33 _G[...] = _M
34 setfenv(1, _M)
35 end
38 input_converters = setmetatable({}, { __mode = "k" })
40 input_converters["boolean"] = function(conn, value)
41 if value then return "TRUE" else return "FALSE" end
42 end
44 input_converters["number"] = function(conn, value)
45 local str = tostring(value)
46 if string.find(str, "^[0-9%.e%-]+$") then
47 return str
48 else
49 return "'NaN'"
50 end
51 end
53 input_converters[atom.fraction] = function(conn, value)
54 if value.invalid then
55 return "'NaN'"
56 else
57 local n, d = tostring(value.numerator), tostring(value.denominator)
58 if string.find(n, "^%-?[0-9]+$") and string.find(d, "^%-?[0-9]+$") then
59 return "(" .. n .. "::numeric / " .. d .. "::numeric)"
60 else
61 return "'NaN'"
62 end
63 end
64 end
66 input_converters[atom.date] = function(conn, value)
67 return conn:quote_string(tostring(value)) .. "::date"
68 end
70 input_converters[atom.timestamp] = function(conn, value)
71 return conn:quote_string(tostring(value)) -- don't define type
72 end
74 input_converters[atom.time] = function(conn, value)
75 return conn:quote_string(tostring(value)) .. "::time"
76 end
78 input_converters[atom.interval] = function(conn, value)
79 return (
80 conn:quote_string(
81 table.concat(
82 {
83 tostring(value.years), "years",
84 tostring(value.months), "months",
85 tostring(value.days), "days",
86 tostring(value.hours), "hours",
87 tostring(value.minutes), "minutes",
88 tostring(value.seconds), "seconds"
89 },
90 " "
91 )
92 ) .. "::interval"
93 )
94 end
97 output_converters = setmetatable({}, { __mode = "k" })
99 output_converters.int8 = function(str) return atom.integer:load(str) end
100 output_converters.int4 = function(str) return atom.integer:load(str) end
101 output_converters.int2 = function(str) return atom.integer:load(str) end
103 output_converters.numeric = function(str) return atom.number:load(str) end
104 output_converters.float4 = function(str) return atom.number:load(str) end
105 output_converters.float8 = function(str) return atom.number:load(str) end
107 output_converters.bool = function(str) return atom.boolean:load(str) end
109 output_converters.date = function(str) return atom.date:load(str) end
111 local timestamp_loader_func = function(str)
112 local year, month, day, hour, minute, second = string.match(
113 str,
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])"
115 )
116 if year then
117 return atom.timestamp{
118 year = tonumber(year),
119 month = tonumber(month),
120 day = tonumber(day),
121 hour = tonumber(hour),
122 minute = tonumber(minute),
123 second = tonumber(second)
124 }
125 else
126 return atom.timestamp.invalid
127 end
128 end
129 output_converters.timestamp = timestamp_loader_func
130 output_converters.timestamptz = timestamp_loader_func
132 local time_loader_func = function(str)
133 local hour, minute, second = string.match(
134 str,
135 "^([0-9]?[0-9]):([0-9][0-9]):([0-9][0-9])"
136 )
137 if hour then
138 return atom.time{
139 hour = tonumber(hour),
140 minute = tonumber(minute),
141 second = tonumber(second)
142 }
143 else
144 return atom.time.invalid
145 end
146 end
147 output_converters.time = time_loader_func
148 output_converters.timetz = time_loader_func
150 output_converters.interval = function(str)
151 local years, months, days, hours, minutes, seconds = 0, 0, 0, 0, 0, 0
152 local any_match = false
153 for amount, unit in string.gmatch(str, "(%-?[0-9]+)%s*([A-Za-z]+)") do
154 local unit = string.lower(unit)
155 if string.match(unit, "^y") then
156 years = years + tonumber(amount)
157 any_match = true
158 elseif string.match(unit, "^mo") then
159 months = months + tonumber(amount)
160 any_match = true
161 elseif string.match(unit, "^d") then
162 days = days + tonumber(amount)
163 any_match = true
164 elseif string.match(unit, "^h") then
165 hours = hours + tonumber(amount)
166 any_match = true
167 elseif string.match(unit, "^mi") then
168 minutes = minutes + tonumber(amount)
169 any_match = true
170 elseif string.match(unit, "^s") then
171 seconds = seconds + tonumber(amount)
172 any_match = true
173 else
174 return atom.interval.invalid
175 end
176 end
177 local sign, h, m, s = string.match(str, "(%-?)([0-9]+):([0-9]+):([0-9]+)")
178 if h then
179 if sign == "-" then
180 hours = hours - tonumber(h)
181 minutes = minutes - tonumber(m)
182 seconds = seconds - tonumber(s)
183 else
184 hours = hours + tonumber(h)
185 minutes = minutes + tonumber(m)
186 seconds = seconds + tonumber(s)
187 end
188 any_match = true
189 end
190 if not any_match then
191 return atom.interval.invalid
192 end
193 if string.match(str, "%sago%s*$") then
194 years, months, days = -years, -months, -days
195 hours, minutes, seconds = -hours, -minutes, -seconds
196 end
197 return atom.interval:new{
198 years = years, months = months, days = days,
199 hours = hours, minutes = minutes, seconds = seconds
200 }
201 end
203 mondelefant.postgresql_connection_prototype.type_mappings = {
204 int8 = atom.integer,
205 int4 = atom.integer,
206 int2 = atom.integer,
207 bool = atom.boolean,
208 date = atom.date,
209 timestamp = atom.timestamp,
210 time = atom.time,
211 text = atom.string,
212 varchar = atom.string,
213 }
216 function mondelefant.postgresql_connection_prototype.input_converter(conn, value, info)
217 if value == nil then
218 return "NULL"
219 else
220 local converter =
221 input_converters[getmetatable(value)] or
222 input_converters[type(value)]
223 if converter then
224 return converter(conn, value)
225 else
226 return conn:quote_string(tostring(value))
227 end
228 end
229 end
231 function mondelefant.postgresql_connection_prototype.output_converter(conn, value, info)
232 if value == nil then
233 return nil
234 else
235 local converter = output_converters[info.type]
236 if converter then
237 return converter(value)
238 else
239 return value
240 end
241 end
242 end
244 return _M
247 --[[
249 db = assert(mondelefant.connect{engine='postgresql', dbname='test'})
250 result = db:query{'SELECT ? + 1', atom.date{ year=1999, month=12, day=31}}
251 print(result[1][1].year)
253 --]]

Impressum / About Us