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 RecordWildCards #-}
14 {-# LANGUAGE TemplateHaskell #-}
15 {-# LANGUAGE TypeOperators #-}
16 {-# LANGUAGE DeriveAnyClass #-}
18 module Gargantext.API.Search
21 import Data.Aeson hiding (defaultTaggedObject)
22 import Data.Maybe (fromMaybe)
23 import Data.Swagger hiding (fieldLabelModifier, Contact)
24 import Data.Text (Text)
25 import Data.Time (UTCTime)
26 import GHC.Generics (Generic)
27 import Gargantext.API.Prelude (GargServer)
28 import Gargantext.Core.Utils.Prefix (unPrefixSwagger, unCapitalize, dropPrefix)
29 import Gargantext.Database.Action.Flow.Pairing (isPairedWith)
30 import Gargantext.Database.Action.Search
31 import Gargantext.Database.Admin.Types.Hyperdata (HyperdataContact(..), HyperdataDocument(..), ContactWho(..))
32 import Gargantext.Database.Admin.Types.Hyperdata.Contact (_cw_organization)
33 import Gargantext.Database.Admin.Types.Node
34 import Gargantext.Database.Query.Facet
35 import Gargantext.Prelude
36 import Gargantext.Utils.Aeson (defaultTaggedObject)
38 import Test.QuickCheck (elements)
39 import Test.QuickCheck.Arbitrary
40 import qualified Data.Text as Text
42 -----------------------------------------------------------------------
43 -- TODO-ACCESS: CanSearch? or is it part of CanGetNode
44 -- TODO-EVENTS: No event, this is a read-only query.
45 type API results = Summary "Search endpoint"
46 :> ReqBody '[JSON] SearchQuery
47 :> QueryParam "offset" Int
48 :> QueryParam "limit" Int
49 :> QueryParam "order" OrderBy
50 :> Post '[JSON] results
51 -----------------------------------------------------------------------
52 -- | Api search function
53 api :: NodeId -> GargServer (API SearchResult)
55 api nId (SearchQuery q SearchDoc) o l order =
56 SearchResult <$> SearchResultDoc
58 <$> searchInCorpus nId False q o l order
60 api nId (SearchQuery q SearchContact) o l order = do
61 printDebug "isPairedWith" nId
62 aIds <- isPairedWith nId NodeAnnuaire
63 -- TODO if paired with several corpus
65 Nothing -> pure $ SearchResult
66 $ SearchNoResult "[G.A.Search] pair corpus with an Annuaire"
67 Just aId -> SearchResult
68 <$> SearchResultContact
70 <$> searchInCorpusWithContacts nId aId q o l order
72 -----------------------------------------------------------------------
73 -----------------------------------------------------------------------
75 -----------------------------------------------------------------------
76 data SearchType = SearchDoc | SearchContact
78 instance FromJSON SearchType
80 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
81 instance ToJSON SearchType
83 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
84 instance ToSchema SearchType
85 instance Arbitrary SearchType where
86 arbitrary = elements [SearchDoc, SearchContact]
88 -----------------------------------------------------------------------
90 SearchQuery { query :: ![Text]
91 , expected :: !SearchType
94 instance FromJSON SearchQuery
96 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
97 instance ToJSON SearchQuery
99 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
100 instance ToSchema SearchQuery
103 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
106 instance Arbitrary SearchQuery where
107 arbitrary = elements [SearchQuery ["electrodes"] SearchDoc]
108 -- arbitrary = elements [SearchQuery "electrodes" 1 ] --SearchDoc]
109 -----------------------------------------------------------------------
111 SearchResult { result :: !SearchResultTypes}
114 instance FromJSON SearchResult
116 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
118 instance ToJSON SearchResult
120 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
122 instance ToSchema SearchResult
125 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
128 instance Arbitrary SearchResult where
129 arbitrary = SearchResult <$> arbitrary
132 data SearchResultTypes =
133 SearchResultDoc { docs :: ![Row] }
134 | SearchResultContact { contacts :: ![Row] }
135 | SearchNoResult { message :: !Text }
137 instance FromJSON SearchResultTypes
139 parseJSON = genericParseJSON (defaultOptions { sumEncoding = defaultTaggedObject })
140 instance ToJSON SearchResultTypes
142 toJSON = genericToJSON (defaultOptions { sumEncoding = defaultTaggedObject })
144 instance Arbitrary SearchResultTypes where
146 srd <- SearchResultDoc <$> arbitrary
147 src <- SearchResultContact <$> arbitrary
148 srn <- pure $ SearchNoResult "No result because.."
149 elements [srd, src, srn]
151 instance ToSchema SearchResultTypes where
152 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
155 --------------------------------------------------------------------
158 Document { id :: !NodeId
159 , created :: !UTCTime
161 , hyperdata :: !HyperdataRow
165 | Contact { c_id :: !Int
166 , c_created :: !UTCTime
167 , c_hyperdata :: !HyperdataRow
169 , c_annuaireId :: !NodeId
172 instance FromJSON Row
174 parseJSON = genericParseJSON
175 ( defaultOptions { sumEncoding = defaultTaggedObject } )
178 toJSON = genericToJSON (defaultOptions { sumEncoding = defaultTaggedObject })
179 instance Arbitrary Row where
180 arbitrary = arbitrary
182 instance ToSchema Row where
183 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
186 toRow :: NodeId -> a -> Row
188 instance ToRow FacetDoc where
189 toRow _ (FacetDoc { .. }) =
190 Document { id = facetDoc_id
191 , created = facetDoc_created
192 , title = facetDoc_title
193 , hyperdata = toHyperdataRow facetDoc_hyperdata
194 , category = fromMaybe 0 facetDoc_category
195 , score = round $ fromMaybe 0 facetDoc_score }
197 -- | TODO rename FacetPaired
198 type FacetContact = FacetPaired Int UTCTime HyperdataContact Int
200 instance ToRow FacetContact where
201 toRow annuaireId (FacetPaired nId utc h s) = Contact nId utc (toHyperdataRow h) s annuaireId
204 --------------------------------------------------------------------
206 HyperdataRowDocument { _hr_abstract :: !Text
207 , _hr_authors :: !Text
210 , _hr_institutes :: !Text
211 , _hr_language_iso2 :: !Text
213 , _hr_publication_date :: !Text
214 , _hr_publication_day :: !Int
215 , _hr_publication_hour :: !Int
216 , _hr_publication_minute :: !Int
217 , _hr_publication_month :: !Int
218 , _hr_publication_second :: !Int
219 , _hr_publication_year :: !Int
220 , _hr_source :: !Text
223 , _hr_uniqId :: !Text
224 , _hr_uniqIdBdd :: !Text
226 | HyperdataRowContact { _hr_firstname :: !Text
227 , _hr_lastname :: !Text
231 instance FromJSON HyperdataRow
233 parseJSON = genericParseJSON
235 { sumEncoding = defaultTaggedObject
236 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
237 , omitNothingFields = False
240 instance ToJSON HyperdataRow
242 toJSON = genericToJSON
244 { sumEncoding = defaultTaggedObject
245 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
246 , omitNothingFields = False
250 instance Arbitrary HyperdataRow where
251 arbitrary = arbitrary
253 instance ToSchema HyperdataRow where
254 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_hr_")
256 class ToHyperdataRow a where
257 toHyperdataRow :: a -> HyperdataRow
259 instance ToHyperdataRow HyperdataDocument where
260 toHyperdataRow (HyperdataDocument { .. }) =
262 { _hr_abstract = fromMaybe "" _hd_abstract
263 , _hr_authors = fromMaybe "" _hd_authors
264 , _hr_bdd = fromMaybe "" _hd_bdd
265 , _hr_doi = fromMaybe "" _hd_doi
266 , _hr_institutes = fromMaybe "" _hd_institutes
267 , _hr_language_iso2 = fromMaybe "EN" _hd_language_iso2
268 , _hr_page = fromMaybe 0 _hd_page
269 , _hr_publication_date = fromMaybe "" _hd_publication_date
270 , _hr_publication_day = fromMaybe 1 _hd_publication_day
271 , _hr_publication_hour = fromMaybe 1 _hd_publication_hour
272 , _hr_publication_minute = fromMaybe 1 _hd_publication_minute
273 , _hr_publication_month = fromMaybe 1 _hd_publication_month
274 , _hr_publication_second = fromMaybe 1 _hd_publication_second
275 , _hr_publication_year = fromMaybe 2020 _hd_publication_year
276 , _hr_source = fromMaybe "" _hd_source
277 , _hr_title = fromMaybe "Title" _hd_title
278 , _hr_url = fromMaybe "" _hd_url
279 , _hr_uniqId = fromMaybe "" _hd_uniqId
280 , _hr_uniqIdBdd = fromMaybe "" _hd_uniqIdBdd }
282 instance ToHyperdataRow HyperdataContact where
283 toHyperdataRow (HyperdataContact { _hc_who = Just (ContactWho _ fn ln _ _), _hc_where = ou} ) =
284 HyperdataRowContact (fromMaybe "FirstName" fn) (fromMaybe "LastName" ln) ou'
286 ou' = maybe "CNRS" (Text.intercalate " " . _cw_organization) (head ou)
287 toHyperdataRow (HyperdataContact {}) =
288 HyperdataRowContact "FirstName" "LastName" "Labs"