formualizer_eval/engine/graph/
sources.rs1use crate::SheetId;
2use crate::engine::graph::DependencyGraph;
3use crate::engine::named_range::NameScope;
4use crate::engine::vertex::{VertexId, VertexKind};
5use formualizer_common::{ExcelError, ExcelErrorKind};
6
7#[derive(Debug, Clone)]
8pub struct SourceScalarEntry {
9 pub name: String,
10 pub vertex: VertexId,
11 pub version: Option<u64>,
12}
13
14#[derive(Debug, Clone)]
15pub struct SourceTableEntry {
16 pub name: String,
17 pub vertex: VertexId,
18 pub version: Option<u64>,
19}
20
21impl DependencyGraph {
22 fn allocate_source_vertex(&mut self) -> VertexId {
23 let scope_sheet_id: SheetId = self.default_sheet_id;
26 self.allocate_symbol_vertex(VertexKind::External, scope_sheet_id)
27 }
28
29 pub fn resolve_source_scalar_entry(&self, name: &str) -> Option<&SourceScalarEntry> {
30 self.source_scalars.get(name)
31 }
32
33 pub fn resolve_source_table_entry(&self, name: &str) -> Option<&SourceTableEntry> {
34 self.source_tables.get(name)
35 }
36
37 pub fn define_source_scalar(
38 &mut self,
39 name: &str,
40 version: Option<u64>,
41 ) -> Result<(), ExcelError> {
42 if name.is_empty() {
43 return Err(ExcelError::new(ExcelErrorKind::Name)
44 .with_message("Source name cannot be empty".to_string()));
45 }
46 if self.source_scalars.contains_key(name) || self.source_tables.contains_key(name) {
47 return Err(ExcelError::new(ExcelErrorKind::Name)
48 .with_message(format!("Source already defined: {name}")));
49 }
50
51 let vertex = self.allocate_source_vertex();
52 self.source_vertex_lookup.insert(vertex, name.to_string());
53 self.mark_volatile(vertex, version.is_none());
54
55 let entry = SourceScalarEntry {
56 name: name.to_string(),
57 vertex,
58 version,
59 };
60 self.source_scalars.insert(name.to_string(), entry);
61 self.authority_note_symbol(Some(vertex));
64 self.resolve_pending_name_references(NameScope::Workbook, name);
65 self.bump_symbol_revision();
66 Ok(())
67 }
68
69 pub fn define_source_table(
70 &mut self,
71 name: &str,
72 version: Option<u64>,
73 ) -> Result<(), ExcelError> {
74 if name.is_empty() {
75 return Err(ExcelError::new(ExcelErrorKind::Name)
76 .with_message("Source name cannot be empty".to_string()));
77 }
78 if self.source_tables.contains_key(name) || self.source_scalars.contains_key(name) {
79 return Err(ExcelError::new(ExcelErrorKind::Name)
80 .with_message(format!("Source already defined: {name}")));
81 }
82
83 let vertex = self.allocate_source_vertex();
84 self.source_vertex_lookup.insert(vertex, name.to_string());
85 self.mark_volatile(vertex, version.is_none());
86
87 let entry = SourceTableEntry {
88 name: name.to_string(),
89 vertex,
90 version,
91 };
92 self.source_tables.insert(name.to_string(), entry);
93 self.authority_note_symbol(Some(vertex));
94 self.bump_symbol_revision();
95 self.resolve_pending_symbol("table", name);
98 Ok(())
99 }
100
101 pub fn set_source_scalar_version(
102 &mut self,
103 name: &str,
104 version: Option<u64>,
105 ) -> Result<(), ExcelError> {
106 let vertex = {
107 let entry = self.source_scalars.get_mut(name).ok_or_else(|| {
108 ExcelError::new(ExcelErrorKind::Name)
109 .with_message(format!("Unknown source: {name}"))
110 })?;
111
112 if entry.version == version {
113 return Ok(());
114 }
115
116 entry.version = version;
117 entry.vertex
118 };
119
120 self.mark_volatile(vertex, version.is_none());
121 self.mark_dirty(vertex);
122 Ok(())
123 }
124
125 pub fn set_source_table_version(
126 &mut self,
127 name: &str,
128 version: Option<u64>,
129 ) -> Result<(), ExcelError> {
130 let vertex = {
131 let entry = self.source_tables.get_mut(name).ok_or_else(|| {
132 ExcelError::new(ExcelErrorKind::Name)
133 .with_message(format!("Unknown source: {name}"))
134 })?;
135
136 if entry.version == version {
137 return Ok(());
138 }
139
140 entry.version = version;
141 entry.vertex
142 };
143
144 self.mark_volatile(vertex, version.is_none());
145 self.mark_dirty(vertex);
146 Ok(())
147 }
148
149 pub fn invalidate_source(&mut self, name: &str) -> Result<(), ExcelError> {
150 if let Some(s) = self.source_scalars.get(name) {
151 self.mark_dirty(s.vertex);
152 return Ok(());
153 }
154 if let Some(t) = self.source_tables.get(name) {
155 self.mark_dirty(t.vertex);
156 return Ok(());
157 }
158 Err(ExcelError::new(ExcelErrorKind::Name).with_message(format!("Unknown source: {name}")))
159 }
160}