-- |
-- Module: Staversion.Internal.Result
-- Description: Result data type and its utilities
-- Maintainer: Toshio Ito <debug.ito@gmail.com>
--
-- __This is an internal module. End-users should not use it.__
module Staversion.Internal.Result
       ( Result(..),
         ResultSource(..),
         resultSourceDesc,
         ResultBody,
         ResultBody'(..),
         resultPackages,
         AggregatedResult(..),
         singletonResult
       ) where

import Data.List.NonEmpty (NonEmpty(..))
import Data.Monoid ((<>))
import Data.Text (Text)
import Staversion.Internal.Query
  ( Query, PackageSource, ErrorMsg, PackageName,
    sourceDesc
  )
import Staversion.Internal.Cabal (Target)
import Staversion.Internal.Version (Version, VersionRange, thisVersion)

-- | Result for a query.
data Result = Result { Result -> ResultSource
resultIn :: ResultSource,
                       Result -> Query
resultFor :: Query,
                       Result -> Either ErrorMsg ResultBody
resultBody :: Either ErrorMsg ResultBody
                     } deriving (Int -> Result -> ShowS
[Result] -> ShowS
Result -> ErrorMsg
(Int -> Result -> ShowS)
-> (Result -> ErrorMsg) -> ([Result] -> ShowS) -> Show Result
forall a.
(Int -> a -> ShowS) -> (a -> ErrorMsg) -> ([a] -> ShowS) -> Show a
showList :: [Result] -> ShowS
$cshowList :: [Result] -> ShowS
show :: Result -> ErrorMsg
$cshow :: Result -> ErrorMsg
showsPrec :: Int -> Result -> ShowS
$cshowsPrec :: Int -> Result -> ShowS
Show,Result -> Result -> Bool
(Result -> Result -> Bool)
-> (Result -> Result -> Bool) -> Eq Result
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Result -> Result -> Bool
$c/= :: Result -> Result -> Bool
== :: Result -> Result -> Bool
$c== :: Result -> Result -> Bool
Eq,Eq Result
Eq Result
-> (Result -> Result -> Ordering)
-> (Result -> Result -> Bool)
-> (Result -> Result -> Bool)
-> (Result -> Result -> Bool)
-> (Result -> Result -> Bool)
-> (Result -> Result -> Result)
-> (Result -> Result -> Result)
-> Ord Result
Result -> Result -> Bool
Result -> Result -> Ordering
Result -> Result -> Result
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Result -> Result -> Result
$cmin :: Result -> Result -> Result
max :: Result -> Result -> Result
$cmax :: Result -> Result -> Result
>= :: Result -> Result -> Bool
$c>= :: Result -> Result -> Bool
> :: Result -> Result -> Bool
$c> :: Result -> Result -> Bool
<= :: Result -> Result -> Bool
$c<= :: Result -> Result -> Bool
< :: Result -> Result -> Bool
$c< :: Result -> Result -> Bool
compare :: Result -> Result -> Ordering
$ccompare :: Result -> Result -> Ordering
$cp1Ord :: Eq Result
Ord)

