use super::{AttachmentError, FileAttachment, FilesData};
pub trait HasAttachments {
fn has_one_files() -> Vec<&'static str>;
fn has_many_files() -> Vec<&'static str>;
fn all_file_relations() -> Vec<&'static str> {
let mut relations = Self::has_one_files();
relations.extend(Self::has_many_files());
relations
}
fn is_has_one_relation(relation: &str) -> bool {
Self::has_one_files().contains(&relation)
}
fn is_has_many_relation(relation: &str) -> bool {
Self::has_many_files().contains(&relation)
}
fn get_files_data(&self) -> Result<FilesData, AttachmentError>;
fn set_files_data(&mut self, data: FilesData) -> Result<(), AttachmentError>;
fn attach(&mut self, relation: &str, file_key: &str) -> Result<(), AttachmentError> {
self.attach_with_metadata(relation, FileAttachment::new(file_key))
}
fn attach_with_metadata(
&mut self,
relation: &str,
attachment: FileAttachment,
) -> Result<(), AttachmentError> {
self.validate_relation(relation)?;
let mut files = self.get_files_data()?;
if Self::is_has_one_relation(relation) {
files.set_one(relation, attachment);
} else {
files.add_many(relation, attachment);
}
self.set_files_data(files)
}
fn attach_many(&mut self, relation: &str, file_keys: Vec<&str>) -> Result<(), AttachmentError> {
if !Self::is_has_many_relation(relation) {
return Err(AttachmentError::InvalidRelation(format!(
"'{}' is not a hasMany relation, use attach() instead",
relation
)));
}
let mut files = self.get_files_data()?;
for key in file_keys {
files.add_many(relation, FileAttachment::new(key));
}
self.set_files_data(files)
}
fn detach(&mut self, relation: &str, file_key: Option<&str>) -> Result<(), AttachmentError> {
self.validate_relation(relation)?;
let mut files = self.get_files_data()?;
if Self::is_has_one_relation(relation) {
files.remove_one(relation);
} else if let Some(key) = file_key {
files.remove_from_many(relation, key);
} else {
files.clear_many(relation);
}
self.set_files_data(files)
}
fn detach_many(&mut self, relation: &str, file_keys: Vec<&str>) -> Result<(), AttachmentError> {
if !Self::is_has_many_relation(relation) {
return Err(AttachmentError::InvalidRelation(format!(
"'{}' is not a hasMany relation",
relation
)));
}
let mut files = self.get_files_data()?;
for key in file_keys {
files.remove_from_many(relation, key);
}
self.set_files_data(files)
}
fn sync(&mut self, relation: &str, file_keys: Vec<&str>) -> Result<(), AttachmentError> {
self.validate_relation(relation)?;
let mut files = self.get_files_data()?;
if Self::is_has_one_relation(relation) {
if file_keys.is_empty() {
files.remove_one(relation);
} else {
files.set_one(relation, FileAttachment::new(file_keys[0]));
}
} else {
files.clear_many(relation);
for key in file_keys {
files.add_many(relation, FileAttachment::new(key));
}
}
self.set_files_data(files)
}
fn sync_with_metadata(
&mut self,
relation: &str,
attachments: Vec<FileAttachment>,
) -> Result<(), AttachmentError> {
self.validate_relation(relation)?;
let mut files = self.get_files_data()?;
if Self::is_has_one_relation(relation) {
if attachments.is_empty() {
files.remove_one(relation);
} else if let Some(first) = attachments.into_iter().next() {
files.set_one(relation, first);
}
} else {
files.clear_many(relation);
for attachment in attachments {
files.add_many(relation, attachment);
}
}
self.set_files_data(files)
}
fn get_file(&self, relation: &str) -> Result<Option<FileAttachment>, AttachmentError> {
let files = self.get_files_data()?;
Ok(files.get_one(relation))
}
fn get_files(&self, relation: &str) -> Result<Vec<FileAttachment>, AttachmentError> {
let files = self.get_files_data()?;
Ok(files.get_many(relation))
}
fn has_files(&self, relation: &str) -> Result<bool, AttachmentError> {
let files = self.get_files_data()?;
Ok(files.has_files(relation))
}
fn count_files(&self, relation: &str) -> Result<usize, AttachmentError> {
let files = self.get_files_data()?;
Ok(files.count_files(relation))
}
fn validate_relation(&self, relation: &str) -> Result<(), AttachmentError> {
if !Self::all_file_relations().contains(&relation) {
return Err(AttachmentError::InvalidRelation(format!(
"Unknown file relation: '{}'. Available: {:?}",
relation,
Self::all_file_relations()
)));
}
Ok(())
}
}