Skip to main content

Database

Struct Database 

Source
pub struct Database { /* private fields */ }
Expand description

Database handle for usenet-dl

Implementations§

Source§

impl Database

Source

pub async fn insert_article(&self, article: &NewArticle) -> Result<i64>

Insert a single article

Source

pub async fn insert_articles_batch(&self, articles: &[NewArticle]) -> Result<()>

Insert multiple articles in a batch (more efficient for large NZB files)

Automatically chunks the input to stay within SQLite’s bind variable limit (5 variables per article, chunked to max 199 articles per INSERT).

Source

pub async fn update_article_status( &self, article_id: i64, status: i32, ) -> Result<()>

Update article status

Source

pub async fn update_article_status_by_message_id( &self, download_id: DownloadId, message_id: &str, status: i32, ) -> Result<()>

Update article status by message_id

Source

pub async fn update_articles_status_batch( &self, updates: &[(i64, i32)], ) -> Result<()>

Update multiple article statuses in a single transaction (more efficient for batch operations)

§Arguments
  • updates - Vector of tuples containing (article_id, status)
§Performance

This method uses a CASE-WHEN statement to update multiple rows in a single query, which is significantly faster than individual UPDATE statements. With 100 updates, this can be 50-100x faster than calling update_article_status 100 times.

§Example
let updates = vec![
    (123, article_status::DOWNLOADED),
    (124, article_status::DOWNLOADED),
    (125, article_status::FAILED),
];
db.update_articles_status_batch(&updates).await?;

Update multiple article statuses in a single transaction (more efficient for batch operations)

Automatically chunks the input to stay within SQLite’s bind variable limit. Each update uses ~3-4 bind variables (article_id x3 + optional timestamp), so we chunk to max 100 updates per query.

Source

pub async fn get_articles( &self, download_id: DownloadId, ) -> Result<Vec<Article>>

Get all articles for a download

Source

pub async fn get_pending_articles( &self, download_id: DownloadId, ) -> Result<Vec<Article>>

Get pending articles for a download, excluding paused files.

Source

pub async fn get_article_by_message_id( &self, download_id: DownloadId, message_id: &str, ) -> Result<Option<Article>>

Get article by message_id

Source

pub async fn count_articles_by_status( &self, download_id: DownloadId, status: i32, ) -> Result<i64>

Count articles by status for a download

Source

pub async fn count_articles(&self, download_id: DownloadId) -> Result<i64>

Get total article count for a download

Source

pub async fn delete_articles(&self, download_id: DownloadId) -> Result<()>

Delete all articles for a download (automatic via CASCADE, but explicit method for clarity)

Source

pub async fn insert_files_batch(&self, files: &[NewDownloadFile]) -> Result<()>

Insert multiple download files in a batch

Source

pub async fn get_download_files( &self, download_id: DownloadId, ) -> Result<Vec<DownloadFile>>

Get all download files for a download

Source

pub async fn get_newly_completed_files( &self, download_id: DownloadId, ) -> Result<Vec<DownloadFile>>

Get newly completed files for DirectUnpack processing.

Returns unpaused files where completed=0 and all articles have been downloaded.

Source

pub async fn mark_file_completed( &self, download_id: DownloadId, file_index: i32, ) -> Result<()>

Mark a file as completed (all segments downloaded)

Source

pub async fn update_direct_unpack_state( &self, download_id: DownloadId, state: i32, ) -> Result<()>

Update the DirectUnpack state for a download

Source

pub async fn get_direct_unpack_state( &self, download_id: DownloadId, ) -> Result<i32>

Get the DirectUnpack state for a download

Source

pub async fn rename_download_file( &self, download_id: DownloadId, file_index: i32, new_filename: &str, ) -> Result<()>

Rename a download file (for DirectRename), storing the original filename

Source

pub async fn update_direct_unpack_extracted_count( &self, download_id: DownloadId, count: i32, ) -> Result<()>

Update the DirectUnpack extracted count for a download

Source

pub async fn get_direct_unpack_extracted_count( &self, download_id: DownloadId, ) -> Result<i32>

Get the DirectUnpack extracted count for a download

Source

