use crate::objects::id::TypedId;
use crate::objects::object::ObjectScope;
use sqrite::connection::Connection;
pub mod blueprint;
pub mod blueprint_folder;
pub mod entity;
pub mod entity_folder;
pub mod id;
pub mod property;
pub mod property_folder;
pub mod property_settings;
pub(crate) mod folder;
pub(crate) mod object;
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct ExpiredConnectionError;
impl std::fmt::Display for ExpiredConnectionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::error::Error for ExpiredConnectionError {}
#[derive(thiserror::Error, Debug)]
pub enum FromObjectScopeError {
#[error("{0} scope cannot be constructed from scope {1}")]
InvalidScope(&'static str, ObjectScope),
}
#[derive(thiserror::Error, Debug)]
pub enum FromIdError {
#[error("{0} cannot be constructed from id {1}")]
InvalidId(&'static str, TypedId),
}
pub trait FromId {
fn from_id(conn: std::rc::Rc<Connection>, id: TypedId) -> Result<Self, FromIdError>
where
Self: Sized;
}
pub trait ToObject {
fn to_object(&self) -> object::Object
where
Self: Sized;
}
#[macro_export]
macro_rules! define_object {
($name:ident, $folder:ident, $scope:ident, $err:ident) => {
#[derive(Clone)]
pub struct $name {
pub(crate) conn: std::rc::Weak<Connection>,
pub(crate) id: TypedId,
}
impl std::cmp::PartialOrd for $name {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.id.partial_cmp(&other.id)
}
}
impl std::cmp::Ord for $name {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.id.cmp(&other.id)
}
}
impl std::hash::Hash for $name {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::hash::Hash::hash(&self.id, state)
}
}
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.id)
}
}
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.id)
}
}
impl std::cmp::PartialEq<$name> for $name {
fn eq(&self, other: &$name) -> bool {
other.id() == self.id()
}
}
impl std::cmp::PartialEq<$name> for &$name {
fn eq(&self, other: &$name) -> bool {
other.id() == self.id()
}
}
impl std::cmp::PartialEq<$name> for Object {
fn eq(&self, other: &$name) -> bool {
other.id() == self.id()
}
}
impl std::cmp::PartialEq<$name> for &Object {
fn eq(&self, other: &$name) -> bool {
other.id() == self.id()
}
}
impl std::cmp::Eq for $name {}
impl crate::objects::FromId for $name {
fn from_id(
conn: std::rc::Rc<Connection>,
id: TypedId,
) -> Result<Self, crate::objects::FromIdError> {
if id.get_object_type() != ObjectType::$name {
Err(crate::objects::FromIdError::InvalidId(
stringify!($name),
id,
))
} else {
Ok(Self {
id,
conn: std::rc::Rc::downgrade(&conn),
})
}
}
}
impl crate::objects::ToObject for $name {
fn to_object(&self) -> crate::objects::object::Object {
Object::$name(self.clone())
}
}
impl $name {
pub fn to_object(&self) -> Object {
Object::$name(self.clone())
}
pub(crate) fn id(&self) -> TypedId {
self.id
}
pub fn conn(
&self,
) -> Result<std::rc::Rc<Connection>, crate::objects::ExpiredConnectionError> {
self.conn
.upgrade()
.ok_or(crate::objects::ExpiredConnectionError)
}
}
impl $name {
#[instrument(level = Level::INFO)]
pub fn delete(self) -> Result<(), $err> {
crate::args::validate::validate_object_exists(self.to_object())?;
Ok(object_delete(self.to_object())?)
}
#[instrument(level = Level::DEBUG)]
pub fn exists(&self) -> Result<bool, $err> {
Ok(object_exists(self.to_object())?)
}
#[instrument(level = Level::DEBUG)]
pub fn location(&self) -> Result<crate::types::location::Location<$folder>, $err> {
crate::args::validate::validate_object_exists(self.to_object())?;
Ok(object_location::<$folder>(self.to_object())?)
}
#[instrument(level = Level::INFO)]
pub fn set_location(
&mut self,
target_folder: Option<$folder>,
target_position: FolderPosition,
) -> Result<(), $err> {
crate::args::validate::validate_object_exists(self.to_object())?;
Ok(object_set_location(
self.to_object(),
target_folder.map(|v| v.to_folder()),
target_position,
)?)
}
#[instrument(level = Level::DEBUG)]
pub fn name(&self) -> Result<String, $err> {
crate::args::validate::validate_object_exists(self.to_object())?;
Ok(object_name(self.to_object())?)
}
#[instrument(level = Level::INFO, skip(new_name), fields(new_name = new_name.as_ref()))]
pub fn set_name(&mut self, new_name: impl AsRef<str>) -> Result<(), $err> {
crate::args::validate::validate_object_exists(self.to_object())?;
crate::args::validate::validate_string_not_blank(&new_name)?;
Ok(object_set_name(self.to_object(), new_name)?)
}
#[instrument(level = Level::DEBUG)]
pub fn information(&self) -> Result<String, $err> {
crate::args::validate::validate_object_exists(self.to_object())?;
Ok(object_information(self.to_object())?)
}
#[instrument(level = Level::INFO, skip(new_information))]
pub fn set_information(
&mut self,
new_information: impl AsRef<str>,
) -> Result<(), $err> {
crate::args::validate::validate_object_exists(self.to_object())?;
Ok(object_set_information(self.to_object(), new_information)?)
}
#[instrument(level = Level::DEBUG)]
pub fn scope(&self) -> Result<$scope, $err> {
crate::args::validate::validate_object_exists(self.to_object())?;
Ok($scope::from_object_scope(object_get_scope(
self.to_object(),
)?)?)
}
}
};
}
#[macro_export]
macro_rules! define_folder_funcs_impl {
($name:ident, $obj:ident, $err:ident) => {
impl $name {
pub fn to_folder(&self) -> Folder {
Folder::$name(self.clone())
}
pub fn from_folder(folder: &Folder) -> Result<$name, $err> {
match &folder {
Folder::$name(v) => Ok(v.clone()),
_ => Err($err::InvalidFolder(folder.clone())),
}
}
}
impl $name {
#[instrument(level = Level::DEBUG)]
pub fn get_children(&self) -> Result<Vec<$obj>, $err> {
crate::args::validate::validate_object_exists(self.to_object())?;
Ok(folder_get_children(
self.conn()?.clone(),
FolderOrScope::Folder(self.to_folder()),
)?)
}
#[instrument(level = Level::DEBUG)]
pub fn get_children_count(&self) -> Result<usize, $err> {
crate::args::validate::validate_object_exists(self.to_object())?;
Ok(folder_get_children_count(
self.conn()?.clone(),
FolderOrScope::Folder(self.to_folder()),
)?)
}
}
};
}
#[macro_export]
macro_rules! define_folder_funcs {
($name:ident, $obj:ident, Value $scope:expr, $err:ident) => {
impl $name {
#[instrument(level = Level::INFO, skip(conn, name, information), fields(name = name.as_ref()))]
pub fn new(
conn: Rc<Connection>,
parent_folder: Option<&$name>,
position: FolderPosition,
name: impl AsRef<str>,
information: impl AsRef<str>,
) -> Result<Self, $err> {
crate::args::validate::validate_string_not_blank(&name)?;
let folder = folder_create(
conn.clone(),
$scope,
ObjectType::$name,
parent_folder.map(|v| v.to_folder()),
position,
name,
information,
)?;
Ok($name {
id: folder,
conn: Rc::downgrade(&conn),
})
}
}
crate::define_folder_funcs_impl!($name, $obj, $err);
};
($name:ident, $obj:ident, Type $scope:ty, $err:ident) => {
impl $name {
#[instrument(level = Level::INFO, skip(conn, name, information), fields(name = name.as_ref()))]
pub fn new(
conn: Rc<Connection>,
scope: $scope,
parent_folder: Option<&$name>,
position: FolderPosition,
name: impl AsRef<str>,
information: impl AsRef<str>,
) -> Result<Self, $err> {
crate::args::validate::validate_string_not_blank(&name)?;
let folder = folder_create(
conn.clone(),
scope.to_object_scope(),
ObjectType::$name,
parent_folder.map(|v| v.to_folder()),
position,
name,
information,
)?;
Ok($name {
id: folder,
conn: Rc::downgrade(&conn),
})
}
}
crate::define_folder_funcs_impl!($name, $obj, $err);
};
}