rework filtering logic to eliminate hack db call

This commit is contained in:
Lucy Cifferello
2023-07-24 11:25:23 -04:00
parent ab8fbbb210
commit 807fdee1e1
5 changed files with 49 additions and 52 deletions

View File

@@ -16,13 +16,13 @@
"build": [ "build": [
"make" "make"
], ],
"hardware-requirements" { "hardware-requirements": {
"device": { "device": {
"processor": "intel", "processor": "intel",
"display": "r'^{.*}$'" "display": "r'^{.*}$'"
}, },
"ram": "8" "ram": "8"
} },
"release-notes": "Upgrade to EmbassyOS v0.3.0", "release-notes": "Upgrade to EmbassyOS v0.3.0",
"license": "mit", "license": "mit",
"wrapper-repo": "https://github.com/Start9Labs/lnd-wrapper", "wrapper-repo": "https://github.com/Start9Labs/lnd-wrapper",

View File

@@ -31,7 +31,7 @@ import Startlude (
getCurrentTime, getCurrentTime,
maybe, maybe,
($), ($),
(.), Bool (False), (.), Bool (False), fst,
) )
import System.FilePath (takeExtension) import System.FilePath (takeExtension)
import UnliftIO ( import UnliftIO (
@@ -97,7 +97,7 @@ import Model (
VersionRecordNumber, VersionRecordNumber,
VersionRecordPkgId, VersionRecordPkgId,
VersionRecordTitle, VersionRecordTitle,
VersionRecordUpdatedAt, PkgRecordHidden, VersionPlatformRam VersionRecordUpdatedAt, PkgRecordHidden, VersionPlatformRam, VersionPlatformCreatedAt, VersionPlatformUpdatedAt
), ),
Key (unPkgRecordKey), Key (unPkgRecordKey),
PkgCategory, PkgCategory,
@@ -116,7 +116,8 @@ import Startlude (
($>), ($>),
(<$>), Int, (<$>), Int,
) )
import Database.Esqueleto.Experimental ((>.)) import Database.Esqueleto.Experimental (isNothing)
import Database.Esqueleto.Experimental ((>=.))
serviceQuerySource :: serviceQuerySource ::
(MonadResource m, MonadIO m) => (MonadResource m, MonadIO m) =>
@@ -124,19 +125,19 @@ serviceQuerySource ::
Text -> Text ->
[OsArch] -> [OsArch] ->
Maybe Int -> Maybe Int ->
ConduitT () (Entity VersionRecord) (ReaderT SqlBackend m) () ConduitT () (Entity VersionRecord, Entity VersionPlatform) (ReaderT SqlBackend m) ()
serviceQuerySource mCat query arches mRam = selectSource $ do serviceQuerySource mCat query arches mRam = selectSource $ do
service <- case mCat of (service, vp) <- case mCat of
Nothing -> do Nothing -> do
(service :& vp :& pr) <- from $ table @VersionRecord (service :& vp :& pr) <- from $ table @VersionRecord
`innerJoin` table @VersionPlatform `on` (\(service :& vp) -> (VersionPlatformPkgId === VersionRecordPkgId) (vp :& service)) `innerJoin` table @VersionPlatform `on` (\(service :& vp) -> (VersionPlatformPkgId === VersionRecordPkgId) (vp :& service))
`innerJoin` table @PkgRecord `on` (\(v :& _ :& p) -> (PkgRecordId === VersionRecordPkgId) (p :& v)) `innerJoin` table @PkgRecord `on` (\(v :& _ :& p) -> (PkgRecordId === VersionRecordPkgId) (p :& v))
where_ (service ^. VersionRecordNumber ==. vp ^. VersionPlatformVersionNumber) where_ (service ^. VersionRecordNumber ==. vp ^. VersionPlatformVersionNumber)
where_ (vp ^. VersionPlatformArch `in_` (valList $ Just <$> arches)) where_ (vp ^. VersionPlatformArch `in_` (valList $ Just <$> arches))
where_ (vp ^. VersionPlatformRam ==. val mRam) where_ (vp ^. VersionPlatformRam >=. val mRam ||. isNothing (vp ^. VersionPlatformRam))
where_ (pr ^. PkgRecordHidden ==. val False) where_ (pr ^. PkgRecordHidden ==. val False)
where_ $ queryInMetadata query service where_ $ queryInMetadata query service
pure service pure (service, vp)
Just category -> do Just category -> do
(service :& _ :& cat :& vp :& pr) <- (service :& _ :& cat :& vp :& pr) <-
from $ from $
@@ -150,16 +151,16 @@ serviceQuerySource mCat query arches mRam = selectSource $ do
where_ $ cat ^. CategoryName ==. val category &&. queryInMetadata query service where_ $ cat ^. CategoryName ==. val category &&. queryInMetadata query service
where_ (service ^. VersionRecordNumber ==. vp ^. VersionPlatformVersionNumber) where_ (service ^. VersionRecordNumber ==. vp ^. VersionPlatformVersionNumber)
where_ (vp ^. VersionPlatformArch `in_` (valList $ Just <$> arches)) where_ (vp ^. VersionPlatformArch `in_` (valList $ Just <$> arches))
where_ (vp ^. VersionPlatformRam >. val mRam) where_ (vp ^. VersionPlatformRam >=. val mRam ||. isNothing (vp ^. VersionPlatformRam))
where_ (pr ^. PkgRecordHidden ==. val False) where_ (pr ^. PkgRecordHidden ==. val False)
pure service pure (service, vp)
groupBy (service ^. VersionRecordPkgId, service ^. VersionRecordNumber) groupBy (service ^. VersionRecordPkgId, service ^. VersionRecordNumber, vp ^. VersionPlatformCreatedAt, vp ^. VersionPlatformUpdatedAt, vp ^. VersionPlatformPkgId, vp ^. VersionPlatformVersionNumber)
orderBy orderBy
[ asc (service ^. VersionRecordPkgId) [ asc (service ^. VersionRecordPkgId)
, desc (service ^. VersionRecordNumber) , desc (service ^. VersionRecordNumber)
, desc (service ^. VersionRecordUpdatedAt) , desc (service ^. VersionRecordUpdatedAt)
] ]
pure service pure (service, vp)
queryInMetadata :: Text -> SqlExpr (Entity VersionRecord) -> (SqlExpr (Value Bool)) queryInMetadata :: Text -> SqlExpr (Entity VersionRecord) -> (SqlExpr (Value Bool))
queryInMetadata query service = queryInMetadata query service =
@@ -168,15 +169,15 @@ queryInMetadata query service =
||. (service ^. VersionRecordTitle `ilike` (%) ++. val query ++. (%)) ||. (service ^. VersionRecordTitle `ilike` (%) ++. val query ++. (%))
getPkgDataSource :: (MonadResource m, MonadIO m) => [PkgId] -> [OsArch] -> Maybe Int -> ConduitT () (Entity VersionRecord) (ReaderT SqlBackend m) () getPkgDataSource :: (MonadResource m, MonadIO m) => [PkgId] -> [OsArch] -> Maybe Int -> ConduitT () (Entity VersionRecord, Entity VersionPlatform) (ReaderT SqlBackend m) ()
getPkgDataSource pkgs arches mRam = selectSource $ do getPkgDataSource pkgs arches mRam = selectSource $ do
(pkgData :& vp) <- from $ table @VersionRecord (pkgData :& vp) <- from $ table @VersionRecord
`innerJoin` table @VersionPlatform `on` (\(service :& vp) -> (VersionPlatformPkgId === VersionRecordPkgId) (vp :& service)) `innerJoin` table @VersionPlatform `on` (\(service :& vp) -> (VersionPlatformPkgId === VersionRecordPkgId) (vp :& service))
where_ (pkgData ^. VersionRecordNumber ==. vp ^. VersionPlatformVersionNumber) where_ (pkgData ^. VersionRecordNumber ==. vp ^. VersionPlatformVersionNumber)
where_ (vp ^. VersionPlatformArch `in_` (valList $ Just <$> arches)) where_ (vp ^. VersionPlatformArch `in_` (valList $ Just <$> arches))
where_ (vp ^. VersionPlatformRam ==. val mRam) where_ (vp ^. VersionPlatformRam >=. val mRam ||. isNothing (vp ^. VersionPlatformRam))
where_ (pkgData ^. VersionRecordPkgId `in_` valList (PkgRecordKey <$> pkgs)) where_ (pkgData ^. VersionRecordPkgId `in_` valList (PkgRecordKey <$> pkgs))
pure pkgData pure (pkgData, vp)
getPkgDependencyData :: getPkgDependencyData ::
@@ -219,18 +220,20 @@ getCategoriesFor pkg = fmap (fmap entityVal) $
collateVersions :: collateVersions ::
MonadUnliftIO m => MonadUnliftIO m =>
ConduitT (Entity VersionRecord) (PkgId, [VersionRecord]) (ReaderT SqlBackend m) () ConduitT (Entity VersionRecord, Entity VersionPlatform) (PkgId, [(VersionRecord, VersionPlatform)]) (ReaderT SqlBackend m) ()
collateVersions = awaitForever $ \v0 -> do collateVersions = awaitForever $ \(v0, _) -> do
let pkg = unPkgRecordKey . versionRecordPkgId $ entityVal v0 let pkg = unPkgRecordKey . versionRecordPkgId $ entityVal v0
minput <- await
let pull = do let pull = do
mvn <- await -- mvn <- await
case mvn of case minput of
Nothing -> pure Nothing Nothing -> pure Nothing
Just vn -> do Just vn -> do
let pkg' = unPkgRecordKey . versionRecordPkgId $ entityVal vn let pkg' = unPkgRecordKey . versionRecordPkgId $ entityVal $ fst vn
if pkg == pkg' then pure (Just vn) else leftover vn $> Nothing if pkg == pkg' then pure (Just vn) else leftover vn $> Nothing
ls <- unfoldM pull ls <- unfoldM pull
yield (pkg, fmap entityVal $ v0 : ls) let withoutEntity = fmap (\a -> (entityVal $ fst a, entityVal $ snd a)) ls
yield (pkg, withoutEntity)
getDependencyVersions :: getDependencyVersions ::

