SeaORM: items and read state
The item list, its counts, filters, sorts and search, positions, pins and mark-all-read move to SeaORM, as SQL written for both databases: - Parameters are gathered as the SQL is written (Args), so only what a statement uses is bound. rusqlite needed every one mentioned, hence the old `?1 IS NULL` and `?2 = ''`; Postgres refuses a parameter it cannot type. - Yes/no columns are tested as booleans (NOT coalesce(s.read, false)) and written as true, not 1; SQLite reads true and false as 1 and 0. - The last tiebreak of the sort is the guid, not SQLite's rowid, which Postgres lacks. Only items with the same date change places. - set_position names entry_state.duration beside excluded.duration. - The status callback on the control socket returns a future, as the counts are now a query. Checked on a copy of production against the live server: 42 of 48 lists identical; the other six differ only in how ties fall, or because the test daemon cleared paths to files this machine does not have. Run on the same file, every filter's count matches the old SQL exactly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -176,7 +176,9 @@ pub async fn daemon_is_live(path: &Path) -> bool {
|
||||
/// healthcheck left waiting behind a scan or a long download timed out and called a busy daemon
|
||||
/// dead. The answer goes to the client that asked and no one else: broadcast, it ended any
|
||||
/// `ipx fetch` that was watching a scan, since `status` is a terminal event.
|
||||
pub type StatusFn = std::sync::Arc<dyn Fn() -> Event + Send + Sync>;
|
||||
/// A future, since reading the counts is a database query.
|
||||
pub type StatusFn =
|
||||
std::sync::Arc<dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = Event> + Send>> + Send + Sync>;
|
||||
|
||||
/// Accepts connections, feeding commands to `cmds` and events from `events` back out.
|
||||
pub async fn serve(
|
||||
@@ -249,7 +251,7 @@ async fn handle(
|
||||
// Answered here, not queued behind whatever the worker is on: see StatusFn.
|
||||
Ok(Command::Status) => {
|
||||
tracing::info!(target: "ipx::io", "-> {line}");
|
||||
let ev = status();
|
||||
let ev = status().await;
|
||||
if let Ok(json) = serde_json::to_string(&ev) {
|
||||
tracing::info!(target: "ipx::io", "<- {json}");
|
||||
}
|
||||
@@ -366,7 +368,8 @@ mod tests {
|
||||
// Another client, watching a scan: it must not be handed someone else's answer, which
|
||||
// would end its session.
|
||||
let mut watcher = events.subscribe();
|
||||
let status: StatusFn = std::sync::Arc::new(|| Event::Status { feeds: 1, pending: 2, downloaded: 3 });
|
||||
let status: StatusFn =
|
||||
std::sync::Arc::new(|| Box::pin(async { Event::Status { feeds: 1, pending: 2, downloaded: 3 } }));
|
||||
let (client, server) = UnixStream::pair().unwrap();
|
||||
tokio::spawn(handle(server, events.subscribe(), cmds, status));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user