use super::{
dtos::{CreateFrameDto, FrameDto, UpdateFrameDto},
units_of_work::{FrameReadUoWFactory, FrameWriteUoWFactory},
};
use crate::FrameRelationshipDto;
use anyhow::{Ok, Result};
use common::direct_access::frame::FrameRelationshipField;
use common::direct_access::use_cases;
use common::undo_redo::UndoRedoManager;
use common::{database::db_context::DbContext, event::EventHub, types::EntityId};
use std::sync::Arc;
pub fn create_orphan(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
entity: &CreateFrameDto,
) -> Result<FrameDto> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let mut uc = use_cases::UndoableCreateOrphanUseCase::new(uow_factory);
let entity_in: common::entities::Frame = entity.into();
let result = uc.execute(&entity_in)?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(result.into())
}
pub fn create_orphan_multi(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
entities: &[CreateFrameDto],
) -> Result<Vec<FrameDto>> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let entities_in: Vec<common::entities::Frame> = entities.iter().map(|dto| dto.into()).collect();
let mut uc = use_cases::UndoableCreateOrphanUseCase::new(uow_factory);
let result = uc.execute_multi(&entities_in)?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(result.into_iter().map(|e| e.into()).collect())
}
pub fn create(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
entity: &CreateFrameDto,
owner_id: EntityId,
index: i32,
) -> Result<FrameDto> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let entity_in: common::entities::Frame = entity.into();
let strategy = use_cases::OwnerStrategy::Appending;
let mut uc = use_cases::UndoableCreateUseCase::new(uow_factory, strategy);
let result = uc.execute(&entity_in, owner_id, index)?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(result.into())
}
pub fn create_multi(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
entities: &[CreateFrameDto],
owner_id: EntityId,
index: i32,
) -> Result<Vec<FrameDto>> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let entities_in: Vec<common::entities::Frame> = entities.iter().map(|dto| dto.into()).collect();
let strategy = use_cases::OwnerStrategy::Appending;
let mut uc = use_cases::UndoableCreateUseCase::new(uow_factory, strategy);
let result = uc.execute_multi(&entities_in, owner_id, index)?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(result.into_iter().map(|e| e.into()).collect())
}
pub fn get(db_context: &DbContext, id: &EntityId) -> Result<Option<FrameDto>> {
let uow_factory = FrameReadUoWFactory::new(db_context);
let uc = use_cases::GetUseCase::new(uow_factory);
Ok(uc.execute(id)?.map(|e| e.into()))
}
pub fn get_all(db_context: &DbContext) -> Result<Vec<FrameDto>> {
let uow_factory = FrameReadUoWFactory::new(db_context);
let uc = use_cases::GetUseCase::new(uow_factory);
Ok(uc.execute_all()?.into_iter().map(|e| e.into()).collect())
}
pub fn get_multi(db_context: &DbContext, ids: &[EntityId]) -> Result<Vec<Option<FrameDto>>> {
let uow_factory = FrameReadUoWFactory::new(db_context);
let uc = use_cases::GetUseCase::new(uow_factory);
Ok(uc
.execute_multi(ids)?
.into_iter()
.map(|o| o.map(|e| e.into()))
.collect())
}
pub fn update(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
entity: &UpdateFrameDto,
) -> Result<FrameDto> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let entity_in: common::entities::Frame = entity.into();
let mut uc = use_cases::UndoableUpdateUseCase::new(uow_factory);
let result = uc.execute(&entity_in)?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(result.into())
}
pub fn update_multi(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
entities: &[UpdateFrameDto],
) -> Result<Vec<FrameDto>> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let entities_in: Vec<common::entities::Frame> = entities.iter().map(|dto| dto.into()).collect();
let mut uc = use_cases::UndoableUpdateUseCase::new(uow_factory);
let result = uc.execute_multi(&entities_in)?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(result.into_iter().map(|e| e.into()).collect())
}
pub fn update_with_relationships(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
entity: &FrameDto,
) -> Result<FrameDto> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let entity_in: common::entities::Frame = entity.into();
let mut uc = use_cases::UndoableUpdateWithRelationshipsUseCase::new(uow_factory);
let result = uc.execute(&entity_in)?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(result.into())
}
pub fn update_with_relationships_multi(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
entities: &[FrameDto],
) -> Result<Vec<FrameDto>> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let entities_in: Vec<common::entities::Frame> = entities.iter().map(|dto| dto.into()).collect();
let mut uc = use_cases::UndoableUpdateWithRelationshipsUseCase::new(uow_factory);
let result = uc.execute_multi(&entities_in)?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(result.into_iter().map(|e| e.into()).collect())
}
pub fn remove(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
id: &EntityId,
) -> Result<()> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let mut uc = use_cases::UndoableRemoveUseCase::new(uow_factory);
uc.execute(id)?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(())
}
pub fn remove_multi(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
ids: &[EntityId],
) -> Result<()> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let mut uc = use_cases::UndoableRemoveUseCase::new(uow_factory);
uc.execute_multi(ids)?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(())
}
pub fn get_relationship(
db_context: &DbContext,
id: &EntityId,
field: &FrameRelationshipField,
) -> Result<Vec<EntityId>> {
let uow_factory = FrameReadUoWFactory::new(db_context);
let uc = use_cases::GetRelationshipUseCase::<FrameRelationshipField, _>::new(uow_factory);
uc.execute(id, field)
}
pub fn get_relationship_many(
db_context: &DbContext,
ids: &[EntityId],
field: &FrameRelationshipField,
) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>> {
let uow_factory = FrameReadUoWFactory::new(db_context);
let uc = use_cases::GetRelationshipManyUseCase::<FrameRelationshipField, _>::new(uow_factory);
uc.execute(ids, field)
}
pub fn get_relationship_count(
db_context: &DbContext,
id: &EntityId,
field: &FrameRelationshipField,
) -> Result<usize> {
let uow_factory = FrameReadUoWFactory::new(db_context);
let uc = use_cases::GetRelationshipCountUseCase::<FrameRelationshipField, _>::new(uow_factory);
uc.execute(id, field)
}
pub fn get_relationship_in_range(
db_context: &DbContext,
id: &EntityId,
field: &FrameRelationshipField,
offset: usize,
limit: usize,
) -> Result<Vec<EntityId>> {
let uow_factory = FrameReadUoWFactory::new(db_context);
let uc =
use_cases::GetRelationshipInRangeUseCase::<FrameRelationshipField, _>::new(uow_factory);
uc.execute(id, field, offset, limit)
}
pub fn set_relationship(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
dto: &FrameRelationshipDto,
) -> Result<()> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let mut uc =
use_cases::UndoableSetRelationshipUseCase::<FrameRelationshipField, _>::new(uow_factory);
uc.execute(&dto.id, &dto.field, dto.right_ids.as_slice())?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(())
}
pub fn move_relationship(
db_context: &DbContext,
event_hub: &Arc<EventHub>,
undo_redo_manager: &mut UndoRedoManager,
stack_id: Option<u64>,
id: &EntityId,
field: &FrameRelationshipField,
ids_to_move: &[EntityId],
new_index: i32,
) -> Result<Vec<EntityId>> {
let uow_factory = FrameWriteUoWFactory::new(db_context, event_hub);
let mut uc =
use_cases::UndoableMoveRelationshipUseCase::<FrameRelationshipField, _>::new(uow_factory);
let result = uc.execute(id, field, ids_to_move, new_index)?;
undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
Ok(result)
}
#[cfg(test)]
mod tests {
#![allow(dead_code)]
#![allow(unused_imports)]
use super::*;
use crate::document::document_controller;
use crate::document::dtos::CreateDocumentDto;
use crate::root::dtos::CreateRootDto;
use crate::root::root_controller;
use common::database::db_context::DbContext;
use common::event::EventHub;
use common::types::EntityId;
use common::undo_redo::UndoRedoManager;
use std::sync::Arc;
struct TestContext {
db: DbContext,
hub: Arc<EventHub>,
undo: UndoRedoManager,
}
impl TestContext {
fn new() -> Self {
let db = DbContext::new().expect("Failed to create in-memory DB");
let hub = Arc::new(EventHub::new());
let mut undo = UndoRedoManager::new();
undo.set_event_hub(&hub);
TestContext { db, hub, undo }
}
}
fn create_owner_chain(ctx: &mut TestContext) -> EntityId {
let root =
root_controller::create_orphan(&ctx.db, &ctx.hub, &CreateRootDto::default()).unwrap();
let document = document_controller::create(
&ctx.db,
&ctx.hub,
&mut ctx.undo,
None,
&CreateDocumentDto::default(),
root.id,
-1,
)
.unwrap();
document.id
}
fn create_one(ctx: &mut TestContext) -> FrameDto {
create_orphan(
&ctx.db,
&ctx.hub,
&mut ctx.undo,
None,
&CreateFrameDto::default(),
)
.unwrap()
}
#[test]
fn test_create_orphan_and_get() {
let mut ctx = TestContext::new();
let created = create_one(&mut ctx);
assert!(created.id > 0);
let fetched = get(&ctx.db, &created.id).unwrap();
assert!(fetched.is_some());
assert_eq!(fetched.unwrap().id, created.id);
}
#[test]
fn test_get_nonexistent() {
let ctx = TestContext::new();
assert!(get(&ctx.db, &999999).unwrap().is_none());
}
#[test]
fn test_get_all() {
let mut ctx = TestContext::new();
create_one(&mut ctx);
let all = get_all(&ctx.db).unwrap();
assert!(!all.is_empty());
}
#[test]
fn test_get_multi() {
let mut ctx = TestContext::new();
let a = create_one(&mut ctx);
let results = get_multi(&ctx.db, &[a.id, 999999]).unwrap();
assert_eq!(results.len(), 2);
assert!(results[0].is_some());
assert!(results[1].is_none());
}
#[test]
fn test_update() {
let mut ctx = TestContext::new();
let created = create_one(&mut ctx);
let update_dto: UpdateFrameDto = created.into();
let updated = update(&ctx.db, &ctx.hub, &mut ctx.undo, None, &update_dto).unwrap();
assert_eq!(updated.id, update_dto.id);
}
#[test]
fn test_remove() {
let mut ctx = TestContext::new();
let created = create_one(&mut ctx);
remove(&ctx.db, &ctx.hub, &mut ctx.undo, None, &created.id).unwrap();
assert!(get(&ctx.db, &created.id).unwrap().is_none());
}
#[test]
fn test_remove_multi() {
let mut ctx = TestContext::new();
let a = create_one(&mut ctx);
remove_multi(&ctx.db, &ctx.hub, &mut ctx.undo, None, &[a.id]).unwrap();
assert!(get(&ctx.db, &a.id).unwrap().is_none());
}
#[test]
fn test_create_with_owner() {
let mut ctx = TestContext::new();
let owner_id = create_owner_chain(&mut ctx);
let created = create(
&ctx.db,
&ctx.hub,
&mut ctx.undo,
None,
&CreateFrameDto::default(),
owner_id,
-1,
)
.unwrap();
assert!(created.id > 0);
let fetched = get(&ctx.db, &created.id).unwrap();
assert!(fetched.is_some());
}
#[test]
fn test_create_orphan_undo() {
let mut ctx = TestContext::new();
let created = create_one(&mut ctx);
assert!(get(&ctx.db, &created.id).unwrap().is_some());
ctx.undo.undo(None).unwrap();
assert!(get(&ctx.db, &created.id).unwrap().is_none());
}
#[test]
fn test_remove_undo() {
let mut ctx = TestContext::new();
let created = create_one(&mut ctx);
remove(&ctx.db, &ctx.hub, &mut ctx.undo, None, &created.id).unwrap();
assert!(get(&ctx.db, &created.id).unwrap().is_none());
ctx.undo.undo(None).unwrap();
assert!(get(&ctx.db, &created.id).unwrap().is_some());
}
#[test]
fn test_get_relationship_empty() {
let mut ctx = TestContext::new();
let created = create_one(&mut ctx);
let rel_ids =
get_relationship(&ctx.db, &created.id, &FrameRelationshipField::Blocks).unwrap();
assert!(rel_ids.is_empty());
}
#[test]
fn test_get_relationship_count_zero() {
let mut ctx = TestContext::new();
let created = create_one(&mut ctx);
let count =
get_relationship_count(&ctx.db, &created.id, &FrameRelationshipField::Blocks).unwrap();
assert_eq!(count, 0);
}
}