Skip to content

Commit 67f80a0

Browse files
committed
feat(#2724): move drep pagination directly into sql
1 parent e1831a9 commit 67f80a0

File tree

9 files changed

+490
-329
lines changed

9 files changed

+490
-329
lines changed

govtool/backend/app/Main.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ startApp vvaConfig sentryService = do
144144

145145
exceptionHandler :: VVAConfig -> SentryService -> Maybe Request -> SomeException -> IO ()
146146
exceptionHandler vvaConfig sentryService mRequest exception = do
147+
print exception
147148
let isNotTimeoutThread x = case fromException x of
148149
Just TimeoutThread -> False
149150
_ -> True

govtool/backend/example-config.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
2-
"dbsyncconfig" : {
3-
"host" : "localhost",
4-
"dbname" : "cexplorer",
5-
"user" : "postgres",
6-
"password" : "postgres",
7-
"port" : 5432
8-
},
9-
"port" : 9999,
10-
"host" : "localhost",
2+
"dbsyncconfig": {
3+
"host": "localhost",
4+
"dbname": "cexplorer",
5+
"user": "postgres",
6+
"password": "postgres",
7+
"port": 5432
8+
},
9+
"port": 9999,
10+
"host": "localhost",
1111
"cachedurationseconds": 20,
1212
"sentrydsn": "https://username:[email protected]/id",
1313
"sentryenv": "dev"

govtool/backend/sql/list-dreps.sql

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,29 @@ DRepData AS (
117117
leva.metadata_hash,
118118
COALESCE(dr_deposit.deposit, 0) as deposit,
119119
DRepDistr.amount,
120-
(DRepActivity.epoch_no - GREATEST(COALESCE(voting_procedure_block.epoch_no, block_first_register.epoch_no), lve.epoch_no, newestRegister.epoch_no)) <= DRepActivity.drep_activity AS active,
121120
RankedDRepRegistration.tx_hash,
122-
newestRegister.time AS last_register_time,
123-
COALESCE(RankedDRepRegistration.deposit, 0) as latest_deposit,
124-
hndva.value AS has_non_deregister_voting_anchor,
121+
newestRegister.time AT TIME ZONE 'UTC' AS last_register_time,
125122
fetch_error.message AS fetch_error,
126123
off_chain_vote_drep_data.payment_address,
127124
off_chain_vote_drep_data.given_name,
128125
off_chain_vote_drep_data.objectives,
129126
off_chain_vote_drep_data.motivations,
130127
off_chain_vote_drep_data.qualifications,
131128
off_chain_vote_drep_data.image_url,
132-
off_chain_vote_drep_data.image_hash
129+
off_chain_vote_drep_data.image_hash,
130+
-- drep type
131+
CASE
132+
WHEN COALESCE(RankedDRepRegistration.deposit, 0) >= 0 AND leva.url IS NULL THEN 'SoleVoter'
133+
WHEN COALESCE(RankedDRepRegistration.deposit, 0) >= 0 AND leva.url IS NOT NULL THEN 'DRep'
134+
WHEN COALESCE(RankedDRepRegistration.deposit, 0) < 0 AND hndva.value = true THEN 'SoleVoter'
135+
WHEN COALESCE(RankedDRepRegistration.deposit, 0) < 0 AND hndva.value = false THEN 'DRep'
136+
END AS drep_type,
137+
-- status
138+
CASE
139+
WHEN COALESCE(RankedDRepRegistration.deposit, 0) < 0 THEN 'Retired'
140+
WHEN COALESCE(RankedDRepRegistration.deposit, 0) >= 0 AND (DRepActivity.epoch_no - GREATEST(COALESCE(voting_procedure_block.epoch_no, block_first_register.epoch_no), lve.epoch_no, newestRegister.epoch_no)) <= DRepActivity.drep_activity THEN 'Active'
141+
WHEN COALESCE(RankedDRepRegistration.deposit, 0) >= 0 AND NOT (DRepActivity.epoch_no - GREATEST(COALESCE(voting_procedure_block.epoch_no, block_first_register.epoch_no), lve.epoch_no, newestRegister.epoch_no)) <= DRepActivity.drep_activity THEN 'Inactive'
142+
END AS status
133143
FROM
134144
drep_hash dh
135145
JOIN RankedDRepRegistration ON RankedDRepRegistration.drep_hash_id = dh.id AND RankedDRepRegistration.rn = 1
@@ -195,33 +205,57 @@ DRepData AS (
195205
leva.metadata_hash,
196206
dr_deposit.deposit,
197207
DRepDistr.amount,
198-
DRepActivity.epoch_no,
199-
voting_procedure_block.epoch_no,
200-
block_first_register.epoch_no,
201-
lve.epoch_no, newestRegister.epoch_no,
202-
DRepActivity.drep_activity,
203208
RankedDRepRegistration.tx_hash,
204209
newestRegister.time,
205-
RankedDRepRegistration.deposit,
206-
hndva.value,
207210
fetch_error.message,
208211
off_chain_vote_drep_data.payment_address,
209212
off_chain_vote_drep_data.given_name,
210213
off_chain_vote_drep_data.objectives,
211214
off_chain_vote_drep_data.motivations,
212215
off_chain_vote_drep_data.qualifications,
213216
off_chain_vote_drep_data.image_url,
214-
off_chain_vote_drep_data.image_hash
215-
)
216-
SELECT * FROM DRepData
217-
WHERE
217+
off_chain_vote_drep_data.image_hash,
218+
RankedDRepRegistration.deposit,
219+
hndva.value,
220+
DRepActivity.epoch_no,
221+
DRepActivity.drep_activity,
222+
voting_procedure_block.epoch_no,
223+
block_first_register.epoch_no,
224+
lve.epoch_no,
225+
newestRegister.epoch_no
226+
),
227+
FilteredDRepData AS (
228+
SELECT * FROM DRepData
229+
WHERE
218230
(
219-
COALESCE(?, '') = '' OR
220-
(CASE WHEN LENGTH(?) % 2 = 0 AND ? ~ '^[0-9a-fA-F]+$' THEN drep_hash = ? ELSE false END) OR
221-
view ILIKE ? OR
222-
given_name ILIKE ? OR
223-
payment_address ILIKE ? OR
224-
objectives ILIKE ? OR
225-
motivations ILIKE ? OR
226-
qualifications ILIKE ?
227-
)
231+
COALESCE(?, '') = ''
232+
OR (
233+
CASE
234+
WHEN LENGTH(?) % 2 = 0 AND ? ~ '^[0-9a-fA-F]+$' THEN drep_hash = ?
235+
ELSE false
236+
END
237+
)
238+
OR (
239+
? ILIKE ANY(ARRAY[view, given_name, payment_address, objectives, motivations, qualifications])
240+
)
241+
)
242+
AND (?::TEXT = '' OR status = ANY(?))
243+
AND (drep_type != 'SoleVoter' OR (COALESCE(?, '') <> '' AND view ILIKE ?))
244+
)
245+
SELECT
246+
(SELECT COUNT(*) FROM FilteredDRepData) AS total,
247+
COALESCE(jsonb_agg(elements), '[]'::jsonb) AS elements
248+
FROM (
249+
SELECT *
250+
FROM FilteredDRepData
251+
ORDER BY
252+
CASE ?
253+
WHEN 'VotingPower' THEN amount::TEXT
254+
WHEN 'RegistrationDate' THEN last_register_time::TEXT
255+
WHEN 'Status' THEN status::TEXT
256+
ELSE NULL
257+
END DESC,
258+
CASE WHEN ? = 'Random' THEN RANDOM() END
259+
LIMIT ?
260+
OFFSET ?
261+
) AS elements

