2 Module : Gargantext.Database.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 DeriveGeneric #-}
16 {-# LANGUAGE FlexibleContexts #-}
17 {-# LANGUAGE FlexibleInstances #-}
18 {-# LANGUAGE FunctionalDependencies #-}
19 {-# LANGUAGE MultiParamTypeClasses #-}
20 {-# LANGUAGE QuasiQuotes #-}
21 {-# LANGUAGE NoImplicitPrelude #-}
22 {-# LANGUAGE NoMonomorphismRestriction #-}
23 {-# LANGUAGE OverloadedStrings #-}
24 {-# LANGUAGE RankNTypes #-}
25 {-# LANGUAGE TemplateHaskell #-}
26 {-# LANGUAGE TypeFamilies #-}
27 ------------------------------------------------------------------------
28 module Gargantext.Database.Facet
42 ------------------------------------------------------------------------
43 import Control.Arrow (returnA)
44 -- import Control.Lens.TH (makeLensesWith, abbreviatedFields)
45 import Data.Aeson (FromJSON, ToJSON)
46 import Data.Aeson.TH (deriveJSON)
47 import Data.Either(Either(Left))
48 import Data.Maybe (Maybe)
49 import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
51 import Data.Text (Text)
52 import Data.Time (UTCTime)
53 import Data.Time.Segment (jour)
54 import GHC.Generics (Generic)
55 import Gargantext.Core.Types
56 import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
57 import Gargantext.Database.Config (nodeTypeId)
58 import Gargantext.Database.Schema.Ngrams
59 import Gargantext.Database.Schema.Node
60 import Gargantext.Database.Schema.NodeNgram
61 import Gargantext.Database.Schema.NodeNode
62 import Gargantext.Database.Utils
63 import Gargantext.Database.Queries.Join
64 import Gargantext.Database.Queries.Filter
66 import Prelude hiding (null, id, map, sum, not, read)
68 import Test.QuickCheck (elements)
69 import Test.QuickCheck.Arbitrary
70 import qualified Opaleye.Internal.Unpackspec()
72 ------------------------------------------------------------------------
75 -- data Facet = FacetDoc | FacetSources | FacetAuthors | FacetTerms
76 -- deriving (Show, Generic)
77 --instance FromJSON Facet
78 --instance ToJSON Facet
84 type FacetDoc = Facet NodeId UTCTime Title HyperdataDocument (Maybe Favorite) (Maybe Double)
85 -- type FacetSources = FacetDoc
86 -- type FacetAuthors = FacetDoc
87 -- type FacetTerms = FacetDoc
90 data Facet id created title hyperdata favorite ngramCount =
91 FacetDoc { facetDoc_id :: id
92 , facetDoc_created :: created
93 , facetDoc_title :: title
94 , facetDoc_hyperdata :: hyperdata
95 , facetDoc_favorite :: favorite
96 , facetDoc_ngramCount :: ngramCount
97 } deriving (Show, Generic)
99 data Facet id date hyperdata score =
100 FacetDoc { facetDoc_id :: id
101 , facetDoc_date :: date
102 , facetDoc_hyperdata :: hyperdata
103 , facetDoc_score :: score
104 } deriving (Show, Generic)
107 data Pair i l = Pair {_p_id :: i
109 } deriving (Show, Generic)
110 $(deriveJSON (unPrefix "_p_") ''Pair)
111 $(makeAdaptorAndInstance "pPair" ''Pair)
113 instance (ToSchema i, ToSchema l) => ToSchema (Pair i l) where
114 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_p_")
115 instance (Arbitrary i, Arbitrary l) => Arbitrary (Pair i l) where
116 arbitrary = Pair <$> arbitrary <*> arbitrary
118 data FacetPaired id date hyperdata score pairs =
119 FacetPaired {_fp_id :: id
121 ,_fp_hyperdata :: hyperdata
124 } deriving (Show, Generic)
125 $(deriveJSON (unPrefix "_fp_") ''FacetPaired)
126 $(makeAdaptorAndInstance "pFacetPaired" ''FacetPaired)
128 instance (ToSchema id, ToSchema date, ToSchema hyperdata, ToSchema pairs, ToSchema score) => ToSchema (FacetPaired id date hyperdata score pairs) where
129 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_fp_")
131 instance ( Arbitrary id
133 , Arbitrary hyperdata
136 ) => Arbitrary (FacetPaired id date hyperdata score pairs) where
137 arbitrary = FacetPaired <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
140 type FacetPairedRead = FacetPaired (Column PGInt4 )
141 (Column PGTimestamptz)
144 (Pair (Column (Nullable PGInt4)) (Column (Nullable PGText)))
150 $(deriveJSON (unPrefix "facetDoc_") ''Facet)
152 -- | Documentation instance
153 instance ToSchema FacetDoc where
154 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "facetDoc_")
156 -- | Mock and Quickcheck instances
157 instance Arbitrary FacetDoc where
158 arbitrary = elements [ FacetDoc id' (jour year 01 01) t hp (Just cat) (Just ngramCount)
160 , year <- [1990..2000]
161 , t <- ["title", "another title"]
162 , hp <- arbitraryHyperdataDocuments
164 , ngramCount <- [3..100]
167 -- Facets / Views for the Front End
168 -- | Database instances
169 $(makeAdaptorAndInstance "pFacetDoc" ''Facet)
170 -- $(makeLensesWith abbreviatedFields ''Facet)
172 type FacetDocRead = Facet (Column PGInt4 )
173 (Column PGTimestamptz)
176 (Column (Nullable PGInt4)) -- Category
177 (Column (Nullable PGFloat8)) -- Score
179 -----------------------------------------------------------------------
180 -----------------------------------------------------------------------
181 data OrderBy = DateAsc | DateDesc
182 | TitleAsc | TitleDesc
183 | ScoreDesc | ScoreAsc
184 | SourceAsc | SourceDesc
185 deriving (Generic, Enum, Bounded, Read, Show)
187 instance FromHttpApiData OrderBy
189 parseUrlPiece "DateAsc" = pure DateAsc
190 parseUrlPiece "DateDesc" = pure DateDesc
191 parseUrlPiece "TitleAsc" = pure TitleAsc
192 parseUrlPiece "TitleDesc" = pure TitleDesc
193 parseUrlPiece "ScoreAsc" = pure ScoreAsc
194 parseUrlPiece "ScoreDesc" = pure ScoreDesc
195 parseUrlPiece "SourceAsc" = pure SourceAsc
196 parseUrlPiece "SourceDesc" = pure SourceDesc
197 parseUrlPiece _ = Left "Unexpected value of OrderBy"
199 instance ToParamSchema OrderBy
200 instance FromJSON OrderBy
201 instance ToJSON OrderBy
202 instance ToSchema OrderBy
203 instance Arbitrary OrderBy
205 arbitrary = elements [minBound..maxBound]
208 -- TODO-SECURITY check
209 runViewAuthorsDoc :: ContactId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc]
210 runViewAuthorsDoc cId t o l order = runOpaQuery $ filterWith o l order $ viewAuthorsDoc cId t ntId
215 viewAuthorsDoc :: ContactId -> IsTrash -> NodeType -> Query FacetDocRead
216 viewAuthorsDoc cId _ nt = proc () -> do
217 (doc,(_,(_,(_,contact)))) <- queryAuthorsDoc -< ()
219 {-nn <- queryNodeNodeTable -< ()
220 restrict -< nn_node1_id nn .== _node_id doc
221 -- restrict -< nn_delete nn .== (pgBool t)
224 restrict -< _node_id contact .== (toNullable $ pgNodeId cId)
225 restrict -< _node_typename doc .== (pgInt4 $ nodeTypeId nt)
227 returnA -< FacetDoc (_node_id doc) (_node_date doc) (_node_name doc) (_node_hyperdata doc) (toNullable $ pgInt4 1) (toNullable $ pgDouble 1)
229 queryAuthorsDoc :: Query (NodeRead, (NodeNgramReadNull, (NgramsReadNull, (NodeNgramReadNull, NodeReadNull))))
230 queryAuthorsDoc = leftJoin5 queryNodeTable queryNodeNgramTable queryNgramsTable queryNodeNgramTable queryNodeTable cond12 cond23 cond34 cond45
232 cond12 :: (NodeNgramRead, NodeRead) -> Column PGBool
233 cond12 (nodeNgram, doc) = _node_id doc
234 .== nng_node_id nodeNgram
236 cond23 :: (NgramsRead, (NodeNgramRead, NodeReadNull)) -> Column PGBool
237 cond23 (ngrams, (nodeNgram, _)) = ngrams_id ngrams
238 .== nng_ngrams_id nodeNgram
240 cond34 :: (NodeNgramRead, (NgramsRead, (NodeNgramReadNull, NodeReadNull))) -> Column PGBool
241 cond34 (nodeNgram2, (ngrams, (_,_)))= ngrams_id ngrams .== nng_ngrams_id nodeNgram2
243 cond45 :: (NodeRead, (NodeNgramRead, (NgramsReadNull, (NodeNgramReadNull, NodeReadNull)))) -> Column PGBool
244 cond45 (contact, (nodeNgram2, (_, (_,_)))) = _node_id contact .== nng_node_id nodeNgram2
247 ------------------------------------------------------------------------
249 -- TODO-SECURITY check
250 runViewDocuments :: CorpusId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc]
251 runViewDocuments cId t o l order =
252 runOpaQuery $ filterWith o l order $ viewDocuments cId t ntId
254 ntId = nodeTypeId NodeDocument
256 viewDocuments :: CorpusId -> IsTrash -> NodeTypeId -> Query FacetDocRead
257 viewDocuments cId t ntId = proc () -> do
258 n <- queryNodeTable -< ()
259 nn <- queryNodeNodeTable -< ()
260 restrict -< _node_id n .== nn_node2_id nn
261 restrict -< nn_node1_id nn .== (pgNodeId cId)
262 restrict -< _node_typename n .== (pgInt4 ntId)
263 restrict -< if t then nn_category nn .== (pgInt4 0)
264 else nn_category nn .>= (pgInt4 1)
265 returnA -< FacetDoc (_node_id n) (_node_date n) (_node_name n) (_node_hyperdata n) (toNullable $ nn_category nn) (toNullable $ nn_score nn)
268 ------------------------------------------------------------------------
269 filterWith :: (PGOrd date, PGOrd title, PGOrd score, hyperdata ~ Column SqlJsonb) =>
270 Maybe Gargantext.Core.Types.Offset
271 -> Maybe Gargantext.Core.Types.Limit
273 -> Select (Facet id (Column date) (Column title) hyperdata (Column score) ngramCount)
274 -> Select (Facet id (Column date) (Column title) hyperdata (Column score) ngramCount)
275 filterWith o l order q = limit' l $ offset' o $ orderBy (orderWith order) q
278 orderWith :: (PGOrd b1, PGOrd b2, PGOrd b3)
280 -> Order (Facet id (Column b1) (Column b2) (Column SqlJsonb) (Column b3) score)
281 orderWith (Just DateAsc) = asc facetDoc_created
282 orderWith (Just DateDesc) = desc facetDoc_created
284 orderWith (Just TitleAsc) = asc facetDoc_title
285 orderWith (Just TitleDesc) = desc facetDoc_title
287 orderWith (Just ScoreAsc) = asc facetDoc_favorite
288 orderWith (Just ScoreDesc) = desc facetDoc_favorite
290 orderWith (Just SourceAsc) = asc facetDoc_source
291 orderWith (Just SourceDesc) = desc facetDoc_source
293 orderWith _ = asc facetDoc_created
295 facetDoc_source :: PGIsJson a
296 => Facet id created title (Column a) favorite ngramCount
297 -> Column (Nullable PGText)
298 facetDoc_source x = toNullable (facetDoc_hyperdata x) .->> pgString "source"