feat: random sort option for front page (#2363)

* Add hook for random sorting

* Add random sorting to front page

* Add multiple tests for random sorting.

* Be extra sure that all recipes are returned.

* Too stable random. seed doesn't reach backend.

* add timestamp to useRecipeSearch

* Update randomization tests for timestamp seeding

* ruff cleanup

* pass timestamp separately in getAll

* remove debugging log items

* remove timestamp from address bar

* remove defaults from backend timestamps

* timestamp should be optional

* fix edge case: query without timestamp

* similar edge case: no timestamp in pagination

* ruff :/

* better edge case handling

* stabilize random search test w/more recipes

* better pagination seeding

* update pagination seed test

* remove redundant random/seed check

* Test for api routes to random sorting.

* please the typing gods

* hack to make query parameters throw correct exc

* ruff

* fix validator message typo

* black reformatting

---------

Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
Jacob Corn
2023-05-30 02:56:20 +02:00
committed by GitHub
parent 7e0d29afc7
commit e1d3a247c7
10 changed files with 202 additions and 7 deletions

View File

@@ -1,12 +1,13 @@
from __future__ import annotations
import random
from collections.abc import Iterable
from math import ceil
from typing import Any, Generic, TypeVar
from fastapi import HTTPException
from pydantic import UUID4, BaseModel
from sqlalchemy import Select, delete, func, select
from sqlalchemy import Select, case, delete, func, select
from sqlalchemy.orm.session import Session
from sqlalchemy.sql import sqltypes
@@ -378,4 +379,16 @@ class RepositoryGeneric(Generic[Schema, Model]):
query = query.order_by(order_attr)
elif pagination.order_by == "random":
# randomize outside of database, since not all db's can set random seeds
# this solution is db-independent & stable to paging
temp_query = query.with_only_columns(self.model.id)
allids = self.session.execute(temp_query).scalars().all() # fast because id is indexed
order = list(range(len(allids)))
random.seed(pagination.pagination_seed)
random.shuffle(order)
random_dict = dict(zip(allids, order, strict=True))
case_stmt = case(random_dict, value=self.model.id)
query = query.order_by(case_stmt)
return query.limit(pagination.per_page).offset((pagination.page - 1) * pagination.per_page), count, total_pages