diff --git a/users/Profpatsch/my-prelude/src/Postgres/MonadPostgres.hs b/users/Profpatsch/my-prelude/src/Postgres/MonadPostgres.hs index 39f087725..2f653bcf2 100644 --- a/users/Profpatsch/my-prelude/src/Postgres/MonadPostgres.hs +++ b/users/Profpatsch/my-prelude/src/Postgres/MonadPostgres.hs @@ -195,6 +195,22 @@ querySingleRowWith :: querySingleRowWith qry params decoder = do queryWith qry params decoder >>= ensureSingleRow +-- | Return the first row, if any. +queryFirstRowWithMaybe :: + ( MonadPostgres m, + ToRow qParams, + Typeable qParams, + Typeable a + ) => + Query -> + qParams -> + Decoder a -> + Transaction m (Maybe a) +queryFirstRowWithMaybe qry params decoder = do + queryWith qry params decoder >>= \case + [] -> pure Nothing + (one : _) -> pure $ Just one + -- TODO: implement via fold, so that the result doesn’t have to be realized in memory querySingleRowMaybe :: ( MonadPostgres m, diff --git a/users/Profpatsch/whatcd-resolver/src/Redacted.hs b/users/Profpatsch/whatcd-resolver/src/Redacted.hs index 7ee64e85d..7f7b1b335 100644 --- a/users/Profpatsch/whatcd-resolver/src/Redacted.hs +++ b/users/Profpatsch/whatcd-resolver/src/Redacted.hs @@ -71,7 +71,7 @@ redactedGetArtist :: ( MonadOtel m, MonadThrow m, MonadRedacted m, - HasField "artistId" r Text, + HasField "artistId" r Int, HasField "page" r (Maybe Natural) ) => r -> @@ -83,7 +83,7 @@ redactedGetArtist dat parser = span ( T3 (label @"action" "artist") - (label @"actionArgs" [("id", buildBytes utf8B dat.artistId)]) + (label @"actionArgs" [("id", buildBytes intDecimalB dat.artistId)]) (getLabel @"page" dat) ) parser @@ -184,7 +184,7 @@ redactedRefreshArtist :: MonadThrow m, MonadOtel m, MonadRedacted m, - HasField "artistId" dat Text + HasField "artistId" dat Int ) => dat -> m (Transaction m (Label "newTorrents" [Label "torrentId" Int])) @@ -610,8 +610,9 @@ getTorrentById dat = do data GetBestTorrentsFilter = GetBestTorrentsFilter { onlyDownloaded :: Bool, - onlyArtist :: Maybe (Label "artistRedactedId" Natural), - onlyTheseTorrents :: Maybe ([Label "torrentId" Int]) + onlyArtist :: Maybe (Label "artistRedactedId" Int), + onlyTheseTorrents :: Maybe ([Label "torrentId" Int]), + limitResults :: Maybe Natural } -- | Find the best torrent for each torrent group (based on the seeding_weight) @@ -662,6 +663,7 @@ getBestTorrents opts = do JOIN redacted.torrents t ON t.id = f.id JOIN redacted.torrent_groups tg ON tg.id = t.torrent_group ORDER BY seeding_weight DESC + LIMIT ?::int |] ( do let (onlyArtistB, onlyArtistId) = case opts.onlyArtist of @@ -672,9 +674,10 @@ getBestTorrents opts = do Just a -> (False, a <&> (.torrentId) & PGArray) ( opts.onlyDownloaded :: Bool, onlyArtistB :: Bool, - onlyArtistId & fromIntegral @Natural @Int, + onlyArtistId :: Int, onlyTheseTorrentsB :: Bool, - onlyTheseTorrents + onlyTheseTorrents, + opts.limitResults <&> naturalToInteger :: Maybe Integer ) ) ( do @@ -714,6 +717,29 @@ getBestTorrents opts = do } ) +getArtistNameById :: (MonadPostgres m, HasField "artistId" r Int) => r -> Transaction m (Maybe Text) +getArtistNameById dat = do + queryFirstRowWithMaybe + [sql| + WITH json as ( + SELECT + -- TODO: different endpoints handle this differently (e.g. action=search and action=artist), we should unify this while parsing + COALESCE( + t.full_json_result->'artists', + tg.full_json_result->'artists', + '[]'::jsonb + ) as artists + FROM redacted.torrents t + JOIN redacted.torrent_groups tg ON tg.id = t.torrent_group + ) + select name from json + join lateral jsonb_to_recordset(artists) as x(id int, name text) on true + where id = ?::int + limit 1 + |] + (getLabel @"artistId" dat) + (Dec.fromField @Text) + -- | Do a request to the redacted API. If you know what that is, you know how to find the API docs. mkRedactedApiRequest :: ( MonadThrow m, diff --git a/users/Profpatsch/whatcd-resolver/src/WhatcdResolver.hs b/users/Profpatsch/whatcd-resolver/src/WhatcdResolver.hs index 99fda5ac4..0ba147468 100644 --- a/users/Profpatsch/whatcd-resolver/src/WhatcdResolver.hs +++ b/users/Profpatsch/whatcd-resolver/src/WhatcdResolver.hs @@ -72,9 +72,7 @@ import System.Environment qualified as Env import System.FilePath ((>)) import Text.Blaze.Html (Html) import Text.Blaze.Html.Renderer.Utf8 qualified as Html -import Text.Blaze.Html5 ((!)) import Text.Blaze.Html5 qualified as Html -import Text.Blaze.Html5.Attributes qualified as HtmlA import Tool (readTool, readTools) import Transmission import UnliftIO hiding (Handler) @@ -141,48 +139,52 @@ htmlUi = do Map.fromList $ ourHtmlIntegrities.handlers <> [ ( "", - Html $ \span -> do - counterHtml <- counterHtmlM - mainHtml ourHtmlIntegrities counterHtml uniqueRunId span + HtmlStream (pure ()) $ \_dat span -> + ( pure $ htmlPageChrome ourHtmlIntegrities "whatcd-resolver", + do + counterHtml <- counterHtmlM + mainHtml counterHtml uniqueRunId span + ) ), ( "redacted-search", - HtmlWithQueryArgs (label @"searchstr" <$> singleQueryArgument "searchstr" Cat.id) $ - \dat _span -> do - t <- redactedSearchAndInsert [("searchstr", dat.queryArgs.searchstr)] - runTransaction $ do - res <- t - (table, settings) <- - concurrentlyTraced - ( getBestTorrentsTable - (label @"groupByReleaseType" True) - ( Just - ( E21 - (label @"onlyTheseTorrents" res.newTorrents) - ) :: - Maybe - ( E2 - "onlyTheseTorrents" - [Label "torrentId" Int] - "artistRedactedId" - Natural - ) + HtmlStream (label @"searchstr" <$> singleQueryArgument "searchstr" Cat.id) $ + \dat _span -> + ( pure $ htmlPageChrome ourHtmlIntegrities [fmt|whatcd-resolver – Search – {dat.queryArgs.searchstr & bytesToTextUtf8Lenient}|], + do + t <- redactedSearchAndInsert [("searchstr", dat.queryArgs.searchstr)] + runTransaction $ do + res <- t + (table, settings) <- + concurrentlyTraced + ( getBestTorrentsTable + (t2 #groupByReleaseType True #limitResults Nothing) + ( Just + ( E21 + (label @"onlyTheseTorrents" res.newTorrents) + ) :: + Maybe + ( E2 + "onlyTheseTorrents" + [Label "torrentId" Int] + "artistRedactedId" + Int + ) + ) ) - ) - (getSettings) - pure $ - mainHtml' - ourHtmlIntegrities - ( MainHtml - { pageTitle = [fmt|whatcd-resolver – Search – {dat.queryArgs.searchstr & bytesToTextUtf8Lenient}|], - returnUrl = dat.returnUrl, - counterHtml = "", - mainContent = - [hsx|
{dat.queryArgs.searchstr}{dat.queryArgs.searchstr}