From 57ff573535bca54bce3cae6f3c1a7c6bc2bac13a Mon Sep 17 00:00:00 2001 From: Alex Vandiver Date: Mon, 15 Apr 2024 19:40:37 +0000 Subject: [PATCH] topic: Move sqlalchemy methods into their own file. Loading sqlalchemy can take a significant amount of time, so splitting these into these own file can be a significant startup-time savings. --- tools/linter_lib/custom_check.py | 1 + zerver/lib/narrow.py | 5 ++--- zerver/lib/topic.py | 18 ------------------ zerver/lib/topic_sqlalchemy.py | 20 ++++++++++++++++++++ zerver/lib/user_topics.py | 2 +- zerver/views/message_fetch.py | 3 ++- 6 files changed, 26 insertions(+), 23 deletions(-) create mode 100644 zerver/lib/topic_sqlalchemy.py diff --git a/tools/linter_lib/custom_check.py b/tools/linter_lib/custom_check.py index 2d95b545a5..1a08da952e 100644 --- a/tools/linter_lib/custom_check.py +++ b/tools/linter_lib/custom_check.py @@ -13,6 +13,7 @@ from zulint.custom_rules import Rule, RuleList FILES_WITH_LEGACY_SUBJECT = { # This basically requires a big DB migration: "zerver/lib/topic.py", + "zerver/lib/topic_sqlalchemy.py", # This is for backward compatibility. "zerver/tests/test_legacy_subject.py", # Other migration-related changes require extreme care. diff --git a/zerver/lib/narrow.py b/zerver/lib/narrow.py index 3116c521ae..4970cfc4ec 100644 --- a/zerver/lib/narrow.py +++ b/zerver/lib/narrow.py @@ -58,10 +58,9 @@ from zerver.lib.streams import ( get_stream_by_narrow_operand_access_unchecked, get_web_public_streams_queryset, ) -from zerver.lib.topic import ( - RESOLVED_TOPIC_PREFIX, +from zerver.lib.topic import RESOLVED_TOPIC_PREFIX, get_topic_from_message_info +from zerver.lib.topic_sqlalchemy import ( get_resolved_topic_condition_sa, - get_topic_from_message_info, topic_column_sa, topic_match_sa, ) diff --git a/zerver/lib/topic.py b/zerver/lib/topic.py index 577d2db3fe..281b3db431 100644 --- a/zerver/lib/topic.py +++ b/zerver/lib/topic.py @@ -5,8 +5,6 @@ import orjson from django.db import connection from django.db.models import F, Func, JSONField, Q, QuerySet, Subquery, TextField, Value from django.db.models.functions import Cast -from sqlalchemy.sql import ColumnElement, column, func, literal -from sqlalchemy.types import Boolean, Text from zerver.lib.request import REQ from zerver.lib.types import EditHistoryEvent @@ -72,22 +70,6 @@ DB_TOPIC_NAME = "subject" MESSAGE__TOPIC = "message__subject" -def topic_match_sa(topic_name: str) -> ColumnElement[Boolean]: - # _sa is short for SQLAlchemy, which we use mostly for - # queries that search messages - topic_cond = func.upper(column("subject", Text)) == func.upper(literal(topic_name)) - return topic_cond - - -def get_resolved_topic_condition_sa() -> ColumnElement[Boolean]: - resolved_topic_cond = column("subject", Text).startswith(RESOLVED_TOPIC_PREFIX) - return resolved_topic_cond - - -def topic_column_sa() -> ColumnElement[Text]: - return column("subject", Text) - - def filter_by_topic_name_via_message( query: QuerySet[UserMessage], topic_name: str ) -> QuerySet[UserMessage]: diff --git a/zerver/lib/topic_sqlalchemy.py b/zerver/lib/topic_sqlalchemy.py new file mode 100644 index 0000000000..6bbab54b89 --- /dev/null +++ b/zerver/lib/topic_sqlalchemy.py @@ -0,0 +1,20 @@ +from sqlalchemy.sql import ColumnElement, column, func, literal +from sqlalchemy.types import Boolean, Text + +from zerver.lib.topic import RESOLVED_TOPIC_PREFIX + + +def topic_match_sa(topic_name: str) -> ColumnElement[Boolean]: + # _sa is short for SQLAlchemy, which we use mostly for + # queries that search messages + topic_cond = func.upper(column("subject", Text)) == func.upper(literal(topic_name)) + return topic_cond + + +def get_resolved_topic_condition_sa() -> ColumnElement[Boolean]: + resolved_topic_cond = column("subject", Text).startswith(RESOLVED_TOPIC_PREFIX) + return resolved_topic_cond + + +def topic_column_sa() -> ColumnElement[Text]: + return column("subject", Text) diff --git a/zerver/lib/user_topics.py b/zerver/lib/user_topics.py index 6daa693310..01dfe432c4 100644 --- a/zerver/lib/user_topics.py +++ b/zerver/lib/user_topics.py @@ -10,7 +10,7 @@ from sqlalchemy.sql import ClauseElement, and_, column, not_, or_ from sqlalchemy.types import Integer from zerver.lib.timestamp import datetime_to_timestamp -from zerver.lib.topic import topic_match_sa +from zerver.lib.topic_sqlalchemy import topic_match_sa from zerver.lib.types import UserTopicDict from zerver.models import UserProfile, UserTopic from zerver.models.streams import get_stream diff --git a/zerver/views/message_fetch.py b/zerver/views/message_fetch.py index 82a96275fb..c2b9b67711 100644 --- a/zerver/views/message_fetch.py +++ b/zerver/views/message_fetch.py @@ -24,7 +24,8 @@ from zerver.lib.narrow import ( from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.lib.sqlalchemy_utils import get_sqlalchemy_connection -from zerver.lib.topic import DB_TOPIC_NAME, MATCH_TOPIC, topic_column_sa +from zerver.lib.topic import DB_TOPIC_NAME, MATCH_TOPIC +from zerver.lib.topic_sqlalchemy import topic_column_sa from zerver.lib.validator import check_bool, check_int, check_list, to_non_negative_int from zerver.models import UserMessage, UserProfile