Skip to content

Commit c93b38e

Browse files
committed
fix: update loading strategy in search_score_sets to use selectinload for all relationships
1 parent 15c6e78 commit c93b38e

1 file changed

Lines changed: 16 additions & 15 deletions

File tree

src/mavedb/lib/score_sets.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -238,21 +238,22 @@ def search_score_sets(db: Session, owner_or_contributor: Optional[User], search:
238238
score_sets: list[ScoreSet] = (
239239
query.join(ScoreSet.experiment)
240240
.options(
241-
# Use selectinload for one-to-many experiment relationships to avoid row
242-
# multiplication in the main query. joinedload would LEFT OUTER JOIN these
243-
# into the main SQL query, and because they're nested inside contains_eager,
244-
# SQLAlchemy's subquery-wrapping logic doesn't protect the LIMIT clause from
245-
# being applied to multiplied rows rather than unique score sets. This would
246-
# cause the count of returned score sets to be less than the requested limit,
247-
# and the count query would be triggered even when the number of unique score
248-
# sets in the main query results exceeds the limit.
241+
# Use selectinload for ALL relationships loaded via the main query. The presence of
242+
# contains_eager disables SQLAlchemy's subquery-wrapping logic for the ENTIRE query,
243+
# not just the relationships nested inside it. This means any joinedload that adds a
244+
# LEFT OUTER JOIN to the main SQL query — even for many-to-one relationships — can
245+
# corrupt the LIMIT clause by applying it to joined rows rather than unique score sets,
246+
# causing fewer results than expected and suppressing the count query fallback.
247+
# The only JOINs that should remain in the main query are the explicit experiment
248+
# INNER JOIN (required by contains_eager) and the superseding score set LEFT OUTER JOIN
249+
# added by the filter builder.
249250
contains_eager(ScoreSet.experiment).options(
250-
joinedload(Experiment.experiment_set),
251+
selectinload(Experiment.experiment_set),
251252
selectinload(Experiment.keyword_objs).joinedload(
252253
ExperimentControlledKeywordAssociation.controlled_keyword
253254
),
254-
joinedload(Experiment.created_by),
255-
joinedload(Experiment.modified_by),
255+
selectinload(Experiment.created_by),
256+
selectinload(Experiment.modified_by),
256257
selectinload(Experiment.doi_identifiers),
257258
selectinload(Experiment.publication_identifier_associations).joinedload(
258259
ExperimentPublicationIdentifierAssociation.publication
@@ -272,12 +273,12 @@ def search_score_sets(db: Session, owner_or_contributor: Optional[User], search:
272273
),
273274
),
274275
),
275-
joinedload(ScoreSet.license),
276-
joinedload(ScoreSet.doi_identifiers),
277-
joinedload(ScoreSet.publication_identifier_associations).joinedload(
276+
selectinload(ScoreSet.license),
277+
selectinload(ScoreSet.doi_identifiers),
278+
selectinload(ScoreSet.publication_identifier_associations).joinedload(
278279
ScoreSetPublicationIdentifierAssociation.publication
279280
),
280-
joinedload(ScoreSet.target_genes).options(
281+
selectinload(ScoreSet.target_genes).options(
281282
joinedload(TargetGene.ensembl_offset).joinedload(EnsemblOffset.identifier),
282283
joinedload(TargetGene.refseq_offset).joinedload(RefseqOffset.identifier),
283284
joinedload(TargetGene.uniprot_offset).joinedload(UniprotOffset.identifier),

0 commit comments

Comments
 (0)