@@ -7,25 +7,60 @@ use reqwest::{StatusCode, Url};
77use sqlx:: sqlite:: SqliteRow ;
88use sqlx:: { QueryBuilder , Row , SqlitePool } ;
99
10+ use deckmaster_domain:: common:: query_set:: { QuerySet , QuerySetMeta } ;
1011use deckmaster_domain:: mtg:: model:: { Card , Deck } ;
1112use deckmaster_domain:: mtg:: service:: { FindCardsFilter , FindDecksFilter } ;
1213use deckmaster_domain:: mtg:: service:: { FindImageFilter , MtgDataAccessLayer } ;
1314
15+ #[ derive( Clone ) ]
16+ struct Counters {
17+ cards : u32 ,
18+ decks : u32 ,
19+ }
20+
1421#[ derive( Clone ) ]
1522pub struct MtgRepository {
1623 db : Arc < SqlitePool > ,
1724 storage_url : Url ,
25+ counters : Counters ,
1826}
1927
2028impl MtgRepository {
2129 pub async fn new ( db : Arc < SqlitePool > , storage_url : Url ) -> Result < Self > {
22- Ok ( MtgRepository { db, storage_url } )
30+ let mut repo = MtgRepository {
31+ db,
32+ storage_url,
33+ counters : Counters { cards : 0 , decks : 0 } ,
34+ } ;
35+
36+ repo. count_tables ( ) . await ?;
37+
38+ Ok ( repo)
39+ }
40+
41+ // The `mtg` table is immutable, so we can cache the count of rows
42+ // to avoid running a COUNT(*) query every time we need it.
43+ async fn count_tables ( & mut self ) -> Result < ( ) > {
44+ let mut conn = self . db . acquire ( ) . await ?. detach ( ) ;
45+ let row: ( i64 , ) = sqlx:: query_as ( "SELECT COUNT(*) FROM cards" )
46+ . fetch_one ( & mut conn)
47+ . await ?;
48+ self . counters . cards = row. 0 as u32 ;
49+
50+ let row: ( i64 , ) = sqlx:: query_as ( "SELECT COUNT(*) FROM decks" )
51+ . fetch_one ( & mut conn)
52+ . await ?;
53+ self . counters . decks = row. 0 as u32 ;
54+
55+ Ok ( ( ) )
2356 }
2457}
2558
2659impl MtgDataAccessLayer for MtgRepository {
27- async fn find_cards ( & self , filter : FindCardsFilter ) -> Result < Vec < Card > > {
60+ async fn find_cards ( & self , filter : FindCardsFilter ) -> Result < QuerySet < Card > > {
2861 let mut conn = self . db . acquire ( ) . await ?. detach ( ) ;
62+ let page = filter. page . unwrap_or ( 1 ) ;
63+ let offset = page * 20 ;
2964 let mut query = QueryBuilder :: new (
3065 r#"SELECT
3166 id,
@@ -47,7 +82,6 @@ impl MtgDataAccessLayer for MtgRepository {
4782 }
4883
4984 query. push ( " FROM cards" ) ;
50- let offset = ( filter. page . unwrap_or ( 1 ) . saturating_sub ( 1 ) ) * 20 ;
5185 query. push ( " LIMIT 20 OFFSET " ) ;
5286 query. push_bind ( offset as i64 ) ;
5387
@@ -86,21 +120,33 @@ impl MtgDataAccessLayer for MtgRepository {
86120 } ) ;
87121 }
88122
89- Ok ( cards)
123+ Ok ( QuerySet :: new (
124+ cards,
125+ QuerySetMeta {
126+ page,
127+ per_page : 20 ,
128+ total_pages : self . counters . cards . div_ceil ( 20 ) ,
129+ } ,
130+ ) )
90131 }
91132
92- async fn find_decks ( & self , _ : FindDecksFilter ) -> Result < Vec < Deck > > {
133+ async fn find_decks ( & self , filter : FindDecksFilter ) -> Result < QuerySet < Deck > > {
93134 let mut conn = self . db . acquire ( ) . await ?. detach ( ) ;
94- let rows: Vec < SqliteRow > = sqlx:: query (
135+ let page = filter. page . unwrap_or ( 1 ) ;
136+ let offset = page * 20 ;
137+ let mut query = QueryBuilder :: new (
95138 r#"SELECT
96139 id,
97140 name,
98141 code,
99142 release
100143 FROM decks"# ,
101- )
102- . fetch_all ( & mut conn)
103- . await ?;
144+ ) ;
145+
146+ query. push ( " LIMIT 20 OFFSET " ) ;
147+ query. push_bind ( offset as i64 ) ;
148+
149+ let rows: Vec < SqliteRow > = query. build ( ) . fetch_all ( & mut conn) . await ?;
104150 let mut decks = Vec :: new ( ) ;
105151
106152 for row in rows {
@@ -119,7 +165,14 @@ impl MtgDataAccessLayer for MtgRepository {
119165 } ) ;
120166 }
121167
122- Ok ( decks)
168+ Ok ( QuerySet :: new (
169+ decks,
170+ QuerySetMeta {
171+ page,
172+ per_page : 20 ,
173+ total_pages : self . counters . decks . div_ceil ( 20 ) ,
174+ } ,
175+ ) )
123176 }
124177
125178 async fn find_image ( & self , filter : FindImageFilter ) -> Result < Bytes > {
@@ -128,7 +181,6 @@ impl MtgDataAccessLayer for MtgRepository {
128181 "magic-the-gathering/images/cards/{}/{}.jpg" ,
129182 deck_id, card_id
130183 ) ) ?;
131- println ! ( "{}" , image_url) ;
132184 let response = reqwest:: get ( image_url) . await ?;
133185
134186 if response. status ( ) == StatusCode :: OK {
0 commit comments