|
1 | 1 | use crate::core::origin::CollabOrigin; |
2 | | -use crate::database::rows::{Cell, ROW_CELLS, ROW_HEIGHT, ROW_VISIBILITY, Row}; |
| 2 | +use crate::database::rows::{ |
| 3 | + Cell, ROW_CELLS, ROW_HEIGHT, ROW_VISIBILITY, Row, RowMetaKey, meta_id_from_row_id, |
| 4 | +}; |
3 | 5 | use crate::entity::uuid_validation::RowId; |
4 | 6 |
|
5 | 7 | use crate::preclude::{DeepObservable, EntryChange, Event, MapRef, TransactionMut}; |
@@ -32,6 +34,10 @@ pub enum RowChange { |
32 | 34 | value: Cell, |
33 | 35 | is_local_change: bool, |
34 | 36 | }, |
| 37 | + DidUpdateRowMeta { |
| 38 | + row_id: RowId, |
| 39 | + is_local_change: bool, |
| 40 | + }, |
35 | 41 | DidUpdateRowComment { |
36 | 42 | row: Row, |
37 | 43 | is_local_change: bool, |
@@ -63,6 +69,38 @@ pub(crate) fn subscribe_row_data_change( |
63 | 69 | }); |
64 | 70 | } |
65 | 71 |
|
| 72 | +pub(crate) fn subscribe_row_meta_change( |
| 73 | + origin: CollabOrigin, |
| 74 | + row_id: RowId, |
| 75 | + row_meta_map: &MapRef, |
| 76 | + change_tx: RowChangeSender, |
| 77 | +) { |
| 78 | + let is_document_empty_key = meta_id_from_row_id(&row_id, RowMetaKey::IsDocumentEmpty); |
| 79 | + row_meta_map.observe_deep_with("meta-change", move |txn, events| { |
| 80 | + let txn_origin = CollabOrigin::from(txn); |
| 81 | + let is_local_change = txn_origin == origin; |
| 82 | + for event in events.iter() { |
| 83 | + if let Event::Map(map_event) = event { |
| 84 | + for (key, entry_change) in map_event.keys(txn).iter() { |
| 85 | + if key.deref() != is_document_empty_key { |
| 86 | + continue; |
| 87 | + } |
| 88 | + if matches!( |
| 89 | + entry_change, |
| 90 | + EntryChange::Inserted(_) | EntryChange::Updated(_, _) | EntryChange::Removed(_) |
| 91 | + ) { |
| 92 | + let _ = change_tx.send(RowChange::DidUpdateRowMeta { |
| 93 | + row_id, |
| 94 | + is_local_change, |
| 95 | + }); |
| 96 | + break; |
| 97 | + } |
| 98 | + } |
| 99 | + } |
| 100 | + } |
| 101 | + }); |
| 102 | +} |
| 103 | + |
66 | 104 | fn handle_map_event( |
67 | 105 | row_id: &RowId, |
68 | 106 | change_tx: &RowChangeSender, |
@@ -477,4 +515,38 @@ mod tests { |
477 | 515 | other => panic!("unexpected row change: {:?}", other), |
478 | 516 | } |
479 | 517 | } |
| 518 | + |
| 519 | + #[tokio::test] |
| 520 | + async fn row_observer_emits_row_meta_changes() { |
| 521 | + let doc = Doc::new(); |
| 522 | + let row_meta_map: MapRef = doc.get_or_insert_map("row_meta"); |
| 523 | + let row_id = Uuid::new_v4(); |
| 524 | + let (origin, _) = local_and_remote_origins(); |
| 525 | + |
| 526 | + let (change_tx, mut change_rx) = broadcast::channel(256); |
| 527 | + subscribe_row_meta_change(origin.clone(), row_id, &row_meta_map, change_tx); |
| 528 | + |
| 529 | + let is_document_empty_key = meta_id_from_row_id(&row_id, RowMetaKey::IsDocumentEmpty); |
| 530 | + { |
| 531 | + let mut txn = doc.transact_mut_with(origin.clone()); |
| 532 | + row_meta_map.insert(&mut txn, is_document_empty_key, false); |
| 533 | + } |
| 534 | + |
| 535 | + let change = loop { |
| 536 | + let change = recv_with_timeout(&mut change_rx).await; |
| 537 | + if matches!(change, RowChange::DidUpdateRowMeta { .. }) { |
| 538 | + break change; |
| 539 | + } |
| 540 | + }; |
| 541 | + match change { |
| 542 | + RowChange::DidUpdateRowMeta { |
| 543 | + row_id: changed_row_id, |
| 544 | + is_local_change, |
| 545 | + } => { |
| 546 | + assert_eq!(changed_row_id, row_id); |
| 547 | + assert!(is_local_change); |
| 548 | + }, |
| 549 | + other => panic!("unexpected row change: {:?}", other), |
| 550 | + } |
| 551 | + } |
480 | 552 | } |
0 commit comments