@@ -4,7 +4,7 @@ use chainhook_postgres::{
4
4
deadpool_postgres:: GenericClient ,
5
5
tokio_postgres:: { types:: ToSql , Client } ,
6
6
types:: { PgNumericU128 , PgNumericU64 } ,
7
- utils, FromPgRow ,
7
+ utils, FromPgRow , BATCH_QUERY_CHUNK_SIZE ,
8
8
} ;
9
9
use chainhook_sdk:: types:: {
10
10
BitcoinBlockData , Brc20BalanceData , Brc20Operation , Brc20TokenDeployData , Brc20TransferData ,
@@ -79,24 +79,43 @@ pub async fn get_token_available_balance_for_address<T: GenericClient>(
79
79
Ok ( Some ( supply. 0 ) )
80
80
}
81
81
82
- pub async fn get_unsent_token_transfer < T : GenericClient > (
83
- ordinal_number : u64 ,
82
+ pub async fn get_unsent_token_transfers < T : GenericClient > (
83
+ ordinal_numbers : & Vec < u64 > ,
84
84
client : & T ,
85
- ) -> Result < Option < DbOperation > , String > {
86
- let row = client
87
- . query_opt (
88
- "SELECT * FROM operations
89
- WHERE ordinal_number = $1 AND operation = 'transfer'
90
- AND NOT EXISTS (SELECT 1 FROM operations WHERE ordinal_number = $1 AND operation = 'transfer_send')
91
- LIMIT 1" ,
92
- & [ & PgNumericU64 ( ordinal_number) ] ,
93
- )
94
- . await
95
- . map_err ( |e| format ! ( "get_unsent_token_transfer: {e}" ) ) ?;
96
- let Some ( row) = row else {
97
- return Ok ( None ) ;
98
- } ;
99
- Ok ( Some ( DbOperation :: from_pg_row ( & row) ) )
85
+ ) -> Result < Vec < DbOperation > , String > {
86
+ if ordinal_numbers. is_empty ( ) {
87
+ return Ok ( vec ! [ ] ) ;
88
+ }
89
+ let mut results = vec ! [ ] ;
90
+ // We can afford a larger chunk size here because we're only using one parameter per ordinal number value.
91
+ for chunk in ordinal_numbers. chunks ( 5000 ) {
92
+ let mut wrapped = Vec :: with_capacity ( chunk. len ( ) ) ;
93
+ for n in chunk {
94
+ wrapped. push ( PgNumericU64 ( * n) ) ;
95
+ }
96
+ let mut params = vec ! [ ] ;
97
+ for number in wrapped. iter ( ) {
98
+ params. push ( number) ;
99
+ }
100
+ let rows = client
101
+ . query (
102
+ "SELECT *
103
+ FROM operations o
104
+ WHERE operation = 'transfer'
105
+ AND o.ordinal_number = ANY($1)
106
+ AND NOT EXISTS (
107
+ SELECT 1 FROM operations
108
+ WHERE ordinal_number = o.ordinal_number
109
+ AND operation = 'transfer_send'
110
+ )
111
+ LIMIT 1" ,
112
+ & [ & params] ,
113
+ )
114
+ . await
115
+ . map_err ( |e| format ! ( "get_unsent_token_transfers: {e}" ) ) ?;
116
+ results. extend ( rows. iter ( ) . map ( |row| DbOperation :: from_pg_row ( row) ) ) ;
117
+ }
118
+ Ok ( results)
100
119
}
101
120
102
121
pub async fn insert_tokens < T : GenericClient > (
@@ -106,7 +125,7 @@ pub async fn insert_tokens<T: GenericClient>(
106
125
if tokens. len ( ) == 0 {
107
126
return Ok ( ( ) ) ;
108
127
}
109
- for chunk in tokens. chunks ( 500 ) {
128
+ for chunk in tokens. chunks ( BATCH_QUERY_CHUNK_SIZE ) {
110
129
let mut params: Vec < & ( dyn ToSql + Sync ) > = vec ! [ ] ;
111
130
for row in chunk. iter ( ) {
112
131
params. push ( & row. ticker ) ;
@@ -148,7 +167,7 @@ pub async fn insert_operations<T: GenericClient>(
148
167
if operations. len ( ) == 0 {
149
168
return Ok ( ( ) ) ;
150
169
}
151
- for chunk in operations. chunks ( 500 ) {
170
+ for chunk in operations. chunks ( BATCH_QUERY_CHUNK_SIZE ) {
152
171
let mut params: Vec < & ( dyn ToSql + Sync ) > = vec ! [ ] ;
153
172
for row in chunk. iter ( ) {
154
173
params. push ( & row. ticker ) ;
@@ -253,7 +272,11 @@ pub async fn update_address_operation_counts<T: GenericClient>(
253
272
if counts. len ( ) == 0 {
254
273
return Ok ( ( ) ) ;
255
274
}
256
- for chunk in counts. keys ( ) . collect :: < Vec < & String > > ( ) . chunks ( 500 ) {
275
+ for chunk in counts
276
+ . keys ( )
277
+ . collect :: < Vec < & String > > ( )
278
+ . chunks ( BATCH_QUERY_CHUNK_SIZE )
279
+ {
257
280
let mut params: Vec < & ( dyn ToSql + Sync ) > = vec ! [ ] ;
258
281
let mut insert_rows = 0 ;
259
282
for address in chunk {
@@ -287,7 +310,11 @@ pub async fn update_token_operation_counts<T: GenericClient>(
287
310
if counts. len ( ) == 0 {
288
311
return Ok ( ( ) ) ;
289
312
}
290
- for chunk in counts. keys ( ) . collect :: < Vec < & String > > ( ) . chunks ( 500 ) {
313
+ for chunk in counts
314
+ . keys ( )
315
+ . collect :: < Vec < & String > > ( )
316
+ . chunks ( BATCH_QUERY_CHUNK_SIZE )
317
+ {
291
318
let mut converted = HashMap :: new ( ) ;
292
319
for tick in chunk {
293
320
converted. insert ( * tick, counts. get ( * tick) . unwrap ( ) . to_string ( ) ) ;
@@ -324,7 +351,11 @@ pub async fn update_token_minted_supplies<T: GenericClient>(
324
351
if supplies. len ( ) == 0 {
325
352
return Ok ( ( ) ) ;
326
353
}
327
- for chunk in supplies. keys ( ) . collect :: < Vec < & String > > ( ) . chunks ( 500 ) {
354
+ for chunk in supplies
355
+ . keys ( )
356
+ . collect :: < Vec < & String > > ( )
357
+ . chunks ( BATCH_QUERY_CHUNK_SIZE )
358
+ {
328
359
let mut converted = HashMap :: new ( ) ;
329
360
for tick in chunk {
330
361
converted. insert ( * tick, supplies. get ( * tick) . unwrap ( ) . 0 . to_string ( ) ) ;
0 commit comments