mirror of
https://github.com/Start9Labs/registry.git
synced 2026-03-26 10:21:51 +00:00
175 lines
8.0 KiB
Haskell
175 lines
8.0 KiB
Haskell
{-# LANGUAGE RankNTypes #-}
|
|
{-# LANGUAGE TypeApplications #-}
|
|
{-# LANGUAGE DeriveGeneric #-}
|
|
|
|
module Database.Marketplace where
|
|
|
|
import Conduit ( ConduitT
|
|
, MonadResource
|
|
, MonadUnliftIO
|
|
, awaitForever
|
|
, yield
|
|
)
|
|
import Database.Esqueleto.Experimental
|
|
( (%)
|
|
, (&&.)
|
|
, (++.)
|
|
, (:&)(..)
|
|
, (==.)
|
|
, (^.)
|
|
, desc
|
|
, from
|
|
, ilike
|
|
, in_
|
|
, innerJoin
|
|
, on
|
|
, orderBy
|
|
, select
|
|
, selectSource
|
|
, table
|
|
, val
|
|
, valList
|
|
, where_
|
|
, (||.)
|
|
)
|
|
import qualified Database.Persist as P
|
|
import Database.Persist.Postgresql
|
|
hiding ( (==.)
|
|
, getJust
|
|
, selectSource
|
|
, (||.)
|
|
)
|
|
import Handler.Types.Marketplace ( PackageDependencyMetadata(..)
|
|
)
|
|
import Lib.Types.AppIndex ( PkgId )
|
|
import Lib.Types.Category
|
|
import Lib.Types.Emver ( Version )
|
|
import Model
|
|
import Startlude hiding ( (%)
|
|
, from
|
|
, on
|
|
, yield
|
|
)
|
|
|
|
searchServices :: (MonadResource m, MonadIO m)
|
|
=> Maybe CategoryTitle
|
|
-> Text
|
|
-> ConduitT () (Entity PkgRecord) (ReaderT SqlBackend m) ()
|
|
searchServices Nothing query = selectSource $ do
|
|
service <- from $ table @PkgRecord
|
|
where_
|
|
( (service ^. PkgRecordDescShort `ilike` (%) ++. val query ++. (%))
|
|
||. (service ^. PkgRecordDescLong `ilike` (%) ++. val query ++. (%))
|
|
||. (service ^. PkgRecordTitle `ilike` (%) ++. val query ++. (%))
|
|
)
|
|
orderBy [desc (service ^. PkgRecordUpdatedAt)]
|
|
pure service
|
|
searchServices (Just category) query = selectSource $ do
|
|
services <- from
|
|
(do
|
|
(service :& _ :& cat) <-
|
|
from
|
|
$ table @PkgRecord
|
|
`innerJoin` table @PkgCategory
|
|
`on` (\(s :& sc) -> sc ^. PkgCategoryPkgId ==. s ^. PkgRecordId)
|
|
`innerJoin` table @Category
|
|
`on` (\(_ :& sc :& cat) -> sc ^. PkgCategoryCategoryId ==. cat ^. CategoryId)
|
|
-- if there is a cateogry, only search in category
|
|
-- weight title, short, long (bitcoin should equal Bitcoin Core)
|
|
where_
|
|
$ cat
|
|
^. CategoryName
|
|
==. val category
|
|
&&. ( (service ^. PkgRecordDescShort `ilike` (%) ++. val query ++. (%))
|
|
||. (service ^. PkgRecordDescLong `ilike` (%) ++. val query ++. (%))
|
|
||. (service ^. PkgRecordTitle `ilike` (%) ++. val query ++. (%))
|
|
)
|
|
pure service
|
|
)
|
|
orderBy [desc (services ^. PkgRecordUpdatedAt)]
|
|
pure services
|
|
|
|
getPkgData :: (MonadResource m, MonadIO m) => [PkgId] -> ConduitT () (Entity PkgRecord) (ReaderT SqlBackend m) ()
|
|
getPkgData pkgs = selectSource $ do
|
|
pkgData <- from $ table @PkgRecord
|
|
where_ (pkgData ^. PkgRecordId `in_` valList (PkgRecordKey <$> pkgs))
|
|
pure pkgData
|
|
|
|
getPkgDependencyData :: MonadIO m
|
|
=> Key PkgRecord
|
|
-> Version
|
|
-> ReaderT SqlBackend m ([(Entity PkgDependency, Entity PkgRecord)])
|
|
getPkgDependencyData pkgId pkgVersion = select $ do
|
|
pd <- from
|
|
(do
|
|
(pkgDepRecord :& depPkgRecord) <-
|
|
from
|
|
$ table @PkgDependency
|
|
`innerJoin` table @PkgRecord
|
|
`on` (\(pdr :& dpr) -> dpr ^. PkgRecordId ==. pdr ^. PkgDependencyDepId)
|
|
where_ (pkgDepRecord ^. PkgDependencyPkgId ==. (val pkgId))
|
|
where_ (pkgDepRecord ^. PkgDependencyPkgVersion ==. val pkgVersion)
|
|
pure (pkgDepRecord, depPkgRecord)
|
|
)
|
|
pure pd
|
|
|
|
zipCategories :: MonadUnliftIO m
|
|
=> ConduitT
|
|
(Entity PkgRecord, [Entity VersionRecord])
|
|
(Entity PkgRecord, [Entity VersionRecord], [Entity Category])
|
|
(ReaderT SqlBackend m)
|
|
()
|
|
zipCategories = awaitForever $ \(pkg, vers) -> do
|
|
let pkgDbId = entityKey pkg
|
|
raw <- lift $ select $ do
|
|
(sc :& cat) <-
|
|
from
|
|
$ table @PkgCategory
|
|
`innerJoin` table @Category
|
|
`on` (\(sc :& cat) -> sc ^. PkgCategoryCategoryId ==. cat ^. CategoryId)
|
|
where_ (sc ^. PkgCategoryPkgId ==. val pkgDbId)
|
|
pure cat
|
|
yield (pkg, vers, raw)
|
|
|
|
zipVersions :: MonadUnliftIO m
|
|
=> ConduitT (Entity PkgRecord) (Entity PkgRecord, [Entity VersionRecord]) (ReaderT SqlBackend m) ()
|
|
zipVersions = awaitForever $ \pkg -> do
|
|
let appDbId = entityKey pkg
|
|
res <- lift $ select $ do
|
|
v <- from $ table @VersionRecord
|
|
where_ $ v ^. VersionRecordPkgId ==. val appDbId
|
|
-- first value in list will be latest version
|
|
orderBy [desc (v ^. VersionRecordNumber)]
|
|
pure v
|
|
yield (pkg, res)
|
|
|
|
zipDependencyVersions :: (Monad m, MonadIO m)
|
|
=> (Entity PkgDependency, Entity PkgRecord)
|
|
-> ReaderT SqlBackend m PackageDependencyMetadata
|
|
zipDependencyVersions (pkgDepRecord, depRecord) = do
|
|
let pkgDbId = entityKey $ depRecord
|
|
depVers <- select $ do
|
|
v <- from $ table @VersionRecord
|
|
where_ $ v ^. VersionRecordPkgId ==. val pkgDbId
|
|
pure v
|
|
pure $ PackageDependencyMetadata { packageDependencyMetadataPkgDependencyRecord = pkgDepRecord
|
|
, packageDependencyMetadataDepPkgRecord = depRecord
|
|
, packageDependencyMetadataDepVersions = depVers
|
|
}
|
|
|
|
fetchAllAppVersions :: MonadUnliftIO m => ConnectionPool -> PkgId -> m [VersionRecord]
|
|
fetchAllAppVersions appConnPool appId = do
|
|
entityAppVersions <- runSqlPool (P.selectList [VersionRecordPkgId P.==. PkgRecordKey appId] []) appConnPool
|
|
pure $ entityVal <$> entityAppVersions
|
|
|
|
fetchLatestApp :: MonadIO m => PkgId -> ReaderT SqlBackend m (Maybe (P.Entity PkgRecord, P.Entity VersionRecord))
|
|
fetchLatestApp appId = fmap headMay . sortResults . select $ do
|
|
(service :& version) <-
|
|
from
|
|
$ table @PkgRecord
|
|
`innerJoin` table @VersionRecord
|
|
`on` (\(service :& version) -> service ^. PkgRecordId ==. version ^. VersionRecordPkgId)
|
|
where_ (service ^. PkgRecordId ==. val (PkgRecordKey appId))
|
|
pure (service, version)
|
|
where sortResults = fmap $ sortOn (Down . versionRecordNumber . entityVal . snd)
|