1use anyhow::Result;
11use common::database::db_context::DbContext;
12use common::entities::InlineContent;
13use common::event::EventHub;
14use common::types::EntityId;
15use common::undo_redo::UndoRedoManager;
16use std::sync::Arc;
17
18pub use common::direct_access::block::block_repository::BlockRelationshipField;
20pub use common::direct_access::document::document_repository::DocumentRelationshipField;
21pub use common::direct_access::frame::frame_repository::FrameRelationshipField;
22pub use common::direct_access::root::root_repository::RootRelationshipField;
23
24pub use common::direct_access::table::table_repository::TableRelationshipField;
25pub use common::direct_access::table_cell::table_cell_repository::TableCellRelationshipField;
26pub use direct_access::block::block_controller;
27pub use direct_access::block::dtos::{BlockRelationshipDto, CreateBlockDto, UpdateBlockDto};
28pub use direct_access::document::document_controller;
29pub use direct_access::document::dtos::CreateDocumentDto;
30pub use direct_access::frame::dtos::CreateFrameDto;
31pub use direct_access::frame::frame_controller;
32pub use direct_access::inline_element::dtos::{CreateInlineElementDto, UpdateInlineElementDto};
33pub use direct_access::inline_element::inline_element_controller;
34pub use direct_access::list::dtos::CreateListDto as CreateListEntityDto;
35pub use direct_access::list::list_controller;
36pub use direct_access::root::dtos::CreateRootDto;
37pub use direct_access::root::root_controller;
38pub use direct_access::table::dtos::{CreateTableDto, TableDto};
39pub use direct_access::table::table_controller;
40pub use direct_access::table_cell::dtos::{CreateTableCellDto, TableCellDto};
41pub use direct_access::table_cell::table_cell_controller;
42
43pub fn setup() -> Result<(DbContext, Arc<EventHub>, UndoRedoManager)> {
47 let db_context = DbContext::new()?;
48 let event_hub = Arc::new(EventHub::new());
49 let mut undo_redo_manager = UndoRedoManager::new();
50
51 let root = root_controller::create_orphan(&db_context, &event_hub, &CreateRootDto::default())?;
52
53 let _doc = document_controller::create(
54 &db_context,
55 &event_hub,
56 &mut undo_redo_manager,
57 None,
58 &CreateDocumentDto::default(),
59 root.id,
60 -1,
61 )?;
62
63 Ok((db_context, event_hub, undo_redo_manager))
64}
65
66pub fn setup_with_text(text: &str) -> Result<(DbContext, Arc<EventHub>, UndoRedoManager)> {
74 let (db_context, event_hub, mut undo_redo_manager) = setup()?;
75
76 let root_rels =
78 root_controller::get_relationship(&db_context, &1, &RootRelationshipField::Document)?;
79 let doc_id = root_rels[0];
80 let frame_ids = document_controller::get_relationship(
81 &db_context,
82 &doc_id,
83 &DocumentRelationshipField::Frames,
84 )?;
85
86 for fid in &frame_ids {
88 frame_controller::remove(&db_context, &event_hub, &mut undo_redo_manager, None, fid)?;
89 }
90
91 let frame = frame_controller::create(
93 &db_context,
94 &event_hub,
95 &mut undo_redo_manager,
96 None,
97 &CreateFrameDto::default(),
98 doc_id,
99 -1,
100 )?;
101
102 let normalized = text.replace("\r\n", "\n").replace('\r', "\n");
104 let lines: Vec<&str> = normalized.split('\n').collect();
105 let mut document_position: i64 = 0;
106 let mut total_chars: i64 = 0;
107 let mut child_order: Vec<i64> = Vec::new();
108
109 for (i, line) in lines.iter().enumerate() {
110 let line_len = line.chars().count() as i64;
111
112 let block_dto = CreateBlockDto {
113 plain_text: line.to_string(),
114 text_length: line_len,
115 document_position,
116 ..Default::default()
117 };
118
119 let block = block_controller::create(
120 &db_context,
121 &event_hub,
122 &mut undo_redo_manager,
123 None,
124 &block_dto,
125 frame.id,
126 i as i32,
127 )?;
128
129 child_order.push(block.id as i64);
130
131 let elem_dto = CreateInlineElementDto {
132 content: InlineContent::Text(line.to_string()),
133 ..Default::default()
134 };
135
136 inline_element_controller::create(
137 &db_context,
138 &event_hub,
139 &mut undo_redo_manager,
140 None,
141 &elem_dto,
142 block.id,
143 0,
144 )?;
145
146 total_chars += line_len;
147 document_position += line_len;
148 if i < lines.len() - 1 {
149 document_position += 1; }
151 }
152
153 let mut updated_frame = frame_controller::get(&db_context, &frame.id)?
155 .ok_or_else(|| anyhow::anyhow!("Frame not found"))?;
156 updated_frame.child_order = child_order;
157 frame_controller::update(
158 &db_context,
159 &event_hub,
160 &mut undo_redo_manager,
161 None,
162 &updated_frame.into(),
163 )?;
164
165 let mut doc = document_controller::get(&db_context, &doc_id)?
167 .ok_or_else(|| anyhow::anyhow!("Document not found"))?;
168 doc.character_count = total_chars;
169 doc.block_count = lines.len() as i64;
170 document_controller::update(
171 &db_context,
172 &event_hub,
173 &mut undo_redo_manager,
174 None,
175 &doc.into(),
176 )?;
177
178 undo_redo_manager.clear_all_stacks();
180
181 Ok((db_context, event_hub, undo_redo_manager))
182}
183
184pub fn export_text(db_context: &DbContext, _event_hub: &Arc<EventHub>) -> Result<String> {
187 let block_ids = get_block_ids(db_context)?;
188 let mut blocks = Vec::new();
189 for id in &block_ids {
190 if let Some(b) = block_controller::get(db_context, id)? {
191 blocks.push(b);
192 }
193 }
194 blocks.sort_by_key(|b| b.document_position);
195 let text = blocks
196 .iter()
197 .map(|b| b.plain_text.as_str())
198 .collect::<Vec<&str>>()
199 .join("\n");
200 Ok(text)
201}
202
203pub fn get_block_ids(db_context: &DbContext) -> Result<Vec<EntityId>> {
205 let root_rels =
206 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
207 let doc_id = root_rels[0];
208 let frame_ids = document_controller::get_relationship(
209 db_context,
210 &doc_id,
211 &DocumentRelationshipField::Frames,
212 )?;
213 let frame_id = frame_ids[0];
214 frame_controller::get_relationship(db_context, &frame_id, &FrameRelationshipField::Blocks)
215}
216
217pub fn get_element_ids(db_context: &DbContext, block_id: &EntityId) -> Result<Vec<EntityId>> {
219 block_controller::get_relationship(db_context, block_id, &BlockRelationshipField::Elements)
220}
221
222pub fn get_first_block_element_ids(db_context: &DbContext) -> Result<Vec<EntityId>> {
224 let block_ids = get_block_ids(db_context)?;
225 get_element_ids(db_context, &block_ids[0])
226}
227
228pub fn get_frame_id(db_context: &DbContext) -> Result<EntityId> {
230 let root_rels =
231 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
232 let doc_id = root_rels[0];
233 let frame_ids = document_controller::get_relationship(
234 db_context,
235 &doc_id,
236 &DocumentRelationshipField::Frames,
237 )?;
238 Ok(frame_ids[0])
239}
240
241pub fn get_table_ids(db_context: &DbContext) -> Result<Vec<EntityId>> {
243 let root_rels =
244 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
245 let doc_id = root_rels[0];
246 document_controller::get_relationship(db_context, &doc_id, &DocumentRelationshipField::Tables)
247}
248
249pub fn get_table_cell_ids(db_context: &DbContext, table_id: &EntityId) -> Result<Vec<EntityId>> {
251 table_controller::get_relationship(db_context, table_id, &TableRelationshipField::Cells)
252}
253
254pub fn get_sorted_cells(db_context: &DbContext, table_id: &EntityId) -> Result<Vec<TableCellDto>> {
256 let cell_ids = get_table_cell_ids(db_context, table_id)?;
257 let cells_opt = table_cell_controller::get_multi(db_context, &cell_ids)?;
258 let mut cells: Vec<TableCellDto> = cells_opt.into_iter().flatten().collect();
259 cells.sort_by(|a, b| a.row.cmp(&b.row).then(a.column.cmp(&b.column)));
260 Ok(cells)
261}
262
263pub fn get_all_block_ids(db_context: &DbContext) -> Result<Vec<EntityId>> {
265 let root_rels =
266 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
267 let doc_id = root_rels[0];
268 let frame_ids = document_controller::get_relationship(
269 db_context,
270 &doc_id,
271 &DocumentRelationshipField::Frames,
272 )?;
273 let mut all_block_ids = Vec::new();
274 for fid in &frame_ids {
275 let block_ids =
276 frame_controller::get_relationship(db_context, fid, &FrameRelationshipField::Blocks)?;
277 all_block_ids.extend(block_ids);
278 }
279 Ok(all_block_ids)
280}
281
282pub struct BasicStats {
284 pub character_count: i64,
285 pub block_count: i64,
286 pub frame_count: i64,
287}
288
289pub fn get_document_stats(db_context: &DbContext) -> Result<BasicStats> {
291 let root_rels =
292 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
293 let doc_id = root_rels[0];
294 let doc = document_controller::get(db_context, &doc_id)?
295 .ok_or_else(|| anyhow::anyhow!("Document not found"))?;
296 let frame_ids = document_controller::get_relationship(
297 db_context,
298 &doc_id,
299 &DocumentRelationshipField::Frames,
300 )?;
301 Ok(BasicStats {
302 character_count: doc.character_count,
303 block_count: doc.block_count,
304 frame_count: frame_ids.len() as i64,
305 })
306}
307
308pub struct InsertTableResult {
314 pub table_id: EntityId,
315}
316
317pub fn insert_table(
322 db_context: &DbContext,
323 event_hub: &Arc<EventHub>,
324 undo_redo_manager: &mut UndoRedoManager,
325 position: i64,
326 rows: i64,
327 columns: i64,
328) -> Result<InsertTableResult> {
329 let doc_id = get_doc_id(db_context)?;
330
331 let table = table_controller::create(
333 db_context,
334 event_hub,
335 undo_redo_manager,
336 None,
337 &CreateTableDto {
338 rows,
339 columns,
340 ..Default::default()
341 },
342 doc_id,
343 -1,
344 )?;
345
346 let table_size = rows * columns;
347 let mut cell_blocks: Vec<EntityId> = Vec::new();
348
349 for r in 0..rows {
350 for c in 0..columns {
351 let cell_frame = frame_controller::create(
353 db_context,
354 event_hub,
355 undo_redo_manager,
356 None,
357 &CreateFrameDto::default(),
358 doc_id,
359 -1,
360 )?;
361
362 let block = block_controller::create(
364 db_context,
365 event_hub,
366 undo_redo_manager,
367 None,
368 &CreateBlockDto::default(),
369 cell_frame.id,
370 0,
371 )?;
372
373 inline_element_controller::create(
375 db_context,
376 event_hub,
377 undo_redo_manager,
378 None,
379 &CreateInlineElementDto {
380 content: InlineContent::Empty,
381 ..Default::default()
382 },
383 block.id,
384 0,
385 )?;
386
387 table_cell_controller::create(
389 db_context,
390 event_hub,
391 undo_redo_manager,
392 None,
393 &CreateTableCellDto {
394 row: r,
395 column: c,
396 row_span: 1,
397 column_span: 1,
398 cell_frame: Some(cell_frame.id),
399 ..Default::default()
400 },
401 table.id,
402 -1,
403 )?;
404
405 cell_blocks.push(block.id);
406 }
407 }
408
409 let mut current_pos = position;
411 for &bid in &cell_blocks {
412 let mut b = block_controller::get(db_context, &bid)?
413 .ok_or_else(|| anyhow::anyhow!("Block not found"))?;
414 b.document_position = current_pos;
415 block_controller::update(db_context, event_hub, undo_redo_manager, None, &b.into())?;
416 current_pos += 1;
417 }
418
419 let all_bids = get_all_block_ids(db_context)?;
421 for bid in &all_bids {
422 if cell_blocks.contains(bid) {
423 continue;
424 }
425 let b = block_controller::get(db_context, bid)?
426 .ok_or_else(|| anyhow::anyhow!("Block not found"))?;
427 if b.document_position >= position {
428 let mut updated = b.clone();
429 updated.document_position += table_size;
430 block_controller::update(
431 db_context,
432 event_hub,
433 undo_redo_manager,
434 None,
435 &updated.into(),
436 )?;
437 }
438 }
439
440 undo_redo_manager.clear_all_stacks();
441 Ok(InsertTableResult { table_id: table.id })
442}
443
444pub struct CreateListResult {
445 pub list_id: EntityId,
446}
447
448pub fn create_list(
450 db_context: &DbContext,
451 event_hub: &Arc<EventHub>,
452 undo_redo_manager: &mut UndoRedoManager,
453 position: i64,
454 anchor: i64,
455 style: common::entities::ListStyle,
456) -> Result<CreateListResult> {
457 let doc_id = get_doc_id(db_context)?;
458 let sel_start = std::cmp::min(position, anchor);
459 let sel_end = std::cmp::max(position, anchor);
460
461 let list = list_controller::create(
462 db_context,
463 event_hub,
464 undo_redo_manager,
465 None,
466 &CreateListEntityDto {
467 style,
468 ..Default::default()
469 },
470 doc_id,
471 -1,
472 )?;
473
474 let all_bids = get_all_block_ids(db_context)?;
476 for bid in &all_bids {
477 let b = block_controller::get(db_context, bid)?
478 .ok_or_else(|| anyhow::anyhow!("Block not found"))?;
479 let block_start = b.document_position;
480 let block_end = block_start + b.text_length;
481 if block_end >= sel_start && block_start <= sel_end {
482 block_controller::set_relationship(
483 db_context,
484 event_hub,
485 undo_redo_manager,
486 None,
487 &BlockRelationshipDto {
488 id: b.id,
489 field: BlockRelationshipField::List,
490 right_ids: vec![list.id],
491 },
492 )?;
493 }
494 }
495
496 undo_redo_manager.clear_all_stacks();
497 Ok(CreateListResult { list_id: list.id })
498}
499
500pub struct InsertImageResult {
501 pub new_position: i64,
502 pub element_id: EntityId,
503}
504
505pub fn insert_image(
509 db_context: &DbContext,
510 event_hub: &Arc<EventHub>,
511 undo_redo_manager: &mut UndoRedoManager,
512 position: i64,
513 image_name: &str,
514 width: i64,
515 height: i64,
516) -> Result<InsertImageResult> {
517 let all_bids = get_all_block_ids(db_context)?;
519 let mut blocks = Vec::new();
520 for bid in &all_bids {
521 blocks.push(
522 block_controller::get(db_context, bid)?
523 .ok_or_else(|| anyhow::anyhow!("Block not found"))?,
524 );
525 }
526 blocks.sort_by_key(|b| b.document_position);
527
528 let (target_block, offset) = blocks
529 .iter()
530 .find_map(|b| {
531 let s = b.document_position;
532 let e = s + b.text_length;
533 if position >= s && position <= e {
534 Some((b.clone(), (position - s) as usize))
535 } else {
536 None
537 }
538 })
539 .ok_or_else(|| anyhow::anyhow!("No block at position {}", position))?;
540
541 let elem_ids = block_controller::get_relationship(
543 db_context,
544 &target_block.id,
545 &BlockRelationshipField::Elements,
546 )?;
547
548 let mut running = 0usize;
549 let mut insert_after_idx: i32 = -1;
550 for (idx, eid) in elem_ids.iter().enumerate() {
551 let elem = inline_element_controller::get(db_context, eid)?
552 .ok_or_else(|| anyhow::anyhow!("Element not found"))?;
553 let elen = match &elem.content {
554 InlineContent::Text(s) => s.chars().count(),
555 InlineContent::Image { .. } => 1,
556 InlineContent::Empty => 0,
557 };
558
559 if running + elen > offset && offset > running {
560 if let InlineContent::Text(ref text) = elem.content {
562 let chars: Vec<char> = text.chars().collect();
563 let local = offset - running;
564 let before: String = chars[..local].iter().collect();
565 let after: String = chars[local..].iter().collect();
566
567 let mut upd: UpdateInlineElementDto = elem.clone().into();
569 upd.content = InlineContent::Text(before);
570 inline_element_controller::update(
571 db_context,
572 event_hub,
573 undo_redo_manager,
574 None,
575 &upd,
576 )?;
577
578 let after_entity: common::entities::InlineElement = elem.clone().into();
580 let mut after_create = CreateInlineElementDto::from(after_entity);
581 after_create.content = InlineContent::Text(after);
582 inline_element_controller::create(
583 db_context,
584 event_hub,
585 undo_redo_manager,
586 None,
587 &after_create,
588 target_block.id,
589 (idx as i32) + 1,
590 )?;
591 }
592 insert_after_idx = (idx as i32) + 1;
593 break;
594 }
595 running += elen;
596 if running >= offset {
597 insert_after_idx = (idx as i32) + 1;
598 break;
599 }
600 }
601 if insert_after_idx < 0 {
602 insert_after_idx = elem_ids.len() as i32;
603 }
604
605 let img = inline_element_controller::create(
607 db_context,
608 event_hub,
609 undo_redo_manager,
610 None,
611 &CreateInlineElementDto {
612 content: InlineContent::Image {
613 name: image_name.to_string(),
614 width,
615 height,
616 quality: 100,
617 },
618 ..Default::default()
619 },
620 target_block.id,
621 insert_after_idx,
622 )?;
623
624 let mut upd_block = target_block.clone();
626 upd_block.text_length += 1;
627 block_controller::update(
628 db_context,
629 event_hub,
630 undo_redo_manager,
631 None,
632 &upd_block.into(),
633 )?;
634
635 for b in &blocks {
636 if b.id != target_block.id && b.document_position > target_block.document_position {
637 let mut shifted = b.clone();
638 shifted.document_position += 1;
639 block_controller::update(
640 db_context,
641 event_hub,
642 undo_redo_manager,
643 None,
644 &shifted.into(),
645 )?;
646 }
647 }
648
649 undo_redo_manager.clear_all_stacks();
650 Ok(InsertImageResult {
651 new_position: position + 1,
652 element_id: img.id,
653 })
654}
655
656pub struct InsertFrameResult {
657 pub frame_id: EntityId,
658}
659
660pub fn insert_frame(
665 db_context: &DbContext,
666 event_hub: &Arc<EventHub>,
667 undo_redo_manager: &mut UndoRedoManager,
668 position: i64,
669) -> Result<InsertFrameResult> {
670 let doc_id = get_doc_id(db_context)?;
671
672 let new_frame = frame_controller::create(
673 db_context,
674 event_hub,
675 undo_redo_manager,
676 None,
677 &CreateFrameDto::default(),
678 doc_id,
679 -1,
680 )?;
681
682 let block = block_controller::create(
683 db_context,
684 event_hub,
685 undo_redo_manager,
686 None,
687 &CreateBlockDto {
688 document_position: position,
689 ..Default::default()
690 },
691 new_frame.id,
692 0,
693 )?;
694
695 inline_element_controller::create(
696 db_context,
697 event_hub,
698 undo_redo_manager,
699 None,
700 &CreateInlineElementDto {
701 content: InlineContent::Empty,
702 ..Default::default()
703 },
704 block.id,
705 0,
706 )?;
707
708 undo_redo_manager.clear_all_stacks();
709 Ok(InsertFrameResult {
710 frame_id: new_frame.id,
711 })
712}
713
714fn get_doc_id(db_context: &DbContext) -> Result<EntityId> {
715 let root_rels =
716 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
717 Ok(root_rels[0])
718}