Skip to content

Commit

Permalink
Allow extra keys in params to query_formatted()
Browse files Browse the repository at this point in the history
  • Loading branch information
Cito committed Jul 21, 2016
1 parent 5a02166 commit dc26299
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
2 changes: 2 additions & 0 deletions docs/contents/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Version 5.0.1
old versions of PostgreSQL are not officially supported and tested any more.
- Fixed an issue with Postgres types that have an OID >= 0x80000000 (reported
on the mailing list by Justin Pryzby).
- Allow extra values that are not used in the command in the parameter dict
passed to the query_formatted() method (as suggested by Justin Pryzby).
- Made C extension compatible with MSVC 9 again (this was needed to compile for
Python 2 on Windows).

Expand Down
21 changes: 16 additions & 5 deletions pg.py
Original file line number Diff line number Diff line change
Expand Up @@ -619,8 +619,20 @@ def format_query(self, command, values, types=None, inline=False):
else:
for value in values:
append(add(value))
command = command % tuple(literals)
command %= tuple(literals)
elif isinstance(values, dict):
# we want to allow extra keys in the dictionary,
# so we first must find the values actually used in the command
used_values = {}
literals = dict.fromkeys(values, '')
for key in literals:
del literals[key]
try:
command % literals
except KeyError:
used_values[key] = values[key]
literals[key] = ''
values = used_values
if inline:
adapt = self.adapt_inline
literals = dict((key, adapt(value))
Expand All @@ -629,15 +641,14 @@ def format_query(self, command, values, types=None, inline=False):
add = params.add
literals = {}
if types:
if (not isinstance(types, dict) or
len(types) < len(values)):
if not isinstance(types, dict):
raise TypeError('The values and types do not match')
for key in sorted(values):
literals[key] = add(values[key], types[key])
literals[key] = add(values[key], types.get(key))
else:
for key in sorted(values):
literals[key] = add(values[key])
command = command % literals
command %= literals
else:
raise TypeError('The values must be passed as tuple, list or dict')
return command, params
Expand Down
24 changes: 24 additions & 0 deletions tests/test_classic_dbwrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -893,10 +893,12 @@ def testQueryDataError(self):
def testQueryFormatted(self):
f = self.db.query_formatted
t = True if pg.get_bool() else 't'
# test with tuple
q = f("select %s::int, %s::real, %s::text, %s::bool",
(3, 2.5, 'hello', True))
r = q.getresult()[0]
self.assertEqual(r, (3, 2.5, 'hello', t))
# test with tuple, inline
q = f("select %s, %s, %s, %s", (3, 2.5, 'hello', True), inline=True)
r = q.getresult()[0]
if isinstance(r[1], Decimal):
Expand All @@ -905,6 +907,28 @@ def testQueryFormatted(self):
r[1] = float(r[1])
r = tuple(r)
self.assertEqual(r, (3, 2.5, 'hello', t))
# test with dict
q = f("select %(a)s::int, %(b)s::real, %(c)s::text, %(d)s::bool",
dict(a=3, b=2.5, c='hello', d=True))
r = q.getresult()[0]
self.assertEqual(r, (3, 2.5, 'hello', t))
# test with dict, inline
q = f("select %(a)s, %(b)s, %(c)s, %(d)s",
dict(a=3, b=2.5, c='hello', d=True), inline=True)
r = q.getresult()[0]
if isinstance(r[1], Decimal):
# Python 2.6 cannot compare float and Decimal
r = list(r)
r[1] = float(r[1])
r = tuple(r)
self.assertEqual(r, (3, 2.5, 'hello', t))
# test with dict and extra values
q = f("select %(a)s||%(b)s||%(c)s||%(d)s||'epsilon'",
dict(a='alpha', b='beta', c='gamma', d='delta', e='extra'))
r = q.getresult()[0][0]
self.assertEqual(r, 'alphabetagammadeltaepsilon')



def testPkey(self):
query = self.db.query
Expand Down

0 comments on commit dc26299

Please sign in to comment.