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.List (concat)
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 qualified Gargantext.Defaults as Defaults
36 import Gargantext.Prelude
37 import Gargantext.Utils.Aeson (defaultTaggedObject)
39 import Test.QuickCheck (elements)
40 import Test.QuickCheck.Arbitrary
41 import qualified Data.Text as Text
43 -----------------------------------------------------------------------
44 -- TODO-ACCESS: CanSearch? or is it part of CanGetNode
45 -- TODO-EVENTS: No event, this is a read-only query.
46 type API results = Summary "Search endpoint"
47 :> ReqBody '[JSON] SearchQuery
48 :> QueryParam "offset" Int
49 :> QueryParam "limit" Int
50 :> QueryParam "order" OrderBy
51 :> Post '[JSON] results
52 -----------------------------------------------------------------------
53 -- | Api search function
54 api :: NodeId -> GargServer (API SearchResult)
56 api nId (SearchQuery q SearchDoc) o l order =
57 SearchResult <$> SearchResultDoc
59 <$> searchInCorpus nId False q o l order
60 -- <$> searchInCorpus nId False (concat q) o l order
62 api nId (SearchQuery q SearchContact) o l order = do
63 printDebug "isPairedWith" nId
64 aIds <- isPairedWith nId NodeAnnuaire
65 -- TODO if paired with several corpus
67 Nothing -> pure $ SearchResult
68 $ SearchNoResult "[G.A.Search] pair corpus with an Annuaire"
69 Just aId -> SearchResult
70 <$> SearchResultContact
72 <$> searchInCorpusWithContacts nId aId q o l order
74 api _nId (SearchQuery _q SearchDocWithNgrams) _o _l _order = undefined
76 -----------------------------------------------------------------------
77 -----------------------------------------------------------------------
79 -----------------------------------------------------------------------
80 data SearchType = SearchDoc | SearchContact | SearchDocWithNgrams
82 instance FromJSON SearchType where
83 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
84 instance ToJSON SearchType where
85 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
96 instance FromJSON SearchQuery where
97 parseJSON = genericParseJSON defaultOptions
98 instance ToJSON SearchQuery where
99 toJSON = genericToJSON defaultOptions
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 where
115 parseJSON = genericParseJSON defaultOptions
117 instance ToJSON SearchResult where
118 toJSON = genericToJSON defaultOptions
120 instance ToSchema SearchResult
123 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
126 instance Arbitrary SearchResult where
127 arbitrary = SearchResult <$> arbitrary
130 data SearchResultTypes =
131 SearchResultDoc { docs :: ![Row] }
132 | SearchResultContact { contacts :: ![Row] }
133 | SearchNoResult { message :: !Text }
135 instance FromJSON SearchResultTypes where
136 parseJSON = genericParseJSON (defaultOptions { sumEncoding = defaultTaggedObject })
137 instance ToJSON SearchResultTypes where
138 toJSON = genericToJSON (defaultOptions { sumEncoding = defaultTaggedObject })
140 instance Arbitrary SearchResultTypes where
142 srd <- SearchResultDoc <$> arbitrary
143 src <- SearchResultContact <$> arbitrary
144 srn <- pure $ SearchNoResult "No result because.."
145 elements [srd, src, srn]
147 instance ToSchema SearchResultTypes where
148 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
151 --------------------------------------------------------------------
154 Document { id :: !NodeId
155 , created :: !UTCTime
157 , hyperdata :: !HyperdataRow
161 | Contact { c_id :: !Int
162 , c_created :: !UTCTime
163 , c_hyperdata :: !HyperdataRow
165 , c_annuaireId :: !NodeId
168 instance FromJSON Row
170 parseJSON = genericParseJSON
171 ( defaultOptions { sumEncoding = defaultTaggedObject } )
174 toJSON = genericToJSON (defaultOptions { sumEncoding = defaultTaggedObject })
175 instance Arbitrary Row where
176 arbitrary = arbitrary
178 instance ToSchema Row where
179 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
182 toRow :: NodeId -> a -> Row
184 instance ToRow FacetDoc where
185 toRow _ (FacetDoc { .. }) =
186 Document { id = facetDoc_id
187 , created = facetDoc_created
188 , title = facetDoc_title
189 , hyperdata = toHyperdataRow facetDoc_hyperdata
190 , category = fromMaybe 0 facetDoc_category
191 , score = round $ fromMaybe 0 facetDoc_score }
193 -- | TODO rename FacetPaired
194 type FacetContact = FacetPaired Int UTCTime HyperdataContact Int
196 instance ToRow FacetContact where
197 toRow annuaireId (FacetPaired nId utc h s) = Contact nId utc (toHyperdataRow h) s annuaireId
200 --------------------------------------------------------------------
202 HyperdataRowDocument { _hr_abstract :: !Text
203 , _hr_authors :: !Text
206 , _hr_institutes :: !Text
207 , _hr_language_iso2 :: !Text
209 , _hr_publication_date :: !Text
210 , _hr_publication_day :: !Int
211 , _hr_publication_hour :: !Int
212 , _hr_publication_minute :: !Int
213 , _hr_publication_month :: !Int
214 , _hr_publication_second :: !Int
215 , _hr_publication_year :: !Int
216 , _hr_source :: !Text
219 , _hr_uniqId :: !Text
220 , _hr_uniqIdBdd :: !Text
222 | HyperdataRowContact { _hr_firstname :: !Text
223 , _hr_lastname :: !Text
227 instance FromJSON HyperdataRow
229 parseJSON = genericParseJSON
231 { sumEncoding = defaultTaggedObject
232 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
233 , omitNothingFields = False
236 instance ToJSON HyperdataRow
238 toJSON = genericToJSON
240 { sumEncoding = defaultTaggedObject
241 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
242 , omitNothingFields = False
246 instance Arbitrary HyperdataRow where
247 arbitrary = arbitrary
249 instance ToSchema HyperdataRow where
250 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_hr_")
252 class ToHyperdataRow a where
253 toHyperdataRow :: a -> HyperdataRow
255 instance ToHyperdataRow HyperdataDocument where
256 toHyperdataRow (HyperdataDocument { .. }) =
258 { _hr_abstract = fromMaybe "" _hd_abstract
259 , _hr_authors = fromMaybe "" _hd_authors
260 , _hr_bdd = fromMaybe "" _hd_bdd
261 , _hr_doi = fromMaybe "" _hd_doi
262 , _hr_institutes = fromMaybe "" _hd_institutes
263 , _hr_language_iso2 = fromMaybe "EN" _hd_language_iso2
264 , _hr_page = fromMaybe 0 _hd_page
265 , _hr_publication_date = fromMaybe "" _hd_publication_date
266 , _hr_publication_year = fromMaybe (fromIntegral Defaults.year) _hd_publication_year
267 , _hr_publication_month = fromMaybe Defaults.month _hd_publication_month
268 , _hr_publication_day = fromMaybe Defaults.day _hd_publication_day
269 , _hr_publication_hour = fromMaybe 0 _hd_publication_hour
270 , _hr_publication_minute = fromMaybe 0 _hd_publication_minute
271 , _hr_publication_second = fromMaybe 0 _hd_publication_second
272 , _hr_source = fromMaybe "" _hd_source
273 , _hr_title = fromMaybe "Title" _hd_title
274 , _hr_url = fromMaybe "" _hd_url
275 , _hr_uniqId = fromMaybe "" _hd_uniqId
276 , _hr_uniqIdBdd = fromMaybe "" _hd_uniqIdBdd }
278 instance ToHyperdataRow HyperdataContact where
279 toHyperdataRow (HyperdataContact { _hc_who = Just (ContactWho _ fn ln _ _ _), _hc_where = ou} ) =
280 HyperdataRowContact (fromMaybe "FirstName" fn) (fromMaybe "LastName" ln) ou'
282 ou' = maybe "CNRS" (Text.intercalate " " . _cw_organization) (head ou)
283 toHyperdataRow (HyperdataContact {}) =
284 HyperdataRowContact "FirstName" "LastName" "Labs"