1
- use sqlx:: { Row , SqlitePool } ;
1
+ use crate :: utils:: types:: { ContentType , HistoryItem } ;
2
+ use base64:: { engine:: general_purpose:: STANDARD , Engine } ;
2
3
use rand:: distributions:: Alphanumeric ;
3
4
use rand:: { thread_rng, Rng } ;
4
- use crate :: utils :: types :: { HistoryItem , ContentType } ;
5
+ use sqlx :: { Row , SqlitePool } ;
5
6
use std:: fs;
6
- use base64:: { Engine , engine:: general_purpose:: STANDARD } ;
7
7
8
8
pub async fn initialize_history ( pool : & SqlitePool ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
9
9
let id: String = thread_rng ( )
@@ -27,19 +27,22 @@ pub async fn initialize_history(pool: &SqlitePool) -> Result<(), Box<dyn std::er
27
27
#[ tauri:: command]
28
28
pub async fn get_history ( pool : tauri:: State < ' _ , SqlitePool > ) -> Result < Vec < HistoryItem > , String > {
29
29
let rows = sqlx:: query (
30
- "SELECT id, content_type, content, favicon, timestamp FROM history ORDER BY timestamp DESC"
30
+ "SELECT id, content_type, content, favicon, timestamp FROM history ORDER BY timestamp DESC" ,
31
31
)
32
32
. fetch_all ( & * pool)
33
33
. await
34
34
. map_err ( |e| e. to_string ( ) ) ?;
35
35
36
- let items = rows. iter ( ) . map ( |row| HistoryItem {
37
- id : row. get ( "id" ) ,
38
- content_type : ContentType :: from ( row. get :: < String , _ > ( "content_type" ) ) ,
39
- content : row. get ( "content" ) ,
40
- favicon : row. get ( "favicon" ) ,
41
- timestamp : row. get ( "timestamp" ) ,
42
- } ) . collect ( ) ;
36
+ let items = rows
37
+ . iter ( )
38
+ . map ( |row| HistoryItem {
39
+ id : row. get ( "id" ) ,
40
+ content_type : ContentType :: from ( row. get :: < String , _ > ( "content_type" ) ) ,
41
+ content : row. get ( "content" ) ,
42
+ favicon : row. get ( "favicon" ) ,
43
+ timestamp : row. get ( "timestamp" ) ,
44
+ } )
45
+ . collect ( ) ;
43
46
44
47
Ok ( items)
45
48
}
@@ -50,7 +53,19 @@ pub async fn add_history_item(
50
53
item : HistoryItem ,
51
54
) -> Result < ( ) , String > {
52
55
let ( id, content_type, content, favicon, timestamp) = item. to_row ( ) ;
53
-
56
+
57
+ let last_content: Option < String > = sqlx:: query_scalar (
58
+ "SELECT content FROM history WHERE content_type = ? ORDER BY timestamp DESC LIMIT 1" ,
59
+ )
60
+ . bind ( content_type. clone ( ) )
61
+ . fetch_one ( & * pool)
62
+ . await
63
+ . unwrap_or ( None ) ;
64
+
65
+ if last_content. as_deref ( ) == Some ( & content) {
66
+ return Ok ( ( ) ) ;
67
+ }
68
+
54
69
sqlx:: query (
55
70
"INSERT INTO history (id, content_type, content, favicon, timestamp) VALUES (?, ?, ?, ?, ?)"
56
71
)
@@ -69,7 +84,7 @@ pub async fn add_history_item(
69
84
#[ tauri:: command]
70
85
pub async fn search_history (
71
86
pool : tauri:: State < ' _ , SqlitePool > ,
72
- query : String
87
+ query : String ,
73
88
) -> Result < Vec < HistoryItem > , String > {
74
89
let query = format ! ( "%{}%" , query) ;
75
90
let rows = sqlx:: query (
@@ -80,13 +95,16 @@ pub async fn search_history(
80
95
. await
81
96
. map_err ( |e| e. to_string ( ) ) ?;
82
97
83
- let items = rows. iter ( ) . map ( |row| HistoryItem {
84
- id : row. get ( "id" ) ,
85
- content_type : ContentType :: from ( row. get :: < String , _ > ( "content_type" ) ) ,
86
- content : row. get ( "content" ) ,
87
- favicon : row. get ( "favicon" ) ,
88
- timestamp : row. get ( "timestamp" ) ,
89
- } ) . collect ( ) ;
98
+ let items = rows
99
+ . iter ( )
100
+ . map ( |row| HistoryItem {
101
+ id : row. get ( "id" ) ,
102
+ content_type : ContentType :: from ( row. get :: < String , _ > ( "content_type" ) ) ,
103
+ content : row. get ( "content" ) ,
104
+ favicon : row. get ( "favicon" ) ,
105
+ timestamp : row. get ( "timestamp" ) ,
106
+ } )
107
+ . collect ( ) ;
90
108
91
109
Ok ( items)
92
110
}
@@ -95,7 +113,7 @@ pub async fn search_history(
95
113
pub async fn load_history_chunk (
96
114
pool : tauri:: State < ' _ , SqlitePool > ,
97
115
offset : i64 ,
98
- limit : i64
116
+ limit : i64 ,
99
117
) -> Result < Vec < HistoryItem > , String > {
100
118
let rows = sqlx:: query (
101
119
"SELECT id, content_type, content, favicon, timestamp FROM history ORDER BY timestamp DESC LIMIT ? OFFSET ?"
@@ -106,21 +124,24 @@ pub async fn load_history_chunk(
106
124
. await
107
125
. map_err ( |e| e. to_string ( ) ) ?;
108
126
109
- let items = rows. iter ( ) . map ( |row| HistoryItem {
110
- id : row. get ( "id" ) ,
111
- content_type : ContentType :: from ( row. get :: < String , _ > ( "content_type" ) ) ,
112
- content : row. get ( "content" ) ,
113
- favicon : row. get ( "favicon" ) ,
114
- timestamp : row. get ( "timestamp" ) ,
115
- } ) . collect ( ) ;
127
+ let items = rows
128
+ . iter ( )
129
+ . map ( |row| HistoryItem {
130
+ id : row. get ( "id" ) ,
131
+ content_type : ContentType :: from ( row. get :: < String , _ > ( "content_type" ) ) ,
132
+ content : row. get ( "content" ) ,
133
+ favicon : row. get ( "favicon" ) ,
134
+ timestamp : row. get ( "timestamp" ) ,
135
+ } )
136
+ . collect ( ) ;
116
137
117
138
Ok ( items)
118
139
}
119
140
120
141
#[ tauri:: command]
121
142
pub async fn delete_history_item (
122
143
pool : tauri:: State < ' _ , SqlitePool > ,
123
- id : String
144
+ id : String ,
124
145
) -> Result < ( ) , String > {
125
146
sqlx:: query ( "DELETE FROM history WHERE id = ?" )
126
147
. bind ( id)
@@ -145,4 +166,4 @@ pub async fn clear_history(pool: tauri::State<'_, SqlitePool>) -> Result<(), Str
145
166
pub async fn read_image ( filename : String ) -> Result < String , String > {
146
167
let bytes = fs:: read ( filename) . map_err ( |e| e. to_string ( ) ) ?;
147
168
Ok ( STANDARD . encode ( bytes) )
148
- }
169
+ }
0 commit comments