Skip to content

Commit a096d49

Browse files
committed
(PC-39018)[API] refactor: optimize query for get_expired_offers()
1 parent 5e53ace commit a096d49

File tree

3 files changed

+36
-22
lines changed

3 files changed

+36
-22
lines changed

api/src/pcapi/core/offers/api.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,17 +1607,15 @@ def unindex_expired_offers(process_all_expired: bool = False) -> None:
16071607
offers.
16081608
"""
16091609
start_of_day = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
1610-
interval = [start_of_day - datetime.timedelta(days=2), start_of_day]
1610+
start_time = start_of_day - datetime.timedelta(days=2)
1611+
end_time = start_of_day
16111612
if process_all_expired:
1612-
interval[0] = datetime.datetime(2000, 1, 1) # arbitrary old date
1613+
start_time = datetime.datetime(2000, 1, 1) # arbitrary old date
16131614

16141615
page = 0
16151616
limit = settings.ALGOLIA_DELETING_OFFERS_CHUNK_SIZE
16161617
while True:
1617-
offers = offers_repository.get_expired_offers(interval)
1618-
offers = offers.offset(page * limit).limit(limit)
1619-
offer_ids = [offer_id for (offer_id,) in offers.with_entities(models.Offer.id)]
1620-
1618+
offer_ids = offers_repository.get_expired_offers(start_time, end_time, offset=page * limit, limit=limit)
16211619
if not offer_ids:
16221620
break
16231621

api/src/pcapi/core/offers/repository.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -744,24 +744,42 @@ def find_event_stocks_day(start: datetime.datetime, end: datetime.datetime) -> s
744744
)
745745

746746

747-
def get_expired_offers(interval: list[datetime.datetime]) -> sa_orm.Query:
747+
def get_expired_offers(
748+
start_time: datetime.datetime, end_time: datetime.datetime, offset: int | None = None, limit: int | None = None
749+
) -> typing.Sequence[int]:
748750
"""Return a query of offers whose latest booking limit occurs within
749751
the given interval.
750752
751753
Inactive or deleted offers are ignored.
752754
"""
753-
return (
754-
db.session.query(models.Offer)
755-
.join(models.Stock)
756-
.filter(
757-
models.Offer.isActive,
755+
exists_future_stock = (
756+
sa.select(models.Stock.id)
757+
.where(
758+
models.Stock.offerId == models.Offer.id,
759+
models.Stock.bookingLimitDatetime > end_time,
760+
models.Stock.isSoftDeleted.is_(False),
761+
)
762+
.exists()
763+
.correlate(models.Offer)
764+
)
765+
query = (
766+
sa.select(models.Offer.id.distinct())
767+
.select_from(models.Offer)
768+
.join(models.Offer.stocks)
769+
.where(
770+
models.Offer.publicationDatetime.is_not(None),
758771
models.Stock.isSoftDeleted.is_(False),
759772
models.Stock.bookingLimitDatetime.is_not(None),
773+
models.Stock.bookingLimitDatetime.between(start_time, end_time),
774+
sa.not_(exists_future_stock),
760775
)
761-
.having(sa.func.max(models.Stock.bookingLimitDatetime).between(*interval)) # type: ignore[arg-type]
762-
.group_by(models.Offer.id)
763776
.order_by(models.Offer.id)
764777
)
778+
if offset:
779+
query = query.offset(offset)
780+
if limit:
781+
query = query.limit(limit)
782+
return db.session.execute(query).scalars().all()
765783

766784

767785
def find_today_event_stock_ids_metropolitan_france(

api/tests/core/offers/test_repository.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,10 +1239,8 @@ def test_find_today_digital_stock_ids_by_departments_with_address_different_than
12391239

12401240
@pytest.mark.usefixtures("db_session")
12411241
class GetExpiredOffersTest:
1242-
interval = [
1243-
datetime.datetime(2021, 1, 1, 0, 0),
1244-
datetime.datetime(2021, 1, 2, 0, 0),
1245-
]
1242+
start_time = (datetime.datetime(2021, 1, 1, 0, 0),)
1243+
end_time = (datetime.datetime(2021, 1, 2, 0, 0),)
12461244
dt_before = datetime.datetime(2020, 12, 31)
12471245
dt_within = datetime.datetime(2021, 1, 1)
12481246
dt_after = datetime.datetime(2021, 1, 3)
@@ -1260,9 +1258,9 @@ def test_basics(self):
12601258
factories.StockFactory(bookingLimitDatetime=self.dt_before)
12611259
factories.StockFactory(bookingLimitDatetime=self.dt_after)
12621260

1263-
offers = repository.get_expired_offers(self.interval)
1261+
offer_ids = repository.get_expired_offers(self.start_time, self.end_time)
12641262

1265-
assert offers.all() == [offer1, offer2, offer3]
1263+
assert offer_ids == [offer.id for offer in (offer1, offer2, offer3)]
12661264

12671265
def test_exclude_if_latest_stock_outside_interval(self):
12681266
offer1 = factories.OfferFactory()
@@ -1271,9 +1269,9 @@ def test_exclude_if_latest_stock_outside_interval(self):
12711269
factories.StockFactory(offer=offer2, bookingLimitDatetime=self.dt_within)
12721270
factories.StockFactory(offer=offer2, bookingLimitDatetime=self.dt_after)
12731271

1274-
offers = repository.get_expired_offers(self.interval)
1272+
offer_ids = repository.get_expired_offers(self.start_time, self.end_time)
12751273

1276-
assert offers.all() == [offer1]
1274+
assert offer_ids == [offer1.id]
12771275

12781276

12791277
@pytest.mark.usefixtures("db_session")

0 commit comments

Comments
 (0)