3232
3333import attr
3434
35- from synapse .api .constants import EventContentFields , EventTypes , JoinRules
35+ from synapse .api .constants import (
36+ EventContentFields ,
37+ EventTypes ,
38+ JoinRules ,
39+ PublicRoomsFilterFields ,
40+ )
3641from synapse .api .errors import StoreError
3742from synapse .api .room_versions import RoomVersion , RoomVersions
3843from synapse .config .homeserver import HomeServerConfig
3944from synapse .events import EventBase
40- from synapse .storage ._base import SQLBaseStore , db_to_json
45+ from synapse .storage ._base import SQLBaseStore , db_to_json , make_in_list_sql_clause
4146from synapse .storage .database import (
4247 DatabasePool ,
4348 LoggingDatabaseConnection ,
@@ -199,22 +204,50 @@ async def get_public_room_ids(self) -> List[str]:
199204 desc = "get_public_room_ids" ,
200205 )
201206
207+ def _construct_room_type_where_clause (
208+ self , room_types : Union [List [Union [str , None ]], None ]
209+ ) -> Tuple [Union [str , None ], List [str ]]:
210+ if not room_types or not self .config .experimental .msc3827_enabled :
211+ return None , []
212+ else :
213+ # We use None when we want get rooms without a type
214+ is_null_clause = ""
215+ if None in room_types :
216+ is_null_clause = "OR room_type IS NULL"
217+ room_types = [value for value in room_types if value is not None ]
218+
219+ list_clause , args = make_in_list_sql_clause (
220+ self .database_engine , "room_type" , room_types
221+ )
222+
223+ return f"({ list_clause } { is_null_clause } )" , args
224+
202225 async def count_public_rooms (
203226 self ,
204227 network_tuple : Optional [ThirdPartyInstanceID ],
205228 ignore_non_federatable : bool ,
229+ search_filter : Optional [dict ],
206230 ) -> int :
207231 """Counts the number of public rooms as tracked in the room_stats_current
208232 and room_stats_state table.
209233
210234 Args:
211235 network_tuple
212236 ignore_non_federatable: If true filters out non-federatable rooms
237+ search_filter
213238 """
214239
215240 def _count_public_rooms_txn (txn : LoggingTransaction ) -> int :
216241 query_args = []
217242
243+ room_type_clause , args = self ._construct_room_type_where_clause (
244+ search_filter .get (PublicRoomsFilterFields .ROOM_TYPES , None )
245+ if search_filter
246+ else None
247+ )
248+ room_type_clause = f" AND { room_type_clause } " if room_type_clause else ""
249+ query_args += args
250+
218251 if network_tuple :
219252 if network_tuple .appservice_id :
220253 published_sql = """
@@ -249,6 +282,7 @@ def _count_public_rooms_txn(txn: LoggingTransaction) -> int:
249282 OR join_rules = '{ JoinRules .KNOCK_RESTRICTED } '
250283 OR history_visibility = 'world_readable'
251284 )
285+ { room_type_clause }
252286 AND joined_members > 0
253287 """
254288
@@ -347,8 +381,12 @@ async def get_largest_public_rooms(
347381 if ignore_non_federatable :
348382 where_clauses .append ("is_federatable" )
349383
350- if search_filter and search_filter .get ("generic_search_term" , None ):
351- search_term = "%" + search_filter ["generic_search_term" ] + "%"
384+ if search_filter and search_filter .get (
385+ PublicRoomsFilterFields .GENERIC_SEARCH_TERM , None
386+ ):
387+ search_term = (
388+ "%" + search_filter [PublicRoomsFilterFields .GENERIC_SEARCH_TERM ] + "%"
389+ )
352390
353391 where_clauses .append (
354392 """
@@ -365,6 +403,15 @@ async def get_largest_public_rooms(
365403 search_term .lower (),
366404 ]
367405
406+ room_type_clause , args = self ._construct_room_type_where_clause (
407+ search_filter .get (PublicRoomsFilterFields .ROOM_TYPES , None )
408+ if search_filter
409+ else None
410+ )
411+ if room_type_clause :
412+ where_clauses .append (room_type_clause )
413+ query_args += args
414+
368415 where_clause = ""
369416 if where_clauses :
370417 where_clause = " AND " + " AND " .join (where_clauses )
@@ -373,7 +420,7 @@ async def get_largest_public_rooms(
373420 sql = f"""
374421 SELECT
375422 room_id, name, topic, canonical_alias, joined_members,
376- avatar, history_visibility, guest_access, join_rules
423+ avatar, history_visibility, guest_access, join_rules, room_type
377424 FROM (
378425 { published_sql }
379426 ) published
@@ -1166,6 +1213,7 @@ class _BackgroundUpdates:
11661213 POPULATE_ROOM_DEPTH_MIN_DEPTH2 = "populate_room_depth_min_depth2"
11671214 REPLACE_ROOM_DEPTH_MIN_DEPTH = "replace_room_depth_min_depth"
11681215 POPULATE_ROOMS_CREATOR_COLUMN = "populate_rooms_creator_column"
1216+ ADD_ROOM_TYPE_COLUMN = "add_room_type_column"
11691217
11701218
11711219_REPLACE_ROOM_DEPTH_SQL_COMMANDS = (
@@ -1200,6 +1248,11 @@ def __init__(
12001248 self ._background_add_rooms_room_version_column ,
12011249 )
12021250
1251+ self .db_pool .updates .register_background_update_handler (
1252+ _BackgroundUpdates .ADD_ROOM_TYPE_COLUMN ,
1253+ self ._background_add_room_type_column ,
1254+ )
1255+
12031256 # BG updates to change the type of room_depth.min_depth
12041257 self .db_pool .updates .register_background_update_handler (
12051258 _BackgroundUpdates .POPULATE_ROOM_DEPTH_MIN_DEPTH2 ,
@@ -1569,6 +1622,69 @@ def _background_populate_rooms_creator_column_txn(
15691622
15701623 return batch_size
15711624
1625+ async def _background_add_room_type_column (
1626+ self , progress : JsonDict , batch_size : int
1627+ ) -> int :
1628+ """Background update to go and add room_type information to `room_stats_state`
1629+ table from `event_json` table.
1630+ """
1631+
1632+ last_room_id = progress .get ("room_id" , "" )
1633+
1634+ def _background_add_room_type_column_txn (
1635+ txn : LoggingTransaction ,
1636+ ) -> bool :
1637+ sql = """
1638+ SELECT state.room_id, json FROM event_json
1639+ INNER JOIN current_state_events AS state USING (event_id)
1640+ WHERE state.room_id > ? AND type = 'm.room.create'
1641+ ORDER BY state.room_id
1642+ LIMIT ?
1643+ """
1644+
1645+ txn .execute (sql , (last_room_id , batch_size ))
1646+ room_id_to_create_event_results = txn .fetchall ()
1647+
1648+ new_last_room_id = None
1649+ for room_id , event_json in room_id_to_create_event_results :
1650+ event_dict = db_to_json (event_json )
1651+
1652+ room_type = event_dict .get ("content" , {}).get (
1653+ EventContentFields .ROOM_TYPE , None
1654+ )
1655+ if isinstance (room_type , str ):
1656+ self .db_pool .simple_update_txn (
1657+ txn ,
1658+ table = "room_stats_state" ,
1659+ keyvalues = {"room_id" : room_id },
1660+ updatevalues = {"room_type" : room_type },
1661+ )
1662+
1663+ new_last_room_id = room_id
1664+
1665+ if new_last_room_id is None :
1666+ return True
1667+
1668+ self .db_pool .updates ._background_update_progress_txn (
1669+ txn ,
1670+ _BackgroundUpdates .ADD_ROOM_TYPE_COLUMN ,
1671+ {"room_id" : new_last_room_id },
1672+ )
1673+
1674+ return False
1675+
1676+ end = await self .db_pool .runInteraction (
1677+ "_background_add_room_type_column" ,
1678+ _background_add_room_type_column_txn ,
1679+ )
1680+
1681+ if end :
1682+ await self .db_pool .updates ._end_background_update (
1683+ _BackgroundUpdates .ADD_ROOM_TYPE_COLUMN
1684+ )
1685+
1686+ return batch_size
1687+
15721688
15731689class RoomStore (RoomBackgroundUpdateStore , RoomWorkerStore ):
15741690 def __init__ (
0 commit comments