Document in the DoD that data-model structs (domain models, query row types, DTOs/views) belong in a crate's models.rs rather than the file that produces/consumes them, once used outside that function - matching the existing crates/core/src/models.rs pattern. Component- local structs (Props, Styles, context) are exempt. Apply it to db: move RankedArticleRow out of articles.rs into a new crates/db/src/models.rs.
53 lines
2 KiB
Rust
53 lines
2 KiB
Rust
mod affinities;
|
|
mod articles;
|
|
mod feeds;
|
|
mod models;
|
|
mod reading_events;
|
|
|
|
pub use models::RankedArticleRow;
|
|
pub(crate) mod schema;
|
|
|
|
use anyhow::Result;
|
|
use diesel::prelude::*;
|
|
use diesel::sqlite::SqliteConnection;
|
|
use diesel_async::pooled_connection::bb8::Pool;
|
|
use diesel_async::pooled_connection::AsyncDieselConnectionManager;
|
|
use diesel_async::sync_connection_wrapper::SyncConnectionWrapper;
|
|
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
|
|
|
|
const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations");
|
|
|
|
/// SQLite has no native async driver, so `diesel-async` wraps a blocking
|
|
/// `SqliteConnection` and runs it on a blocking thread under the hood.
|
|
type AsyncSqliteConnection = SyncConnectionWrapper<SqliteConnection>;
|
|
|
|
#[derive(Clone)]
|
|
pub struct Db {
|
|
pool: Pool<AsyncSqliteConnection>,
|
|
}
|
|
|
|
impl Db {
|
|
/// `database_url` is a plain SQLite file path (e.g. "feedsignal.db"),
|
|
/// created if it doesn't exist. Everything lives in one file, no
|
|
/// separate database server to run.
|
|
pub async fn connect(database_url: &str) -> Result<Self> {
|
|
// `MigrationHarness` only works on a synchronous `Connection`, and
|
|
// this only runs once at boot, so open a throwaway sync connection
|
|
// just for it rather than pulling migrations through the async pool.
|
|
// Each pending migration runs in its own transaction (SQLite
|
|
// supports transactional DDL), and `down.sql` gives each one a
|
|
// matching revert.
|
|
let url = database_url.to_string();
|
|
tokio::task::spawn_blocking(move || -> Result<()> {
|
|
let mut conn = SqliteConnection::establish(&url)?;
|
|
conn.run_pending_migrations(MIGRATIONS)
|
|
.map_err(|e| anyhow::anyhow!(e))?;
|
|
Ok(())
|
|
})
|
|
.await??;
|
|
|
|
let manager = AsyncDieselConnectionManager::<AsyncSqliteConnection>::new(database_url);
|
|
let pool = Pool::builder().max_size(5).build(manager).await?;
|
|
Ok(Self { pool })
|
|
}
|
|
}
|