Add storage and inimplemented file model

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent 9e5d6c9bdd
commit b22e85c77f

@ -1,18 +1,22 @@
use sea_orm::DbErr;
use thiserror::Error; use thiserror::Error;
pub type RepoResult<T> = Result<T, RepoError>; pub type RepoResult<T> = Result<T, RepoError>;
pub type RepoDatabaseResult<T> = Result<T, RepoDatabaseError>; pub type RepoDatabaseResult<T> = Result<T, RepoDatabaseError>;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum RepoError { pub enum RepoError {
#[error(transparent)] #[error(transparent)]
Db(#[from] RepoDatabaseError) Db(#[from] RepoDatabaseError),
#[error(transparent)]
Io(#[from] std::io::Error),
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum RepoDatabaseError { pub enum RepoDatabaseError {
#[error(transparent)] #[error(transparent)]
SeaOrmDb(#[from] sea_orm::error::DbErr), SeaOrmDb(#[from] sea_orm::DbErr),
#[error(transparent)] #[error(transparent)]
SeaOrmColumn(#[from] sea_orm::error::ColumnFromStrErr), SeaOrmColumn(#[from] sea_orm::error::ColumnFromStrErr),
@ -21,5 +25,11 @@ pub enum RepoDatabaseError {
Sqlx(#[from] sqlx::error::Error), Sqlx(#[from] sqlx::error::Error),
#[error(transparent)] #[error(transparent)]
SqlxMigrateError(#[from] sqlx::migrate::MigrateError) SqlxMigrateError(#[from] sqlx::migrate::MigrateError),
}
impl From<sea_orm::DbErr> for RepoError {
fn from(other: DbErr) -> Self {
Self::Db(RepoDatabaseError::from(other))
}
} }

@ -6,7 +6,7 @@ pub struct Model {
#[sea_orm(primary_key)] #[sea_orm(primary_key)]
pub id: u64, pub id: u64,
pub name: String, pub name: String,
pub path: String pub path: String,
} }
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

@ -1,14 +1,12 @@
use mediarepo_core::error::{RepoDatabaseResult}; use mediarepo_core::error::RepoDatabaseResult;
use crate::database::RepoDatabase; use sea_orm::{Database, DatabaseConnection};
use sea_orm::{DatabaseConnection, Database};
pub mod entities; pub mod entities;
/// Connects to the database, runs migrations and returns the RepoDatabase wrapper type /// Connects to the database, runs migrations and returns the RepoDatabase wrapper type
pub async fn get_database<S: AsRef<str>>(uri: S) -> RepoDatabaseResult<DatabaseConnection> { pub async fn get_database<S: AsRef<str>>(uri: S) -> RepoDatabaseResult<DatabaseConnection> {
migrate(uri.as_ref()).await?; migrate(uri.as_ref()).await?;
let conn = Database::connect(uri).await?; let conn = Database::connect(uri.as_ref()).await?;
Ok(conn) Ok(conn)
} }

File diff suppressed because it is too large Load Diff

@ -0,0 +1,24 @@
[package]
name = "mediarepo-model"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = "0.4.19"
[dependencies.mediarepo-core]
path = "../mediarepo-core"
[dependencies.mediarepo-database]
path = "../mediarepo-database"
[dependencies.sea-orm]
version = "0.2.3"
features = ["runtime-tokio-native-tls", "macros"]
default-features = false
[dependencies.tokio]
version = "1.12.0"
features = ["fs", "io-std", "io-util"]

@ -0,0 +1,9 @@
use mediarepo_database::entities::file;
use mediarepo_database::entities::file::Model as FileModel;
use sea_orm::DatabaseConnection;
use tokio::fs;
pub struct File {
db: DatabaseConnection,
model: FileModel,
}

@ -0,0 +1,2 @@
pub mod file;
pub mod storage;

@ -0,0 +1,120 @@
use mediarepo_core::error::RepoResult;
use mediarepo_database::entities::storage;
use mediarepo_database::entities::storage::ActiveModel as ActiveStorage;
use mediarepo_database::entities::storage::Model as StorageModel;
use sea_orm::prelude::*;
use sea_orm::{DatabaseConnection, Set, Unset};
use std::path::PathBuf;
use tokio::fs;
pub struct Storage {
db: DatabaseConnection,
model: StorageModel,
}
impl Storage {
fn new(db: DatabaseConnection, model: StorageModel) -> Self {
Self { db, model }
}
/// Returns the storage by id
pub async fn by_id(db: DatabaseConnection, id: u64) -> RepoResult<Option<Self>> {
if let Some(model) = storage::Entity::find_by_id(id).one(&db).await? {
let storage = Self::new(db, model);
Ok(Some(storage))
} else {
Ok(None)
}
}
pub async fn by_path<S: ToString>(db: DatabaseConnection, path: S) -> RepoResult<Option<Self>> {
if let Some(model) = storage::Entity::find()
.filter(storage::Column::Path.eq(path.to_string()))
.one(&db)
.await?
{
let storage = Self::new(db, model);
Ok(Some(storage))
} else {
Ok(None)
}
}
/// Creates a new active storage and also creates the associated directory
/// if it doesn't exist yet.
pub async fn create<S1: ToString, S2: ToString>(
db: DatabaseConnection,
name: S1,
path: S2,
) -> RepoResult<Self> {
let path = path.to_string();
let name = name.to_string();
let path_buf = PathBuf::from(&path);
if !path_buf.exists() {
fs::create_dir(path_buf).await?;
}
let storage = ActiveStorage {
id: Unset(None),
name: Set(name),
path: Set(path),
..Default::default()
};
let storage: ActiveStorage = storage.insert(&db).await?;
let storage = Self::by_id(db, storage.id.unwrap())
.await?
.expect("Inserted storage doesn't exist?!");
Ok(storage)
}
/// Returns the unique identifier of this storage
pub fn id(&self) -> u64 {
self.model.id
}
/// Returns the name of the storage
pub fn name(&self) -> &String {
&self.model.name
}
/// Returns the path of the storage
pub fn path(&self) -> &String {
&self.model.path
}
/// Sets a new name for the storage
pub async fn set_name<S: ToString>(&self, name: S) -> RepoResult<()> {
let mut active_storage: ActiveStorage = self.get_active_model();
active_storage.name = Set(name.to_string());
active_storage.update(&self.db).await?;
Ok(())
}
/// Sets a new path for the storage. This will only update the database record
/// so if the physical part of the storage is already created it needs to be migrated first
pub async fn set_path<S: ToString>(&mut self, path: S) -> RepoResult<()> {
let mut active_storage: ActiveStorage = self.get_active_model();
active_storage.path = Set(path.to_string());
let storage: ActiveStorage = active_storage.update(&self.db).await?;
self.model.path = storage.path.unwrap();
Ok(())
}
/// Checks if the storage exists on the harddrive
pub fn exists(&self) -> bool {
let path = PathBuf::from(&self.path());
path.exists()
}
/// Returns the active model with only the ID filled so saves always perform an update
fn get_active_model(&self) -> ActiveStorage {
ActiveStorage {
id: Set(self.model.id),
..Default::default()
}
}
}
Loading…
Cancel
Save