@@ -7,15 +7,14 @@ use crate::{
7
7
use async_graphql:: {
8
8
connection, types, ComplexObject , Context , Enum , Interface , Object , SimpleObject , Union ,
9
9
} ;
10
- use futures:: TryStreamExt ;
11
10
12
11
#[ derive( Default ) ]
13
12
pub ( crate ) struct QueryBlocks ;
14
13
15
14
#[ Object ]
16
15
impl QueryBlocks {
17
- async fn block < ' a > ( & self , ctx : & Context < ' a > , height_id : types:: ID ) -> ApiResult < Block > {
18
- let height: BlockHeight = height_id . try_into ( ) . map_err ( ApiError :: InvalidIdInt ) ?;
16
+ async fn block < ' a > ( & self , ctx : & Context < ' a > , id : types:: ID ) -> ApiResult < Block > {
17
+ let height: BlockHeight = id . try_into ( ) . map_err ( ApiError :: InvalidIdInt ) ?;
19
18
Block :: query_by_height ( get_pool ( ctx) ?, height) . await
20
19
}
21
20
@@ -27,9 +26,10 @@ impl QueryBlocks {
27
26
Block :: query_by_hash ( get_pool ( ctx) ?, block_hash) . await
28
27
}
29
28
30
- async fn blocks < ' a > (
29
+ /// Query the list of blocks ordered descendingly by block height.
30
+ async fn blocks (
31
31
& self ,
32
- ctx : & Context < ' a > ,
32
+ ctx : & Context < ' _ > ,
33
33
#[ graphql( desc = "Returns the first _n_ elements from the list." ) ] first : Option < u64 > ,
34
34
#[ graphql( desc = "Returns the elements in the list that come after the specified cursor." ) ]
35
35
after : Option < String > ,
@@ -46,11 +46,11 @@ impl QueryBlocks {
46
46
before,
47
47
config. block_connection_limit ,
48
48
) ?;
49
- // The CCDScan front-end currently expects an ASC order of the nodes/edges
49
+ // The CCDScan front-end currently expects an DESC order of the nodes/edges
50
50
// returned (outer `ORDER BY`), while the inner `ORDER BY` is a trick to
51
51
// get the correct nodes/edges selected based on the `after/before` key
52
52
// specified.
53
- let mut row_stream = sqlx:: query_as!(
53
+ let rows = sqlx:: query_as!(
54
54
Block ,
55
55
"SELECT * FROM (
56
56
SELECT
@@ -64,29 +64,36 @@ impl QueryBlocks {
64
64
FROM blocks
65
65
WHERE height > $1 AND height < $2
66
66
ORDER BY
67
- (CASE WHEN $4 THEN height END) DESC ,
68
- (CASE WHEN NOT $4 THEN height END) ASC
67
+ (CASE WHEN $4 THEN height END) ASC ,
68
+ (CASE WHEN NOT $4 THEN height END) DESC
69
69
LIMIT $3
70
- ) ORDER BY height ASC " ,
70
+ ) ORDER BY height DESC " ,
71
71
query. from,
72
72
query. to,
73
73
query. limit,
74
74
query. desc
75
75
)
76
- . fetch ( pool) ;
77
-
78
- let mut connection = connection:: Connection :: new ( true , true ) ;
79
- while let Some ( block) = row_stream. try_next ( ) . await ? {
80
- connection. edges . push ( connection:: Edge :: new ( block. height . to_string ( ) , block) ) ;
76
+ . fetch_all ( pool)
77
+ . await ?;
78
+ let has_prev_page = if let Some ( first) = rows. first ( ) {
79
+ sqlx:: query_scalar!( "SELECT true FROM blocks WHERE height > $1 LIMIT 1" , first. height)
80
+ . fetch_optional ( pool)
81
+ . await ?
82
+ . flatten ( )
83
+ . unwrap_or_default ( )
84
+ } else {
85
+ false
86
+ } ;
87
+ let has_next_page = if let Some ( last) = rows. last ( ) {
88
+ // Genesis block have height 0, so we check whether the last block is higher.
89
+ last. height > 0
90
+ } else {
91
+ false
92
+ } ;
93
+ let mut connection = connection:: Connection :: new ( has_prev_page, has_next_page) ;
94
+ for row in rows {
95
+ connection. edges . push ( connection:: Edge :: new ( row. height . to_string ( ) , row) ) ;
81
96
}
82
- if last. is_some ( ) {
83
- if let Some ( edge) = connection. edges . last ( ) {
84
- connection. has_previous_page = edge. node . height != 0 ;
85
- }
86
- } else if let Some ( edge) = connection. edges . first ( ) {
87
- connection. has_previous_page = edge. node . height != 0 ;
88
- }
89
-
90
97
Ok ( connection)
91
98
}
92
99
}
0 commit comments