View File

@@ -9,14 +9,14 @@ import Data.List (lookup)
import Data.List.NonEmpty.Extra qualified as NE import Data.List.NonEmpty.Extra qualified as NE
import Data.Tuple.Extra (second) import Data.Tuple.Extra (second)
import Database.Queries (collateVersions, getPkgDataSource) import Database.Queries (collateVersions, getPkgDataSource)
import Foundation (Handler, RegistryCtx (appSettings, appConnPool)) import Foundation (Handler, RegistryCtx (appSettings))
import Handler.Package.V1.Index (getOsVersionCompat, getRamQuery, getHardwareDevicesQuery) import Handler.Package.V1.Index (getOsVersionCompat, getRamQuery, getHardwareDevicesQuery)
import Lib.Error (S9Error (..)) import Lib.Error (S9Error (..))
import Lib.Types.Core (PkgId) import Lib.Types.Core (PkgId)
import Lib.Types.Emver (Version (..), satisfies) import Lib.Types.Emver (Version (..), satisfies)
import Model (VersionRecord (..)) import Model (VersionRecord (..))
import Network.HTTP.Types (status400) import Network.HTTP.Types (status400)
import Startlude (Bool (True), Down (Down), Either (..), Generic, Maybe (..), NonEmpty, Show, const, encodeUtf8, filter, flip, nonEmpty, pure, ($), (.), (<$>), (<&>), (>>=)) import Startlude (Bool (True), Down (Down), Either (..), Generic, Maybe (..), NonEmpty, Show, const, encodeUtf8, filter, flip, nonEmpty, pure, ($), (.), (<$>), (<&>), (>>=), fst)
import Yesod (ToContent (..), ToTypedContent (..), YesodPersist (runDB), YesodRequest (reqGetParams), getRequest, sendResponseStatus) import Yesod (ToContent (..), ToTypedContent (..), YesodPersist (runDB), YesodRequest (reqGetParams), getRequest, sendResponseStatus)
import Handler.Util (filterDeprecatedVersions, getPkgArch, filterDevices) import Handler.Util (filterDeprecatedVersions, getPkgArch, filterDevices)
import Yesod.Core (getsYesod) import Yesod.Core (getsYesod)
@@ -45,7 +45,6 @@ getVersionLatestR = do
ram <- getRamQuery ram <- getRamQuery
hardwareDevices <- getHardwareDevicesQuery hardwareDevices <- getHardwareDevicesQuery
communityServiceDeprecationVersion <- getsYesod $ communityVersion . appSettings communityServiceDeprecationVersion <- getsYesod $ communityVersion . appSettings
pool <- getsYesod appConnPool
do do
case lookup "ids" getParameters of case lookup "ids" getParameters of
Nothing -> sendResponseStatus status400 (InvalidParamsE "get:ids" "<MISSING>") Nothing -> sendResponseStatus status400 (InvalidParamsE "get:ids" "<MISSING>")
@@ -61,14 +60,14 @@ getVersionLatestR = do
-- group conduit pipeline by pkg id -- group conduit pipeline by pkg id
.| collateVersions .| collateVersions
-- filter out versions of apps that are incompatible with the OS predicate -- filter out versions of apps that are incompatible with the OS predicate
.| mapC (second (filter (osPredicate' . versionRecordOsVersion))) .| mapC (second (filter (osPredicate' . versionRecordOsVersion . fst)))
-- filter out deprecated service versions after community registry release
.| mapC (second (filterDeprecatedVersions communityServiceDeprecationVersion osPredicate'))
-- filter hardware device compatability -- filter hardware device compatability
.| mapMC (\(b,c) -> do .| mapMC (\(b,c) -> do
l <- filterDevices pool hardwareDevices pkgArch c l <- filterDevices hardwareDevices pkgArch c
pure (b, l) pure (b, l)
) )
-- filter out deprecated service versions after community registry release
.| mapC (second (filterDeprecatedVersions communityServiceDeprecationVersion osPredicate'))
-- prune empty version sets -- prune empty version sets
.| concatMapC (\(pkgId, vs) -> (pkgId,) <$> nonEmpty vs) .| concatMapC (\(pkgId, vs) -> (pkgId,) <$> nonEmpty vs)
-- grab the latest matching version if it exists -- grab the latest matching version if it exists

View File

@@ -25,7 +25,7 @@ import Database.Queries (
getPkgDependencyData, getPkgDependencyData,
serviceQuerySource, serviceQuerySource,
) )
import Foundation (Handler, Route (InstructionsR, LicenseR), RegistryCtx (appSettings, appConnPool)) import Foundation (Handler, Route (InstructionsR, LicenseR), RegistryCtx (appSettings))
import Handler.Package.Api (DependencyRes (..), PackageListRes (..), PackageRes (..)) import Handler.Package.Api (DependencyRes (..), PackageListRes (..), PackageRes (..))
import Handler.Types.Api (ApiVersion (..)) import Handler.Types.Api (ApiVersion (..))
import Handler.Util (basicRender, parseQueryParam, filterDeprecatedVersions, filterDevices, getPkgArch) import Handler.Util (basicRender, parseQueryParam, filterDeprecatedVersions, filterDevices, getPkgArch)
@@ -129,7 +129,6 @@ getPackageIndexR = do
ram <- getRamQuery ram <- getRamQuery
hardwareDevices <- getHardwareDevicesQuery hardwareDevices <- getHardwareDevicesQuery
communityVersion <- getsYesod $ communityVersion . appSettings communityVersion <- getsYesod $ communityVersion . appSettings
pool <- getsYesod appConnPool
pkgIds <- getPkgIdsQuery pkgIds <- getPkgIdsQuery
category <- getCategoryQuery category <- getCategoryQuery
page <- fromMaybe 1 <$> getPageQuery page <- fromMaybe 1 <$> getPageQuery
@@ -148,14 +147,14 @@ getPackageIndexR = do
-- group conduit pipeline by pkg id -- group conduit pipeline by pkg id
.| collateVersions .| collateVersions
-- filter out versions of apps that are incompatible with the OS predicate -- filter out versions of apps that are incompatible with the OS predicate
.| mapC (second (filter (osPredicate . versionRecordOsVersion))) .| mapC (second (filter (osPredicate . versionRecordOsVersion . fst)))
-- filter out deprecated service versions after community registry release
.| mapC (second (filterDeprecatedVersions communityVersion osPredicate))
-- filter hardware device compatability -- filter hardware device compatability
.| mapMC (\(b,c) -> do .| mapMC (\(b,c) -> do
l <- filterDevices pool hardwareDevices pkgArch c l <- filterDevices hardwareDevices pkgArch c
pure (b, l) pure (b, l)
) )
-- filter out deprecated service versions after community registry release
.| mapC (second (filterDeprecatedVersions communityVersion osPredicate))
-- prune empty version sets -- prune empty version sets
.| concatMapC (\(pkgId, vs) -> (pkgId,) <$> nonEmpty vs) .| concatMapC (\(pkgId, vs) -> (pkgId,) <$> nonEmpty vs)
-- grab the latest matching version if it exists -- grab the latest matching version if it exists

View File

@@ -1,5 +1,6 @@
{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -Wno-unused-imports #-}
module Handler.Util where module Handler.Util where
@@ -61,7 +62,7 @@ import Startlude (
($), ($),
(.), (.),
(<$>), (<$>),
(>>=), note, (=<<), catMaybes, all, traverse, or, encodeUtf8, toS (>>=), note, (=<<), catMaybes, all, encodeUtf8, toS, fmap
) )
import UnliftIO (MonadUnliftIO) import UnliftIO (MonadUnliftIO)
import Yesod ( import Yesod (
@@ -82,10 +83,7 @@ import Lib.Error (S9Error (..))
import Data.Maybe (isJust) import Data.Maybe (isJust)
import qualified Data.HashMap.Strict as HM import qualified Data.HashMap.Strict as HM
import Lib.Types.Manifest import Lib.Types.Manifest
import Startlude (MonadIO)
import Text.Regex.TDFA ((=~)) import Text.Regex.TDFA ((=~))
import Startlude (filterM)
import Database.Persist.Postgresql (ConnectionPool, runSqlPool)
import Data.Aeson (eitherDecodeStrict) import Data.Aeson (eitherDecodeStrict)
import Data.Bifunctor (Bifunctor(first)) import Data.Bifunctor (Bifunctor(first))
@@ -229,25 +227,23 @@ filterDeprecatedVersions communityVersion osPredicate vrs = do
then filter (\v -> not $ isJust $ versionRecordDeprecatedAt v) $ vrs then filter (\v -> not $ isJust $ versionRecordDeprecatedAt v) $ vrs
else vrs else vrs
filterDevices :: (MonadUnliftIO m) => ConnectionPool -> (HM.HashMap Text Text) -> [OsArch] -> [VersionRecord] -> m [VersionRecord] filterDevices :: (MonadUnliftIO m) => (HM.HashMap Text Text) -> [OsArch] -> [(VersionRecord, VersionPlatform)] -> m [VersionRecord]
filterDevices pool hardwareDevices arches pkgRecords = do filterDevices hardwareDevices arches pkgRecords = do
res <- filterM compareHd pkgRecords pure $ catMaybes $ fmap (compareHd hardwareDevices) pkgRecords
pure res
where where
compareHd pkgRecord = do compareHd :: HM.HashMap Text Text -> (VersionRecord, VersionPlatform) -> Maybe VersionRecord
let id = versionRecordPkgId pkgRecord compareHd hd (vr, vp) = case versionPlatformDevice vp of
platformDetails <- flip runSqlPool pool $ getVersionPlatform id arches Nothing -> Just vr
let pkgDevices = catMaybes $ versionPlatformDevice <$> platformDetails Just d -> if areRegexMatchesEqual hd d
t <- traverse (areRegexMatchesEqual hardwareDevices) pkgDevices then Just vr
pure $ or t else Nothing
regexMatch :: RegexPattern -> Text -> Bool regexMatch :: RegexPattern -> Text -> Bool
regexMatch (RegexPattern pattern) text = text =~ pattern regexMatch (RegexPattern pattern) text = text =~ pattern
areRegexMatchesEqual :: (MonadIO m) => HM.HashMap Text Text -> PackageDevice -> m Bool areRegexMatchesEqual :: HM.HashMap Text Text -> PackageDevice -> Bool
areRegexMatchesEqual textMap (PackageDevice regexMap) = areRegexMatchesEqual textMap (PackageDevice regexMap) =
-- putStrLn @Text textMap all checkMatch (HM.toList regexMap)
pure $ all checkMatch (HM.toList regexMap)
where where
checkMatch :: (Text, RegexPattern) -> Bool checkMatch :: (Text, RegexPattern) -> Bool
checkMatch (key, regexPattern) = case HM.lookup key textMap of checkMatch (key, regexPattern) = case HM.lookup key textMap of