data ResultSource =
  ResultSource { ResultSource -> PackageSource
resultSourceQueried :: PackageSource,
                 -- ^ the 'PackageSource' queried by user.
                 ResultSource -> Maybe PackageSource
resultSourceReal :: Maybe PackageSource
                 -- ^ the real (exact) 'PackageSource' resolved.
               } deriving (Int -> ResultSource -> ShowS
[ResultSource] -> ShowS
ResultSource -> ErrorMsg
(Int -> ResultSource -> ShowS)
-> (ResultSource -> ErrorMsg)
-> ([ResultSource] -> ShowS)
-> Show ResultSource
forall a.
(Int -> a -> ShowS) -> (a -> ErrorMsg) -> ([a] -> ShowS) -> Show a
showList :: [ResultSource] -> ShowS
$cshowList :: [ResultSource] -> ShowS
show :: ResultSource -> ErrorMsg
$cshow :: ResultSource -> ErrorMsg
showsPrec :: Int -> ResultSource -> ShowS
$cshowsPrec :: Int -> ResultSource -> ShowS
Show,ResultSource -> ResultSource -> Bool
(ResultSource -> ResultSource -> Bool)
-> (ResultSource -> ResultSource -> Bool) -> Eq ResultSource
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ResultSource -> ResultSource -> Bool
$c/= :: ResultSource -> ResultSource -> Bool
== :: ResultSource -> ResultSource -> Bool
$c== :: ResultSource -> ResultSource -> Bool
Eq,Eq ResultSource
Eq ResultSource
-> (ResultSource -> ResultSource -> Ordering)
-> (ResultSource -> ResultSource -> Bool)
-> (ResultSource -> ResultSource -> Bool)
-> (ResultSource -> ResultSource -> Bool)
-> (ResultSource -> ResultSource -> Bool)
-> (ResultSource -> ResultSource -> ResultSource)
-> (ResultSource -> ResultSource -> ResultSource)
-> Ord ResultSource
ResultSource -> ResultSource -> Bool
ResultSource -> ResultSource -> Ordering
ResultSource -> ResultSource -> ResultSource
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: ResultSource -> ResultSource -> ResultSource
$cmin :: ResultSource -> ResultSource -> ResultSource
max :: ResultSource -> ResultSource -> ResultSource
$cmax :: ResultSource -> ResultSource -> ResultSource
>= :: ResultSource -> ResultSource -> Bool
$c>= :: ResultSource -> ResultSource -> Bool
> :: ResultSource -> ResultSource -> Bool
$c> :: ResultSource -> ResultSource -> Bool
<= :: ResultSource -> ResultSource -> Bool
$c<= :: ResultSource -> ResultSource -> Bool
< :: ResultSource -> ResultSource -> Bool
$c< :: ResultSource -> ResultSource -> Bool
compare :: ResultSource -> ResultSource -> Ordering
$ccompare :: ResultSource -> ResultSource -> Ordering
$cp1Ord :: Eq ResultSource
Ord)

resultSourceDesc :: ResultSource -> Text
resultSourceDesc :: ResultSource -> Text
resultSourceDesc ResultSource
src = Text
query_source Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
real_source where
  query_source :: Text
query_source = PackageSource -> Text
sourceDesc (PackageSource -> Text) -> PackageSource -> Text
forall a b. (a -> b) -> a -> b
$ ResultSource -> PackageSource
resultSourceQueried (ResultSource -> PackageSource) -> ResultSource -> PackageSource
forall a b. (a -> b) -> a -> b
$ ResultSource
src
  real_source :: Text
real_source = case ResultSource -> Maybe PackageSource
resultSourceReal ResultSource
src of
    Maybe PackageSource
Nothing -> Text
""
    Just PackageSource
real_psource -> if PackageSource
real_psource PackageSource -> PackageSource -> Bool
forall a. Eq a => a -> a -> Bool
== ResultSource -> PackageSource
resultSourceQueried ResultSource
src
                         then Text
""
                         else Text
" (" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> PackageSource -> Text
sourceDesc PackageSource
real_psource Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
")"

-- | For backward-compatibility.
type ResultBody = ResultBody' (Maybe Version)

