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
50
Cargo.lock
generated
50
Cargo.lock
generated
@ -201,6 +201,7 @@ dependencies = [
|
||||
"r2d2_sqlite",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"time",
|
||||
]
|
||||
@ -452,6 +453,16 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
@ -464,6 +475,12 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.30"
|
||||
@ -887,9 +904,15 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "little-hesinde"
|
||||
version = "0.2.1"
|
||||
version = "0.2.3"
|
||||
dependencies = [
|
||||
"calibre-db",
|
||||
"clap",
|
||||
@ -1435,6 +1458,19 @@ version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.17"
|
||||
@ -1657,6 +1693,18 @@ dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tera"
|
||||
version = "1.19.1"
|
||||
|
@ -19,5 +19,6 @@ FROM scratch
|
||||
COPY --from=builder /app /app
|
||||
CMD ["/app", "--listen-address", "[::]:3000", "--", "/library"]
|
||||
|
||||
ENV TMPDIR=/
|
||||
VOLUME ["/library"]
|
||||
EXPOSE 3000
|
||||
|
@ -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(())
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "little-hesinde"
|
||||
version = "0.2.1"
|
||||
version = "0.2.3"
|
||||
edition = "2021"
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
|
@ -76,7 +76,7 @@ pub mod opds {
|
||||
pub mod templates;
|
||||
|
||||
pub const APP_NAME: &str = "little-hesinde";
|
||||
pub const VERSION: &str = "0.2.1";
|
||||
pub const VERSION: &str = "0.2.3";
|
||||
|
||||
/// Internal marker data in lieu of a proper `Accept` header.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
Loading…
Reference in New Issue
Block a user