Skip to content

Commit

Permalink
refactor(common): improve database trait api
Browse files Browse the repository at this point in the history
  • Loading branch information
heat1q committed Oct 27, 2023
1 parent ccb586f commit 56e2b08
Show file tree
Hide file tree
Showing 14 changed files with 358 additions and 402 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ path = "src/lib.rs"
doctest = false

[dependencies]
anyhow.workspace = true
async-trait.workspace = true
axum.workspace = true
http.workspace = true
Expand Down
50 changes: 19 additions & 31 deletions crates/common/src/database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

use std::sync::Arc;

use anyhow::Result;
use async_trait::async_trait;
use std::error::Error;
use time::OffsetDateTime;

use crate::auth::user::User;
Expand All @@ -30,57 +32,43 @@ pub mod reference;
pub mod tag;
pub mod user;

pub type ArcDynDatabase = Arc<dyn Database + Send + Sync>;

#[async_trait]
pub trait Database {
/// Initialize the database and run required migrations
async fn setup(&mut self) -> Result<(), Box<dyn Error>>;

/// List registered user accounts
async fn get_users(&self) -> Result<Vec<User>, Box<dyn Error>>;
async fn get_users(&self) -> Result<Vec<User>>;

/// Create a new user account
async fn create_user(&self, user: &User) -> Result<(), Box<dyn Error>>;
async fn create_user(&self, user: &User) -> Result<()>;

/// Get user by user_id
async fn get_user(&self, user_id: &str) -> Result<User, Box<dyn Error>>;
async fn get_user(&self, user_id: &str) -> Result<User>;

/// Partial update a single user account
async fn update_email(&self, email: &str, user_id: &str) -> Result<(), Box<dyn Error>>;
async fn update_nickname(&self, nickname: &str) -> Result<(), Box<dyn Error>>;
async fn update_names(
&self,
firstname: &str,
lastname: &str,
user_id: &str,
) -> Result<(), Box<dyn Error>>;
async fn update_email(&self, email: &str, user_id: &str) -> Result<()>;
async fn update_nickname(&self, nickname: &str) -> Result<()>;
async fn update_names(&self, firstname: &str, lastname: &str, user_id: &str) -> Result<()>;

async fn disable_user(&self, user_id: &str) -> Result<(), Box<dyn Error>>;
async fn enable_user(&self, user_id: &str) -> Result<(), Box<dyn Error>>;
async fn disable_user(&self, user_id: &str) -> Result<()>;
async fn enable_user(&self, user_id: &str) -> Result<()>;

async fn get_media_items(&self, user_id: &str) -> Result<Vec<MediaItem>, Box<dyn Error>>;
async fn get_media_items(&self, user_id: &str) -> Result<Vec<MediaItem>>;
async fn create_media_item(
&self,
user_id: &str,
name: &str,
date_taken: OffsetDateTime,
) -> Result<String, Box<dyn Error>>;
async fn get_media_item(&self, media_id: &str) -> Result<MediaItem, Box<dyn Error>>;
) -> Result<String>;
async fn get_media_item(&self, media_id: &str) -> Result<MediaItem>;
async fn add_reference(
&self,
user_id: &str,
media_id: &str,
reference: &Reference,
) -> Result<String, Box<dyn Error>>;
) -> Result<String>;

async fn update_reference(
&self,
reference_id: &str,
reference: &Reference,
) -> Result<(), Box<dyn Error>>;
async fn update_reference(&self, reference_id: &str, reference: &Reference) -> Result<()>;

async fn remove_reference(
&self,
media_id: &str,
reference_id: &str,
) -> Result<(), Box<dyn Error>>;
async fn remove_reference(&self, media_id: &str, reference_id: &str) -> Result<()>;
}
17 changes: 7 additions & 10 deletions crates/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
//! This crate offers shared data models for [Photos.network](https://photos.network) core application.
//!

use std::collections::HashMap;
use std::{collections::HashMap, sync::Arc};

use axum::Router;
use config::configuration::Configuration;
use database::Database;
use database::ArcDynDatabase;
use photos_network_plugin::{PluginFactoryRef, PluginId};

