Skip to content

Commit c5e5cff

Browse files
committed
Add support for IN clauses to db.query()
Expanding IN clauses in bindings with SQLAlchemy requires a little more work (and the existing IN clauses were broken). This expose the needed mechanics in the query() interface, used such as: db.query( "SELECT * FROM blah WHERE id IN :ids", ids=[1,2,3], bind_expanding=['ids'] )
1 parent e4c559a commit c5e5cff

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

sogs/db.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import logging
66
import importlib.resources
77
import sqlalchemy
8+
from sqlalchemy.sql.expression import bindparam
89

910
HAVE_FILE_ID_HACKS = False
1011
# 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():
1819
return engine.connect()
1920

2021

21-
def query(query, *, dbconn=None, **params):
22+
def query(query, *, dbconn=None, bind_expanding=None, **params):
2223
"""Executes a query containing :param style placeholders (regardless of the actual underlying
2324
database placeholder style), binding them using the given params keyword arguments.
2425
@@ -33,6 +34,9 @@ def query(query, *, dbconn=None, **params):
3334
3435
See sqlalchemy.text for details.
3536
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+
3640
Can execute on a specific connection by passing it as dbconn; if omitted, uses web.appdb. (Note
3741
that dbconn *cannot* be used as a placeholder bind name).
3842
"""
@@ -42,7 +46,12 @@ def query(query, *, dbconn=None, **params):
4246

4347
dbconn = web.appdb
4448

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)
4655

4756

4857
# Begins a (potentially nested) transaction. Takes an optional connection; if omitted uses

sogs/model/room.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ def delete_posts(self, message_ids: List[int], deleter: User):
685685
""",
686686
r=self.id,
687687
ids=tuple(message_ids[i : i + 50]),
688+
bind_expanding=['ids'],
688689
)
689690
)
690691

@@ -700,11 +701,16 @@ def delete_posts(self, message_ids: List[int], deleter: User):
700701
""",
701702
u=deleter.id,
702703
ids=ids,
704+
bind_expanding=['ids'],
703705
)
704706
if res.first()[0]:
705707
raise BadPermission()
706708

707-
query("DELETE FROM message_details WHERE id IN :ids", ids=ids)
709+
query(
710+
"DELETE FROM message_details WHERE id IN :ids",
711+
ids=ids,
712+
bind_expanding=['ids'],
713+
)
708714

709715
deleted += ids
710716
i += 50

0 commit comments

Comments
 (0)