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
108 for (i, line) in lines.iter().enumerate() {
109 let line_len = line.chars().count() as i64;
110
111 let block_dto = CreateBlockDto {
112 plain_text: line.to_string(),
113 text_length: line_len,
114 document_position,
115 ..Default::default()
116 };
117
118 let block = block_controller::create(
119 &db_context,
120 &event_hub,
121 &mut undo_redo_manager,
122 None,
123 &block_dto,
124 frame.id,
125 i as i32,
126 )?;
127
128 let elem_dto = CreateInlineElementDto {
129 content: InlineContent::Text(line.to_string()),
130 ..Default::default()
131 };
132
133 inline_element_controller::create(
134 &db_context,
135 &event_hub,
136 &mut undo_redo_manager,
137 None,
138 &elem_dto,
139 block.id,
140 0,
141 )?;
142
143 total_chars += line_len;
144 document_position += line_len;
145 if i < lines.len() - 1 {
146 document_position += 1; }
148 }
149
150 let mut doc = document_controller::get(&db_context, &doc_id)?
152 .ok_or_else(|| anyhow::anyhow!("Document not found"))?;
153 doc.character_count = total_chars;
154 doc.block_count = lines.len() as i64;
155 document_controller::update(
156 &db_context,
157 &event_hub,
158 &mut undo_redo_manager,
159 None,
160 &doc.into(),
161 )?;
162
163 undo_redo_manager.clear_all_stacks();
165
166 Ok((db_context, event_hub, undo_redo_manager))
167}
168
169pub fn export_text(db_context: &DbContext, _event_hub: &Arc<EventHub>) -> Result<String> {
172 let block_ids = get_block_ids(db_context)?;
173 let mut blocks = Vec::new();
174 for id in &block_ids {
175 if let Some(b) = block_controller::get(db_context, id)? {
176 blocks.push(b);
177 }
178 }
179 blocks.sort_by_key(|b| b.document_position);
180 let text = blocks
181 .iter()
182 .map(|b| b.plain_text.as_str())
183 .collect::<Vec<&str>>()
184 .join("\n");
185 Ok(text)
186}
187
188pub fn get_block_ids(db_context: &DbContext) -> Result<Vec<EntityId>> {
190 let root_rels =
191 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
192 let doc_id = root_rels[0];
193 let frame_ids = document_controller::get_relationship(
194 db_context,
195 &doc_id,
196 &DocumentRelationshipField::Frames,
197 )?;
198 let frame_id = frame_ids[0];
199 frame_controller::get_relationship(db_context, &frame_id, &FrameRelationshipField::Blocks)
200}
201
202pub fn get_element_ids(db_context: &DbContext, block_id: &EntityId) -> Result<Vec<EntityId>> {
204 block_controller::get_relationship(db_context, block_id, &BlockRelationshipField::Elements)
205}
206
207pub fn get_first_block_element_ids(db_context: &DbContext) -> Result<Vec<EntityId>> {
209 let block_ids = get_block_ids(db_context)?;
210 get_element_ids(db_context, &block_ids[0])
211}
212
213pub fn get_frame_id(db_context: &DbContext) -> Result<EntityId> {
215 let root_rels =
216 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
217 let doc_id = root_rels[0];
218 let frame_ids = document_controller::get_relationship(
219 db_context,
220 &doc_id,
221 &DocumentRelationshipField::Frames,
222 )?;
223 Ok(frame_ids[0])
224}
225
226pub fn get_table_ids(db_context: &DbContext) -> Result<Vec<EntityId>> {
228 let root_rels =
229 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
230 let doc_id = root_rels[0];
231 document_controller::get_relationship(db_context, &doc_id, &DocumentRelationshipField::Tables)
232}
233
234pub fn get_table_cell_ids(db_context: &DbContext, table_id: &EntityId) -> Result<Vec<EntityId>> {
236 table_controller::get_relationship(db_context, table_id, &TableRelationshipField::Cells)
237}
238
239pub fn get_sorted_cells(db_context: &DbContext, table_id: &EntityId) -> Result<Vec<TableCellDto>> {
241 let cell_ids = get_table_cell_ids(db_context, table_id)?;
242 let cells_opt = table_cell_controller::get_multi(db_context, &cell_ids)?;
243 let mut cells: Vec<TableCellDto> = cells_opt.into_iter().flatten().collect();
244 cells.sort_by(|a, b| a.row.cmp(&b.row).then(a.column.cmp(&b.column)));
245 Ok(cells)
246}
247
248pub fn get_all_block_ids(db_context: &DbContext) -> Result<Vec<EntityId>> {
250 let root_rels =
251 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
252 let doc_id = root_rels[0];
253 let frame_ids = document_controller::get_relationship(
254 db_context,
255 &doc_id,
256 &DocumentRelationshipField::Frames,
257 )?;
258 let mut all_block_ids = Vec::new();
259 for fid in &frame_ids {
260 let block_ids =
261 frame_controller::get_relationship(db_context, fid, &FrameRelationshipField::Blocks)?;
262 all_block_ids.extend(block_ids);
263 }
264 Ok(all_block_ids)
265}
266
267pub struct BasicStats {
269 pub character_count: i64,
270 pub block_count: i64,
271 pub frame_count: i64,
272}
273
274pub fn get_document_stats(db_context: &DbContext) -> Result<BasicStats> {
276 let root_rels =
277 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
278 let doc_id = root_rels[0];
279 let doc = document_controller::get(db_context, &doc_id)?
280 .ok_or_else(|| anyhow::anyhow!("Document not found"))?;
281 let frame_ids = document_controller::get_relationship(
282 db_context,
283 &doc_id,
284 &DocumentRelationshipField::Frames,
285 )?;
286 Ok(BasicStats {
287 character_count: doc.character_count,
288 block_count: doc.block_count,
289 frame_count: frame_ids.len() as i64,
290 })
291}
292
293pub struct InsertTableResult {
299 pub table_id: EntityId,
300}
301
302pub fn insert_table(
307 db_context: &DbContext,
308 event_hub: &Arc<EventHub>,
309 undo_redo_manager: &mut UndoRedoManager,
310 position: i64,
311 rows: i64,
312 columns: i64,
313) -> Result<InsertTableResult> {
314 let doc_id = get_doc_id(db_context)?;
315
316 let table = table_controller::create(
318 db_context,
319 event_hub,
320 undo_redo_manager,
321 None,
322 &CreateTableDto {
323 rows,
324 columns,
325 ..Default::default()
326 },
327 doc_id,
328 -1,
329 )?;
330
331 let table_size = rows * columns;
332 let mut cell_blocks: Vec<EntityId> = Vec::new();
333
334 for r in 0..rows {
335 for c in 0..columns {
336 let cell_frame = frame_controller::create(
338 db_context,
339 event_hub,
340 undo_redo_manager,
341 None,
342 &CreateFrameDto::default(),
343 doc_id,
344 -1,
345 )?;
346
347 let block = block_controller::create(
349 db_context,
350 event_hub,
351 undo_redo_manager,
352 None,
353 &CreateBlockDto::default(),
354 cell_frame.id,
355 0,
356 )?;
357
358 inline_element_controller::create(
360 db_context,
361 event_hub,
362 undo_redo_manager,
363 None,
364 &CreateInlineElementDto {
365 content: InlineContent::Empty,
366 ..Default::default()
367 },
368 block.id,
369 0,
370 )?;
371
372 table_cell_controller::create(
374 db_context,
375 event_hub,
376 undo_redo_manager,
377 None,
378 &CreateTableCellDto {
379 row: r,
380 column: c,
381 row_span: 1,
382 column_span: 1,
383 cell_frame: Some(cell_frame.id),
384 ..Default::default()
385 },
386 table.id,
387 -1,
388 )?;
389
390 cell_blocks.push(block.id);
391 }
392 }
393
394 let mut current_pos = position;
396 for &bid in &cell_blocks {
397 let mut b = block_controller::get(db_context, &bid)?
398 .ok_or_else(|| anyhow::anyhow!("Block not found"))?;
399 b.document_position = current_pos;
400 block_controller::update(db_context, event_hub, undo_redo_manager, None, &b.into())?;
401 current_pos += 1;
402 }
403
404 let all_bids = get_all_block_ids(db_context)?;
406 for bid in &all_bids {
407 if cell_blocks.contains(bid) {
408 continue;
409 }
410 let b = block_controller::get(db_context, bid)?
411 .ok_or_else(|| anyhow::anyhow!("Block not found"))?;
412 if b.document_position >= position {
413 let mut updated = b.clone();
414 updated.document_position += table_size;
415 block_controller::update(
416 db_context,
417 event_hub,
418 undo_redo_manager,
419 None,
420 &updated.into(),
421 )?;
422 }
423 }
424
425 undo_redo_manager.clear_all_stacks();
426 Ok(InsertTableResult { table_id: table.id })
427}
428
429pub struct CreateListResult {
430 pub list_id: EntityId,
431}
432
433pub fn create_list(
435 db_context: &DbContext,
436 event_hub: &Arc<EventHub>,
437 undo_redo_manager: &mut UndoRedoManager,
438 position: i64,
439 anchor: i64,
440 style: common::entities::ListStyle,
441) -> Result<CreateListResult> {
442 let doc_id = get_doc_id(db_context)?;
443 let sel_start = std::cmp::min(position, anchor);
444 let sel_end = std::cmp::max(position, anchor);
445
446 let list = list_controller::create(
447 db_context,
448 event_hub,
449 undo_redo_manager,
450 None,
451 &CreateListEntityDto {
452 style,
453 ..Default::default()
454 },
455 doc_id,
456 -1,
457 )?;
458
459 let all_bids = get_all_block_ids(db_context)?;
461 for bid in &all_bids {
462 let b = block_controller::get(db_context, bid)?
463 .ok_or_else(|| anyhow::anyhow!("Block not found"))?;
464 let block_start = b.document_position;
465 let block_end = block_start + b.text_length;
466 if block_end >= sel_start && block_start <= sel_end {
467 block_controller::set_relationship(
468 db_context,
469 event_hub,
470 undo_redo_manager,
471 None,
472 &BlockRelationshipDto {
473 id: b.id,
474 field: BlockRelationshipField::List,
475 right_ids: vec![list.id],
476 },
477 )?;
478 }
479 }
480
481 undo_redo_manager.clear_all_stacks();
482 Ok(CreateListResult { list_id: list.id })
483}
484
485pub struct InsertImageResult {
486 pub new_position: i64,
487 pub element_id: EntityId,
488}
489
490pub fn insert_image(
494 db_context: &DbContext,
495 event_hub: &Arc<EventHub>,
496 undo_redo_manager: &mut UndoRedoManager,
497 position: i64,
498 image_name: &str,
499 width: i64,
500 height: i64,
501) -> Result<InsertImageResult> {
502 let all_bids = get_all_block_ids(db_context)?;
504 let mut blocks = Vec::new();
505 for bid in &all_bids {
506 blocks.push(
507 block_controller::get(db_context, bid)?
508 .ok_or_else(|| anyhow::anyhow!("Block not found"))?,
509 );
510 }
511 blocks.sort_by_key(|b| b.document_position);
512
513 let (target_block, offset) = blocks
514 .iter()
515 .find_map(|b| {
516 let s = b.document_position;
517 let e = s + b.text_length;
518 if position >= s && position <= e {
519 Some((b.clone(), (position - s) as usize))
520 } else {
521 None
522 }
523 })
524 .ok_or_else(|| anyhow::anyhow!("No block at position {}", position))?;
525
526 let elem_ids = block_controller::get_relationship(
528 db_context,
529 &target_block.id,
530 &BlockRelationshipField::Elements,
531 )?;
532
533 let mut running = 0usize;
534 let mut insert_after_idx: i32 = -1;
535 for (idx, eid) in elem_ids.iter().enumerate() {
536 let elem = inline_element_controller::get(db_context, eid)?
537 .ok_or_else(|| anyhow::anyhow!("Element not found"))?;
538 let elen = match &elem.content {
539 InlineContent::Text(s) => s.chars().count(),
540 InlineContent::Image { .. } => 1,
541 InlineContent::Empty => 0,
542 };
543
544 if running + elen > offset && offset > running {
545 if let InlineContent::Text(ref text) = elem.content {
547 let chars: Vec<char> = text.chars().collect();
548 let local = offset - running;
549 let before: String = chars[..local].iter().collect();
550 let after: String = chars[local..].iter().collect();
551
552 let mut upd: UpdateInlineElementDto = elem.clone().into();
554 upd.content = InlineContent::Text(before);
555 inline_element_controller::update(
556 db_context,
557 event_hub,
558 undo_redo_manager,
559 None,
560 &upd,
561 )?;
562
563 let after_entity: common::entities::InlineElement = elem.clone().into();
565 let mut after_create = CreateInlineElementDto::from(after_entity);
566 after_create.content = InlineContent::Text(after);
567 inline_element_controller::create(
568 db_context,
569 event_hub,
570 undo_redo_manager,
571 None,
572 &after_create,
573 target_block.id,
574 (idx as i32) + 1,
575 )?;
576 }
577 insert_after_idx = (idx as i32) + 1;
578 break;
579 }
580 running += elen;
581 if running >= offset {
582 insert_after_idx = (idx as i32) + 1;
583 break;
584 }
585 }
586 if insert_after_idx < 0 {
587 insert_after_idx = elem_ids.len() as i32;
588 }
589
590 let img = inline_element_controller::create(
592 db_context,
593 event_hub,
594 undo_redo_manager,
595 None,
596 &CreateInlineElementDto {
597 content: InlineContent::Image {
598 name: image_name.to_string(),
599 width,
600 height,
601 quality: 100,
602 },
603 ..Default::default()
604 },
605 target_block.id,
606 insert_after_idx,
607 )?;
608
609 let mut upd_block = target_block.clone();
611 upd_block.text_length += 1;
612 block_controller::update(
613 db_context,
614 event_hub,
615 undo_redo_manager,
616 None,
617 &upd_block.into(),
618 )?;
619
620 for b in &blocks {
621 if b.id != target_block.id && b.document_position > target_block.document_position {
622 let mut shifted = b.clone();
623 shifted.document_position += 1;
624 block_controller::update(
625 db_context,
626 event_hub,
627 undo_redo_manager,
628 None,
629 &shifted.into(),
630 )?;
631 }
632 }
633
634 undo_redo_manager.clear_all_stacks();
635 Ok(InsertImageResult {
636 new_position: position + 1,
637 element_id: img.id,
638 })
639}
640
641pub struct InsertFrameResult {
642 pub frame_id: EntityId,
643}
644
645pub fn insert_frame(
650 db_context: &DbContext,
651 event_hub: &Arc<EventHub>,
652 undo_redo_manager: &mut UndoRedoManager,
653 position: i64,
654) -> Result<InsertFrameResult> {
655 let doc_id = get_doc_id(db_context)?;
656
657 let new_frame = frame_controller::create(
658 db_context,
659 event_hub,
660 undo_redo_manager,
661 None,
662 &CreateFrameDto::default(),
663 doc_id,
664 -1,
665 )?;
666
667 let block = block_controller::create(
668 db_context,
669 event_hub,
670 undo_redo_manager,
671 None,
672 &CreateBlockDto {
673 document_position: position,
674 ..Default::default()
675 },
676 new_frame.id,
677 0,
678 )?;
679
680 inline_element_controller::create(
681 db_context,
682 event_hub,
683 undo_redo_manager,
684 None,
685 &CreateInlineElementDto {
686 content: InlineContent::Empty,
687 ..Default::default()
688 },
689 block.id,
690 0,
691 )?;
692
693 undo_redo_manager.clear_all_stacks();
694 Ok(InsertFrameResult {
695 frame_id: new_frame.id,
696 })
697}
698
699fn get_doc_id(db_context: &DbContext) -> Result<EntityId> {
700 let root_rels =
701 root_controller::get_relationship(db_context, &1, &RootRelationshipField::Document)?;
702 Ok(root_rels[0])
703}