5
5
import logging
6
6
import importlib .resources
7
7
import sqlalchemy
8
+ from sqlalchemy .sql .expression import bindparam
8
9
9
10
HAVE_FILE_ID_HACKS = False
10
11
# roomid => (max, offset). Max is the highest message id that was in the old table; offset is the
@@ -18,7 +19,7 @@ def get_conn():
18
19
return engine .connect ()
19
20
20
21
21
- def query (query , * , dbconn = None , ** params ):
22
+ def query (query , * , dbconn = None , bind_expanding = None , ** params ):
22
23
"""Executes a query containing :param style placeholders (regardless of the actual underlying
23
24
database placeholder style), binding them using the given params keyword arguments.
24
25
@@ -33,6 +34,9 @@ def query(query, *, dbconn=None, **params):
33
34
34
35
See sqlalchemy.text for details.
35
36
37
+ bind_expanding can be passed a sequence of bind names that are "expanding" to a tuple, most
38
+ commonly used to bind and expand the RHS of a `x IN :x` clause.
39
+
36
40
Can execute on a specific connection by passing it as dbconn; if omitted, uses web.appdb. (Note
37
41
that dbconn *cannot* be used as a placeholder bind name).
38
42
"""
@@ -42,7 +46,12 @@ def query(query, *, dbconn=None, **params):
42
46
43
47
dbconn = web .appdb
44
48
45
- return dbconn .execute (sqlalchemy .text (query ), ** params )
49
+ q = sqlalchemy .text (query )
50
+
51
+ if bind_expanding :
52
+ q = q .bindparams (* (bindparam (c , expanding = True ) for c in bind_expanding ))
53
+
54
+ return dbconn .execute (q , ** params )
46
55
47
56
48
57
# Begins a (potentially nested) transaction. Takes an optional connection; if omitted uses
0 commit comments