Skip to content

Commit 7c8f450

Browse files
ben851Ben LarabieCopilotjimleroyer
authored
eager fix (#2804)
* eager fix * format * Update app/dao/templates_dao.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update tests/app/dao/test_templates_dao.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix test * Update tests/app/dao/test_templates_dao.py Co-authored-by: Jimmy Royer <jimleroyer@gmail.com> * Update app/dao/templates_dao.py Co-authored-by: Jimmy Royer <jimleroyer@gmail.com> * Update tests/app/dao/test_templates_dao.py Co-authored-by: Jimmy Royer <jimleroyer@gmail.com> --------- Co-authored-by: Ben Larabie <ben.larabie@blarabie-jtfk.home> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Jimmy Royer <jimleroyer@gmail.com>
1 parent 1d8d432 commit 7c8f450

2 files changed

Lines changed: 47 additions & 4 deletions

File tree

app/dao/templates_dao.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from flask import current_app
77
from notifications_utils.clients.redis import template_version_cache_key
88
from sqlalchemy import asc, desc
9+
from sqlalchemy.orm import joinedload
910

1011
from app import db, redis_store
1112
from app.dao.dao_utils import VersionOptions, transactional, version_class
@@ -178,9 +179,17 @@ def dao_get_template_by_id(template_id, version=None, use_cache=False) -> Union[
178179

179180

180181
def dao_get_all_templates_for_service(service_id, template_type=None):
182+
# Eager load fields required for serialization; otherwise lazy loading these will trigger thousands of individual queries.
183+
query = Template.query.options(
184+
joinedload("template_redacted"),
185+
joinedload("template_category"),
186+
joinedload("created_by"),
187+
joinedload("service_letter_contact"),
188+
)
189+
181190
if template_type is not None:
182191
return (
183-
Template.query.filter_by(
192+
query.filter_by(
184193
service_id=service_id,
185194
template_type=template_type,
186195
hidden=False,
@@ -194,7 +203,7 @@ def dao_get_all_templates_for_service(service_id, template_type=None):
194203
)
195204

196205
return (
197-
Template.query.filter_by(service_id=service_id, hidden=False, archived=False)
206+
query.filter_by(service_id=service_id, hidden=False, archived=False)
198207
.order_by(
199208
asc(Template.name),
200209
asc(Template.template_type),

tests/app/dao/test_templates_dao.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
import pytest
66
from freezegun import freeze_time
7+
from sqlalchemy import event
78
from sqlalchemy.exc import SQLAlchemyError
89
from sqlalchemy.orm.exc import NoResultFound
910

10-
from app import redis_store
11+
from app import db, redis_store
1112
from app.dao.templates_dao import (
1213
dao_create_template,
1314
dao_get_all_templates_for_service,
@@ -20,7 +21,7 @@
2021
dao_update_template_reply_to,
2122
)
2223
from app.models import Template, TemplateHistory, TemplateRedacted
23-
from app.schemas import template_schema
24+
from app.schemas import reduced_template_schema, template_schema
2425
from tests.app.db import create_letter_contact, create_template
2526

2627

@@ -232,6 +233,39 @@ def test_get_all_templates_for_service(service_factory):
232233
assert len(dao_get_all_templates_for_service(service_2.id)) == 2
233234

234235

236+
def test_get_all_templates_for_service_eager_loads_redaction_for_serialization(sample_service):
237+
service_id = sample_service.id
238+
239+
for i in range(5):
240+
create_template(
241+
service=sample_service,
242+
template_name=f"Sample Template {i}",
243+
template_type="sms",
244+
content=f"Template content {i}",
245+
)
246+
247+
db.session.remove()
248+
249+
matching_statements = []
250+
251+
# Make sure that individual lazy queries are not called after serializing the templates.
252+
def before_cursor_execute(_conn, _cursor, statement, _parameters, _context, _executemany):
253+
normalized_statement = " ".join(statement.split())
254+
if "FROM template_redacted" in normalized_statement and "WHERE template_redacted.template_id =" in normalized_statement:
255+
matching_statements.append(normalized_statement)
256+
257+
writer_engine = db.get_engine(bind="writer")
258+
event.listen(writer_engine, "before_cursor_execute", before_cursor_execute)
259+
try:
260+
templates = dao_get_all_templates_for_service(service_id)
261+
# Trigger serialization and potential lazy loading if there are any remaining
262+
reduced_template_schema.dump(templates, many=True)
263+
finally:
264+
event.remove(writer_engine, "before_cursor_execute", before_cursor_execute)
265+
266+
assert matching_statements == []
267+
268+
235269
def test_get_all_templates_for_service_is_alphabetised(sample_service):
236270
create_template(
237271
template_name="Sample Template 1",

0 commit comments

Comments
 (0)