pub async fn set_file_paused( &self, download_id: DownloadId, file_index: i32, paused: bool, ) -> Result<()>

Set a file’s paused state.

Source

pub async fn get_download_file( &self, download_id: DownloadId, file_index: i32, ) -> Result<Option<DownloadFile>>

Get a single download file by download and file index.

Source

pub async fn has_active_pending_articles( &self, download_id: DownloadId, ) -> Result<bool>

Return true when a download still has unpaused pending articles.

Source

pub async fn has_any_pending_articles( &self, download_id: DownloadId, ) -> Result<bool>

Return true when a download still has any pending articles, including paused files.

Source

pub async fn count_failed_articles( &self, download_id: DownloadId, ) -> Result<i64>

Count failed articles for a download

Source§

impl Database

Source

pub async fn insert_download( &self, download: &NewDownload, ) -> Result<DownloadId>

Insert a new download record

Source

pub async fn get_download(&self, id: DownloadId) -> Result<Option<Download>>

Get a download by ID

Source

pub async fn list_downloads(&self) -> Result<Vec<Download>>

List all downloads

Source

pub async fn list_downloads_by_status( &self, status: i32, ) -> Result<Vec<Download>>

List downloads with a specific status

Source

pub async fn update_status(&self, id: DownloadId, status: i32) -> Result<()>

Update download status

Source

pub async fn update_progress( &self, id: DownloadId, progress: f32, speed_bps: u64, downloaded_bytes: u64, ) -> Result<()>

Update download progress

Source

pub async fn update_priority(&self, id: DownloadId, priority: i32) -> Result<()>

Update download priority

Source

pub async fn set_error(&self, id: DownloadId, error: &str) -> Result<()>

Set download error message

Source

pub async fn set_started(&self, id: DownloadId) -> Result<()>

Set download started timestamp

Source

pub async fn set_completed(&self, id: DownloadId) -> Result<()>

Set download completed timestamp

Source

pub async fn delete_download(&self, id: DownloadId) -> Result<()>

Delete a download

Source

pub async fn get_incomplete_downloads(&self) -> Result<Vec<Download>>

Get incomplete downloads (for resume on startup)

Source

pub async fn get_all_downloads(&self) -> Result<Vec<Download>>

Get all downloads (for state persistence during shutdown)

Source§

impl Database

Source

pub async fn find_by_nzb_hash(&self, nzb_hash: &str) -> Result<Option<Download>>

Find a download by NZB hash

This is the most reliable duplicate detection method as it compares the actual NZB file content (via SHA-256 hash).

Source

pub async fn find_by_name(&self, name: &str) -> Result<Option<Download>>

Find a download by exact name match

This is useful for detecting duplicates when the NZB filename is used as the download name. Case-sensitive match.

Source

pub async fn find_by_job_name(&self, job_name: &str) -> Result<Option<Download>>

Find a download by job name

This detects duplicates using the deobfuscated job name, which catches cases where the same content is uploaded with different NZB filenames.

Source§

impl Database

Source

pub async fn insert_history(&self, entry: &NewHistoryEntry) -> Result<i64>

Insert a download into history

This is typically called when a download is completed (successfully or failed) to create a historical record separate from the active downloads table.

Source

pub async fn query_history( &self, status_filter: Option<i32>, limit: usize, offset: usize, ) -> Result<Vec<HistoryEntry>>

Query history with pagination and optional status filter

Returns history entries ordered by completion time (most recent first). Use limit and offset for pagination.

Source

pub async fn count_history(&self, status_filter: Option<i32>) -> Result<i64>

Count history entries (optionally filtered by status)

Useful for pagination - returns total count of records matching the filter.

Source

pub async fn delete_history_before(&self, before_timestamp: i64) -> Result<u64>

Delete history entries older than the specified timestamp

Returns the number of records deleted. This is useful for cleanup - e.g., delete history older than 30 days.

Source

pub async fn delete_history_by_status(&self, status: i32) -> Result<u64>

Delete history entries with a specific status

Returns the number of records deleted. This is useful for cleanup - e.g., delete all failed downloads from history.

Source

pub async fn clear_history(&self) -> Result<u64>

Clear all history

Returns the number of records deleted. This is a destructive operation - use with caution.

