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
20 import Data.Aeson hiding (defaultTaggedObject)
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
35 import Gargantext.Utils.Aeson (defaultTaggedObject)
37 import Test.QuickCheck (elements)
38 import Test.QuickCheck.Arbitrary
39 import qualified Data.Text as Text
41 -----------------------------------------------------------------------
42 -- TODO-ACCESS: CanSearch? or is it part of CanGetNode
43 -- TODO-EVENTS: No event, this is a read-only query.
44 type API results = Summary "Search endpoint"
45 :> ReqBody '[JSON] SearchQuery
46 :> QueryParam "offset" Int
47 :> QueryParam "limit" Int
48 :> QueryParam "order" OrderBy
49 :> Post '[JSON] results
50 -----------------------------------------------------------------------
51 -- | Api search function
52 api :: NodeId -> GargServer (API SearchResult)
54 api nId (SearchQuery q SearchDoc) o l order =
55 SearchResult <$> SearchResultDoc
57 <$> searchInCorpus nId False q o l order
59 api nId (SearchQuery q SearchContact) o l order = do
60 printDebug "isPairedWith" nId
61 aIds <- isPairedWith nId NodeAnnuaire
62 -- TODO if paired with several corpus
64 Nothing -> pure $ SearchResult
65 $ SearchNoResult "[G.A.Search] pair corpus with an Annuaire"
66 Just aId -> SearchResult
67 <$> SearchResultContact
69 <$> searchInCorpusWithContacts nId aId q o l order
71 -----------------------------------------------------------------------
72 -----------------------------------------------------------------------
74 -----------------------------------------------------------------------
75 data SearchType = SearchDoc | SearchContact
77 instance FromJSON SearchType
79 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
80 instance ToJSON SearchType
82 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
83 instance ToSchema SearchType
84 instance Arbitrary SearchType where
85 arbitrary = elements [SearchDoc, SearchContact]
87 -----------------------------------------------------------------------
89 SearchQuery { query :: ![Text]
90 , expected :: !SearchType
93 instance FromJSON SearchQuery
95 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
96 instance ToJSON SearchQuery
98 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
99 instance ToSchema SearchQuery
102 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
105 instance Arbitrary SearchQuery where
106 arbitrary = elements [SearchQuery ["electrodes"] SearchDoc]
107 -- arbitrary = elements [SearchQuery "electrodes" 1 ] --SearchDoc]
108 -----------------------------------------------------------------------
110 SearchResult { result :: !SearchResultTypes}
113 instance FromJSON SearchResult
115 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
117 instance ToJSON SearchResult
119 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
121 instance ToSchema SearchResult
124 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
127 instance Arbitrary SearchResult where
128 arbitrary = SearchResult <$> arbitrary
131 data SearchResultTypes =
132 SearchResultDoc { docs :: ![Row] }
133 | SearchResultContact { contacts :: ![Row] }
134 | SearchNoResult { message :: !Text }
136 instance FromJSON SearchResultTypes
138 parseJSON = genericParseJSON (defaultOptions { sumEncoding = defaultTaggedObject })
139 instance ToJSON SearchResultTypes
141 toJSON = genericToJSON (defaultOptions { sumEncoding = defaultTaggedObject })
143 instance Arbitrary SearchResultTypes where
145 srd <- SearchResultDoc <$> arbitrary
146 src <- SearchResultContact <$> arbitrary
147 srn <- pure $ SearchNoResult "No result because.."
148 elements [srd, src, srn]
150 instance ToSchema SearchResultTypes where
151 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
154 --------------------------------------------------------------------
157 Document { id :: !NodeId
158 , created :: !UTCTime
160 , hyperdata :: !HyperdataRow
164 | Contact { c_id :: !Int
165 , c_created :: !UTCTime
166 , c_hyperdata :: !HyperdataRow
168 , c_annuaireId :: !NodeId
171 instance FromJSON Row
173 parseJSON = genericParseJSON
174 ( defaultOptions { sumEncoding = defaultTaggedObject } )
177 toJSON = genericToJSON (defaultOptions { sumEncoding = defaultTaggedObject })
178 instance Arbitrary Row where
179 arbitrary = arbitrary
181 instance ToSchema Row where
182 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
185 toRow :: NodeId -> a -> Row
187 instance ToRow FacetDoc where
188 toRow _ (FacetDoc { .. }) =
189 Document { id = facetDoc_id
190 , created = facetDoc_created
191 , title = facetDoc_title
192 , hyperdata = toHyperdataRow facetDoc_hyperdata
193 , category = fromMaybe 0 facetDoc_category
194 , score = round $ fromMaybe 0 facetDoc_score }
196 -- | TODO rename FacetPaired
197 type FacetContact = FacetPaired Int UTCTime HyperdataContact Int
199 instance ToRow FacetContact where
200 toRow annuaireId (FacetPaired nId utc h s) = Contact nId utc (toHyperdataRow h) s annuaireId
203 --------------------------------------------------------------------
205 HyperdataRowDocument { _hr_abstract :: !Text
206 , _hr_authors :: !Text
209 , _hr_institutes :: !Text
210 , _hr_language_iso2 :: !Text
212 , _hr_publication_date :: !Text
213 , _hr_publication_day :: !Int
214 , _hr_publication_hour :: !Int
215 , _hr_publication_minute :: !Int
216 , _hr_publication_month :: !Int
217 , _hr_publication_second :: !Int
218 , _hr_publication_year :: !Int
219 , _hr_source :: !Text
222 , _hr_uniqId :: !Text
223 , _hr_uniqIdBdd :: !Text
225 | HyperdataRowContact { _hr_firstname :: !Text
226 , _hr_lastname :: !Text
230 instance FromJSON HyperdataRow
232 parseJSON = genericParseJSON
234 { sumEncoding = defaultTaggedObject
235 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
236 , omitNothingFields = False
239 instance ToJSON HyperdataRow
241 toJSON = genericToJSON
243 { sumEncoding = defaultTaggedObject
244 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
245 , omitNothingFields = False
249 instance Arbitrary HyperdataRow where
250 arbitrary = arbitrary
252 instance ToSchema HyperdataRow where
253 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_hr_")
255 class ToHyperdataRow a where
256 toHyperdataRow :: a -> HyperdataRow
258 instance ToHyperdataRow HyperdataDocument where
259 toHyperdataRow (HyperdataDocument { .. }) =
261 { _hr_abstract = fromMaybe "" _hd_abstract
262 , _hr_authors = fromMaybe "" _hd_authors
263 , _hr_bdd = fromMaybe "" _hd_bdd
264 , _hr_doi = fromMaybe "" _hd_doi
265 , _hr_institutes = fromMaybe "" _hd_institutes
266 , _hr_language_iso2 = fromMaybe "EN" _hd_language_iso2
267 , _hr_page = fromMaybe 0 _hd_page
268 , _hr_publication_date = fromMaybe "" _hd_publication_date
269 , _hr_publication_day = fromMaybe 1 _hd_publication_day
270 , _hr_publication_hour = fromMaybe 1 _hd_publication_hour
271 , _hr_publication_minute = fromMaybe 1 _hd_publication_minute
272 , _hr_publication_month = fromMaybe 1 _hd_publication_month
273 , _hr_publication_second = fromMaybe 1 _hd_publication_second
274 , _hr_publication_year = fromMaybe 2020 _hd_publication_year
275 , _hr_source = fromMaybe "" _hd_source
276 , _hr_title = fromMaybe "Title" _hd_title
277 , _hr_url = fromMaybe "" _hd_url
278 , _hr_uniqId = fromMaybe "" _hd_uniqId
279 , _hr_uniqIdBdd = fromMaybe "" _hd_uniqIdBdd }
281 instance ToHyperdataRow HyperdataContact where
282 toHyperdataRow (HyperdataContact { _hc_who = Just (ContactWho _ fn ln _ _), _hc_where = ou} ) =
283 HyperdataRowContact (fromMaybe "FirstName" fn) (fromMaybe "LastName" ln) ou'
285 ou' = maybe "CNRS" (Text.intercalate " " . _cw_organization) (head ou)
286 toHyperdataRow (HyperdataContact {}) =
287 HyperdataRowContact "FirstName" "LastName" "Labs"