use crate::blob::{BlobId, MediaType};
use crate::core::Instant;
use crate::user::{UserId, UserIdRef};
use async_trait::async_trait;
use auto_impl::auto_impl;
use etwin_core::types::AnyError;
use etwin_core::{declare_new_string, declare_new_uuid};
#[cfg(feature = "serde")]
use etwin_serde_tools::{Deserialize, Serialize};
declare_new_uuid! {
pub struct DriveId(Uuid);
pub type ParseError = DriveIdParseError;
const SQL_NAME = "drive_id";
}
declare_new_uuid! {
pub struct FileId(Uuid);
pub type ParseError = FileIdParseError;
const SQL_NAME = "file_id";
}
declare_new_uuid! {
pub struct DirectoryId(Uuid);
pub type ParseError = DirectoryIdParseError;
const SQL_NAME = "directory_id";
}
declare_new_uuid! {
pub struct DriveItemId(Uuid);
pub type ParseError = DriveItemIdParseError;
const SQL_NAME = "drive_item_id";
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "Directory"))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DirectoryIdRef {
pub id: DirectoryId,
}
declare_new_string! {
pub struct DriveItemDisplayName(String);
pub type ParseError = DriveItemDisplayNameParseError;
const PATTERN = r"^\S.{0,99}$";
const SQL_NAME = "drive_item_display_name";
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "Drive"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Drive {
pub id: DriveId,
pub owner: UserIdRef,
pub root: DirectoryIdRef,
pub created_at: Instant,
pub updated_at: Instant,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "File"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct File {
pub id: FileId,
pub display_name: DriveItemDisplayName,
pub byte_size: u32,
pub media_type: MediaType,
pub created_at: Instant,
pub updated_at: Instant,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "Directory"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Directory {
pub id: DirectoryId,
pub display_name: DriveItemDisplayName,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub children: Option<Vec<DriveItem>>,
pub created_at: Instant,
pub updated_at: Instant,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(untagged))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DriveItem {
Directory(Directory),
File(File),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GetDriveOptions {
pub id: DriveId,
}
#[derive(Debug, thiserror::Error)]
pub enum GetDriveError {
#[error("Failed to find drive: {:?}", .0)]
NotFound(DriveId),
#[error(transparent)]
Other(#[from] AnyError),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GetDriveByOwnerOptions {
pub id: UserId,
}
#[derive(Debug, thiserror::Error)]
pub enum GetDriveByOwnerError {
#[error("Failed to find user drive, user not found: {:?}", .0)]
NotFound(UserId),
#[error(transparent)]
Other(#[from] AnyError),
}
impl GetDriveByOwnerError {
pub fn other<E>(e: E) -> Self
where
E: ::std::error::Error + Send + Sync + 'static,
{
Self::Other(Box::new(e))
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GetItemByPathOptions {
pub drive: DriveId,
pub path: Vec<DriveItemDisplayName>,
}
#[derive(Debug, thiserror::Error)]
pub enum GetItemByPathError {
#[error("Failed to find drive, user not found: {:?}", .0)]
NotFound(DriveId),
#[error(transparent)]
Other(#[from] AnyError),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GetDirectoryOptions {
pub id: DirectoryId,
}
#[derive(Debug, thiserror::Error)]
pub enum GetDirectoryError {
#[error("Failed to find directory: {:?}", .0)]
NotFound(DirectoryId),
#[error(transparent)]
Other(#[from] AnyError),
}
#[derive(Debug, thiserror::Error)]
pub enum GetDirectoryChildrenError {
#[error("Failed to find directory: {:?}", .0)]
NotFound(DirectoryId),
#[error(transparent)]
Other(#[from] AnyError),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GetFileOptions {
pub id: FileId,
}
#[derive(Debug, thiserror::Error)]
pub enum GetFileError {
#[error("Failed to find file: {:?}", .0)]
NotFound(FileId),
#[error(transparent)]
Other(#[from] AnyError),
}
#[derive(Debug, thiserror::Error)]
pub enum GetFileDataError {
#[error("Failed to find file: {:?}", .0)]
NotFound(FileId),
#[error(transparent)]
Other(#[from] AnyError),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CreateFileOptions {
pub parent_id: DirectoryId,
pub blob_id: BlobId,
pub display_name: DriveItemDisplayName,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CreateStoreFileOptions {
pub parent_id: DirectoryId,
pub blob_id: BlobId,
pub display_name: DriveItemDisplayName,
pub check_owner: Option<UserId>,
}
#[derive(Debug, thiserror::Error)]
pub enum CreateFileError {
#[error("Failed to find parent directory")]
ParentNotFound,
#[error("Failed to create as current user is not the drive owner")]
NotOwner,
#[error(transparent)]
Other(#[from] AnyError),
}
impl CreateFileError {
pub fn other<E>(e: E) -> Self
where
E: ::std::error::Error + Send + Sync + 'static,
{
Self::Other(Box::new(e))
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CreateDirectoryOptions {
pub parent_id: DirectoryId,
pub display_name: DriveItemDisplayName,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CreateStoreDirectoryOptions {
pub parent_id: DirectoryId,
pub display_name: DriveItemDisplayName,
pub check_owner: Option<UserId>,
}
#[derive(Debug, thiserror::Error)]
pub enum CreateDirectoryError {
#[error("Failed to find parent directory")]
ParentNotFound,
#[error("Failed to create as current user is not the drive owner")]
NotOwner,
#[error(transparent)]
Other(#[from] AnyError),
}
impl CreateDirectoryError {
pub fn other<E>(e: E) -> Self
where
E: ::std::error::Error + Send + Sync + 'static,
{
Self::Other(Box::new(e))
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeleteItemOptions {
pub id: DriveItemId,
}
#[derive(Debug, thiserror::Error)]
pub enum DeleteItemError {
#[error("Failed to find node to delete: {:?}", .0)]
NotFound(DriveItemId),
#[error(transparent)]
Other(#[from] AnyError),
}
#[async_trait]
#[auto_impl(&, Arc)]
pub trait FileStore: Send + Sync {
async fn get_drive(&self, options: &GetDriveOptions) -> Result<Drive, GetDriveError>;
async fn get_drive_by_owner(&self, options: &GetDriveByOwnerOptions) -> Result<Drive, GetDriveByOwnerError>;
async fn get_item_by_path(&self, options: &GetItemByPathOptions) -> Result<DriveItem, GetItemByPathError>;
async fn create_directory(&self, options: &CreateStoreDirectoryOptions) -> Result<Directory, CreateDirectoryError>;
async fn get_directory(&self, options: &GetDirectoryOptions) -> Result<Directory, GetDirectoryError>;
async fn get_directory_children(
&self,
options: &GetDirectoryOptions,
) -> Result<Vec<DriveItem>, GetDirectoryChildrenError>;
async fn create_file(&self, options: &CreateStoreFileOptions) -> Result<File, CreateFileError>;
async fn get_file(&self, options: &GetFileOptions) -> Result<File, GetFileError>;
async fn get_file_data(&self, options: &GetFileOptions) -> Result<Vec<u8>, GetFileDataError>;
async fn delete_item(&self, options: &DeleteItemOptions) -> Result<(), DeleteItemError>;
}