pub mod auth;
Expand All @@ -35,18 +35,15 @@ pub mod model {

/// Aggregates the applications configuration, its loaded plugins and the router for all REST APIs
#[derive(Clone)]
pub struct ApplicationState<D> {
pub config: Configuration,
pub struct ApplicationState {
pub config: Arc<Configuration>,
pub plugins: HashMap<PluginId, PluginFactoryRef>,
pub router: Option<Router>,
pub database: D,
pub database: ArcDynDatabase,
}

impl<D> ApplicationState<D>
where
D: Database,
{
pub fn new(config: Configuration, database: D) -> Self {
impl ApplicationState {
pub fn new(config: Arc<Configuration>, database: ArcDynDatabase) -> Self {
Self {
config,
plugins: HashMap::new(),
Expand Down
1 change: 1 addition & 0 deletions crates/database/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ path = "src/lib.rs"
doctest = false

[dependencies]
anyhow.workspace = true
common.workspace = true
async-trait.workspace = true
tracing.workspace = true
Expand Down
79 changes: 31 additions & 48 deletions crates/database/src/postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

//! This crate offers a database abstraction for [Photos.network](https://photos.network) core application.
//!
use anyhow::Result;
use async_trait::async_trait;
use common::auth::user::User;
use common::database::media_item::MediaItem;
Expand All @@ -25,7 +26,6 @@ use common::database::Database;
use sqlx::types::time::OffsetDateTime;
use sqlx::PgPool;
use sqlx::Row;
use std::error::Error;
use tracing::info;
use uuid::Uuid;

Expand All @@ -35,23 +35,19 @@ pub struct PostgresDatabase {
}

impl PostgresDatabase {
pub async fn new(db_url: &str) -> Self {
let pool = PgPool::connect(db_url).await.unwrap();
pub async fn new(db_url: &str) -> Result<Self> {
let pool = PgPool::connect(db_url).await?;

PostgresDatabase { pool }
// run migrations from `migrations` directory
sqlx::migrate!("./migrations").run(&pool).await?;

Ok(PostgresDatabase { pool })
}
}

#[async_trait]
impl Database for PostgresDatabase {
async fn setup(&mut self) -> Result<(), Box<dyn Error>> {
// run migrations from `migrations` directory
sqlx::migrate!("./migrations").run(&self.pool).await?;

Ok(())
}

async fn get_users(&self) -> Result<Vec<User>, Box<dyn Error>> {
async fn get_users(&self) -> Result<Vec<User>> {
let query = "SELECT uuid, email, password, lastname, firstname FROM users";

let res = sqlx::query(query);
Expand All @@ -76,7 +72,7 @@ impl Database for PostgresDatabase {
Ok(users)
}

async fn create_user(&self, user: &User) -> Result<(), Box<dyn Error>> {
async fn create_user(&self, user: &User) -> Result<()> {
let query = "INSERT INTO users (uuid, email, password, lastname, firstname) VALUES ($1, $2, $3, $4, $5)";
let id = Uuid::new_v4().hyphenated().to_string();
info!("create new user with id `{}`.", id);
Expand All @@ -92,11 +88,11 @@ impl Database for PostgresDatabase {
Ok(())
}

async fn get_user(&self, _user_id: &str) -> Result<User, Box<dyn Error>> {
Err("Not implemented".into())
async fn get_user(&self, _user_id: &str) -> Result<User> {
unimplemented!()
}

async fn update_email(&self, email: &str, user_id: &str) -> Result<(), Box<dyn Error>> {
async fn update_email(&self, email: &str, user_id: &str) -> Result<()> {
let query = "UPDATE users SET email = $1 WHERE uuid = $2";

sqlx::query(query)
Expand All @@ -108,28 +104,23 @@ impl Database for PostgresDatabase {
Ok(())
}

async fn update_nickname(&self, _nickname: &str) -> Result<(), Box<dyn Error>> {
Err("Not implemented".into())
async fn update_nickname(&self, _nickname: &str) -> Result<()> {
unimplemented!()
}

async fn update_names(
&self,
_firstname: &str,
_lastname: &str,
_user_id: &str,
) -> Result<(), Box<dyn Error>> {
Err("Not implemented".into())
async fn update_names(&self, _firstname: &str, _lastname: &str, _user_id: &str) -> Result<()> {
unimplemented!()
}

async fn disable_user(&self, _user_id: &str) -> Result<(), Box<dyn Error>> {
Err("Not implemented".into())
async fn disable_user(&self, _user_id: &str) -> Result<()> {
unimplemented!()
}
async fn enable_user(&self, _user_id: &str) -> Result<(), Box<dyn Error>> {
Err("Not implemented".into())
async fn enable_user(&self, _user_id: &str) -> Result<()> {
unimplemented!()
}

async fn get_media_items(&self, _user_id: &str) -> Result<Vec<MediaItem>, Box<dyn Error>> {
Err("Not implemented".into())
async fn get_media_items(&self, _user_id: &str) -> Result<Vec<MediaItem>> {
unimplemented!()
}

/// Creates a new media item if it doesn't exist and returns the media_id
Expand All @@ -138,7 +129,7 @@ impl Database for PostgresDatabase {
user_id: &str,
name: &str,
date_taken: OffsetDateTime,
) -> Result<String, Box<dyn Error>> {
) -> Result<String> {
let query = "SELECT COUNT(*) FROM media WHERE owner is $1 and taken_at like $2";
let res = sqlx::query(query).bind(user_id).bind(date_taken);
let rows = res.fetch_all(&self.pool).await?;
Expand All @@ -164,31 +155,23 @@ impl Database for PostgresDatabase {

Ok("".to_string())
}
async fn get_media_item(&self, _media_id: &str) -> Result<MediaItem, Box<dyn Error>> {
Err("Not implemented".into())
async fn get_media_item(&self, _media_id: &str) -> Result<MediaItem> {
unimplemented!()
}
async fn add_reference(
&self,
_user_id: &str,
_media_id: &str,
_reference: &Reference,
) -> Result<String, Box<dyn Error>> {
Err("Not implemented".into())
) -> Result<String> {
unimplemented!()
}

async fn update_reference(
&self,
_reference_id: &str,
_reference: &Reference,
) -> Result<(), Box<dyn Error>> {
Err("Not implemented".into())
async fn update_reference(&self, _reference_id: &str, _reference: &Reference) -> Result<()> {
unimplemented!()
}

async fn remove_reference(
&self,
_media_id: &str,
_reference_id: &str,
) -> Result<(), Box<dyn Error>> {
Err("Not implemented".into())
async fn remove_reference(&self, _media_id: &str, _reference_id: &str) -> Result<()> {
unimplemented!()
}
}
Loading

0 comments on commit 56e2b08

Please sign in to comment.