Reimplement the get public rooms api to work with new DB schema

This commit is contained in:
Erik Johnston 2014-08-15 10:26:35 +01:00
parent 2c46bb6208
commit 5002efa31b
7 changed files with 100 additions and 36 deletions

View file

@ -15,7 +15,7 @@
from synapse.api.events.room import ( from synapse.api.events.room import (
RoomTopicEvent, MessageEvent, RoomMemberEvent, FeedbackEvent, RoomTopicEvent, MessageEvent, RoomMemberEvent, FeedbackEvent,
InviteJoinEvent, RoomConfigEvent InviteJoinEvent, RoomConfigEvent, RoomNameEvent,
) )
from synapse.util.stringutils import random_string from synapse.util.stringutils import random_string
@ -25,6 +25,7 @@ class EventFactory(object):
_event_classes = [ _event_classes = [
RoomTopicEvent, RoomTopicEvent,
RoomNameEvent,
MessageEvent, MessageEvent,
RoomMemberEvent, RoomMemberEvent,
FeedbackEvent, FeedbackEvent,

View file

@ -19,14 +19,37 @@ from . import SynapseEvent
class RoomTopicEvent(SynapseEvent): class RoomTopicEvent(SynapseEvent):
TYPE = "m.room.topic" TYPE = "m.room.topic"
internal_keys = SynapseEvent.internal_keys + [
"topic",
]
def __init__(self, **kwargs): def __init__(self, **kwargs):
kwargs["state_key"] = "" kwargs["state_key"] = ""
if "topic" in kwargs["content"]:
kwargs["topic"] = kwargs["content"]["topic"]
super(RoomTopicEvent, self).__init__(**kwargs) super(RoomTopicEvent, self).__init__(**kwargs)
def get_content_template(self): def get_content_template(self):
return {"topic": u"string"} return {"topic": u"string"}
class RoomNameEvent(SynapseEvent):
TYPE = "m.room.name"
internal_keys = SynapseEvent.internal_keys + [
"name",
]
def __init__(self, **kwargs):
kwargs["state_key"] = ""
if "name" in kwargs["content"]:
kwargs["name"] = kwargs["content"]["name"]
super(RoomNameEvent, self).__init__(**kwargs)
def get_content_template(self):
return {"name": u"string"}
class RoomMemberEvent(SynapseEvent): class RoomMemberEvent(SynapseEvent):
TYPE = "m.room.member" TYPE = "m.room.member"

View file

@ -790,5 +790,5 @@ class RoomListHandler(BaseHandler):
@defer.inlineCallbacks @defer.inlineCallbacks
def get_public_room_list(self): def get_public_room_list(self):
chunk = yield self.store.get_rooms(is_public=True, with_topics=True) chunk = yield self.store.get_rooms(is_public=True)
defer.returnValue({"start": "START", "end": "END", "chunk": chunk}) defer.returnValue({"start": "START", "end": "END", "chunk": chunk})

View file

@ -17,7 +17,7 @@ from twisted.internet import defer
from synapse.api.events.room import ( from synapse.api.events.room import (
RoomMemberEvent, MessageEvent, RoomTopicEvent, FeedbackEvent, RoomMemberEvent, MessageEvent, RoomTopicEvent, FeedbackEvent,
RoomConfigEvent RoomConfigEvent, RoomNameEvent,
) )
from .directory import DirectoryStore from .directory import DirectoryStore
@ -52,6 +52,10 @@ class DataStore(RoomMemberStore, RoomStore,
yield self._store_feedback(event) yield self._store_feedback(event)
elif event.type == RoomConfigEvent.TYPE: elif event.type == RoomConfigEvent.TYPE:
yield self._store_room_config(event) yield self._store_room_config(event)
elif event.type == RoomNameEvent.TYPE:
yield self._store_room_name(event)
elif event.type == RoomTopicEvent.TYPE:
yield self._store_room_topic(event)
yield self._store_event(event) yield self._store_event(event)

View file

@ -68,7 +68,7 @@ class SQLBaseStore(object):
if decoder: if decoder:
return decoder(cursor) return decoder(cursor)
else: else:
return cursor return cursor.fetchall()
return self._db_pool.runInteraction(interaction) return self._db_pool.runInteraction(interaction)

View file

@ -76,49 +76,73 @@ class RoomStore(SQLBaseStore):
) )
@defer.inlineCallbacks @defer.inlineCallbacks
def get_rooms(self, is_public, with_topics): def get_rooms(self, is_public):
"""Retrieve a list of all public rooms. """Retrieve a list of all public rooms.
Args: Args:
is_public (bool): True if the rooms returned should be public. is_public (bool): True if the rooms returned should be public.
with_topics (bool): True to include the current topic for the room
in the response.
Returns: Returns:
A list of room dicts containing at least a "room_id" key, and a A list of room dicts containing at least a "room_id" key, a
"topic" key if one is set and with_topic=True. "topic" key if one is set, and a "name" key if one is set
""" """
room_data_type = RoomTopicEvent.TYPE
public = 1 if is_public else 0
latest_topic = ("SELECT max(room_data.id) FROM room_data WHERE " topic_subquery = (
+ "room_data.type = ? GROUP BY room_id") "SELECT topics.event_id as event_id, topics.room_id as room_id, topic FROM topics "
"INNER JOIN current_state_events as c "
query = ("SELECT rooms.*, room_data.content, room_alias FROM rooms " "ON c.event_id = topics.event_id "
+ "LEFT JOIN "
+ "room_aliases ON room_aliases.room_id = rooms.room_id "
+ "LEFT JOIN "
+ "room_data ON rooms.room_id = room_data.room_id WHERE "
+ "(room_data.id IN (" + latest_topic + ") "
+ "OR room_data.id IS NULL) AND rooms.is_public = ?")
res = yield self._execute(
self.cursor_to_dict, query, room_data_type, public
) )
# return only the keys the specification expects name_subquery = (
ret_keys = ["room_id", "topic", "room_alias"] "SELECT room_names.event_id as event_id, room_names.room_id as room_id, name FROM room_names "
"INNER JOIN current_state_events as c "
"ON c.event_id = room_names.event_id "
)
# extract topic from the json (icky) FIXME sql = (
for i, room_row in enumerate(res): "SELECT r.room_id, n.name, t.topic, group_concat(a.room_alias) FROM rooms AS r "
try: "LEFT JOIN (%(topic)s) AS t ON t.room_id = r.room_id "
content_json = json.loads(room_row["content"]) "LEFT JOIN (%(name)s) AS n ON n.room_id = r.room_id "
room_row["topic"] = content_json["topic"] "INNER JOIN room_aliases AS a ON a.room_id = r.room_id "
except: "WHERE r.is_public = ? "
pass # no topic set "GROUP BY r.room_id "
# filter the dict based on ret_keys ) % {
res[i] = {k: v for k, v in room_row.iteritems() if k in ret_keys} "topic": topic_subquery,
"name": name_subquery,
}
defer.returnValue(res) rows = yield self._execute(None, sql, is_public)
ret = [
{
"room_id": r[0],
"name": r[1],
"topic": r[2],
"aliases": r[3].split(","),
}
for r in rows
]
defer.returnValue(ret)
def _store_room_topic(self, event):
return self._simple_insert(
"topics",
{
"event_id": event.event_id,
"room_id": event.room_id,
"topic": event.topic,
}
)
def _store_room_name(self, event):
return self._simple_insert(
"room_names",
{
"event_id": event.event_id,
"room_id": event.room_id,
"name": event.name,
}
)
class RoomsTable(Table): class RoomsTable(Table):

View file

@ -51,6 +51,18 @@ CREATE TABLE IF NOT EXISTS feedback(
room_id TEXT room_id TEXT
); );
CREATE TABLE IF NOT EXISTS topics(
event_id TEXT NOT NULL,
room_id TEXT NOT NULL,
topic TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS room_names(
event_id TEXT NOT NULL,
room_id TEXT NOT NULL,
name TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS rooms( CREATE TABLE IF NOT EXISTS rooms(
room_id TEXT PRIMARY KEY NOT NULL, room_id TEXT PRIMARY KEY NOT NULL,
is_public INTEGER, is_public INTEGER,