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 {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
15 {-# LANGUAGE TemplateHaskell #-}
16 {-# LANGUAGE TypeOperators #-}
17 {-# LANGUAGE DeriveAnyClass #-}
19 module Gargantext.API.Search
23 import Data.Maybe (fromMaybe)
24 import Data.Swagger hiding (fieldLabelModifier)
25 import Data.Text (Text)
26 import Data.Time (UTCTime)
27 import GHC.Generics (Generic)
28 import Gargantext.API.Prelude (GargServer)
29 import Gargantext.Core.Utils.Prefix (unPrefixSwagger, unCapitalize, dropPrefix)
30 import Gargantext.Database.Query.Facet
31 import Gargantext.Database.Action.Search
32 import Gargantext.Database.Action.Flow.Pairing (isPairedWith)
33 import Gargantext.Database.Admin.Types.Hyperdata (HyperdataContact, HyperdataDocument(..))
34 import Gargantext.Database.Admin.Types.Node
35 import Gargantext.Prelude
37 import Test.QuickCheck (elements)
38 import Test.QuickCheck.Arbitrary
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 :: NodeId -> GargServer (API SearchResult)
52 api nId (SearchQuery q SearchDoc) o l order =
53 SearchResult <$> SearchResultDoc <$> map toRow <$> searchInCorpus nId False q o l order
54 api nId (SearchQuery q SearchContact) o l order = do
55 aIds <- isPairedWith NodeAnnuaire nId
56 -- TODO if paired with several corpus
58 Nothing -> pure $ SearchResult $ SearchNoResult "[G.A.Search] pair corpus with an Annuaire"
59 Just aId -> SearchResult <$> SearchResultContact <$> searchInCorpusWithContacts nId aId q o l order
60 api _ _ _ _ _ = undefined
62 -----------------------------------------------------------------------
63 -----------------------------------------------------------------------
65 -----------------------------------------------------------------------
66 data SearchType = SearchDoc | SearchContact
69 instance FromJSON SearchType
71 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
73 instance ToJSON SearchType
75 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
77 instance ToSchema SearchType
78 instance Arbitrary SearchType where
79 arbitrary = elements [SearchDoc, SearchContact]
81 -----------------------------------------------------------------------
83 SearchQuery { query :: ![Text]
84 , expected :: !SearchType
86 | SearchQueryErr !Text
89 instance FromJSON SearchQuery
91 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
93 instance ToJSON SearchQuery
95 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
97 instance ToSchema SearchQuery
100 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
103 instance Arbitrary SearchQuery where
104 arbitrary = elements [SearchQuery ["electrodes"] SearchDoc]
105 -- arbitrary = elements [SearchQuery "electrodes" 1 ] --SearchDoc]
106 -----------------------------------------------------------------------
109 SearchResult { result :: !SearchResultTypes
111 | SearchResultErr !Text
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 = SearchResultDoc { docs :: ![Row]}
133 | SearchResultContact { contacts :: ![FacetPaired Int UTCTime HyperdataContact Int] }
134 | SearchNoResult { message :: !Text }
138 instance FromJSON SearchResultTypes
140 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
142 instance ToJSON SearchResultTypes
144 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
146 instance Arbitrary SearchResultTypes where
148 srd <- SearchResultDoc <$> arbitrary
149 src <- SearchResultContact <$> arbitrary
150 srn <- pure $ SearchNoResult "No result because.."
151 elements [srd, src, srn]
153 instance ToSchema SearchResultTypes where
154 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
157 --------------------------------------------------------------------
160 Document { id :: !NodeId
161 , created :: !UTCTime
163 , hyperdata :: !HyperdataRow
167 | Contact { c_id :: !Int
169 , c_hyperdata :: !HyperdataContact
174 instance FromJSON Row
176 parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
180 toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })
182 instance Arbitrary Row where
183 arbitrary = arbitrary
185 instance ToSchema Row where
186 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")
188 toRow :: FacetDoc -> Row
189 toRow (FacetDoc nId utc t h mc md) = Document nId utc t (toHyperdataRow h) (fromMaybe 0 mc) (round $ fromMaybe 0 md)
191 --------------------------------------------------------------------
194 HyperdataRowDocument { _hr_bdd :: !Text
197 , _hr_uniqId :: !Text
198 , _hr_uniqIdBdd :: !Text
201 , _hr_authors :: !Text
202 , _hr_institutes :: !Text
203 , _hr_source :: !Text
204 , _hr_abstract :: !Text
205 , _hr_publication_date :: !Text
206 , _hr_publication_year :: !Int
207 , _hr_publication_month :: !Int
208 , _hr_publication_day :: !Int
209 , _hr_publication_hour :: !Int
210 , _hr_publication_minute :: !Int
211 , _hr_publication_second :: !Int
212 , _hr_language_iso2 :: !Text
214 | HyperdataRowContact { _hr_name :: !Text }
217 instance FromJSON HyperdataRow
219 parseJSON = genericParseJSON
221 { sumEncoding = ObjectWithSingleField
222 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
223 , omitNothingFields = True
227 instance ToJSON HyperdataRow
229 toJSON = genericToJSON
231 { sumEncoding = ObjectWithSingleField
232 , fieldLabelModifier = unCapitalize . dropPrefix "_hr_"
233 , omitNothingFields = True
237 instance Arbitrary HyperdataRow where
238 arbitrary = arbitrary
240 instance ToSchema HyperdataRow where
241 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_hr_")
243 toHyperdataRow :: HyperdataDocument -> HyperdataRow
244 toHyperdataRow (HyperdataDocument b d u ui ub p t a i s abs pd py pm pda ph pmin psec l) =
252 (fromMaybe "Title" t)