More conduit/cmdline fixes. Added filter to client query

parent 8d3a0ab8
...@@ -9,6 +9,7 @@ import qualified OpenAlex.Types as OA ...@@ -9,6 +9,7 @@ import qualified OpenAlex.Types as OA
main :: IO () main :: IO ()
main = do main = do
let filterHelp = help "Filter, for example: display_name.search:einstein , see https://docs.openalex.org/how-to-use-the-api/get-lists-of-entities/filter-entity-lists"
(opts, runCmd) <- (opts, runCmd) <-
simpleOptions "0.1.0.0" simpleOptions "0.1.0.0"
"OpenAlex" "OpenAlex"
...@@ -16,46 +17,46 @@ main = do ...@@ -16,46 +17,46 @@ main = do
(pure ()) $ do (pure ()) $ do
addCommand "concepts" addCommand "concepts"
"Fetch OpenAlex concepts (https://docs.openalex.org/api-entities/concepts/concept-object)" "Fetch OpenAlex concepts (https://docs.openalex.org/api-entities/concepts/concept-object)"
(const fetchConcepts) fetchConcepts
(pure ()) (strOption (long "filter"))
addCommand "works" addCommand "works"
"Fetch OpenAlex works (https://docs.openalex.org/api-entities/works/work-object)" "Fetch OpenAlex works (https://docs.openalex.org/api-entities/works/work-object)"
(const fetchWorks) fetchWorks
(pure ()) (strOption (long "filter"))
addCommand "works-c" addCommand "works-c"
"Fetch OpenAlex works (https://docs.openalex.org/api-entities/works/work-object) with conduit" "Fetch OpenAlex works (https://docs.openalex.org/api-entities/works/work-object) with conduit"
(const fetchWorksC) fetchWorksC
(pure ()) (strOption (long "filter"))
runCmd () runCmd ()
fetchConcepts :: () -> IO () fetchConcepts :: OA.Filter -> () -> IO ()
fetchConcepts _ = do fetchConcepts fltr _ = do
ec <- OA.fetchConcepts (Just 1) (Just 1) (Just "*") ec <- OA.fetchConcepts (Just 1) (Just 1) (Just "*") (Just fltr)
case ec of case ec of
Left err -> putText $ "error: " <> show err Left err -> putText $ "error: " <> show err
Right c -> do Right c -> do
putText $ show c putText $ show c
fetchWorks :: () -> IO () fetchWorks :: OA.Filter -> () -> IO ()
fetchWorks _ = do fetchWorks fltr _ = do
ew <- OA.fetchWorks (Just 1) (Just 1) (Just "*") ew <- OA.fetchWorks (Just 1) (Just 1) (Just "*") (Just fltr)
case ew of case ew of
Left err -> putText $ "error: " <> show err Left err -> putText $ "error: " <> show err
Right w -> do Right w -> do
putText $ show w putText $ show w
fetchWorksC :: () -> IO () fetchWorksC :: OA.Filter -> () -> IO ()
fetchWorksC _ = do fetchWorksC fltr _ = do
eWorksC <- OA.fetchWorksC Nothing eWorksC <- OA.fetchWorksC Nothing (Just fltr)
case eWorksC of case eWorksC of
Left err -> putText $ "error: " <> show err Left err -> putText $ "error: " <> show err
Right (Just count, c) -> do Right (mCount, c) -> do
putText $ "Count: " <> show count putText $ "Count: " <> show mCount
_ <- runConduit $ c _ <- runConduit $ c
.| takeC 1000 .| takeC 1000
.| mapM_C (\(OA.Work { .. }) -> do .| mapM_C (\(OA.Work { .. }) -> do
liftIO $ putText $ show id liftIO $ putText $ show id <> " :: " <> show display_name
) )
pure () pure ()
...@@ -27,7 +27,7 @@ import Network.HTTP.Client.TLS (tlsManagerSettings) ...@@ -27,7 +27,7 @@ import Network.HTTP.Client.TLS (tlsManagerSettings)
import Protolude hiding (yield) import Protolude hiding (yield)
import OpenAlex.Client import OpenAlex.Client
import OpenAlex.ServantClientLogging import OpenAlex.ServantClientLogging
import OpenAlex.Types (ListOf(..), Meta(..), Page, PerPage, Cursor, Concept, Work) import OpenAlex.Types (ListOf(..), Meta(..), Page, PerPage, Cursor, Filter, Concept, Work)
import Servant.Client (BaseUrl(..), ClientEnv(..), ClientError, Scheme(Https), defaultMakeClientRequest, mkClientEnv, runClientM) import Servant.Client (BaseUrl(..), ClientEnv(..), ClientError, Scheme(Https), defaultMakeClientRequest, mkClientEnv, runClientM)
defaultClientEnv :: IO ClientEnv defaultClientEnv :: IO ClientEnv
...@@ -41,23 +41,33 @@ defaultClientEnv = do ...@@ -41,23 +41,33 @@ defaultClientEnv = do
pure $ addLoggingToClientEnv env pure $ addLoggingToClientEnv env
fetchConcepts :: Maybe Page -> Maybe PerPage -> Maybe Cursor -> IO (Either ClientError (ListOf Concept)) fetchConcepts :: Maybe Page
fetchConcepts mPage mPerPage mCursor = do -> Maybe PerPage
-> Maybe Cursor
-> Maybe Filter
-> IO (Either ClientError (ListOf Concept))
fetchConcepts mPage mPerPage mCursor mFilter = do
env <- defaultClientEnv env <- defaultClientEnv
runClientM (concepts mPage mPerPage mCursor) env runClientM (concepts mPage mPerPage mCursor mFilter) env
fetchWorks :: Maybe Page -> Maybe PerPage -> Maybe Cursor -> IO (Either ClientError (ListOf Work)) fetchWorks :: Maybe Page
fetchWorks mPage mPerPage mCursor = do -> Maybe PerPage
-> Maybe Cursor
-> Maybe Filter
-> IO (Either ClientError (ListOf Work))
fetchWorks mPage mPerPage mCursor mFilter = do
env <- defaultClientEnv env <- defaultClientEnv
runClientM (works mPage mPerPage mCursor) env runClientM (works mPage mPerPage mCursor mFilter) env
fetchWorksC :: Maybe Cursor -> IO (Either ClientError (Maybe Integer, ConduitT () Work IO ())) fetchWorksC :: Maybe Cursor
fetchWorksC Nothing = do -> Maybe Filter
fetchWorksC (Just "*") -> IO (Either ClientError (Maybe Integer, ConduitT () Work IO ()))
fetchWorksC mCursor = do fetchWorksC Nothing mFilter = do
fetchWorksC (Just "*") mFilter
fetchWorksC mCursor mFilter = do
env <- defaultClientEnv env <- defaultClientEnv
-- NOTE: per-page max is 200 -- NOTE: per-page max is 200
eRes <- runClientM (works (Just 1) (Just 1) Nothing) env eRes <- runClientM (works (Just 1) (Just 1) Nothing mFilter) env
case eRes of case eRes of
Left err -> pure $ Left err Left err -> pure $ Left err
Right ListOf { meta = Meta { count }} -> do Right ListOf { meta = Meta { count }} -> do
...@@ -66,11 +76,11 @@ fetchWorksC mCursor = do ...@@ -66,11 +76,11 @@ fetchWorksC mCursor = do
where where
producer :: ClientEnv -> Maybe Cursor -> ConduitT () Work IO () producer :: ClientEnv -> Maybe Cursor -> ConduitT () Work IO ()
producer env mCursor' = do producer env mCursor' = do
eRes <- liftIO $ runClientM (works Nothing (Just 20) mCursor') env eRes <- liftIO $ runClientM (works Nothing (Just 200) mCursor' mFilter) env
liftIO $ putText $ "Conduit fetching page with cursor " <> show mCursor' -- liftIO $ putText $ "Conduit fetching page with cursor " <> show mCursor'
case eRes of case eRes of
Left err -> panic $ "error: " <> show err Left err -> panic $ "error: " <> show err
Right (ListOf { results, meta = meta@(Meta { next_cursor }) }) -> do Right (ListOf { results, meta = _meta@(Meta { next_cursor }) }) -> do
liftIO $ putText $ "Meta: " <> show meta -- liftIO $ putText $ "Meta: " <> show meta
yieldMany results yieldMany results
producer env next_cursor producer env next_cursor
...@@ -16,7 +16,7 @@ import Protolude ...@@ -16,7 +16,7 @@ import Protolude
import Servant.API import Servant.API
import Servant.Client import Servant.Client
import OpenAlex.Types (Page, PerPage, Cursor, ListOf(..), Concept, Work) import OpenAlex.Types (Page, PerPage, Cursor, Filter, ListOf(..), Concept, Work)
type API_URL = Text type API_URL = Text
apiUrl :: API_URL apiUrl :: API_URL
...@@ -34,6 +34,7 @@ type OpenAlexAPI = ...@@ -34,6 +34,7 @@ type OpenAlexAPI =
:> QueryParam "page" Page :> QueryParam "page" Page
:> QueryParam "per-page" PerPage :> QueryParam "per-page" PerPage
:> QueryParam "cursor" Cursor :> QueryParam "cursor" Cursor
:> QueryParam "filter" Filter
-- TODO: filter, search, sort -- TODO: filter, search, sort
:> Get '[JSON] (ListOf Concept) :> Get '[JSON] (ListOf Concept)
...@@ -42,14 +43,15 @@ type OpenAlexAPI = ...@@ -42,14 +43,15 @@ type OpenAlexAPI =
:> QueryParam "page" Page :> QueryParam "page" Page
:> QueryParam "per-page" PerPage :> QueryParam "per-page" PerPage
:> QueryParam "cursor" Cursor :> QueryParam "cursor" Cursor
:> QueryParam "filter" Filter
-- TODO: filter, search, sort -- TODO: filter, search, sort
:> Get '[JSON] (ListOf Work) :> Get '[JSON] (ListOf Work)
openAlexApi :: Proxy OpenAlexAPI openAlexApi :: Proxy OpenAlexAPI
openAlexApi = Proxy openAlexApi = Proxy
concepts :: Maybe Page -> Maybe PerPage -> Maybe Cursor -> ClientM (ListOf Concept) concepts :: Maybe Page -> Maybe PerPage -> Maybe Cursor -> Maybe Filter -> ClientM (ListOf Concept)
works :: Maybe Page -> Maybe PerPage -> Maybe Cursor -> ClientM (ListOf Work) works :: Maybe Page -> Maybe PerPage -> Maybe Cursor -> Maybe Filter -> ClientM (ListOf Work)
concepts :<|> works = client openAlexApi concepts :<|> works = client openAlexApi
...@@ -23,9 +23,17 @@ import Data.Time.Calendar (Day) ...@@ -23,9 +23,17 @@ import Data.Time.Calendar (Day)
import qualified Data.Time.Format as DTF import qualified Data.Time.Format as DTF
import Protolude hiding (Location, Meta) import Protolude hiding (Location, Meta)
-- API request types
type Cursor = Text
type Page = Int
type PerPage = Int
type Filter = Text
-- API response types
type Count = Int type Count = Int
type Cursor = Text
type DOI = Text type DOI = Text
data ExternalID = ExtIDUrl URL | ExtIDUrls [URL] | ExtIDInt Int data ExternalID = ExtIDUrl URL | ExtIDUrls [URL] | ExtIDInt Int
deriving (Generic, Show) deriving (Generic, Show)
...@@ -54,8 +62,6 @@ instance FromJSON OAStatus where ...@@ -54,8 +62,6 @@ instance FromJSON OAStatus where
parseJSON (String "closed") = pure OAClosed parseJSON (String "closed") = pure OAClosed
parseJSON _ = fail "Don't know how to parse this oa status" parseJSON _ = fail "Don't know how to parse this oa status"
type OpenAlexID = Text type OpenAlexID = Text
type Page = Int
type PerPage = Int
type URL = Text type URL = Text
type Year = Int type Year = Int
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment