2 Module : Gargantext.API.Count
3 Description : Server API
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
10 Count API part of Gargantext.
13 {-# LANGUAGE TemplateHaskell #-}
14 {-# LANGUAGE TypeOperators #-}
15 {-# LANGUAGE DeriveAnyClass #-}
17 module Gargantext.API.Search
21 import Data.Maybe (fromMaybe)
22 import Data.Swagger hiding (fieldLabelModifier, Contact)
23 import Data.Text (Text)
24 import Data.Time (UTCTime)
25 import GHC.Generics (Generic)
26 import Gargantext.API.Prelude (GargServer)
27 import Gargantext.Core.Utils.Prefix (unPrefixSwagger, unCapitalize, dropPrefix)
28 import Gargantext.Database.Action.Flow.Pairing (isPairedWith)
29 import Gargantext.Database.Action.Search
30 import Gargantext.Database.Admin.Types.Hyperdata (HyperdataContact(..), HyperdataDocument(..), ContactWho(..))
31 import Gargantext.Database.Admin.Types.Hyperdata.Contact (_cw_organization)
32 import Gargantext.Database.Admin.Types.Node
33 import Gargantext.Database.Query.Facet
34 import Gargantext.Prelude
36 import Test.QuickCheck (elements)
37 import Test.QuickCheck.Arbitrary
38 import qualified Data.Text as Text
40 -----------------------------------------------------------------------
41 -- TODO-ACCESS: CanSearch? or is it part of CanGetNode
42 -- TODO-EVENTS: No event, this is a read-only query.
43 type API results = Summary "Search endpoint"
44 :> ReqBody '[JSON] SearchQuery
45 :> QueryParam "offset" Int
46 :> QueryParam "limit" Int
47 :> QueryParam "order" OrderBy
48 :> Post '[JSON] results
49 -----------------------------------------------------------------------
50 -- | Api search function
51 api :: NodeId -> GargServer (API SearchResult)
53 api nId (SearchQuery q SearchDoc) o l order =
54 SearchResult <$> SearchResultDoc
56 <$> searchInCorpus nId False q o l order
58 api nId (SearchQuery q SearchContact) o l order = do
59 printDebug "isPairedWith" nId
60 aIds <- isPairedWith nId NodeAnnuaire
61 -- TODO if paired with several corpus
63 Nothing -> pure $ SearchResult
64 $ SearchNoResult "[G.A.Search] pair corpus with an Annuaire"
65 Just aId -> SearchResult
66 <$> SearchResultContact
68 <$> searchInCorpusWithContacts nId aId q o l order
69 api _ _ _ _ _ = undefined
71 -----------------------------------------------------------------------
72 -----------------------------------------------------------------------
74 -----------------------------------------------------------------------
75 data SearchType = SearchDoc | SearchContact
78 instance FromJSON SearchType
80 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
82 instance ToJSON SearchType
84 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
86 instance ToSchema SearchType
87 instance Arbitrary SearchType where
88 arbitrary = elements [SearchDoc, SearchContact]
90 -----------------------------------------------------------------------
92 SearchQuery { query :: ![Text]
93 , expected :: !SearchType
95 | SearchQueryErr !Text
98 instance FromJSON SearchQuery
100 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
102 instance ToJSON SearchQuery
104 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
106 instance ToSchema SearchQuery
109 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
112 instance Arbitrary SearchQuery where
113 arbitrary = elements [SearchQuery ["electrodes"] SearchDoc]
114 -- arbitrary = elements [SearchQuery "electrodes" 1 ] --SearchDoc]
115 -----------------------------------------------------------------------
117 SearchResult { result :: !SearchResultTypes}
118 | SearchResultErr !Text
121 instance FromJSON SearchResult
123 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
125 instance ToJSON SearchResult
127 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
129 instance ToSchema SearchResult
132 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
135 instance Arbitrary SearchResult where
136 arbitrary = SearchResult <$> arbitrary
139 data SearchResultTypes = SearchResultDoc { docs :: ![Row]}
140 | SearchResultContact { contacts :: ![Row] }
141 | SearchNoResult { message :: !Text }
145 instance FromJSON SearchResultTypes
147 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
149 instance ToJSON SearchResultTypes
151 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
153 instance Arbitrary SearchResultTypes where
155 srd <- SearchResultDoc <$> arbitrary
156 src <- SearchResultContact <$> arbitrary
157 srn <- pure $ SearchNoResult "No result because.."
158 elements [srd, src, srn]
160 instance ToSchema SearchResultTypes where
161 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
164 --------------------------------------------------------------------
167 Document { id :: !NodeId
168 , created :: !UTCTime
170 , hyperdata :: !HyperdataRow
174 | Contact { c_id :: !Int
175 , c_created :: !UTCTime
176 , c_hyperdata :: !HyperdataRow
178 , c_annuaireId :: !NodeId
182 instance FromJSON Row
184 parseJSON = genericParseJSON
185 ( defaultOptions { sumEncoding = ObjectWithSingleField
191 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
193 instance Arbitrary Row where
194 arbitrary = arbitrary
196 instance ToSchema Row where
197 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
200 toRow :: NodeId -> a -> Row
202 instance ToRow FacetDoc where
203 toRow _ (FacetDoc nId utc t h mc _md sc) =
204 Document nId utc t (toHyperdataRow h) (fromMaybe 0 mc) (round $ fromMaybe 0 sc)
206 -- | TODO rename FacetPaired
207 type FacetContact = FacetPaired Int UTCTime HyperdataContact Int
209 instance ToRow FacetContact where
210 toRow annuaireId (FacetPaired nId utc h s) = Contact nId utc (toHyperdataRow h) s annuaireId
213 --------------------------------------------------------------------
215 HyperdataRowDocument { _hr_bdd :: !Text
218 , _hr_uniqId :: !Text
219 , _hr_uniqIdBdd :: !Text
222 , _hr_authors :: !Text
223 , _hr_institutes :: !Text
224 , _hr_source :: !Text
225 , _hr_abstract :: !Text
226 , _hr_publication_date :: !Text
227 , _hr_publication_year :: !Int
228 , _hr_publication_month :: !Int
229 , _hr_publication_day :: !Int
230 , _hr_publication_hour :: !Int
231 , _hr_publication_minute :: !Int
232 , _hr_publication_second :: !Int
233 , _hr_language_iso2 :: !Text
235 | HyperdataRowContact { _hr_firstname :: !Text
236 , _hr_lastname :: !Text
241 instance FromJSON HyperdataRow
243 parseJSON = genericParseJSON
245 { sumEncoding = ObjectWithSingleField
246 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
247 , omitNothingFields = False
251 instance ToJSON HyperdataRow
253 toJSON = genericToJSON
255 { sumEncoding = ObjectWithSingleField
256 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
257 , omitNothingFields = False
261 instance Arbitrary HyperdataRow where
262 arbitrary = arbitrary
264 instance ToSchema HyperdataRow where
265 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_hr_")
267 class ToHyperdataRow a where
268 toHyperdataRow :: a -> HyperdataRow
270 instance ToHyperdataRow HyperdataDocument where
271 toHyperdataRow (HyperdataDocument b d u ui ub p t a i s abs' pd py pm pda ph pmin psec l) =
279 (fromMaybe "Title" t)
293 instance ToHyperdataRow HyperdataContact where
294 toHyperdataRow (HyperdataContact _ (Just (ContactWho _ fn ln _ _)) ou _ _ _ _ _ ) =
295 HyperdataRowContact (fromMaybe "FirstName" fn) (fromMaybe "LastName" ln) ou'
297 ou' = maybe "CNRS" (Text.intercalate " " . _cw_organization) (head ou)
298 toHyperdataRow (HyperdataContact _ _ _ _ _ _ _ _ ) =
299 HyperdataRowContact "FirstName" "LastName" "Labs"