Some checks failed
CI - Multi-Platform Native / Build iOS (RSSuper) (push) Has been cancelled
CI - Multi-Platform Native / Build macOS (push) Has been cancelled
CI - Multi-Platform Native / Build Android (push) Has been cancelled
CI - Multi-Platform Native / Build Linux (push) Has been cancelled
CI - Multi-Platform Native / Build Summary (push) Has been cancelled
172 lines
4.8 KiB
Vala
172 lines
4.8 KiB
Vala
/*
|
|
* SearchHistoryStore.vala
|
|
*
|
|
* CRUD operations for search history.
|
|
*/
|
|
|
|
/**
|
|
* SearchHistoryStore - Manages search history persistence
|
|
*/
|
|
public class RSSuper.SearchHistoryStore : Object {
|
|
private Database db;
|
|
|
|
/**
|
|
* Maximum number of history entries to keep
|
|
*/
|
|
public int max_entries { get; set; default = 100; }
|
|
|
|
/**
|
|
* Signal emitted when a search is recorded
|
|
*/
|
|
public signal void search_recorded(SearchQuery query, int result_count);
|
|
|
|
/**
|
|
* Signal emitted when history is cleared
|
|
*/
|
|
public signal void history_cleared();
|
|
|
|
/**
|
|
* Create a new search history store
|
|
*/
|
|
public SearchHistoryStore(Database db) {
|
|
this.db = db;
|
|
}
|
|
|
|
/**
|
|
* Record a search query
|
|
*/
|
|
public int record_search(SearchQuery query, int result_count = 0) throws Error {
|
|
var stmt = db.prepare(
|
|
"INSERT INTO search_history (query, filters_json, sort_option, page, page_size, result_count) " +
|
|
"VALUES (?, ?, ?, ?, ?, ?);"
|
|
);
|
|
|
|
stmt.bind_text(1, query.query, -1, null);
|
|
stmt.bind_text(2, query.filters_json ?? "", -1, null);
|
|
stmt.bind_text(3, SearchFilters.sort_option_to_string(query.sort), -1, null);
|
|
stmt.bind_int(4, query.page);
|
|
stmt.bind_int(5, query.page_size);
|
|
stmt.bind_int(6, result_count);
|
|
|
|
stmt.step();
|
|
|
|
debug("Search recorded: %s (%d results)", query.query, result_count);
|
|
search_recorded(query, result_count);
|
|
|
|
// Clean up old entries if needed
|
|
cleanup_old_entries();
|
|
|
|
return 0; // Returns the last inserted row ID in SQLite
|
|
}
|
|
|
|
/**
|
|
* Get search history
|
|
*/
|
|
public SearchQuery[] get_history(int limit = 50) throws Error {
|
|
var queries = new GLib.List<SearchQuery?>();
|
|
|
|
var stmt = db.prepare(
|
|
"SELECT query, filters_json, sort_option, page, page_size, result_count, created_at " +
|
|
"FROM search_history " +
|
|
"ORDER BY created_at DESC " +
|
|
"LIMIT ?;"
|
|
);
|
|
|
|
stmt.bind_int(1, limit);
|
|
|
|
while (stmt.step() == Sqlite.ROW) {
|
|
var query = row_to_query(stmt);
|
|
queries.append(query);
|
|
}
|
|
|
|
return queries_to_array(queries);
|
|
}
|
|
|
|
/**
|
|
* Get recent searches (last 24 hours)
|
|
*/
|
|
public SearchQuery[] get_recent() throws Error {
|
|
var queries = new GLib.List<SearchQuery?>();
|
|
var now = new DateTime.now_local();
|
|
var yesterday = now.add_days(-1);
|
|
var threshold = yesterday.format("%Y-%m-%dT%H:%M:%S");
|
|
|
|
var stmt = db.prepare(
|
|
"SELECT query, filters_json, sort_option, page, page_size, result_count, created_at " +
|
|
"FROM search_history " +
|
|
"WHERE created_at >= ? " +
|
|
"ORDER BY created_at DESC " +
|
|
"LIMIT 20;"
|
|
);
|
|
|
|
stmt.bind_text(1, threshold, -1, null);
|
|
|
|
while (stmt.step() == Sqlite.ROW) {
|
|
var query = row_to_query(stmt);
|
|
queries.append(query);
|
|
}
|
|
|
|
return queries_to_array(queries);
|
|
}
|
|
|
|
/**
|
|
* Delete a search history entry by ID
|
|
*/
|
|
public void delete(int id) throws Error {
|
|
var stmt = db.prepare("DELETE FROM search_history WHERE id = ?;");
|
|
stmt.bind_int(1, id);
|
|
stmt.step();
|
|
|
|
debug("Search history entry deleted: %d", id);
|
|
}
|
|
|
|
/**
|
|
* Clear all search history
|
|
*/
|
|
public void clear() throws Error {
|
|
var stmt = db.prepare("DELETE FROM search_history;");
|
|
stmt.step();
|
|
|
|
debug("Search history cleared");
|
|
history_cleared();
|
|
}
|
|
|
|
/**
|
|
* Clear old search history entries
|
|
*/
|
|
private void cleanup_old_entries() throws Error {
|
|
var stmt = db.prepare(
|
|
"DELETE FROM search_history WHERE id NOT IN (" +
|
|
"SELECT id FROM search_history ORDER BY created_at DESC LIMIT ?" +
|
|
");"
|
|
);
|
|
|
|
stmt.bind_int(1, max_entries);
|
|
stmt.step();
|
|
}
|
|
|
|
/**
|
|
* Convert a database row to a SearchQuery
|
|
*/
|
|
private SearchQuery row_to_query(Sqlite.Statement stmt) {
|
|
string query_str = stmt.column_text(0);
|
|
string? filters_json = stmt.column_text(1);
|
|
string sort_str = stmt.column_text(2);
|
|
int page = stmt.column_int(3);
|
|
int page_size = stmt.column_int(4);
|
|
|
|
return SearchQuery(query_str, page, page_size, filters_json,
|
|
SearchFilters.sort_option_from_string(sort_str));
|
|
}
|
|
|
|
private SearchQuery[] queries_to_array(GLib.List<SearchQuery?> list) {
|
|
SearchQuery[] arr = {};
|
|
for (unowned var node = list; node != null; node = node.next) {
|
|
arr += node.data;
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
}
|
|
|