Source

pub async fn delete_history_filtered( &self, before_timestamp: Option<i64>, status: Option<i32>, ) -> Result<u64>

Delete history entries with optional filters

Returns the number of records deleted. Supports filtering by:

  • before_timestamp: Delete entries completed before this timestamp
  • status: Delete only entries with this status

If both filters are None, deletes all history (same as clear_history).

Source

pub async fn get_history_entry(&self, id: i64) -> Result<Option<HistoryEntry>>

Get a single history entry by ID

Source§

impl Database

Source

pub async fn new(path: &Path) -> Result<Self>

Create a new database connection

Creates the database file if it doesn’t exist and runs migrations.

Source

pub async fn close(self)

Close the database connection

Source

pub fn pool(&self) -> &SqlitePool

Get the underlying connection pool

Source§

impl Database

Source

pub async fn set_correct_password( &self, download_id: DownloadId, password: &str, ) -> Result<()>

Cache a correct password for a download

This is used after successfully extracting an archive with a password, so if the download needs to be reprocessed, we can try this password first.

Source

pub async fn get_cached_password( &self, download_id: DownloadId, ) -> Result<Option<String>>

Get the cached correct password for a download

Returns None if no password is cached for this download.

Source

pub async fn delete_cached_password( &self, download_id: DownloadId, ) -> Result<()>

Delete cached password for a download

Note: This is automatically deleted via CASCADE when the download is deleted.

Source§

impl Database

Source

pub async fn get_all_rss_feeds(&self) -> Result<Vec<RssFeed>>

Get all RSS feeds

Source

pub async fn get_rss_feed(&self, id: i64) -> Result<Option<RssFeed>>

Get RSS feed by ID

Source

pub async fn insert_rss_feed( &self, params: InsertRssFeedParams<'_>, ) -> Result<i64>

Insert a new RSS feed

Source

pub async fn update_rss_feed( &self, params: UpdateRssFeedParams<'_>, ) -> Result<bool>

Update an existing RSS feed

Source

pub async fn delete_rss_feed(&self, id: i64) -> Result<bool>

Delete an RSS feed (cascades to filters and seen items)

Source

pub async fn get_rss_filters(&self, feed_id: i64) -> Result<Vec<RssFilterRow>>

Get all filters for a specific RSS feed

Source

pub async fn insert_rss_filter( &self, params: InsertRssFilterParams<'_>, ) -> Result<i64>

Insert a new RSS filter

Source

pub async fn delete_rss_filters(&self, feed_id: i64) -> Result<()>

Delete all filters for a feed (used during update)

Source

pub async fn update_rss_feed_check_status( &self, id: i64, last_error: Option<&str>, ) -> Result<()>

Update last check time and error for an RSS feed

Source§

impl Database

Source

pub async fn was_unclean_shutdown(&self) -> Result<bool>

Check if the last shutdown was unclean

Returns true if the previous session did not call set_clean_shutdown(), indicating a crash or forced termination.

This method is called on startup to determine if state recovery is needed.

Source

pub async fn set_clean_start(&self) -> Result<()>

Mark that the application has started cleanly

This should be called during UsenetDownloader::new() to indicate that the application is running. If shutdown() is not called before the next startup, was_unclean_shutdown() will return true.

Source

pub async fn set_clean_shutdown(&self) -> Result<()>

Mark that the application is shutting down cleanly

This should be called during UsenetDownloader::shutdown() to indicate a graceful shutdown. If this is not called before the process exits, the next startup will detect an unclean shutdown.

Source

pub async fn mark_nzb_processed(&self, path: &Path) -> Result<()>

Mark an NZB file as processed

This is used by the folder watcher with WatchFolderAction::Keep to track which NZB files have already been processed to avoid re-adding them.

Source

pub async fn is_nzb_processed(&self, path: &Path) -> Result<bool>

Check if an NZB file has been processed

Source

pub async fn is_rss_item_seen(&self, feed_id: i64, guid: &str) -> Result<bool>

Check if an RSS feed item has been seen before

Source

pub async fn mark_rss_item_seen(&self, feed_id: i64, guid: &str) -> Result<()>

Mark an RSS feed item as seen

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,