govtool/backend/src/VVA/API.hs

Lines changed: 15 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import VVA.Network as Network
4343
import qualified VVA.Proposal as Proposal
4444
import qualified VVA.Transaction as Transaction
4545
import qualified VVA.Types as Types
46+
import VVA.Common.Types
4647
import VVA.Types (App, AppEnv (..),
4748
AppError (CriticalError, InternalError, ValidationError),
4849
CacheEnv (..))
@@ -140,60 +141,24 @@ delegationToResponse Types.Delegation {..} =
140141
drepList :: App m => Maybe Text -> [DRepStatus] -> Maybe DRepSortMode -> Maybe Natural -> Maybe Natural -> m ListDRepsResponse
141142
drepList mSearchQuery statuses mSortMode mPage mPageSize = do
142143
CacheEnv {dRepListCache} <- asks vvaCache
143-
dreps <- cacheRequest dRepListCache (fromMaybe "" mSearchQuery) (DRep.listDReps mSearchQuery)
144-
145-
let filterDRepsByQuery = case mSearchQuery of
146-
Nothing -> filter $ \Types.DRepRegistration {..} ->
147-
dRepRegistrationType /= Types.SoleVoter
148-
Just query -> filter $ \Types.DRepRegistration {..} ->
149-
let searchLower = Text.toLower query
150-
viewLower = Text.toLower dRepRegistrationView
151-
hashLower = Text.toLower dRepRegistrationDRepHash
152-
in case dRepRegistrationType of
153-
Types.SoleVoter ->
154-
searchLower == viewLower || searchLower == hashLower
155-
Types.DRep ->
156-
True
157-
158-
159-
let filterDRepsByStatus = case statuses of
160-
[] -> id
161-
_ -> filter $ \Types.DRepRegistration {..} ->
162-
mapDRepStatus dRepRegistrationStatus `elem` statuses
163-
164-
randomizedOrderList <- mapM (\_ -> randomRIO (0, 1 :: Double)) dreps
165-
166-
let sortDReps = case mSortMode of
167-
Nothing -> id
168-
Just Random -> fmap snd . sortOn fst . Prelude.zip randomizedOrderList
169-
Just VotingPower -> sortOn $ \Types.DRepRegistration {..} ->
170-
Down dRepRegistrationVotingPower
171-
Just RegistrationDate -> sortOn $ \Types.DRepRegistration {..} ->
172-
Down dRepRegistrationLatestRegistrationDate
173-
Just Status -> sortOn $ \Types.DRepRegistration {..} ->
174-
dRepRegistrationStatus
175-
176-
appEnv <- ask
177-
178-
allValidDReps <- liftIO $ mapConcurrently
179-
(\d@Types.DRepRegistration{..} -> do
180-
let drep = drepRegistrationToDrep d
181-
return drep)
182-
$ sortDReps $ filterDRepsByQuery $ filterDRepsByStatus dreps
183144

