2 Module : Gargantext.Database.Query.Facet
3 Description : Main requests of Node to the database
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
11 {-# OPTIONS_GHC -fno-warn-orphans #-}
12 {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
14 {-# LANGUAGE Arrows #-}
15 {-# LANGUAGE FunctionalDependencies #-}
16 {-# LANGUAGE QuasiQuotes #-}
17 {-# LANGUAGE NoMonomorphismRestriction #-}
18 {-# LANGUAGE TemplateHaskell #-}
19 {-# LANGUAGE TypeFamilies #-}
20 ------------------------------------------------------------------------
21 module Gargantext.Database.Query.Facet
34 , FacetPairedReadNullAgg
39 import Control.Arrow (returnA)
40 import Control.Lens ((^.))
41 import Data.Aeson (FromJSON, ToJSON)
42 import Data.Aeson.TH (deriveJSON)
43 import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
45 import Data.Text (Text)
46 import Data.Time (UTCTime)
47 import Data.Time.Segment (jour)
48 import Data.Typeable (Typeable)
49 import GHC.Generics (Generic)
51 import Prelude hiding (null, id, map, sum, not, read)
53 import Test.QuickCheck (elements)
54 import Test.QuickCheck.Arbitrary
55 import qualified Opaleye.Internal.Unpackspec()
57 import Gargantext.Core.Types
58 import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger, wellNamedSchema)
59 import Gargantext.Database.Admin.Config (nodeTypeId)
60 import Gargantext.Database.Admin.Types.Hyperdata
61 import Gargantext.Database.Query.Filter
62 import Gargantext.Database.Query.Join (leftJoin5)
63 import Gargantext.Database.Query.Table.Ngrams
64 import Gargantext.Database.Query.Table.NodeNode
65 import Gargantext.Database.Query.Table.NodeNodeNgrams
66 import Gargantext.Database.Prelude
67 import Gargantext.Database.Schema.Node
69 ------------------------------------------------------------------------
72 -- data Facet = FacetDoc | FacetSources | FacetAuthors | FacetTerms
73 -- deriving (Show, Generic)
74 --instance FromJSON Facet
75 --instance ToJSON Facet
81 type FacetDoc = Facet NodeId UTCTime Title HyperdataDocument (Maybe Category) (Maybe Double)
82 -- type FacetSources = FacetDoc
83 -- type FacetAuthors = FacetDoc
84 -- type FacetTerms = FacetDoc
87 data Facet id created title hyperdata category ngramCount =
88 FacetDoc { facetDoc_id :: id
89 , facetDoc_created :: created
90 , facetDoc_title :: title
91 , facetDoc_hyperdata :: hyperdata
92 , facetDoc_category :: category
93 , facetDoc_score :: ngramCount
94 } deriving (Show, Generic)
96 data Facet id date hyperdata score =
97 FacetDoc { facetDoc_id :: id
98 , facetDoc_date :: date
99 , facetDoc_hyperdata :: hyperdata
100 , facetDoc_score :: score
101 } deriving (Show, Generic)
104 data Pair i l = Pair {_p_id :: i
106 } deriving (Show, Generic)
107 $(deriveJSON (unPrefix "_p_") ''Pair)
108 $(makeAdaptorAndInstance "pPair" ''Pair)
110 instance (Typeable i, Typeable l, ToSchema i, ToSchema l) => ToSchema (Pair i l) where
111 declareNamedSchema = wellNamedSchema "_p_"
112 instance (Arbitrary i, Arbitrary l) => Arbitrary (Pair i l) where
113 arbitrary = Pair <$> arbitrary <*> arbitrary
115 data FacetPaired id date hyperdata score =
116 FacetPaired {_fp_id :: id
118 ,_fp_hyperdata :: hyperdata
120 } deriving (Show, Generic)
121 $(deriveJSON (unPrefix "_fp_") ''FacetPaired)
122 $(makeAdaptorAndInstance "pFacetPaired" ''FacetPaired)
126 instance ( ToSchema id
134 ) => ToSchema (FacetPaired id date hyperdata score) where
135 declareNamedSchema = wellNamedSchema "_fp_"
137 instance ( Arbitrary id
139 , Arbitrary hyperdata
141 ) => Arbitrary (FacetPaired id date hyperdata score) where
142 arbitrary = FacetPaired <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
144 type FacetPairedRead = FacetPaired (Column PGInt4 )
145 (Column PGTimestamptz)
149 type FacetPairedReadNull = FacetPaired (Column (Nullable PGInt4) )
150 (Column (Nullable PGTimestamptz))
151 (Column (Nullable PGJsonb) )
152 (Column (Nullable PGInt4) )
154 type FacetPairedReadNullAgg = FacetPaired (Aggregator (Column (Nullable PGInt4) )
155 (Column (Nullable PGInt4) )
157 (Aggregator (Column (Nullable PGTimestamptz))
158 (Column (Nullable PGTimestamptz))
161 (Aggregator (Column (Nullable PGJsonb) )
162 (Column (Nullable PGJsonb) )
164 (Aggregator (Column (Nullable PGInt4) )
165 (Column (Nullable PGInt4) )
172 $(deriveJSON (unPrefix "facetDoc_") ''Facet)
174 -- | Documentation instance
175 instance ToSchema FacetDoc where
176 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "facetDoc_")
178 -- | Mock and Quickcheck instances
179 instance Arbitrary FacetDoc where
180 arbitrary = elements [ FacetDoc id' (jour year 01 01) t hp (Just cat) (Just ngramCount)
182 , year <- [1990..2000]
183 , t <- ["title", "another title"]
184 , hp <- arbitraryHyperdataDocuments
186 , ngramCount <- [3..100]
189 -- Facets / Views for the Front End
190 -- | Database instances
191 $(makeAdaptorAndInstance "pFacetDoc" ''Facet)
192 -- $(makeLensesWith abbreviatedFields ''Facet)
194 type FacetDocRead = Facet (Column PGInt4 )
195 (Column PGTimestamptz)
198 (Column (Nullable PGInt4)) -- Category
199 (Column (Nullable PGFloat8)) -- Score
201 -----------------------------------------------------------------------
202 -----------------------------------------------------------------------
203 data OrderBy = DateAsc | DateDesc
204 | TitleAsc | TitleDesc
205 | ScoreDesc | ScoreAsc
206 | SourceAsc | SourceDesc
207 deriving (Generic, Enum, Bounded, Read, Show)
209 instance FromHttpApiData OrderBy
211 parseUrlPiece "DateAsc" = pure DateAsc
212 parseUrlPiece "DateDesc" = pure DateDesc
213 parseUrlPiece "TitleAsc" = pure TitleAsc
214 parseUrlPiece "TitleDesc" = pure TitleDesc
215 parseUrlPiece "ScoreAsc" = pure ScoreAsc
216 parseUrlPiece "ScoreDesc" = pure ScoreDesc
217 parseUrlPiece "SourceAsc" = pure SourceAsc
218 parseUrlPiece "SourceDesc" = pure SourceDesc
219 parseUrlPiece _ = Left "Unexpected value of OrderBy"
221 instance ToParamSchema OrderBy
222 instance FromJSON OrderBy
223 instance ToJSON OrderBy
224 instance ToSchema OrderBy
225 instance Arbitrary OrderBy
227 arbitrary = elements [minBound..maxBound]
230 -- TODO-SECURITY check
233 runViewAuthorsDoc :: ContactId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc]
234 runViewAuthorsDoc cId t o l order = runOpaQuery $ filterWith o l order $ viewAuthorsDoc cId t ntId
239 viewAuthorsDoc :: ContactId -> IsTrash -> NodeType -> Query FacetDocRead
240 viewAuthorsDoc cId _ nt = proc () -> do
241 (doc,(_,(_,(_,contact)))) <- queryAuthorsDoc -< ()
243 {-nn <- queryNodeNodeTable -< ()
244 restrict -< nn_node1_id nn .== _node_id doc
245 -- restrict -< nn_delete nn .== (pgBool t)
248 restrict -< _node_id contact .== (toNullable $ pgNodeId cId)
249 restrict -< _node_typename doc .== (pgInt4 $ nodeTypeId nt)
251 returnA -< FacetDoc (_node_id doc)
254 (_node_hyperdata doc)
255 (toNullable $ pgInt4 1)
256 (toNullable $ pgDouble 1)
258 queryAuthorsDoc :: Query (NodeRead, (NodeNodeNgramsReadNull, (NgramsReadNull, (NodeNodeNgramsReadNull, NodeReadNull))))
259 queryAuthorsDoc = leftJoin5 queryNodeTable queryNodeNodeNgramsTable queryNgramsTable queryNodeNodeNgramsTable queryNodeTable cond12 cond23 cond34 cond45
261 cond12 :: (NodeNodeNgramsRead, NodeRead) -> Column PGBool
262 cond12 (nodeNgram, doc) = _node_id doc
263 .== _nnng_node1_id nodeNgram
265 cond23 :: (NgramsRead, (NodeNodeNgramsRead, NodeReadNull)) -> Column PGBool
266 cond23 (ngrams, (nodeNgram, _)) = ngrams^.ngrams_id
267 .== _nnng_ngrams_id nodeNgram
269 cond34 :: (NodeNodeNgramsRead, (NgramsRead, (NodeNodeNgramsReadNull, NodeReadNull))) -> Column PGBool
270 cond34 (nodeNgram2, (ngrams, (_,_)))= ngrams^.ngrams_id .== _nnng_ngrams_id nodeNgram2
272 cond45 :: (NodeRead, (NodeNodeNgramsRead, (NgramsReadNull, (NodeNodeNgramsReadNull, NodeReadNull)))) -> Column PGBool
273 cond45 (contact, (nodeNgram2, (_, (_,_)))) = _node_id contact .== _nnng_node1_id nodeNgram2
276 ------------------------------------------------------------------------
278 -- TODO-SECURITY check
279 runViewDocuments :: CorpusId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc]
280 runViewDocuments cId t o l order =
281 runOpaQuery $ filterWith o l order $ viewDocuments cId t ntId
283 ntId = nodeTypeId NodeDocument
285 runCountDocuments :: CorpusId -> IsTrash -> Cmd err Int
286 runCountDocuments cId t =
287 runCountOpaQuery $ viewDocuments cId t $ nodeTypeId NodeDocument
290 viewDocuments :: CorpusId -> IsTrash -> NodeTypeId -> Query FacetDocRead
291 viewDocuments cId t ntId = proc () -> do
292 n <- queryNodeTable -< ()
293 nn <- queryNodeNodeTable -< ()
294 restrict -< n^.node_id .== nn^.nn_node2_id
295 restrict -< nn^.nn_node1_id .== (pgNodeId cId)
296 restrict -< n^.node_typename .== (pgInt4 ntId)
297 restrict -< if t then nn^.nn_category .== (pgInt4 0)
298 else nn^.nn_category .>= (pgInt4 1)
299 returnA -< FacetDoc (_node_id n)
303 (toNullable $ nn^.nn_category)
304 (toNullable $ nn^.nn_score)
306 ------------------------------------------------------------------------
307 filterWith :: (PGOrd date, PGOrd title, PGOrd score, hyperdata ~ Column SqlJsonb) =>
308 Maybe Gargantext.Core.Types.Offset
309 -> Maybe Gargantext.Core.Types.Limit
311 -> Select (Facet id (Column date) (Column title) hyperdata (Column score) ngramCount)
312 -> Select (Facet id (Column date) (Column title) hyperdata (Column score) ngramCount)
313 filterWith o l order q = limit' l $ offset' o $ orderBy (orderWith order) q
316 orderWith :: (PGOrd b1, PGOrd b2, PGOrd b3)
318 -> Order (Facet id (Column b1) (Column b2) (Column SqlJsonb) (Column b3) score)
319 orderWith (Just DateAsc) = asc facetDoc_created
320 orderWith (Just DateDesc) = desc facetDoc_created
322 orderWith (Just TitleAsc) = asc facetDoc_title
323 orderWith (Just TitleDesc) = desc facetDoc_title
325 orderWith (Just ScoreAsc) = asc facetDoc_category
326 orderWith (Just ScoreDesc) = desc facetDoc_category
328 orderWith (Just SourceAsc) = asc facetDoc_source
329 orderWith (Just SourceDesc) = desc facetDoc_source
331 orderWith _ = asc facetDoc_created
333 facetDoc_source :: PGIsJson a
334 => Facet id created title (Column a) favorite ngramCount
335 -> Column (Nullable PGText)
336 facetDoc_source x = toNullable (facetDoc_hyperdata x) .->> pgString "source"