1 #=======================================================================
3 __version__
= '''0.0.01'''
4 __sub_version__
= '''20051010144817'''
5 __copyright__
= '''(c) Alex A. Naanou 2003'''
8 #-----------------------------------------------------------------------
13 #-----------------------------------------------------------------------
14 #-------------------------------------------------------transactioned---
15 # XXX transaction decorator...
16 def transactioned(meth
):
19 def _transactioned(*p
, **n
):
30 #-------------------------------------------------------autoreconnect---
31 # XXX this will restore the connection if needed...
32 def autoreconnect(meth
):
35 def _autoreconnect(self
, *p
, **n
):
43 cur
= connection
.cursor()
45 cur
.execute('SELECT 1;').fetchone()[0]
54 #-----------------------------------------------------------------------
55 #------------------------------------------------------------SQLError---
56 class SQLError(Exception):
62 #--------------------------------------------------------------py2sql---
65 translate a value into an apropriate sql type.
68 if t
in (int, float, long):
70 if t
in (str, unicode):
72 return '\'%s\'' % value
75 raise TypeError, 'can\'t convert objects of type %s.' % t
78 #-----------------------------------------------------------------------
79 #--------------------------------------------------------------_WHERE---
80 ##!!! THINK OF A BETTER WAY TO DO THIS !!!##
81 # XXX should the condition return the WHERE kw??
84 compile and check a condition string...
86 ##!!! wrap values !!!##
87 def __init__(self
, *p
, **n
):
90 if len(p
) == 1 and type(p
[0]) is str:
93 self
.condition
= ' AND '.join([ '"%s" = %s' % (k
, py2sql(v
)) for k
, v
in n
.items() ])
102 return str(self
.condition
)
106 #-----------------------------------------------------------------------
107 #-----------------------------------------------------------------SQL---
108 # XXX Revise extensibility to other SQL dialects...
109 # TODO rename to pgSQL
113 # the condition clause processor...
116 def __init__(self
, connection
):
119 self
.connection
= connection
121 def checksqlname(self
, name
):
124 return '"%s"' % name
.replace('"', '\\"')
126 def sql2py(self
, value
):
130 # SQL expression generators
131 # TODO add other expressions... (CREATE, DROP, ...)
132 # TODO make these dialect independent...
133 # TODO add filter support for select (e.g. rename columns... etc.)
134 # TODO write more docs...
135 ##!!! TODO more pedantic input checking!
136 def select_sql(self
, columns
, source
,
139 # XXX the next two appear to PostgresSQL
140 # specific... REVISE!
145 SQL Syntax Reference:
149 checksqlname
= self
.checksqlname
151 # construct the source...
152 ##!!! CAN THIS BE ANOTHER SELECT HERE????
153 source
= checksqlname(source
)
155 # construct columns...
156 # NOTE: columns can be:
159 # - combination (???)
160 if type(columns
) is not str:
161 columns
= ', '.join([ checksqlname(n
) for n
in columns
])
163 # process the condition...
164 if condition
is None:
166 elif type(condition
) is self
.where
:
167 condition
= '\n\tWHERE ' + str(condition
)
169 condition
= '\n\tWHERE ' + str(self
.where(condition
))
172 # XXX do we need direction here???
174 order
= '\n\tORDER BY %s' % checksqlname(order
)
180 count
= '\n\tLIMIT %s' % py2sql(count
)
186 offset
= '\n\tOFFSET %s' % py2sql(offset
)
190 return 'SELECT %(columns)s \n\tFROM %(source)s%(where)s%(count)s%(offset)s%(order)s ;' \
191 % {'columns': columns
,
197 # TODO make setting defaults possible... (e.g. clo_x=DEFAULT)
198 # TODO support complex expression... (???)
199 ##!!! TODO more pedantic input checking!
200 def insert_sql(self
, table
, *p
, **n
):
202 generate an insert query.
205 insert_sql(<table_name>[, <value>[, ...]][, <column>=<value>[, ...]]) -> QUERY
207 SQL Syntax Reference:
208 INSERT INTO table [ ( column [, ...] ) ]
209 { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) | query }
212 checksqlname
= self
.checksqlname
215 table
= checksqlname(table
)
217 values
= (tuple([ n
[k
] for k
in columns
]) + p
) or ''
218 # sqlify the values...
222 values
= '( %s ) ' % ', '.join([ py2sql(v
) for v
in values
])
223 # sqlify the columns...
224 if len(columns
) == 0:
227 columns
= ' ( %s )' % ', '.join([ checksqlname(n
) for n
in columns
])
228 # generate the query...
229 return 'INSERT INTO %s%s VALUES %s;' % (table
, columns
, values
)
230 # TODO support complex expression... (???)
231 # TODO a more elaborate condition... (maybe a whwre method?)
232 ##!!! TODO more pedantic input checking!
233 def update_sql(self
, table
, condition
, *p
, **n
):
238 SQL Syntax Reference:
239 UPDATE [ ONLY ] table SET column = { expression | DEFAULT } [, ...]
244 raise SQLError
, 'must update at least one column (none given)'
246 checksqlname
= self
.checksqlname
249 table
= checksqlname(table
)
251 columns
= ', '.join([ '%s = %s' % (checksqlname(k
), py2sql(v
)) for k
, v
in n
.items() ])
253 # process the condition...
254 if condition
is None:
256 elif type(condition
) is self
.where
:
257 condition
= '\n\tWHERE ' + str(condition
)
259 condition
= '\n\tWHERE ' + str(self
.where(condition
))
261 # XXX should the condition return the WHERE kw??
262 return 'UPDATE %s SET %s%s ;' % (table
, columns
, condition
)
263 ##!!! TODO more pedantic input checking!
264 def delete_sql(self
, table
, condition
=None):
269 SQL Syntax Reference:
270 DELETE FROM [ ONLY ] table [ WHERE condition ]
273 checksqlname
= self
.checksqlname
276 table
= checksqlname(table
)
278 # process the condition...
279 if condition
is None:
281 elif type(condition
) is self
.where
:
282 condition
= '\n\tWHERE ' + str(condition
)
284 condition
= '\n\tWHERE ' + str(self
.where(condition
))
286 return 'DELETE FROM %(table)s%(where)s ;' \
290 # XXX make all of the following packable into transactions!!!
291 # XXX do we need to process the result here???
292 def select(self
, columns
, source
, condition
=None,
293 order
=None, count
=None, offset
=None):
296 cur
= self
.connection
.cursor()
297 cur
.execute(self
.select_sql(columns
, source
, condition
, order
, count
, offset
))
299 def insert(self
, table
, *p
, **n
):
302 cur
= self
.connection
.cursor()
303 cur
.execute(self
.insert_sql(table
, *p
, **n
))
305 def update(self
, table
, condition
, *p
, **n
):
308 cur
= self
.connection
.cursor()
309 cur
.execute(self
.update_sql(table
, condition
, *p
, **n
))
311 def delete(self
, table
, condition
=None):
314 cur
= self
.connection
.cursor()
315 cur
.execute(self
.delete_sql(table
, condition
))
320 #=======================================================================
321 # vim:set ts=4 sw=4 nowrap :