data ResultBody' a = SimpleResultBody PackageName a
                   | CabalResultBody FilePath Target [(PackageName, a)]
                   deriving (Int -> ResultBody' a -> ShowS
[ResultBody' a] -> ShowS
ResultBody' a -> ErrorMsg
(Int -> ResultBody' a -> ShowS)
-> (ResultBody' a -> ErrorMsg)
-> ([ResultBody' a] -> ShowS)
-> Show (ResultBody' a)
forall a. Show a => Int -> ResultBody' a -> ShowS
forall a. Show a => [ResultBody' a] -> ShowS
forall a. Show a => ResultBody' a -> ErrorMsg
forall a.
(Int -> a -> ShowS) -> (a -> ErrorMsg) -> ([a] -> ShowS) -> Show a
showList :: [ResultBody' a] -> ShowS
$cshowList :: forall a. Show a => [ResultBody' a] -> ShowS
show :: ResultBody' a -> ErrorMsg
$cshow :: forall a. Show a => ResultBody' a -> ErrorMsg
showsPrec :: Int -> ResultBody' a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> ResultBody' a -> ShowS
Show,ResultBody' a -> ResultBody' a -> Bool
(ResultBody' a -> ResultBody' a -> Bool)
-> (ResultBody' a -> ResultBody' a -> Bool) -> Eq (ResultBody' a)
forall a. Eq a => ResultBody' a -> ResultBody' a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ResultBody' a -> ResultBody' a -> Bool
$c/= :: forall a. Eq a => ResultBody' a -> ResultBody' a -> Bool
== :: ResultBody' a -> ResultBody' a -> Bool
$c== :: forall a. Eq a => ResultBody' a -> ResultBody' a -> Bool
Eq,Eq (ResultBody' a)
Eq (ResultBody' a)
-> (ResultBody' a -> ResultBody' a -> Ordering)
-> (ResultBody' a -> ResultBody' a -> Bool)
-> (ResultBody' a -> ResultBody' a -> Bool)
-> (ResultBody' a -> ResultBody' a -> Bool)
-> (ResultBody' a -> ResultBody' a -> Bool)
-> (ResultBody' a -> ResultBody' a -> ResultBody' a)
-> (ResultBody' a -> ResultBody' a -> ResultBody' a)
-> Ord (ResultBody' a)
ResultBody' a -> ResultBody' a -> Bool
ResultBody' a -> ResultBody' a -> Ordering
ResultBody' a -> ResultBody' a -> ResultBody' a
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (ResultBody' a)
forall a. Ord a => ResultBody' a -> ResultBody' a -> Bool
forall a. Ord a => ResultBody' a -> ResultBody' a -> Ordering
forall a. Ord a => ResultBody' a -> ResultBody' a -> ResultBody' a
min :: ResultBody' a -> ResultBody' a -> ResultBody' a
$cmin :: forall a. Ord a => ResultBody' a -> ResultBody' a -> ResultBody' a
max :: ResultBody' a -> ResultBody' a -> ResultBody' a
$cmax :: forall a. Ord a => ResultBody' a -> ResultBody' a -> ResultBody' a
>= :: ResultBody' a -> ResultBody' a -> Bool
$c>= :: forall a. Ord a => ResultBody' a -> ResultBody' a -> Bool
> :: ResultBody' a -> ResultBody' a -> Bool
$c> :: forall a. Ord a => ResultBody' a -> ResultBody' a -> Bool
<= :: ResultBody' a -> ResultBody' a -> Bool
$c<= :: forall a. Ord a => ResultBody' a -> ResultBody' a -> Bool
< :: ResultBody' a -> ResultBody' a -> Bool
$c< :: forall a. Ord a => ResultBody' a -> ResultBody' a -> Bool
compare :: ResultBody' a -> ResultBody' a -> Ordering
$ccompare :: forall a. Ord a => ResultBody' a -> ResultBody' a -> Ordering
$cp1Ord :: forall a. Ord a => Eq (ResultBody' a)
Ord)

instance Functor ResultBody' where
  fmap :: (a -> b) -> ResultBody' a -> ResultBody' b
fmap a -> b
f (SimpleResultBody Text
n a
a) = Text -> b -> ResultBody' b
forall a. Text -> a -> ResultBody' a
SimpleResultBody Text
n (a -> b
f a
a)
  fmap a -> b
f (CabalResultBody ErrorMsg
fp Target
t [(Text, a)]
pairs) = ErrorMsg -> Target -> [(Text, b)] -> ResultBody' b
forall a. ErrorMsg -> Target -> [(Text, a)] -> ResultBody' a
CabalResultBody ErrorMsg
fp Target
t (((Text, a) -> (Text, b)) -> [(Text, a)] -> [(Text, b)]
forall a b. (a -> b) -> [a] -> [b]
map (\(Text
n, a
a) -> (Text
n, a -> b
f a
a)) [(Text, a)]
pairs)

-- | Results for a query aggregated over different sources.
data AggregatedResult =
  AggregatedResult { AggregatedResult -> NonEmpty ResultSource
aggResultIn :: NonEmpty ResultSource,
                     AggregatedResult -> Query
aggResultFor :: Query,
                     AggregatedResult
-> Either ErrorMsg (ResultBody' (Maybe VersionRange))
aggResultBody :: Either ErrorMsg (ResultBody' (Maybe VersionRange))
                   } deriving (Int -> AggregatedResult -> ShowS
[AggregatedResult] -> ShowS
AggregatedResult -> ErrorMsg
(Int -> AggregatedResult -> ShowS)
-> (AggregatedResult -> ErrorMsg)
-> ([AggregatedResult] -> ShowS)
-> Show AggregatedResult
forall a.
(Int -> a -> ShowS) -> (a -> ErrorMsg) -> ([a] -> ShowS) -> Show a
showList :: [AggregatedResult] -> ShowS
$cshowList :: [AggregatedResult] -> ShowS
show :: AggregatedResult -> ErrorMsg
$cshow :: AggregatedResult -> ErrorMsg
showsPrec :: Int -> AggregatedResult -> ShowS
$cshowsPrec :: Int -> AggregatedResult -> ShowS
Show,AggregatedResult -> AggregatedResult -> Bool
(AggregatedResult -> AggregatedResult -> Bool)
-> (AggregatedResult -> AggregatedResult -> Bool)
-> Eq AggregatedResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AggregatedResult -> AggregatedResult -> Bool
$c/= :: AggregatedResult -> AggregatedResult -> Bool
== :: AggregatedResult -> AggregatedResult -> Bool
$c== :: AggregatedResult -> AggregatedResult -> Bool
Eq)

-- | Create an 'AggregatedResult' that includes just one 'Result'.
singletonResult :: Result -> AggregatedResult
singletonResult :: Result -> AggregatedResult
singletonResult Result
ret = AggregatedResult :: NonEmpty ResultSource
-> Query
-> Either ErrorMsg (ResultBody' (Maybe VersionRange))
-> AggregatedResult
AggregatedResult { aggResultIn :: NonEmpty ResultSource
aggResultIn = (Result -> ResultSource
resultIn Result
ret ResultSource -> [ResultSource] -> NonEmpty ResultSource
forall a. a -> [a] -> NonEmpty a
:| []),
                                         aggResultFor :: Query
aggResultFor = Result -> Query
resultFor Result
ret,
                                         aggResultBody :: Either ErrorMsg (ResultBody' (Maybe VersionRange))
aggResultBody = ((ResultBody -> ResultBody' (Maybe VersionRange))
-> Either ErrorMsg ResultBody
-> Either ErrorMsg (ResultBody' (Maybe VersionRange))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ResultBody -> ResultBody' (Maybe VersionRange))
 -> Either ErrorMsg ResultBody
 -> Either ErrorMsg (ResultBody' (Maybe VersionRange)))
-> ((Version -> VersionRange)
    -> ResultBody -> ResultBody' (Maybe VersionRange))
-> (Version -> VersionRange)
-> Either ErrorMsg ResultBody
-> Either ErrorMsg (ResultBody' (Maybe VersionRange))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe Version -> Maybe VersionRange)
-> ResultBody -> ResultBody' (Maybe VersionRange)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Maybe Version -> Maybe VersionRange)
 -> ResultBody -> ResultBody' (Maybe VersionRange))
-> ((Version -> VersionRange)
    -> Maybe Version -> Maybe VersionRange)
-> (Version -> VersionRange)
-> ResultBody
-> ResultBody' (Maybe VersionRange)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Version -> VersionRange) -> Maybe Version -> Maybe VersionRange
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) Version -> VersionRange
thisVersion (Either ErrorMsg ResultBody
 -> Either ErrorMsg (ResultBody' (Maybe VersionRange)))
-> Either ErrorMsg ResultBody
-> Either ErrorMsg (ResultBody' (Maybe VersionRange))
forall a b. (a -> b) -> a -> b
$ Result -> Either ErrorMsg ResultBody
resultBody Result
ret
                                       }

-- | Get package names and corresponding values from 'ResultBody'',
-- regardless of its internal structure.
--
-- @since 0.2.4.0
resultPackages :: ResultBody' a -> [(PackageName, a)]
resultPackages :: ResultBody' a -> [(Text, a)]
resultPackages (SimpleResultBody Text
p a
a) = [(Text
p, a
a)]
resultPackages (CabalResultBody ErrorMsg
_ Target
_ [(Text, a)]
pairs) = [(Text, a)]
pairs