else/SQLHelpers/sqlhelpers.py

107 lines
3.4 KiB
Python

def delete_filler(pairs):
'''
Manually aligning the bindings for DELETE statements is annoying.
Given a dictionary of {column: value}, return the "WHERE ..." portion of
the query and the bindings in the correct order.
Example:
pairs={'test': 'toast', 'ping': 'pong'}
->
returns ('WHERE test = ? AND ping = ?', ['toast', 'pong'])
In context:
(qmarks, bindings) = delete_filler(pairs)
query = 'DELETE FROM table %s' % qmarks
cur.execute(query, bindings)
'''
qmarks = []
bindings = []
for (key, value) in pairs.items():
qmarks.append('%s = ?' % key)
bindings.append(value)
qmarks = ' AND '.join(qmarks)
qmarks = 'WHERE %s' % qmarks
return (qmarks, bindings)
def insert_filler(column_names, values, require_all=True):
'''
Manually aligning the bindings for INSERT statements is annoying.
Given the table's column names and a dictionary of {column: value},
return the question marks and the list of bindings in the right order.
require_all:
If `values` does not contain one of the column names, should we raise
an exception?
Otherwise, that column will simply receive None.
Example:
column_names=['id', 'name', 'score'],
values={'score': 20, 'id': '1111', 'name': 'James'}
->
returns ('?, ?, ?', ['1111', 'James', 20])
In context:
(qmarks, bindings) = insert_filler(COLUMN_NAMES, data)
query = 'INSERT INTO table VALUES(%s)' % qmarks
cur.execute(query, bindings)
'''
values = values.copy()
for column in column_names:
if column in values:
continue
if require_all:
raise ValueError('Missing column "%s"' % column)
else:
values[column] = None
qmarks = '?' * len(column_names)
qmarks = ', '.join(qmarks)
bindings = [values[column] for column in column_names]
return (qmarks, bindings)
def update_filler(pairs, where_key):
'''
Manually aligning the bindings for UPDATE statements is annoying.
Given a dictionary of {column: value} as well as the name of the column
to be used as the WHERE, return the "SET ..." portion of the query and the
bindings in the correct order.
If the where_key needs to be reassigned also, let its value be a 2-tuple
where [0] is the current value used for WHERE, and [1] is the new value
used for SET.
Example:
pairs={'id': '1111', 'name': 'James', 'score': 20},
where_key='id'
->
returns ('SET name = ?, score = ? WHERE id == ?', ['James', 20, '1111'])
Example:
pairs={'filepath': ('/oldplace', '/newplace')},
where_key='filepath'
->
returns ('SET filepath = ? WHERE filepath == ?', ['/newplace', '/oldplace'])
In context:
(qmarks, bindings) = update_filler(data, where_key)
query = 'UPDATE table %s' % qmarks
cur.execute(query, bindings)
'''
pairs = pairs.copy()
where_value = pairs.pop(where_key)
if isinstance(where_value, tuple):
(where_value, pairs[where_key]) = where_value
if len(pairs) == 0:
raise ValueError('No pairs left after where_key.')
qmarks = []
bindings = []
for (key, value) in pairs.items():
qmarks.append('%s = ?' % key)
bindings.append(value)
bindings.append(where_value)
setters = ', '.join(qmarks)
qmarks = 'SET {setters} WHERE {where_key} == ?'
qmarks = qmarks.format(setters=setters, where_key=where_key)
return (qmarks, bindings)