184-
let page = (fromIntegral $ fromMaybe 0 mPage) :: Int
185-
pageSize = (fromIntegral $ fromMaybe 10 mPageSize) :: Int
145+
let page = fromMaybe 0 mPage
146+
let pageSize = fromMaybe 10 mPageSize
147+
let offset = page * pageSize
148+
let sortMode = fromMaybe VotingPower mSortMode
186149

187-
total = length allValidDReps :: Int
150+
let cacheKey = pack (show (mSearchQuery, statuses, sortMode, page, pageSize))
188151

189-
let elements = take pageSize $ drop (page * pageSize) allValidDReps
190-
return $ ListDRepsResponse
191-
{ listDRepsResponsePage = fromIntegral page
192-
, listDRepsResponsePageSize = fromIntegral pageSize
193-
, listDRepsResponseTotal = fromIntegral total
194-
, listDRepsResponseElements = elements
195-
}
152+
(totalCount, cachedDReps) <- cacheRequest dRepListCache cacheKey $
153+
DRep.listDReps mSearchQuery statuses (Just sortMode) (fromIntegral pageSize) (fromIntegral offset)
196154

155+
let response = ListDRepsResponse
156+
{ listDRepsResponsePage = fromIntegral page
157+
, listDRepsResponsePageSize = fromIntegral pageSize
158+
, listDRepsResponseTotal = fromIntegral totalCount
159+
, listDRepsResponseElements = cachedDReps
160+
}
161+
return response
197162

198163
getVotingPower :: App m => HexText -> m Integer
199164
getVotingPower (unHexText -> dRepId) = do

0 commit comments

Comments
 (0)