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 nId utc t h mc _md sc) =
189 Document nId utc t (toHyperdataRow h) (fromMaybe 0 mc) (round $ fromMaybe 0 sc)
191 -- | TODO rename FacetPaired
192 type FacetContact = FacetPaired Int UTCTime HyperdataContact Int
194 instance ToRow FacetContact where
195 toRow annuaireId (FacetPaired nId utc h s) = Contact nId utc (toHyperdataRow h) s annuaireId
198 --------------------------------------------------------------------
200 HyperdataRowDocument { _hr_abstract :: !Text
201 , _hr_authors :: !Text
204 , _hr_institutes :: !Text
205 , _hr_language_iso2 :: !Text
207 , _hr_publication_date :: !Text
208 , _hr_publication_day :: !Int
209 , _hr_publication_hour :: !Int
210 , _hr_publication_minute :: !Int
211 , _hr_publication_month :: !Int
212 , _hr_publication_second :: !Int
213 , _hr_publication_year :: !Int
214 , _hr_source :: !Text
217 , _hr_uniqId :: !Text
218 , _hr_uniqIdBdd :: !Text
220 | HyperdataRowContact { _hr_firstname :: !Text
221 , _hr_lastname :: !Text
225 instance FromJSON HyperdataRow
227 parseJSON = genericParseJSON
229 { sumEncoding = defaultTaggedObject
230 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
231 , omitNothingFields = False
234 instance ToJSON HyperdataRow
236 toJSON = genericToJSON
238 { sumEncoding = defaultTaggedObject
239 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
240 , omitNothingFields = False
244 instance Arbitrary HyperdataRow where
245 arbitrary = arbitrary
247 instance ToSchema HyperdataRow where
248 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_hr_")
250 class ToHyperdataRow a where
251 toHyperdataRow :: a -> HyperdataRow
253 instance ToHyperdataRow HyperdataDocument where
254 toHyperdataRow (HyperdataDocument b d u ui ub p t a i s abs' pd py pm pda ph pmin psec l) =
262 (fromMaybe "Title" t)
276 instance ToHyperdataRow HyperdataContact where
277 toHyperdataRow (HyperdataContact _ (Just (ContactWho _ fn ln _ _)) ou _ _ _ _ _ ) =
278 HyperdataRowContact (fromMaybe "FirstName" fn) (fromMaybe "LastName" ln) ou'
280 ou' = maybe "CNRS" (Text.intercalate " " . _cw_organization) (head ou)
281 toHyperdataRow (HyperdataContact _ _ _ _ _ _ _ _ ) =
282 HyperdataRowContact "FirstName" "LastName" "Labs"