search database has to be a file, as in-memory dbs are per connection
Some checks failed
Build Multiarch Container Image / call-reusable-workflow (push) Has been cancelled
Some checks failed
Build Multiarch Container Image / call-reusable-workflow (push) Has been cancelled
This commit is contained in:
parent
97cf9db9ff
commit
b8ed5b1cdf
7 changed files with 72 additions and 7 deletions
|
@ -12,5 +12,6 @@ r2d2 = "0.8.10"
|
|||
r2d2_sqlite = "0.24.0"
|
||||
rusqlite = { version = "0.31.0", features = ["bundled", "time"] }
|
||||
serde = { workspace = true }
|
||||
tempfile = "3.10.1"
|
||||
thiserror = { workspace = true }
|
||||
time = { workspace = true }
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
//! Error handling for calibre database access.
|
||||
|
||||
use std::io;
|
||||
|
||||
use tempfile::PersistError;
|
||||
use thiserror::Error;
|
||||
use time::error::Parse;
|
||||
|
||||
|
@ -16,9 +19,15 @@ pub enum DataStoreError {
|
|||
/// Error connecting to the database.
|
||||
#[error("connection error")]
|
||||
ConnectionError(#[from] r2d2::Error),
|
||||
/// Error wparsing a datetime from the database.
|
||||
/// Error parsing a datetime from the database.
|
||||
#[error("failed to parse datetime")]
|
||||
DateTimeError(#[from] Parse),
|
||||
/// Error creating the search database.
|
||||
#[error("failed to create search database")]
|
||||
SearchDbError(#[from] io::Error),
|
||||
/// Error marking the search database as persistent.
|
||||
#[error("failed to persist search database")]
|
||||
PersistSearchDbError(#[from] PersistError),
|
||||
}
|
||||
|
||||
/// Convert an SQLite error into a proper NoResults one if the query
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
//! Provide search funcitonality for calibre.
|
||||
//!
|
||||
//! Because the calibre database can not be disturbed (it is treated as read-only)
|
||||
//! it attaches an in-memory database and inserts the relevant data into a
|
||||
//! it attaches a temporary database and inserts the relevant data into a
|
||||
//! virtual table leveraging fts5 (https://www.sqlite.org/fts5.html). Full-text search is run on
|
||||
//! that virtual table.
|
||||
|
||||
use r2d2::{Pool, PooledConnection};
|
||||
use r2d2_sqlite::SqliteConnectionManager;
|
||||
use rusqlite::named_params;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
use crate::data::{book::Book, error::DataStoreError};
|
||||
|
||||
|
@ -31,11 +32,16 @@ const SEARCH_INIT_QUERY: &str = "INSERT INTO search.fts(book_id, data)
|
|||
LEFT JOIN main.series AS s ON b2s.series = s.id
|
||||
GROUP BY b.id";
|
||||
|
||||
/// Attach the fts in-memory database to the read-only calibre database.
|
||||
/// Attach the fts temporary database to the read-only calibre database.
|
||||
pub(crate) fn attach(pool: &Pool<SqliteConnectionManager>) -> Result<(), DataStoreError> {
|
||||
let conn = pool.get()?;
|
||||
let tmpfile = NamedTempFile::new()?;
|
||||
let (_, path) = tmpfile.keep()?;
|
||||
|
||||
conn.execute("ATTACH DATABASE ':memory:' AS search", [])?;
|
||||
conn.execute(
|
||||
&format!("ATTACH DATABASE '{}' AS search", path.to_string_lossy()),
|
||||
[],
|
||||
)?;
|
||||
init(&conn)?;
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue