Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
H
haskell-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Przemyslaw Kaminski
haskell-gargantext
Commits
a2788ade
Commit
a2788ade
authored
Aug 30, 2022
by
Przemyslaw Kaminski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[nodeStory] optimize node_stories table
Read in backend works now, insert and upsert not yet.
parent
f43b4bb1
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
295 additions
and
174 deletions
+295
-174
0.0.6.1.sql
devops/postgres/upgrade/0.0.6.1.sql
+58
-0
0.0.6.sql
devops/postgres/upgrade/0.0.6.sql
+0
-1
gargantext.cabal
gargantext.cabal
+0
-1
Ngrams.hs
src/Gargantext/API/Ngrams.hs
+1
-0
Tools.hs
src/Gargantext/API/Ngrams/Tools.hs
+2
-2
Types.hs
src/Gargantext/API/Ngrams/Types.hs
+7
-19
NodeStory.hs
src/Gargantext/Core/NodeStory.hs
+157
-83
Metrics.hs
src/Gargantext/Database/Action/Metrics.hs
+6
-9
Config.hs
src/Gargantext/Database/Admin/Config.hs
+0
-1
Node.hs
src/Gargantext/Database/Admin/Types/Node.hs
+16
-18
Ngrams.hs
src/Gargantext/Database/Query/Table/Ngrams.hs
+0
-1
Node.hs
src/Gargantext/Database/Query/Table/Node.hs
+14
-13
Ngrams.hs
src/Gargantext/Database/Schema/Ngrams.hs
+34
-26
No files found.
devops/postgres/upgrade/0.0.6.1.sql
0 → 100644
View file @
a2788ade
-- we will migrate data here
-- rename old table and create a new one
ALTER
TABLE
public
.
node_stories
RENAME
TO
node_stories_old
;
CREATE
TABLE
public
.
node_stories
(
id
SERIAL
,
node_id
INTEGER
NOT
NULL
,
version
INTEGER
NOT
NULL
,
ngrams_type_id
INTEGER
NOT
NULL
,
ngrams_id
INTEGER
NOT
NULL
,
--children TEXT[],
ngrams_repo_element
jsonb
DEFAULT
'{}'
::
jsonb
NOT
NULL
,
PRIMARY
KEY
(
id
),
FOREIGN
KEY
(
node_id
)
REFERENCES
public
.
nodes
(
id
)
ON
DELETE
CASCADE
,
FOREIGN
KEY
(
ngrams_id
)
REFERENCES
public
.
ngrams
(
id
)
ON
DELETE
CASCADE
);
ALTER
TABLE
public
.
node_stories
OWNER
TO
gargantua
;
CREATE
UNIQUE
INDEX
ON
public
.
node_stories
USING
btree
(
node_id
,
ngrams_type_id
,
ngrams_id
);
-- Authors (ngrams_type_id = 1), see G.D.S.Ngrams.hs -> ngramsTypeId
INSERT
INTO
public
.
node_stories
(
node_id
,
version
,
ngrams_type_id
,
ngrams_id
,
ngrams_repo_element
)
SELECT
node_id
,
(
archive
->
'version'
)::
int
,
1
,
ngrams
.
id
,
j
.
value
FROM
node_stories_old
CROSS
JOIN
jsonb_each
(
archive
->
'state'
->
'Authors'
)
AS
j
JOIN
ngrams
ON
terms
=
j
.
key
;
-- we will leave children for later, small steps
-- INSERT INTO public.node_stories
-- (node_id, version, ngrams_type_id, ngrams_id, children, ngrams_repo_element)
-- SELECT node_id, (archive->'version')::int, 1, ngrams.id, c.children, (j.value - 'children')
-- FROM node_stories_old
-- CROSS JOIN jsonb_each(archive->'state'->'Authors') AS j
-- CROSS JOIN LATERAL (SELECT array_agg(d.elem) AS children FROM jsonb_array_elements_text(j.value->'children') AS d(elem)) AS c
-- JOIN ngrams ON terms = j.key;
-- Institutes (ngrams_type_id = 2)
INSERT
INTO
public
.
node_stories
(
node_id
,
version
,
ngrams_type_id
,
ngrams_id
,
ngrams_repo_element
)
SELECT
node_id
,
(
archive
->
'version'
)::
int
,
2
,
ngrams
.
id
,
j
.
value
FROM
node_stories_old
CROSS
JOIN
jsonb_each
(
archive
->
'state'
->
'Institutes'
)
AS
j
JOIN
ngrams
ON
terms
=
j
.
key
;
-- Sources (ngrams_type_id = 3)
INSERT
INTO
public
.
node_stories
(
node_id
,
version
,
ngrams_type_id
,
ngrams_id
,
ngrams_repo_element
)
SELECT
node_id
,
(
archive
->
'version'
)::
int
,
3
,
ngrams
.
id
,
j
.
value
FROM
node_stories_old
CROSS
JOIN
jsonb_each
(
archive
->
'state'
->
'Sources'
)
AS
j
JOIN
ngrams
ON
terms
=
j
.
key
;
-- NgramsTerms (ngrams_type_id = 4)
INSERT
INTO
public
.
node_stories
(
node_id
,
version
,
ngrams_type_id
,
ngrams_id
,
ngrams_repo_element
)
SELECT
node_id
,
(
archive
->
'version'
)::
int
,
4
,
ngrams
.
id
,
j
.
value
FROM
node_stories_old
CROSS
JOIN
jsonb_each
(
archive
->
'state'
->
'NgramsTerms'
)
AS
j
JOIN
ngrams
ON
terms
=
j
.
key
;
devops/postgres/upgrade/0.0.6.sql
View file @
a2788ade
...
@@ -36,4 +36,3 @@ ALTER TABLE public.node_story_archive_history OWNER TO gargantua;
...
@@ -36,4 +36,3 @@ ALTER TABLE public.node_story_archive_history OWNER TO gargantua;
-- UNION (SELECT node_id, sid, 3 AS ngrams_type_id, "Sources" AS patch FROM q WHERE "Sources" IS NOT NULL)
-- UNION (SELECT node_id, sid, 3 AS ngrams_type_id, "Sources" AS patch FROM q WHERE "Sources" IS NOT NULL)
-- ORDER BY node_id, ngrams_type_id, sid
-- ORDER BY node_id, ngrams_type_id, sid
-- ) AS t;
-- ) AS t;
gargantext.cabal
View file @
a2788ade
...
@@ -96,7 +96,6 @@ library
...
@@ -96,7 +96,6 @@ library
Gargantext.Core.Viz.Phylo.SynchronicClustering
Gargantext.Core.Viz.Phylo.SynchronicClustering
Gargantext.Core.Viz.Types
Gargantext.Core.Viz.Types
other-modules:
other-modules:
ConcurrentTest
Gargantext.API.Admin.Auth
Gargantext.API.Admin.Auth
Gargantext.API.Admin.FrontEnd
Gargantext.API.Admin.FrontEnd
Gargantext.API.Admin.Orchestrator
Gargantext.API.Admin.Orchestrator
...
...
src/Gargantext/API/Ngrams.hs
View file @
a2788ade
...
@@ -29,6 +29,7 @@ module Gargantext.API.Ngrams
...
@@ -29,6 +29,7 @@ module Gargantext.API.Ngrams
,
TableNgramsApiPut
,
TableNgramsApiPut
,
getTableNgrams
,
getTableNgrams
,
getTableNgramsCorpus
,
setListNgrams
,
setListNgrams
--, rmListNgrams TODO fix before exporting
--, rmListNgrams TODO fix before exporting
,
apiNgramsTableCorpus
,
apiNgramsTableCorpus
...
...
src/Gargantext/API/Ngrams/Tools.hs
View file @
a2788ade
...
@@ -22,6 +22,7 @@ import Data.Hashable (Hashable)
...
@@ -22,6 +22,7 @@ import Data.Hashable (Hashable)
import
Data.Set
(
Set
)
import
Data.Set
(
Set
)
import
Data.Validity
import
Data.Validity
import
Gargantext.API.Ngrams.Types
import
Gargantext.API.Ngrams.Types
import
Gargantext.Core.NodeStory
import
Gargantext.Core.Types
(
ListType
(
..
),
NodeId
,
NodeType
(
..
),
ListId
)
import
Gargantext.Core.Types
(
ListType
(
..
),
NodeId
,
NodeType
(
..
),
ListId
)
import
Gargantext.Database.Prelude
(
CmdM
,
HasConnectionPool
(
..
))
import
Gargantext.Database.Prelude
(
CmdM
,
HasConnectionPool
(
..
))
import
Gargantext.Database.Schema.Ngrams
(
NgramsType
)
import
Gargantext.Database.Schema.Ngrams
(
NgramsType
)
...
@@ -29,7 +30,6 @@ import Gargantext.Prelude
...
@@ -29,7 +30,6 @@ import Gargantext.Prelude
import
qualified
Data.HashMap.Strict
as
HM
import
qualified
Data.HashMap.Strict
as
HM
import
qualified
Data.Map.Strict
as
Map
import
qualified
Data.Map.Strict
as
Map
import
qualified
Data.Set
as
Set
import
qualified
Data.Set
as
Set
import
Gargantext.Core.NodeStory
import
qualified
Gargantext.Core.NodeStoryFile
as
NSF
import
qualified
Gargantext.Core.NodeStoryFile
as
NSF
...
@@ -209,7 +209,7 @@ migrateFromDirToDb = do
...
@@ -209,7 +209,7 @@ migrateFromDirToDb = do
_
<-
mapM
(
\
(
nId
,
a
)
->
do
_
<-
mapM
(
\
(
nId
,
a
)
->
do
n
<-
liftBase
$
nodeExists
pool
nId
n
<-
liftBase
$
nodeExists
pool
nId
case
n
of
case
n
of
False
->
pure
0
False
->
pure
()
True
->
liftBase
$
upsertNodeArchive
pool
nId
a
True
->
liftBase
$
upsertNodeArchive
pool
nId
a
)
$
Map
.
toList
nls
)
$
Map
.
toList
nls
--
_
<-
nodeStoryIncs
(
Just
$
NodeStory
nls
)
listIds
--
_
<-
nodeStoryIncs
(
Just
$
NodeStory
nls
)
listIds
...
...
src/Gargantext/API/Ngrams/Types.hs
View file @
a2788ade
...
@@ -28,7 +28,7 @@ import Data.String (IsString, fromString)
...
@@ -28,7 +28,7 @@ import Data.String (IsString, fromString)
import
Data.Swagger
hiding
(
version
,
patch
)
import
Data.Swagger
hiding
(
version
,
patch
)
import
Data.Text
(
Text
,
pack
,
strip
)
import
Data.Text
(
Text
,
pack
,
strip
)
import
Data.Validity
import
Data.Validity
import
Database.PostgreSQL.Simple.FromField
(
FromField
,
fromField
,
fromJSONField
,
ResultError
(
ConversionFailed
),
returnError
)
import
Database.PostgreSQL.Simple.FromField
(
FromField
,
fromField
,
fromJSONField
)
import
Database.PostgreSQL.Simple.ToField
(
ToField
,
toJSONField
,
toField
)
import
Database.PostgreSQL.Simple.ToField
(
ToField
,
toJSONField
,
toField
)
import
GHC.Generics
(
Generic
)
import
GHC.Generics
(
Generic
)
import
Gargantext.Core.Text
(
size
)
import
Gargantext.Core.Text
(
size
)
...
@@ -44,7 +44,6 @@ import Servant.Job.Utils (jsonOptions)
...
@@ -44,7 +44,6 @@ import Servant.Job.Utils (jsonOptions)
import
Test.QuickCheck
(
elements
,
frequency
)
import
Test.QuickCheck
(
elements
,
frequency
)
import
Test.QuickCheck.Arbitrary
(
Arbitrary
,
arbitrary
)
import
Test.QuickCheck.Arbitrary
(
Arbitrary
,
arbitrary
)
import
qualified
Data.HashMap.Strict.InsOrd
as
InsOrdHashMap
import
qualified
Data.HashMap.Strict.InsOrd
as
InsOrdHashMap
import
qualified
Data.List
as
List
import
qualified
Data.Map.Strict
as
Map
import
qualified
Data.Map.Strict
as
Map
import
qualified
Data.Map.Strict.Patch
as
PM
import
qualified
Data.Map.Strict.Patch
as
PM
import
qualified
Data.Set
as
Set
import
qualified
Data.Set
as
Set
...
@@ -124,7 +123,7 @@ instance (ToJSONKey a, ToSchema a) => ToSchema (MSet a) where
...
@@ -124,7 +123,7 @@ instance (ToJSONKey a, ToSchema a) => ToSchema (MSet a) where
------------------------------------------------------------------------
------------------------------------------------------------------------
newtype
NgramsTerm
=
NgramsTerm
{
unNgramsTerm
::
Text
}
newtype
NgramsTerm
=
NgramsTerm
{
unNgramsTerm
::
Text
}
deriving
(
Ord
,
Eq
,
Show
,
Generic
,
ToJSONKey
,
ToJSON
,
FromJSON
,
Semigroup
,
Arbitrary
,
Serialise
,
ToSchema
,
Hashable
,
NFData
)
deriving
(
Ord
,
Eq
,
Show
,
Generic
,
ToJSONKey
,
ToJSON
,
FromJSON
,
Semigroup
,
Arbitrary
,
Serialise
,
ToSchema
,
Hashable
,
NFData
,
FromField
,
ToField
)
instance
IsHashable
NgramsTerm
where
instance
IsHashable
NgramsTerm
where
hash
(
NgramsTerm
t
)
=
hash
t
hash
(
NgramsTerm
t
)
=
hash
t
instance
Monoid
NgramsTerm
where
instance
Monoid
NgramsTerm
where
...
@@ -133,18 +132,6 @@ instance FromJSONKey NgramsTerm where
...
@@ -133,18 +132,6 @@ instance FromJSONKey NgramsTerm where
fromJSONKey
=
FromJSONKeyTextParser
$
\
t
->
pure
$
NgramsTerm
$
strip
t
fromJSONKey
=
FromJSONKeyTextParser
$
\
t
->
pure
$
NgramsTerm
$
strip
t
instance
IsString
NgramsTerm
where
instance
IsString
NgramsTerm
where
fromString
s
=
NgramsTerm
$
pack
s
fromString
s
=
NgramsTerm
$
pack
s
instance
FromField
NgramsTerm
where
fromField
field
mb
=
do
v
<-
fromField
field
mb
case
fromJSON
v
of
Success
a
->
pure
$
NgramsTerm
$
strip
a
Error
_err
->
returnError
ConversionFailed
field
$
List
.
intercalate
" "
[
"cannot parse hyperdata for JSON: "
,
show
v
]
instance
ToField
NgramsTerm
where
toField
(
NgramsTerm
n
)
=
toField
n
data
RootParent
=
RootParent
data
RootParent
=
RootParent
...
@@ -164,19 +151,20 @@ data NgramsRepoElement = NgramsRepoElement
...
@@ -164,19 +151,20 @@ data NgramsRepoElement = NgramsRepoElement
,
_nre_children
::
!
(
MSet
NgramsTerm
)
,
_nre_children
::
!
(
MSet
NgramsTerm
)
}
}
deriving
(
Ord
,
Eq
,
Show
,
Generic
)
deriving
(
Ord
,
Eq
,
Show
,
Generic
)
deriveJSON
(
unPrefix
"_nre_"
)
''
N
gramsRepoElement
deriveJSON
(
unPrefix
"_nre_"
)
''
N
gramsRepoElement
-- TODO
-- TODO
-- if ngrams & not size => size
-- if ngrams & not size => size
-- drop occurrences
-- drop occurrences
makeLenses
''
N
gramsRepoElement
makeLenses
''
N
gramsRepoElement
instance
ToSchema
NgramsRepoElement
where
instance
ToSchema
NgramsRepoElement
where
declareNamedSchema
=
genericDeclareNamedSchema
(
unPrefixSwagger
"_nre_"
)
declareNamedSchema
=
genericDeclareNamedSchema
(
unPrefixSwagger
"_nre_"
)
instance
Serialise
NgramsRepoElement
instance
FromField
NgramsRepoElement
where
fromField
=
fromJSONField
instance
ToField
NgramsRepoElement
where
toField
=
toJSONField
instance
Serialise
(
MSet
NgramsTerm
)
instance
Serialise
(
MSet
NgramsTerm
)
instance
Serialise
NgramsRepoElement
data
NgramsElement
=
data
NgramsElement
=
NgramsElement
{
_ne_ngrams
::
NgramsTerm
NgramsElement
{
_ne_ngrams
::
NgramsTerm
...
...
src/Gargantext/Core/NodeStory.hs
View file @
a2788ade
...
@@ -71,29 +71,29 @@ module Gargantext.Core.NodeStory
...
@@ -71,29 +71,29 @@ module Gargantext.Core.NodeStory
,
a_state
,
a_state
,
a_version
,
a_version
,
nodeExists
,
nodeExists
,
runPGSQuery
,
getNodesIdWithType
,
getNodesIdWithType
,
readNodeStoryEnv
,
readNodeStoryEnv
,
upsertNodeArchive
,
upsertNodeArchive
,
getNodeStory
)
,
getNodeStory
,
nodeStoriesQuery
)
where
where
-- import Debug.Trace (traceShow)
-- import Debug.Trace (traceShow)
import
Control.Debounce
(
mkDebounce
,
defaultDebounceSettings
,
debounceFreq
,
debounceAction
)
import
Control.Debounce
(
mkDebounce
,
defaultDebounceSettings
,
debounceFreq
,
debounceAction
)
import
Codec.Serialise.Class
import
Codec.Serialise.Class
import
Control.Arrow
(
returnA
)
import
Control.Concurrent
(
MVar
(),
withMVar
,
newMVar
,
modifyMVar_
)
import
Control.Concurrent
(
MVar
(),
withMVar
,
newMVar
,
modifyMVar_
)
import
Control.Exception
(
catch
,
throw
,
SomeException
(
..
))
import
Control.Exception
(
catch
,
throw
,
SomeException
(
..
))
import
Control.Lens
(
makeLenses
,
Getter
,
(
^.
),
(
.~
),
traverse
)
import
Control.Lens
(
makeLenses
,
Getter
,
(
^.
),
(
.~
),
(
%~
),
traverse
)
import
Control.Monad.Except
import
Control.Monad.Except
import
Control.Monad.Reader
import
Control.Monad.Reader
import
Data.Aeson
hiding
((
.=
),
decode
)
import
Data.Aeson
hiding
((
.=
),
decode
)
import
Data.ByteString.Char8
(
hPutStrLn
)
import
Data.ByteString.Char8
(
hPutStrLn
)
import
Data.Map.Strict
(
Map
)
import
Data.Map.Strict
(
Map
)
import
Data.Maybe
(
catMaybes
,
mapMaybe
)
import
Data.Maybe
(
catMaybes
)
import
Data.Monoid
import
Data.Monoid
import
Data.Pool
(
Pool
,
withResource
)
import
Data.Pool
(
Pool
,
withResource
)
import
Data.Semigroup
import
Data.Semigroup
import
qualified
Database.PostgreSQL.Simple
as
PGS
import
Database.PostgreSQL.Simple.SqlQQ
(
sql
)
import
Database.PostgreSQL.Simple.SqlQQ
(
sql
)
import
Database.PostgreSQL.Simple.FromField
(
FromField
(
fromField
),
fromJSONField
)
import
Database.PostgreSQL.Simple.FromField
(
FromField
(
fromField
),
fromJSONField
)
import
Data.Profunctor.Product.TH
(
makeAdaptorAndInstance
)
import
Data.Profunctor.Product.TH
(
makeAdaptorAndInstance
)
...
@@ -101,15 +101,14 @@ import GHC.Generics (Generic)
...
@@ -101,15 +101,14 @@ import GHC.Generics (Generic)
import
Gargantext.API.Ngrams.Types
import
Gargantext.API.Ngrams.Types
import
Gargantext.Core.Types
(
NodeId
(
..
),
NodeType
)
import
Gargantext.Core.Types
(
NodeId
(
..
),
NodeType
)
import
Gargantext.Core.Utils.Prefix
(
unPrefix
)
import
Gargantext.Core.Utils.Prefix
(
unPrefix
)
import
Gargantext.Database.Admin.Config
(
nodeTypeId
)
import
Gargantext.Database.Prelude
(
CmdM
'
,
HasConnectionPool
,
HasConfig
)
import
Gargantext.Database.Prelude
(
CmdM
'
,
HasConnectionPool
,
HasConfig
)
import
Gargantext.Database.Query.Table.Node.Error
(
HasNodeError
())
import
Gargantext.Database.Query.Table.Node.Error
(
HasNodeError
())
import
Gargantext.Prelude
import
Gargantext.Prelude
import
Opaleye
(
Column
,
DefaultFromField
(
..
),
Insert
(
..
),
Select
,
SqlInt4
,
SqlJsonb
,
Table
,
Update
(
..
),
(
.==
),
fromPGSFromField
,
rCount
,
restrict
,
runInsert
,
runSelect
,
runUpdate
,
selectTable
,
sqlInt4
,
sqlValueJSONB
,
tableField
,
updateEasy
)
import
Opaleye
(
DefaultFromField
(
..
),
SqlJsonb
,
fromPGSFromField
)
import
Opaleye.Internal.Table
(
Table
(
..
))
import
System.IO
(
stderr
)
import
System.IO
(
stderr
)
import
qualified
Data.Map.Strict
as
Map
import
qualified
Data.Map.Strict
as
Map
import
qualified
Data.Map.Strict.Patch
as
PM
import
qualified
Data.Map.Strict.Patch
as
PM
import
qualified
Database.PostgreSQL.Simple
as
PGS
import
qualified
Gargantext.Database.Query.Table.Ngrams
as
TableNgrams
import
qualified
Gargantext.Database.Query.Table.Ngrams
as
TableNgrams
------------------------------------------------------------------------
------------------------------------------------------------------------
...
@@ -185,6 +184,13 @@ instance DefaultFromField SqlJsonb (Archive NgramsState' NgramsStatePatch')
...
@@ -185,6 +184,13 @@ instance DefaultFromField SqlJsonb (Archive NgramsState' NgramsStatePatch')
where
where
defaultFromField
=
fromPGSFromField
defaultFromField
=
fromPGSFromField
-- | Combine `NgramsState'`. This is because the structure is (Map
-- NgramsType (Map ...)) and the default `(<>)` operator is
-- left-biased
-- (https://hackage.haskell.org/package/containers-0.6.6/docs/Data-Map-Internal.html#v:union)
combineState
::
NgramsState'
->
NgramsState'
->
NgramsState'
combineState
=
Map
.
unionWith
(
<>
)
-- TODO Semigroup instance for unions
-- TODO Semigroup instance for unions
-- TODO check this
-- TODO check this
instance
(
Semigroup
s
,
Semigroup
p
)
=>
Semigroup
(
Archive
s
p
)
where
instance
(
Semigroup
s
,
Semigroup
p
)
=>
Semigroup
(
Archive
s
p
)
where
...
@@ -218,9 +224,9 @@ initNodeListStoryMock :: NodeListStory
...
@@ -218,9 +224,9 @@ initNodeListStoryMock :: NodeListStory
initNodeListStoryMock
=
NodeStory
$
Map
.
singleton
nodeListId
archive
initNodeListStoryMock
=
NodeStory
$
Map
.
singleton
nodeListId
archive
where
where
nodeListId
=
0
nodeListId
=
0
archive
=
Archive
{
_a_version
=
0
archive
=
Archive
{
_a_version
=
0
,
_a_state
=
ngramsTableMap
,
_a_state
=
ngramsTableMap
,
_a_history
=
[]
}
,
_a_history
=
[]
}
ngramsTableMap
=
Map
.
singleton
TableNgrams
.
NgramsTerms
ngramsTableMap
=
Map
.
singleton
TableNgrams
.
NgramsTerms
$
Map
.
fromList
$
Map
.
fromList
[
(
n
^.
ne_ngrams
,
ngramsElementToRepo
n
)
[
(
n
^.
ne_ngrams
,
ngramsElementToRepo
n
)
...
@@ -239,17 +245,31 @@ makeLenses ''Archive
...
@@ -239,17 +245,31 @@ makeLenses ''Archive
-----------------------------------------
-----------------------------------------
data
NodeStoryPoly
a
b
=
NodeStoryDB
{
node_id
::
a
data
NodeStoryPoly
nid
v
ngtid
ngid
nre
=
,
archive
::
b
}
NodeStoryDB
{
node_id
::
nid
,
version
::
v
,
ngrams_type_id
::
ngtid
,
ngrams_id
::
ngid
,
ngrams_repo_element
::
nre
}
deriving
(
Eq
)
deriving
(
Eq
)
type
ArchiveQ
=
Archive
NgramsState'
NgramsStatePatch'
data
NodeStoryArchivePoly
nid
a
=
NodeStoryArchiveDB
{
a_node_id
::
nid
type
NodeStoryWrite
=
NodeStoryPoly
(
Column
SqlInt4
)
(
Column
SqlJsonb
)
,
archive
::
a
}
type
NodeStoryRead
=
NodeStoryPoly
(
Column
SqlInt4
)
(
Column
SqlJsonb
)
deriving
(
Eq
)
$
(
makeAdaptorAndInstance
"pNodeStory"
''
N
odeStoryPoly
)
$
(
makeAdaptorAndInstance
"pNodeStory"
''
N
odeStoryPoly
)
$
(
makeAdaptorAndInstance
"pNodeArchiveStory"
''
N
odeStoryArchivePoly
)
-- type NodeStoryWrite = NodeStoryPoly (Column SqlInt4) (Column SqlInt4) (Column SqlInt4) (Column SqlInt4) (Column SqlJsonb)
-- type NodeStoryRead = NodeStoryPoly (Column SqlInt4) (Column SqlInt4) (Column SqlInt4) (Column SqlInt4) (Column SqlJsonb)
-- type NodeStoryArchiveWrite = NodeStoryArchivePoly (Column SqlInt4) (Column SqlJsonb)
-- type NodeStoryArchiveRead = NodeStoryArchivePoly (Column SqlInt4) (Column SqlJsonb)
type
ArchiveQ
=
Archive
NgramsState'
NgramsStatePatch'
-- DB stuff
runPGSExecuteMany
::
(
PGS
.
ToRow
q
)
=>
Pool
PGS
.
Connection
->
PGS
.
Query
->
[
q
]
->
IO
Int64
runPGSExecuteMany
::
(
PGS
.
ToRow
q
)
=>
Pool
PGS
.
Connection
->
PGS
.
Query
->
[
q
]
->
IO
Int64
runPGSExecuteMany
pool
qs
a
=
withResource
pool
$
\
c
->
catch
(
PGS
.
executeMany
c
qs
a
)
(
printError
c
)
runPGSExecuteMany
pool
qs
a
=
withResource
pool
$
\
c
->
catch
(
PGS
.
executeMany
c
qs
a
)
(
printError
c
)
...
@@ -269,108 +289,158 @@ runPGSQuery pool q a = withResource pool $ \c -> catch (PGS.query c q a) (printE
...
@@ -269,108 +289,158 @@ runPGSQuery pool q a = withResource pool $ \c -> catch (PGS.query c q a) (printE
nodeExists
::
Pool
PGS
.
Connection
->
NodeId
->
IO
Bool
nodeExists
::
Pool
PGS
.
Connection
->
NodeId
->
IO
Bool
nodeExists
pool
nId
=
(
==
[
PGS
.
Only
True
])
nodeExists
pool
nId
=
(
==
[
PGS
.
Only
True
])
<$>
runPGSQuery
pool
[
sql
|
SELECT true FROM nodes WHERE id = ? AND ?
|]
(
nId
,
True
)
<$>
runPGSQuery
pool
[
sql
|
SELECT true FROM nodes WHERE id = ? LIMIT 1
|]
(
PGS
.
Only
nId
)
getNodesIdWithType
::
Pool
PGS
.
Connection
->
NodeType
->
IO
[
NodeId
]
getNodesIdWithType
::
Pool
PGS
.
Connection
->
NodeType
->
IO
[
NodeId
]
getNodesIdWithType
pool
nt
=
do
getNodesIdWithType
pool
nt
=
do
ns
<-
runPGSQuery
pool
query
(
nodeTypeId
nt
,
True
)
ns
<-
runPGSQuery
pool
query
(
PGS
.
Only
nt
)
pure
$
map
(
\
(
PGS
.
Only
nId
)
->
NodeId
nId
)
ns
pure
$
map
(
\
(
PGS
.
Only
nId
)
->
NodeId
nId
)
ns
where
where
query
::
PGS
.
Query
query
::
PGS
.
Query
query
=
[
sql
|
SELECT id FROM nodes WHERE typename = ? AND ?
|]
query
=
[
sql
|
SELECT id FROM nodes WHERE typename = ?
|]
-- nodeStoryTable :: Table NodeStoryRead NodeStoryWrite
-- nodeStoryTable =
-- Table "node_stories"
-- ( pNodeStory NodeStoryDB { node_id = tableField "node_id"
-- , version = tableField "version"
-- , ngrams_type_id = tableField "ngrams_type_id"
-- , ngrams_id = tableField "ngrams_id"
-- , ngrams_repo_element = tableField "ngrams_repo_element"
-- } )
nodeStoryTable
::
Table
NodeStoryRead
NodeStory
Write
-- nodeStoryArchiveTable :: Table NodeStoryArchiveRead NodeStoryArchive
Write
nodeStory
Table
=
-- nodeStoryArchive
Table =
Table
"node_stories
"
-- Table "node_story_archive_history
"
(
pNodeStory
NodeStoryDB
{
node_id
=
tableField
"node_id"
-- ( pNodeArchiveStory NodeStoryArchiveDB { a_
node_id = tableField "node_id"
,
archive
=
tableField
"archive"
}
)
-- , archive
= tableField "archive" } )
nodeStorySelect
::
Select
NodeStoryRead
--
nodeStorySelect :: Select NodeStoryRead
nodeStorySelect
=
selectTable
nodeStoryTable
--
nodeStorySelect = selectTable nodeStoryTable
-- TODO Check ordering, "first patch in the _a_history list is the most recent"
-- TODO Check ordering, "first patch in the _a_history list is the most recent"
getNodeArchiveHistory
::
Pool
PGS
.
Connection
->
NodeId
->
IO
[
NgramsStatePatch'
]
getNodeArchiveHistory
::
Pool
PGS
.
Connection
->
NodeId
->
IO
[
NgramsStatePatch'
]
getNodeArchiveHistory
pool
nodeId
=
do
getNodeArchiveHistory
pool
nodeId
=
do
as
<-
runPGSQuery
pool
query
(
nodeId
,
True
)
as
<-
runPGSQuery
pool
query
(
PGS
.
Only
nodeId
)
::
IO
[(
TableNgrams
.
NgramsType
,
NgramsTerm
,
NgramsPatch
)]
let
asTuples
=
mapMaybe
(
\
(
ngrams_type_id
,
ngrams
,
patch
)
->
(
\
ntId
->
(
ntId
,
ngrams
,
patch
))
<$>
(
TableNgrams
.
fromNgramsTypeId
ngrams_type_id
))
as
pure
$
(
\
(
ngramsType
,
terms
,
patch
)
->
fst
$
PM
.
singleton
ngramsType
(
NgramsTablePatch
$
fst
$
PM
.
singleton
terms
patch
))
<$>
as
pure
$
(
\
(
ntId
,
terms
,
patch
)
->
fst
$
PM
.
singleton
ntId
(
NgramsTablePatch
$
fst
$
PM
.
singleton
terms
patch
))
<$>
asTuples
where
where
query
::
PGS
.
Query
query
::
PGS
.
Query
query
=
[
sql
|
SELECT ngrams_type_id, terms, patch
query
=
[
sql
|
SELECT ngrams_type_id, terms, patch
FROM node_story_archive_history
FROM node_story_archive_history
JOIN ngrams ON ngrams.id = ngrams_id
JOIN ngrams ON ngrams.id = ngrams_id
WHERE node_id = ? AND ?
|]
WHERE node_id = ?
|]
ngramsIdQuery
::
PGS
.
Query
ngramsIdQuery
=
[
sql
|
SELECT id FROM ngrams WHERE terms = ?
|]
insertNodeArchiveHistory
::
Pool
PGS
.
Connection
->
NodeId
->
[
NgramsStatePatch'
]
->
IO
()
insertNodeArchiveHistory
::
Pool
PGS
.
Connection
->
NodeId
->
[
NgramsStatePatch'
]
->
IO
()
insertNodeArchiveHistory
_
_
[]
=
pure
()
insertNodeArchiveHistory
_
_
[]
=
pure
()
insertNodeArchiveHistory
pool
nodeId
(
h
:
hs
)
=
do
insertNodeArchiveHistory
pool
nodeId
(
h
:
hs
)
=
do
let
tuples
=
mconcat
$
(
\
(
nType
,
(
NgramsTablePatch
patch
))
->
let
tuples
=
mconcat
$
(
\
(
nType
,
(
NgramsTablePatch
patch
))
->
(
\
(
term
,
p
)
->
(
\
(
term
,
p
)
->
(
nodeId
,
TableNgrams
.
ngramsTypeId
nType
,
term
,
p
))
<$>
PM
.
toList
patch
)
<$>
PM
.
toList
h
::
[(
NodeId
,
TableNgrams
.
NgramsTypeId
,
NgramsTerm
,
NgramsPatch
)]
(
nodeId
,
nType
,
term
,
p
))
<$>
PM
.
toList
patch
)
<$>
PM
.
toList
h
::
[(
NodeId
,
TableNgrams
.
NgramsType
,
NgramsTerm
,
NgramsPatch
)]
tuplesM
<-
mapM
(
\
(
nId
,
nType
Id
,
term
,
patch
)
->
do
tuplesM
<-
mapM
(
\
(
nId
,
nType
,
term
,
patch
)
->
do
ngrams
<-
runPGSQuery
pool
ngrams
Query
(
term
,
True
)
ngrams
<-
runPGSQuery
pool
ngrams
IdQuery
(
PGS
.
Only
term
)
pure
$
(
\
(
PGS
.
Only
termId
)
->
(
nId
,
nType
Id
,
termId
,
term
,
patch
))
<$>
(
headMay
ngrams
)
pure
$
(
\
(
PGS
.
Only
termId
)
->
(
nId
,
nType
,
termId
,
term
,
patch
))
<$>
(
headMay
ngrams
)
)
tuples
::
IO
[
Maybe
(
NodeId
,
TableNgrams
.
NgramsType
Id
,
Int
,
NgramsTerm
,
NgramsPatch
)]
)
tuples
::
IO
[
Maybe
(
NodeId
,
TableNgrams
.
NgramsType
,
Int
,
NgramsTerm
,
NgramsPatch
)]
_
<-
runPGSExecuteMany
pool
query
$
((
\
(
nId
,
nType
Id
,
termId
,
_term
,
patch
)
->
(
nId
,
nTypeId
,
termId
,
patch
))
<$>
(
catMaybes
tuplesM
))
_
<-
runPGSExecuteMany
pool
query
$
((
\
(
nId
,
nType
,
termId
,
_term
,
patch
)
->
(
nId
,
nType
,
termId
,
patch
))
<$>
(
catMaybes
tuplesM
))
_
<-
insertNodeArchiveHistory
pool
nodeId
hs
_
<-
insertNodeArchiveHistory
pool
nodeId
hs
pure
()
pure
()
where
where
ngramsQuery
::
PGS
.
Query
ngramsQuery
=
[
sql
|
SELECT id FROM ngrams WHERE terms = ? AND ?
|]
query
::
PGS
.
Query
query
::
PGS
.
Query
query
=
[
sql
|
INSERT INTO node_story_archive_history(node_id, ngrams_type_id, ngrams_id, patch) VALUES (?, ?, ?, ?)
|]
query
=
[
sql
|
INSERT INTO node_story_archive_history(node_id, ngrams_type_id, ngrams_id, patch) VALUES (?, ?, ?, ?)
|]
getNodeStory
::
Pool
PGS
.
Connection
->
NodeId
->
IO
NodeListStory
getNodeStory
::
Pool
PGS
.
Connection
->
NodeId
->
IO
NodeListStory
getNodeStory
pool
(
NodeId
nodeId
)
=
do
getNodeStory
pool
nId
@
(
NodeId
nodeId
)
=
do
res
<-
withResource
pool
$
\
c
->
runSelect
c
query
::
IO
[
NodeStoryPoly
NodeId
ArchiveQ
]
--res <- withResource pool $ \c -> runSelect c query :: IO [NodeStoryPoly NodeId Version Int Int NgramsRepoElement]
withArchive
<-
mapM
(
\
(
NodeStoryDB
{
node_id
=
nId
,
archive
=
Archive
{
..
}
})
->
do
res
<-
runPGSQuery
pool
nodeStoriesQuery
(
PGS
.
Only
nodeId
)
::
IO
[(
Version
,
TableNgrams
.
NgramsType
,
NgramsTerm
,
NgramsRepoElement
)]
--a <- getNodeArchiveHistory pool nId
-- We have multiple rows with same node_id and different (ngrams_type_id, ngrams_id).
let
a
=
[]
::
[
NgramsStatePatch'
]
-- Need to create a map: {<node_id>: {<ngrams_type_id>: {<ngrams_id>: <data>}}}
-- Don't read whole history. Only state is needed and most recent changes.
let
dbData
=
map
(
\
(
version
,
ngramsType
,
ngrams
,
ngrams_repo_element
)
->
pure
(
nId
,
Archive
{
_a_history
=
a
,
..
}))
res
Archive
{
_a_version
=
version
pure
$
NodeStory
$
Map
.
fromListWith
(
<>
)
withArchive
,
_a_history
=
[]
,
_a_state
=
Map
.
singleton
ngramsType
$
Map
.
singleton
ngrams
ngrams_repo_element
})
res
-- TODO (<>) for Archive doesn't concatenate states!
-- NOTE When concatenating, check that the same version is for all states
pure
$
NodeStory
$
Map
.
singleton
nId
$
foldl
combine
mempty
dbData
--pure $ NodeStory $ Map.fromListWith (<>) $ (\(NodeStoryDB nId a) -> (nId, a)) <$> res
--pure $ NodeStory $ Map.fromListWith (<>) $ (\(NodeStoryDB nId a) -> (nId, a)) <$> res
where
where
query
::
Select
NodeStoryRead
-- query :: Select NodeStoryRead
query
=
proc
()
->
do
-- query = proc () -> do
row
@
(
NodeStoryDB
node_id
_
)
<-
nodeStorySelect
-<
()
-- row@(NodeStoryDB node_id _) <- nodeStorySelect -< ()
restrict
-<
node_id
.==
sqlInt4
nodeId
-- restrict -< node_id .== sqlInt4 nodeId
returnA
-<
row
-- returnA -< row
combine
a1
a2
=
a1
&
a_state
%~
combineState
(
a2
^.
a_state
)
insertNodeArchive
::
Pool
PGS
.
Connection
->
NodeId
->
ArchiveQ
->
IO
Int64
&
a_version
.~
(
a2
^.
a_version
)
-- version should be updated from list, not taken from the empty Archive
insertNodeArchive
pool
nodeId
@
(
NodeId
nId
)
(
Archive
{
..
})
=
do
ret
<-
withResource
pool
$
\
c
->
runInsert
c
insert
nodeStoriesQuery
::
PGS
.
Query
nodeStoriesQuery
=
[
sql
|
SELECT version, ngrams_type_id, terms, ngrams_repo_element
FROM node_stories
JOIN ngrams ON ngrams.id = ngrams_id
WHERE node_id = ?
|]
-- Functions to convert archive state (which is a Map NgramsType (Map
-- NgramsTerm NgramsRepoElement)) to/from a flat list
archiveStateAsList
::
NgramsState'
->
[(
TableNgrams
.
NgramsType
,
NgramsTerm
,
NgramsRepoElement
)]
archiveStateAsList
s
=
mconcat
$
(
\
(
nt
,
ntm
)
->
(
\
(
n
,
nre
)
->
(
nt
,
n
,
nre
))
<$>
Map
.
toList
ntm
)
<$>
Map
.
toList
s
-- archiveStateFromList :: [(TableNgrams.NgramsType, NgramsTerm, NgramsRepoElement)] -> NgramsState'
-- archiveStateFromList l = Map.fromListWith (<>) $ (\(nt, t, nre) -> (nt, Map.singleton t nre)) <$> l
-- | This function inserts whole new node story and archive for given node_id.
insertNodeStory
::
Pool
PGS
.
Connection
->
NodeId
->
ArchiveQ
->
IO
()
insertNodeStory
pool
nodeId
@
(
NodeId
nId
)
(
Archive
{
..
})
=
do
_
<-
mapM
(
\
(
ngramsType
,
ngrams
,
ngramsRepoElement
)
->
do
termIdM
<-
runPGSQuery
pool
ngramsIdQuery
(
PGS
.
Only
ngrams
)
::
IO
[
PGS
.
Only
Int64
]
case
headMay
termIdM
of
Nothing
->
pure
0
Just
(
PGS
.
Only
termId
)
->
runPGSExecuteMany
pool
query
[(
nId
,
_a_version
,
ngramsType
,
termId
,
ngramsRepoElement
)])
$
archiveStateAsList
_a_state
-- runInsert c $ insert ngramsType ngrams ngramsRepoElement) $ archiveStateAsList _a_state
-- NOTE: It is assumed that the most recent change is the first in the
-- NOTE: It is assumed that the most recent change is the first in the
-- list, so we save these in reverse order
-- list, so we save these in reverse order
insertNodeArchiveHistory
pool
nodeId
$
reverse
_a_history
insertNodeArchiveHistory
pool
nodeId
$
reverse
_a_history
pure
ret
pure
()
where
where
emptyHistory
=
[]
::
[
NgramsStatePatch'
]
query
::
PGS
.
Query
insert
=
Insert
{
iTable
=
nodeStoryTable
query
=
[
sql
|
INSERT INTO node_stories(node_id, ngrams_type_id, ngrams_id, ngrams_repo_element) VALUES (?, ?, ?, ?)
|]
,
iRows
=
[
NodeStoryDB
{
node_id
=
sqlInt4
nId
-- insert ngramsType ngrams ngramsRepoElement =
,
archive
=
sqlValueJSONB
$
Archive
{
_a_history
=
emptyHistory
-- Insert { iTable = nodeStoryTable
,
..
}
}]
-- , iRows = [NodeStoryDB { node_id = sqlInt4 nId
,
iReturning
=
rCount
-- , version = sqlInt4 _a_version
,
iOnConflict
=
Nothing
}
-- , ngrams_type_id = sqlInt4 $ TableNgrams.ngramsTypeId ngramsType
-- , ngrams_id = ...
updateNodeArchive
::
Pool
PGS
.
Connection
->
NodeId
->
ArchiveQ
->
IO
Int64
-- , ngrams_repo_element = sqlValueJSONB ngramsRepoElement
updateNodeArchive
pool
nodeId
@
(
NodeId
nId
)
(
Archive
{
..
})
=
do
-- }]
ret
<-
withResource
pool
$
\
c
->
runUpdate
c
update
-- , iReturning = rCount
-- , iOnConflict = Nothing }
-- | This function updates the node story and archive for given node_id.
updateNodeStory
::
Pool
PGS
.
Connection
->
NodeId
->
ArchiveQ
->
IO
()
updateNodeStory
pool
nodeId
@
(
NodeId
_nId
)
(
Archive
{
..
})
=
do
-- TODO This requires updating current DB state (which is spanned
-- along many rows)
-- The idea is this: fetch all current state data from the DB
-- (locking the rows), perform a diff and update what is necessary.
-- ret <- withResource pool $ \c -> runUpdate c update
-- NOTE: It is assumed that the most recent change is the first in the
-- NOTE: It is assumed that the most recent change is the first in the
-- list, so we save these in reverse order
-- list, so we save these in reverse order
insertNodeArchiveHistory
pool
nodeId
$
reverse
_a_history
insertNodeArchiveHistory
pool
nodeId
$
reverse
_a_history
pure
ret
pure
()
where
--
where
emptyHistory
=
[]
::
[
NgramsStatePatch'
]
-- update = Update { uTable = nodeStoryTable
update
=
Update
{
uTable
=
nodeStoryTable
-- , uUpdateWith = updateEasy (\(NodeStoryDB { node_id }) ->
,
uUpdateWith
=
updateEasy
(
\
(
NodeStoryDB
{
node_id
})
->
NodeStoryDB
{
archive
=
sqlValueJSONB
$
Archive
{
_a_history
=
emptyHistory
--
NodeStoryDB { archive = sqlValueJSONB $ Archive { _a_history = emptyHistory
,
..
}
--
, ..}
,
..
})
--
, .. })
,
uWhere
=
(
\
row
->
node_id
row
.==
sqlInt4
nId
)
--
, uWhere = (\row -> node_id row .== sqlInt4 nId)
,
uReturning
=
rCount
}
--
, uReturning = rCount }
-- nodeStoryRemove :: Pool PGS.Connection -> NodeId -> IO Int64
-- nodeStoryRemove :: Pool PGS.Connection -> NodeId -> IO Int64
-- nodeStoryRemove pool (NodeId nId) = withResource pool $ \c -> runDelete c delete
-- nodeStoryRemove pool (NodeId nId) = withResource pool $ \c -> runDelete c delete
...
@@ -379,12 +449,16 @@ updateNodeArchive pool nodeId@(NodeId nId) (Archive {..}) = do
...
@@ -379,12 +449,16 @@ updateNodeArchive pool nodeId@(NodeId nId) (Archive {..}) = do
-- , dWhere = (\row -> node_id row .== sqlInt4 nId)
-- , dWhere = (\row -> node_id row .== sqlInt4 nId)
-- , dReturning = rCount }
-- , dReturning = rCount }
upsertNodeArchive
::
Pool
PGS
.
Connection
->
NodeId
->
ArchiveQ
->
IO
Int64
upsertNodeArchive
::
Pool
PGS
.
Connection
->
NodeId
->
ArchiveQ
->
IO
()
upsertNodeArchive
pool
nId
a
=
do
upsertNodeArchive
pool
nId
a
=
do
(
NodeStory
m
)
<-
getNodeStory
pool
nId
(
NodeStory
m
)
<-
getNodeStory
pool
nId
case
Map
.
lookup
nId
m
of
case
Map
.
lookup
nId
m
of
Nothing
->
insertNodeArchive
pool
nId
a
Nothing
->
do
Just
_
->
updateNodeArchive
pool
nId
a
_
<-
insertNodeStory
pool
nId
a
pure
()
Just
_
->
do
_
<-
updateNodeStory
pool
nId
a
pure
()
writeNodeStories
::
Pool
PGS
.
Connection
->
NodeListStory
->
IO
()
writeNodeStories
::
Pool
PGS
.
Connection
->
NodeListStory
->
IO
()
writeNodeStories
pool
(
NodeStory
nls
)
=
do
writeNodeStories
pool
(
NodeStory
nls
)
=
do
...
...
src/Gargantext/Database/Action/Metrics.hs
View file @
a2788ade
...
@@ -27,7 +27,7 @@ import Gargantext.API.Ngrams.Tools (filterListWithRoot, groupNodesByNgrams, Diag
...
@@ -27,7 +27,7 @@ import Gargantext.API.Ngrams.Tools (filterListWithRoot, groupNodesByNgrams, Diag
import
Gargantext.Database.Prelude
(
runPGSQuery
{-, formatPGSQuery-}
)
import
Gargantext.Database.Prelude
(
runPGSQuery
{-, formatPGSQuery-}
)
import
Gargantext.API.Ngrams.Types
(
TabType
(
..
),
ngramsTypeFromTabType
,
NgramsTerm
(
..
))
import
Gargantext.API.Ngrams.Types
(
TabType
(
..
),
ngramsTypeFromTabType
,
NgramsTerm
(
..
))
import
Gargantext.Core.Mail.Types
(
HasMail
)
import
Gargantext.Core.Mail.Types
(
HasMail
)
import
Gargantext.Core.NodeStory
import
Gargantext.Core.NodeStory
hiding
(
runPGSQuery
)
import
Gargantext.Core.Text.Metrics
(
scored
,
Scored
(
..
),
{-localMetrics, toScored-}
)
import
Gargantext.Core.Text.Metrics
(
scored
,
Scored
(
..
),
{-localMetrics, toScored-}
)
import
Database.PostgreSQL.Simple.ToField
(
toField
,
Action
{-, ToField-}
)
import
Database.PostgreSQL.Simple.ToField
(
toField
,
Action
{-, ToField-}
)
import
Gargantext.Core.Types
(
ListType
(
..
),
Limit
,
NodeType
(
..
),
ContextId
)
import
Gargantext.Core.Types
(
ListType
(
..
),
Limit
,
NodeType
(
..
),
ContextId
)
...
@@ -88,7 +88,7 @@ updateNgramsOccurrences cId mlId = do
...
@@ -88,7 +88,7 @@ updateNgramsOccurrences cId mlId = do
updateNgramsOccurrences'
::
(
FlowCmdM
env
err
m
)
updateNgramsOccurrences'
::
(
FlowCmdM
env
err
m
)
=>
CorpusId
->
Maybe
ListId
->
Maybe
Limit
->
TabType
=>
CorpusId
->
Maybe
ListId
->
Maybe
Limit
->
TabType
->
m
[
Int
]
->
m
[
Int
]
updateNgramsOccurrences'
cId
maybeListId
maybeLimit
tabType
=
do
updateNgramsOccurrences'
cId
maybeListId
maybeLimit
tabType
=
do
...
@@ -97,7 +97,7 @@ updateNgramsOccurrences' cId maybeListId maybeLimit tabType = do
...
@@ -97,7 +97,7 @@ updateNgramsOccurrences' cId maybeListId maybeLimit tabType = do
Just
lId'
->
pure
lId'
Just
lId'
->
pure
lId'
result
<-
getNgramsOccurrences
cId
lId
tabType
maybeLimit
result
<-
getNgramsOccurrences
cId
lId
tabType
maybeLimit
let
let
toInsert
::
[[
Action
]]
toInsert
::
[[
Action
]]
toInsert
=
map
(
\
(
ngramsTerm
,
score
)
toInsert
=
map
(
\
(
ngramsTerm
,
score
)
...
@@ -121,7 +121,7 @@ updateNgramsOccurrences' cId maybeListId maybeLimit tabType = do
...
@@ -121,7 +121,7 @@ updateNgramsOccurrences' cId maybeListId maybeLimit tabType = do
RETURNING 1
RETURNING 1
|]
|]
let
fields
=
map
(
\
t
->
QualifiedIdentifier
Nothing
t
)
let
fields
=
map
(
\
t
->
QualifiedIdentifier
Nothing
t
)
$
map
Text
.
pack
[
"int4"
,
"int4"
,
"text"
,
"int4"
,
"int4"
]
$
map
Text
.
pack
[
"int4"
,
"int4"
,
"text"
,
"int4"
,
"int4"
]
map
(
\
(
Only
a
)
->
a
)
<$>
runPGSQuery
queryInsert
(
Only
$
Values
fields
toInsert
)
map
(
\
(
Only
a
)
->
a
)
<$>
runPGSQuery
queryInsert
(
Only
$
Values
fields
toInsert
)
...
@@ -163,7 +163,7 @@ updateContextScore cId maybeListId = do
...
@@ -163,7 +163,7 @@ updateContextScore cId maybeListId = do
Just
lId'
->
pure
lId'
Just
lId'
->
pure
lId'
result
<-
getContextsNgramsScore
cId
lId
Terms
MapTerm
Nothing
result
<-
getContextsNgramsScore
cId
lId
Terms
MapTerm
Nothing
let
let
toInsert
::
[[
Action
]]
toInsert
::
[[
Action
]]
toInsert
=
map
(
\
(
contextId
,
score
)
toInsert
=
map
(
\
(
contextId
,
score
)
...
@@ -185,7 +185,7 @@ updateContextScore cId maybeListId = do
...
@@ -185,7 +185,7 @@ updateContextScore cId maybeListId = do
RETURNING 1
RETURNING 1
|]
|]
let
fields
=
map
(
\
t
->
QualifiedIdentifier
Nothing
t
)
let
fields
=
map
(
\
t
->
QualifiedIdentifier
Nothing
t
)
$
map
Text
.
pack
[
"int4"
,
"int4"
,
"int4"
]
$
map
Text
.
pack
[
"int4"
,
"int4"
,
"int4"
]
map
(
\
(
Only
a
)
->
a
)
<$>
runPGSQuery
queryInsert
(
Only
$
Values
fields
toInsert
)
map
(
\
(
Only
a
)
->
a
)
<$>
runPGSQuery
queryInsert
(
Only
$
Values
fields
toInsert
)
...
@@ -243,6 +243,3 @@ getNgrams lId tabType = do
...
@@ -243,6 +243,3 @@ getNgrams lId tabType = do
take'
::
Maybe
Int
->
[
a
]
->
[
a
]
take'
::
Maybe
Int
->
[
a
]
->
[
a
]
take'
Nothing
xs
=
xs
take'
Nothing
xs
=
xs
take'
(
Just
n
)
xs
=
take
n
xs
take'
(
Just
n
)
xs
=
take
n
xs
src/Gargantext/Database/Admin/Config.hs
View file @
a2788ade
...
@@ -113,4 +113,3 @@ nodeTypes = [ (n, toDBid n) | n <- allNodeTypes ]
...
@@ -113,4 +113,3 @@ nodeTypes = [ (n, toDBid n) | n <- allNodeTypes ]
fromNodeTypeId
::
NodeTypeId
->
NodeType
fromNodeTypeId
::
NodeTypeId
->
NodeType
fromNodeTypeId
tId
=
fromMaybe
(
panic
$
pack
$
"Type Id "
<>
show
tId
<>
" does not exist"
)
fromNodeTypeId
tId
=
fromMaybe
(
panic
$
pack
$
"Type Id "
<>
show
tId
<>
" does not exist"
)
(
lookup
tId
nodeTypeInv
)
(
lookup
tId
nodeTypeInv
)
src/Gargantext/Database/Admin/Types/Node.hs
View file @
a2788ade
...
@@ -30,8 +30,8 @@ import Data.Morpheus.Types (GQLType)
...
@@ -30,8 +30,8 @@ import Data.Morpheus.Types (GQLType)
import
Data.Swagger
import
Data.Swagger
import
Data.Text
(
Text
,
unpack
,
pack
)
import
Data.Text
(
Text
,
unpack
,
pack
)
import
Data.Time
(
UTCTime
)
import
Data.Time
(
UTCTime
)
import
Database.PostgreSQL.Simple.FromField
(
FromField
,
fromField
)
import
Database.PostgreSQL.Simple.FromField
(
FromField
,
fromField
,
fromJSONField
)
import
Database.PostgreSQL.Simple.ToField
(
ToField
,
toField
)
import
Database.PostgreSQL.Simple.ToField
(
ToField
,
toField
,
toJSONField
)
import
GHC.Generics
(
Generic
)
import
GHC.Generics
(
Generic
)
import
Gargantext.Core.Utils.Prefix
(
unPrefix
,
unPrefixSwagger
,
wellNamedSchema
)
import
Gargantext.Core.Utils.Prefix
(
unPrefix
,
unPrefixSwagger
,
wellNamedSchema
)
import
Gargantext.Database.Schema.Context
import
Gargantext.Database.Schema.Context
...
@@ -357,6 +357,20 @@ data NodeType = NodeUser
...
@@ -357,6 +357,20 @@ data NodeType = NodeUser
deriving
(
Show
,
Read
,
Eq
,
Generic
,
Bounded
,
Enum
)
deriving
(
Show
,
Read
,
Eq
,
Generic
,
Bounded
,
Enum
)
instance
GQLType
NodeType
instance
GQLType
NodeType
instance
FromJSON
NodeType
instance
ToJSON
NodeType
instance
FromHttpApiData
NodeType
where
parseUrlPiece
=
Right
.
read
.
unpack
instance
ToHttpApiData
NodeType
where
toUrlPiece
=
pack
.
show
instance
ToParamSchema
NodeType
instance
ToSchema
NodeType
instance
Arbitrary
NodeType
where
arbitrary
=
elements
allNodeTypes
instance
FromField
NodeType
where
fromField
=
fromJSONField
instance
ToField
NodeType
where
toField
=
toJSONField
allNodeTypes
::
[
NodeType
]
allNodeTypes
::
[
NodeType
]
...
@@ -394,21 +408,6 @@ defaultName NodeFrameNotebook = "Code"
...
@@ -394,21 +408,6 @@ defaultName NodeFrameNotebook = "Code"
defaultName
NodeFile
=
"File"
defaultName
NodeFile
=
"File"
instance
FromJSON
NodeType
instance
ToJSON
NodeType
instance
FromHttpApiData
NodeType
where
parseUrlPiece
=
Right
.
read
.
unpack
instance
ToHttpApiData
NodeType
where
toUrlPiece
=
pack
.
show
instance
ToParamSchema
NodeType
instance
ToSchema
NodeType
instance
Arbitrary
NodeType
where
arbitrary
=
elements
allNodeTypes
------------------------------------------------------------------------
------------------------------------------------------------------------
-- Instances
-- Instances
...
@@ -451,4 +450,3 @@ instance DefaultFromField SqlText (Maybe Hash)
...
@@ -451,4 +450,3 @@ instance DefaultFromField SqlText (Maybe Hash)
context2node
::
Context
a
->
Node
a
context2node
::
Context
a
->
Node
a
context2node
(
Context
ci
ch
ct
cu
cp
cn
cd
chy
)
=
Node
ci
ch
ct
cu
cp
cn
cd
chy
context2node
(
Context
ci
ch
ct
cu
cp
cn
cd
chy
)
=
Node
ci
ch
ct
cu
cp
cn
cd
chy
src/Gargantext/Database/Query/Table/Ngrams.hs
View file @
a2788ade
...
@@ -132,4 +132,3 @@ selectNgramsId' ns = runPGSQuery querySelectNgramsId ( PGS.Only
...
@@ -132,4 +132,3 @@ selectNgramsId' ns = runPGSQuery querySelectNgramsId ( PGS.Only
JOIN input_rows ir ON ir.terms = n.terms
JOIN input_rows ir ON ir.terms = n.terms
GROUP BY n.terms, n.id
GROUP BY n.terms, n.id
|]
|]
src/Gargantext/Database/Query/Table/Node.hs
View file @
a2788ade
...
@@ -26,7 +26,6 @@ import Control.Lens (set, view)
...
@@ -26,7 +26,6 @@ import Control.Lens (set, view)
import
Data.Aeson
import
Data.Aeson
import
Data.Maybe
(
fromMaybe
)
import
Data.Maybe
(
fromMaybe
)
import
Data.Text
(
Text
)
import
Data.Text
(
Text
)
import
qualified
Database.PostgreSQL.Simple
as
DPS
import
Database.PostgreSQL.Simple.SqlQQ
(
sql
)
import
Database.PostgreSQL.Simple.SqlQQ
(
sql
)
import
Opaleye
hiding
(
FromField
)
import
Opaleye
hiding
(
FromField
)
import
Prelude
hiding
(
null
,
id
,
map
,
sum
)
import
Prelude
hiding
(
null
,
id
,
map
,
sum
)
...
@@ -41,6 +40,9 @@ import Gargantext.Database.Query.Table.Node.Error
...
@@ -41,6 +40,9 @@ import Gargantext.Database.Query.Table.Node.Error
import
Gargantext.Database.Schema.Node
import
Gargantext.Database.Schema.Node
import
Gargantext.Prelude
hiding
(
sum
,
head
)
import
Gargantext.Prelude
hiding
(
sum
,
head
)
import
qualified
Database.PostgreSQL.Simple
as
PGS
queryNodeSearchTable
::
Select
NodeSearchRead
queryNodeSearchTable
::
Select
NodeSearchRead
queryNodeSearchTable
=
selectTable
nodeTableSearch
queryNodeSearchTable
=
selectTable
nodeTableSearch
...
@@ -123,7 +125,7 @@ getClosestParentIdByType :: HasDBid NodeType
...
@@ -123,7 +125,7 @@ getClosestParentIdByType :: HasDBid NodeType
->
NodeType
->
NodeType
->
Cmd
err
(
Maybe
NodeId
)
->
Cmd
err
(
Maybe
NodeId
)
getClosestParentIdByType
nId
nType
=
do
getClosestParentIdByType
nId
nType
=
do
result
<-
runPGSQuery
query
(
nId
,
0
::
Int
)
result
<-
runPGSQuery
query
(
PGS
.
Only
nId
)
case
result
of
case
result
of
[(
NodeId
parentId
,
pTypename
)]
->
do
[(
NodeId
parentId
,
pTypename
)]
->
do
if
toDBid
nType
==
pTypename
then
if
toDBid
nType
==
pTypename
then
...
@@ -132,12 +134,12 @@ getClosestParentIdByType nId nType = do
...
@@ -132,12 +134,12 @@ getClosestParentIdByType nId nType = do
getClosestParentIdByType
(
NodeId
parentId
)
nType
getClosestParentIdByType
(
NodeId
parentId
)
nType
_
->
pure
Nothing
_
->
pure
Nothing
where
where
query
::
DP
S
.
Query
query
::
PG
S
.
Query
query
=
[
sql
|
query
=
[
sql
|
SELECT n2.id, n2.typename
SELECT n2.id, n2.typename
FROM nodes n1
FROM nodes n1
JOIN nodes n2 ON n1.parent_id = n2.id
JOIN nodes n2 ON n1.parent_id = n2.id
WHERE n1.id = ?
AND 0 = ?
;
WHERE n1.id = ?;
|]
|]
-- | Similar to `getClosestParentIdByType` but includes current node
-- | Similar to `getClosestParentIdByType` but includes current node
...
@@ -147,7 +149,7 @@ getClosestParentIdByType' :: HasDBid NodeType
...
@@ -147,7 +149,7 @@ getClosestParentIdByType' :: HasDBid NodeType
->
NodeType
->
NodeType
->
Cmd
err
(
Maybe
NodeId
)
->
Cmd
err
(
Maybe
NodeId
)
getClosestParentIdByType'
nId
nType
=
do
getClosestParentIdByType'
nId
nType
=
do
result
<-
runPGSQuery
query
(
nId
,
0
::
Int
)
result
<-
runPGSQuery
query
(
PGS
.
Only
nId
)
case
result
of
case
result
of
[(
NodeId
id
,
pTypename
)]
->
do
[(
NodeId
id
,
pTypename
)]
->
do
if
toDBid
nType
==
pTypename
then
if
toDBid
nType
==
pTypename
then
...
@@ -156,11 +158,11 @@ getClosestParentIdByType' nId nType = do
...
@@ -156,11 +158,11 @@ getClosestParentIdByType' nId nType = do
getClosestParentIdByType
nId
nType
getClosestParentIdByType
nId
nType
_
->
pure
Nothing
_
->
pure
Nothing
where
where
query
::
DP
S
.
Query
query
::
PG
S
.
Query
query
=
[
sql
|
query
=
[
sql
|
SELECT n.id, n.typename
SELECT n.id, n.typename
FROM nodes n
FROM nodes n
WHERE n.id = ?
AND 0 = ?
;
WHERE n.id = ?;
|]
|]
-- | Given a node id, find all it's children (no matter how deep) of
-- | Given a node id, find all it's children (no matter how deep) of
...
@@ -170,15 +172,15 @@ getChildrenByType :: HasDBid NodeType
...
@@ -170,15 +172,15 @@ getChildrenByType :: HasDBid NodeType
->
NodeType
->
NodeType
->
Cmd
err
[
NodeId
]
->
Cmd
err
[
NodeId
]
getChildrenByType
nId
nType
=
do
getChildrenByType
nId
nType
=
do
result
<-
runPGSQuery
query
(
nId
,
0
::
Int
)
result
<-
runPGSQuery
query
(
PGS
.
Only
nId
)
children_lst
<-
mapM
(
\
(
id
,
_
)
->
getChildrenByType
id
nType
)
result
children_lst
<-
mapM
(
\
(
id
,
_
)
->
getChildrenByType
id
nType
)
result
pure
$
concat
$
[
fst
<$>
filter
(
\
(
_
,
pTypename
)
->
pTypename
==
toDBid
nType
)
result
]
++
children_lst
pure
$
concat
$
[
fst
<$>
filter
(
\
(
_
,
pTypename
)
->
pTypename
==
toDBid
nType
)
result
]
++
children_lst
where
where
query
::
DP
S
.
Query
query
::
PG
S
.
Query
query
=
[
sql
|
query
=
[
sql
|
SELECT n.id, n.typename
SELECT n.id, n.typename
FROM nodes n
FROM nodes n
WHERE n.parent_id = ?
AND 0 = ?
;
WHERE n.parent_id = ?;
|]
|]
------------------------------------------------------------------------
------------------------------------------------------------------------
...
@@ -231,8 +233,8 @@ selectNodesIdWithType nt = proc () -> do
...
@@ -231,8 +233,8 @@ selectNodesIdWithType nt = proc () -> do
------------------------------------------------------------------------
------------------------------------------------------------------------
nodeExists
::
(
HasNodeError
err
)
=>
NodeId
->
Cmd
err
Bool
nodeExists
::
(
HasNodeError
err
)
=>
NodeId
->
Cmd
err
Bool
nodeExists
nId
=
(
==
[
DP
S
.
Only
True
])
nodeExists
nId
=
(
==
[
PG
S
.
Only
True
])
<$>
runPGSQuery
[
sql
|
SELECT true FROM nodes WHERE id = ?
AND ?
|]
(
nId
,
True
)
<$>
runPGSQuery
[
sql
|
SELECT true FROM nodes WHERE id = ?
|]
(
PGS
.
Only
nId
)
getNode
::
HasNodeError
err
=>
NodeId
->
Cmd
err
(
Node
Value
)
getNode
::
HasNodeError
err
=>
NodeId
->
Cmd
err
(
Node
Value
)
getNode
nId
=
do
getNode
nId
=
do
...
@@ -397,4 +399,3 @@ defaultListMaybe cId = headMay <$> map (view node_id ) <$> getListsWithParentId
...
@@ -397,4 +399,3 @@ defaultListMaybe cId = headMay <$> map (view node_id ) <$> getListsWithParentId
getListsWithParentId
::
HasDBid
NodeType
=>
NodeId
->
Cmd
err
[
Node
HyperdataList
]
getListsWithParentId
::
HasDBid
NodeType
=>
NodeId
->
Cmd
err
[
Node
HyperdataList
]
getListsWithParentId
n
=
runOpaQuery
$
selectNodesWith'
n
(
Just
NodeList
)
getListsWithParentId
n
=
runOpaQuery
$
selectNodesWith'
n
(
Just
NodeList
)
src/Gargantext/Database/Schema/Ngrams.hs
View file @
a2788ade
...
@@ -20,25 +20,27 @@ Ngrams connection to the Database.
...
@@ -20,25 +20,27 @@ Ngrams connection to the Database.
module
Gargantext.Database.Schema.Ngrams
module
Gargantext.Database.Schema.Ngrams
where
where
import
Data.Maybe
(
fromMaybe
)
import
Data.HashMap.Strict
(
HashMap
)
import
Data.Hashable
(
Hashable
)
import
Codec.Serialise
(
Serialise
())
import
Codec.Serialise
(
Serialise
())
import
Control.Lens
(
over
)
import
Control.Lens
(
over
)
import
Control.Monad
(
mzero
)
import
Control.Monad
(
mzero
)
import
Data.Maybe
(
fromMaybe
)
import
Data.HashMap.Strict
(
HashMap
)
import
Data.Hashable
(
Hashable
)
import
Data.Aeson
import
Data.Aeson
import
Data.Aeson.Types
(
toJSONKeyText
)
import
Data.Aeson.Types
(
toJSONKeyText
)
import
Data.Map
(
fromList
,
lookup
)
import
Data.Map
(
fromList
,
lookup
)
import
Database.PostgreSQL.Simple.FromField
(
returnError
,
ResultError
(
..
))
import
Data.Text
(
Text
,
splitOn
,
pack
,
strip
)
import
Data.Text
(
Text
,
splitOn
,
pack
,
strip
)
import
Gargantext.Core.Types
(
TODO
(
..
),
Typed
(
..
))
import
Gargantext.Core.Types
(
TODO
(
..
),
Typed
(
..
))
import
Gargantext.Prelude
import
Gargantext.Prelude
import
Servant
(
FromHttpApiData
(
..
),
Proxy
(
..
),
ToHttpApiData
(
..
))
import
Servant
(
FromHttpApiData
(
..
),
Proxy
(
..
),
ToHttpApiData
(
..
))
import
Text.Read
(
read
)
import
Gargantext.Core
(
HasDBid
(
..
))
import
Gargantext.Core
(
HasDBid
(
..
))
import
Gargantext.Database.Types
import
Gargantext.Database.Types
import
Gargantext.Database.Schema.Prelude
import
Gargantext.Database.Schema.Prelude
import
qualified
Database.PostgreSQL.Simple
as
PGS
import
Text.Read
(
read
)
import
qualified
Data.ByteString.Char8
as
B
import
qualified
Data.HashMap.Strict
as
HashMap
import
qualified
Data.HashMap.Strict
as
HashMap
import
qualified
Database.PostgreSQL.Simple
as
PGS
type
NgramsId
=
Int
type
NgramsId
=
Int
...
@@ -82,8 +84,34 @@ ngramsTable = Table "ngrams" (pNgramsDb NgramsDB { _ngrams_id = optionalTable
...
@@ -82,8 +84,34 @@ ngramsTable = Table "ngrams" (pNgramsDb NgramsDB { _ngrams_id = optionalTable
-- ngrams in text fields of documents has Terms Type (i.e. either title or abstract)
-- ngrams in text fields of documents has Terms Type (i.e. either title or abstract)
data
NgramsType
=
Authors
|
Institutes
|
Sources
|
NgramsTerms
data
NgramsType
=
Authors
|
Institutes
|
Sources
|
NgramsTerms
deriving
(
Eq
,
Show
,
Read
,
Ord
,
Enum
,
Bounded
,
Generic
)
deriving
(
Eq
,
Show
,
Read
,
Ord
,
Enum
,
Bounded
,
Generic
)
instance
Serialise
NgramsType
instance
Serialise
NgramsType
instance
FromJSON
NgramsType
instance
FromJSONKey
NgramsType
where
fromJSONKey
=
FromJSONKeyTextParser
(
parseJSON
.
String
)
instance
ToJSON
NgramsType
instance
ToJSONKey
NgramsType
where
toJSONKey
=
toJSONKeyText
(
pack
.
show
)
instance
FromHttpApiData
NgramsType
where
parseUrlPiece
n
=
pure
$
(
read
.
cs
)
n
instance
ToHttpApiData
NgramsType
where
toUrlPiece
=
pack
.
show
instance
ToParamSchema
NgramsType
where
toParamSchema
_
=
toParamSchema
(
Proxy
::
Proxy
TODO
)
-- map NgramsType to its assigned id
instance
FromField
NgramsType
where
fromField
fld
mdata
=
case
B
.
unpack
`
fmap
`
mdata
of
Nothing
->
returnError
UnexpectedNull
fld
""
Just
dat
->
do
n
<-
fromField
fld
mdata
if
(
n
::
Int
)
>
0
then
case
fromNgramsTypeId
(
NgramsTypeId
n
)
of
Nothing
->
returnError
ConversionFailed
fld
dat
Just
nt
->
pure
nt
else
returnError
ConversionFailed
fld
dat
instance
ToField
NgramsType
where
toField
nt
=
toField
$
ngramsTypeId
nt
ngramsTypes
::
[
NgramsType
]
ngramsTypes
::
[
NgramsType
]
...
@@ -96,33 +124,13 @@ instance ToSchema NgramsType
...
@@ -96,33 +124,13 @@ instance ToSchema NgramsType
newtype
NgramsTypeId
=
NgramsTypeId
Int
newtype
NgramsTypeId
=
NgramsTypeId
Int
deriving
(
Eq
,
Show
,
Ord
,
Num
)
deriving
(
Eq
,
Show
,
Ord
,
Num
)
instance
ToField
NgramsTypeId
where
instance
ToField
NgramsTypeId
where
toField
(
NgramsTypeId
n
)
=
toField
n
toField
(
NgramsTypeId
n
)
=
toField
n
instance
FromField
NgramsTypeId
where
instance
FromField
NgramsTypeId
where
fromField
fld
mdata
=
do
fromField
fld
mdata
=
do
n
<-
fromField
fld
mdata
n
<-
fromField
fld
mdata
if
(
n
::
Int
)
>
0
then
return
$
NgramsTypeId
n
if
(
n
::
Int
)
>
0
then
return
$
NgramsTypeId
n
else
mzero
else
mzero
instance
FromJSON
NgramsType
instance
FromJSONKey
NgramsType
where
fromJSONKey
=
FromJSONKeyTextParser
(
parseJSON
.
String
)
instance
ToJSON
NgramsType
instance
ToJSONKey
NgramsType
where
toJSONKey
=
toJSONKeyText
(
pack
.
show
)
instance
FromHttpApiData
NgramsType
where
parseUrlPiece
n
=
pure
$
(
read
.
cs
)
n
instance
ToHttpApiData
NgramsType
where
toUrlPiece
=
pack
.
show
instance
ToParamSchema
NgramsType
where
toParamSchema
_
=
toParamSchema
(
Proxy
::
Proxy
TODO
)
instance
DefaultFromField
(
Nullable
SqlInt4
)
NgramsTypeId
instance
DefaultFromField
(
Nullable
SqlInt4
)
NgramsTypeId
where
where
defaultFromField
=
fromPGSFromField
defaultFromField
=
fromPGSFromField
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment