positiontup = None
replacement_expressions = {}
+ to_update_sets = {}
+
for name in (
self.compiled.positiontup if compiled.positional
else self.compiled.binds
):
parameter = self.compiled.binds[name]
if parameter.expanding:
- values = compiled_params.pop(name)
- if not values:
- to_update = []
- replacement_expressions[name] = (
- self.compiled.visit_empty_set_expr(
- parameter._expanding_in_types
- if parameter._expanding_in_types
- else [parameter.type]
+
+ if name in replacement_expressions:
+ to_update = to_update_sets[name]
+ else:
+ # we are removing the parameter from compiled_params
+ # because it is a list value, which is not expected by
+ # TypeEngine objects that would otherwise be asked to
+ # process it. the single name is being replaced with
+ # individual numbered parameters for each value in the
+ # param.
+ values = compiled_params.pop(name)
+
+ if not values:
+ to_update = to_update_sets[name] = []
+ replacement_expressions[name] = (
+ self.compiled.visit_empty_set_expr(
+ parameter._expanding_in_types
+ if parameter._expanding_in_types
+ else [parameter.type]
+ )
)
- )
- elif isinstance(values[0], (tuple, list)):
- to_update = [
- ("%s_%s_%s" % (name, i, j), value)
- for i, tuple_element in enumerate(values, 1)
- for j, value in enumerate(tuple_element, 1)
- ]
- replacement_expressions[name] = ", ".join(
- "(%s)" % ", ".join(
+ elif isinstance(values[0], (tuple, list)):
+ to_update = to_update_sets[name] = [
+ ("%s_%s_%s" % (name, i, j), value)
+ for i, tuple_element in enumerate(values, 1)
+ for j, value in enumerate(tuple_element, 1)
+ ]
+ replacement_expressions[name] = ", ".join(
+ "(%s)" % ", ".join(
+ self.compiled.bindtemplate % {
+ "name":
+ to_update[i * len(tuple_element) + j][0]
+ }
+ for j, value in enumerate(tuple_element)
+ )
+ for i, tuple_element in enumerate(values)
+
+ )
+ else:
+ to_update = to_update_sets[name] = [
+ ("%s_%s" % (name, i), value)
+ for i, value in enumerate(values, 1)
+ ]
+ replacement_expressions[name] = ", ".join(
self.compiled.bindtemplate % {
- "name":
- to_update[i * len(tuple_element) + j][0]
- }
- for j, value in enumerate(tuple_element)
+ "name": key}
+ for key, value in to_update
)
- for i, tuple_element in enumerate(values)
- )
- else:
- to_update = [
- ("%s_%s" % (name, i), value)
- for i, value in enumerate(values, 1)
- ]
- replacement_expressions[name] = ", ".join(
- self.compiled.bindtemplate % {
- "name": key}
- for key, value in to_update
- )
compiled_params.update(to_update)
processors.update(
(key, processors[name])
positiontup.append(name)
def process_expanding(m):
- return replacement_expressions.pop(m.group(1))
+ return replacement_expressions[m.group(1)]
self.statement = re.sub(
r"\[EXPANDING_(\S+)\]",
[(8, 'fred'), (9, 'ed')]
)
+ def test_expanding_in_repeated(self):
+ testing.db.execute(
+ users.insert(),
+ [
+ dict(user_id=7, user_name='jack'),
+ dict(user_id=8, user_name='fred'),
+ dict(user_id=9, user_name='ed')
+ ]
+ )
+
+ with testing.db.connect() as conn:
+ stmt = select([users]).where(
+ users.c.user_name.in_(
+ bindparam('uname', expanding=True)
+ ) | users.c.user_name.in_(bindparam('uname2', expanding=True))
+ ).where(users.c.user_id == 8)
+ stmt = stmt.union(
+ select([users]).where(
+ users.c.user_name.in_(
+ bindparam('uname', expanding=True)
+ ) | users.c.user_name.in_(
+ bindparam('uname2', expanding=True))
+ ).where(users.c.user_id == 9)
+ ).order_by(stmt.c.user_id)
+
+ eq_(
+ conn.execute(
+ stmt,
+ {
+ "uname": ['jack', 'fred'],
+ "uname2": ['ed'], "userid": [8, 9]}
+ ).fetchall(),
+ [(8, 'fred'), (9, 'ed')]
+ )
+
@testing.requires.tuple_in
def test_expanding_in_composite(self):
testing.db.execute(