Skip to content
This repository was archived by the owner on Feb 6, 2026. It is now read-only.

Commit 6922a39

Browse files
merge: #3460
3460: feat(sdf, dal): Bring back get_diff endpoint r=stack72 a=stack72 Bring back the sdf endpoint for get_diff. ~~**NOTE**: I don't believe this is quite right to merge yet - I still need to test the way through the system where a change happens in a new changeset and we see a diff from HEAD~~ Co-authored-by: stack72 <public@paulstack.co.uk>
2 parents 3fddac5 + c499250 commit 6922a39

10 files changed

Lines changed: 223 additions & 264 deletions

File tree

lib/dal/src/code_view.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,25 @@ impl CodeView {
110110

111111
let message = code_gen_entry.message.clone();
112112

113-
Ok(Some(CodeView {
113+
Ok(Some(CodeView::assemble(
114114
language,
115115
code,
116116
message,
117-
func: Some(code_view_name),
118-
}))
117+
Some(code_view_name),
118+
)))
119+
}
120+
121+
pub fn assemble(
122+
language: CodeLanguage,
123+
code: Option<String>,
124+
message: Option<String>,
125+
func: Option<String>,
126+
) -> CodeView {
127+
CodeView {
128+
language,
129+
code,
130+
message,
131+
func,
132+
}
119133
}
120134
}

lib/dal/src/component.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,16 @@ use crate::{
4545
TransactionsError, WsEvent, WsEventError, WsEventResult, WsPayload,
4646
};
4747

48-
pub mod resource;
49-
50-
// pub mod code;
51-
// pub mod diff;
52-
mod code;
48+
pub mod code;
49+
pub mod diff;
5350
pub mod frame;
51+
pub mod properties;
5452
pub mod qualification;
53+
pub mod resource;
5554
// pub mod status;
5655
// pub mod validation;
5756
// pub mod view;
5857

59-
// pub use view::{ComponentView, ComponentViewError, ComponentViewProperties};
60-
6158
pub const DEFAULT_COMPONENT_X_POSITION: &str = "0";
6259
pub const DEFAULT_COMPONENT_Y_POSITION: &str = "0";
6360
pub const DEFAULT_COMPONENT_WIDTH: &str = "500";
@@ -102,6 +99,8 @@ pub enum ComponentError {
10299
MissingCodeValue(ComponentId),
103100
#[error("component {0} missing attribute value for qualifications")]
104101
MissingQualificationsValue(ComponentId),
102+
#[error("component {0} missing attribute value for root")]
103+
MissingRootProp(ComponentId),
105104
#[error("found multiple parents for component: {0}")]
106105
MultipleParentsForComponent(ComponentId),
107106
#[error("found multiple root attribute values ({0} and {1}, at minimum) for component: {2}")]

lib/dal/src/component/code.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use super::{ComponentError, ComponentResult};
21
use crate::workspace_snapshot::edge_weight::EdgeWeightKindDiscriminants;
32
use crate::{
43
code_view::CodeView, schema::variant::root_prop::RootPropChild, AttributeValueId, Component,
54
ComponentId, DalContext,
65
};
76

7+
use super::{ComponentError, ComponentResult};
8+
89
impl Component {
910
/// List all [`CodeViews`](crate::CodeView) for based on the "code generation"
1011
/// [`leaves`](crate::schema::variant::leaves) for a given [`ComponentId`](Self).

lib/dal/src/component/diff.rs

Lines changed: 48 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
11
//! This module contains [`ComponentDiff`].
2-
32
use serde::{Deserialize, Serialize};
43
use serde_json::json;
54

5+
use crate::code_view::{CodeLanguage, CodeView};
6+
use crate::component::properties::ComponentProperties;
67
use crate::component::ComponentResult;
7-
use crate::{
8-
CodeLanguage, CodeView, Component, ComponentError, ComponentId, ComponentView,
9-
ComponentViewProperties, DalContext, StandardModel,
10-
};
8+
use crate::{Component, ComponentId, DalContext};
119

10+
//
1211
const NEWLINE: &str = "\n";
1312

14-
// NOTE(nick): while the destination is the browser, we may want to consider platform-specific
15-
// newline characters.
16-
// #[cfg(target_os != "windows")]
17-
// const NEWLINE: &str = "\n";
18-
// #[cfg(target_os = "windows")]
19-
// const NEWLINE: &str = "\r\n";
20-
2113
/// Contains the "diffs" for a given [`Component`](crate::Component). Generated by
2214
/// [`Self::new()`].
2315
#[derive(Deserialize, Serialize, Debug)]
@@ -34,66 +26,55 @@ pub struct ComponentDiff {
3426
pub diffs: Vec<CodeView>,
3527
}
3628

37-
impl ComponentDiff {
38-
pub async fn new(ctx: &DalContext, component_id: ComponentId) -> ComponentResult<Self> {
39-
// We take a clone of the original ctx for comparisons against the head visibility.
40-
// Importantly, this `head_ctx` will be dropped at the end of this function and will not
41-
// live any longer (that is, it's garbage collected at a reasonable time)
42-
let head_ctx = ctx.clone_with_head();
43-
44-
if ctx.visibility().deleted_at.is_some() {
45-
return Err(ComponentError::InvalidContextForDiff);
29+
impl Component {
30+
pub async fn get_diff(
31+
ctx: &DalContext,
32+
component_id: ComponentId,
33+
) -> ComponentResult<ComponentDiff> {
34+
let component = Self::get_by_id(ctx, component_id).await?;
35+
let curr_json: String;
36+
let materialized_view = component.materialized_view(ctx).await?;
37+
if let Some(view) = materialized_view {
38+
let mut current_component_view = ComponentProperties::try_from(view)?;
39+
current_component_view.drop_private();
40+
curr_json = serde_json::to_string_pretty(&current_component_view)?;
41+
} else {
42+
curr_json = serde_json::to_string_pretty(&json!(null))?;
4643
}
4744

48-
let curr_component_view = ComponentView::new(ctx, component_id).await?;
49-
if curr_component_view.properties.is_null() {
50-
return Ok(Self {
45+
let head_ctx = ctx.clone_with_head().await?;
46+
if ctx.change_set_id() == head_ctx.get_workspace_default_change_set_id().await? {
47+
// We are on HEAD and need to react as so!
48+
return Ok(ComponentDiff {
5149
component_id,
52-
current: CodeView::new(CodeLanguage::Json, Some("{}".to_owned()), None, None),
53-
diffs: Vec::new(),
50+
current: CodeView::assemble(CodeLanguage::Json, Some(curr_json), None, None),
51+
diffs: vec![],
5452
});
5553
}
5654

57-
let mut curr_component_view = ComponentViewProperties::try_from(curr_component_view)?;
58-
curr_component_view.drop_private();
59-
60-
let curr_json = serde_json::to_string_pretty(&curr_component_view)?;
61-
62-
if ctx.visibility().is_head() {
63-
return Ok(Self {
64-
component_id,
65-
current: CodeView::new(CodeLanguage::Json, Some(curr_json), None, None),
66-
diffs: Vec::new(),
67-
});
68-
}
69-
70-
// Find the "diffs" given the head dal context only if the component exists on head.
71-
let mut is_new_component = false;
72-
let prev_json: String;
73-
if Component::get_by_id(&head_ctx, &component_id)
74-
.await?
75-
.is_some()
76-
{
77-
let prev_component_view = ComponentView::new(&head_ctx, component_id).await?;
78-
if prev_component_view.properties.is_null() {
79-
return Ok(Self {
80-
component_id,
81-
current: CodeView::new(CodeLanguage::Json, Some(curr_json), None, None),
82-
diffs: Vec::new(),
83-
});
55+
let head_json: String;
56+
let mut is_new_comp = false;
57+
let head_component = Self::get_by_id(&head_ctx, component_id).await;
58+
match head_component {
59+
Ok(comp) => {
60+
let materialized_view = comp.materialized_view(&head_ctx).await?;
61+
if let Some(view) = materialized_view {
62+
let mut head_component_view = ComponentProperties::try_from(view)?;
63+
head_component_view.drop_private();
64+
head_component_view.drop_private();
65+
head_json = serde_json::to_string_pretty(&head_component_view)?;
66+
} else {
67+
head_json = serde_json::to_string_pretty(&json!(null))?;
68+
}
8469
}
85-
86-
let mut prev_component_view = ComponentViewProperties::try_from(prev_component_view)?;
87-
prev_component_view.drop_private();
88-
89-
prev_json = serde_json::to_string_pretty(&prev_component_view)?;
90-
} else {
91-
is_new_component = true;
92-
prev_json = serde_json::to_string_pretty(&json!(null))?;
93-
};
70+
Err(_) => {
71+
is_new_comp = true;
72+
head_json = serde_json::to_string_pretty(&json!(null))?;
73+
}
74+
}
9475

9576
let mut lines = Vec::new();
96-
for diff_object in diff::lines(&prev_json, &curr_json) {
77+
for diff_object in diff::lines(&head_json, &curr_json) {
9778
let line = match diff_object {
9879
diff::Result::Left(left) => format!("-{left}"),
9980
diff::Result::Both(unchanged, _) => format!(" {unchanged}"),
@@ -103,18 +84,14 @@ impl ComponentDiff {
10384
lines.push(line);
10485
}
10586
}
106-
let diff = CodeView::new(CodeLanguage::Diff, Some(lines.join(NEWLINE)), None, None);
87+
let diff = CodeView::assemble(CodeLanguage::Diff, Some(lines.join(NEWLINE)), None, None);
10788
let diffs: Vec<CodeView> = vec![diff];
10889

109-
Ok(Self {
90+
Ok(ComponentDiff {
11091
component_id,
111-
current: CodeView::new(
92+
current: CodeView::assemble(
11293
CodeLanguage::Json,
113-
if is_new_component {
114-
Some(curr_json)
115-
} else {
116-
None
117-
},
94+
if is_new_comp { Some(curr_json) } else { None },
11895
None,
11996
None,
12097
),
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,27 @@
1-
//! This module provides [`ComponentViewProperties`], which is a builder-pattern struct that enables
2-
//! users to modify an existing [`ComponentView`] safely.
1+
//! This module provides [`ComponentProperties`], which is a builder-pattern struct that enables
2+
//! users to modify an existing component safely.
33
4+
use crate::ComponentError;
45
use serde::{Deserialize, Serialize};
6+
use serde_json::Value;
57

6-
use crate::component::view::ComponentViewResult;
7-
use crate::component::ComponentViewError;
8-
use crate::ComponentView;
9-
10-
/// This struct provides the ability to drop fields from a [`ComponentView`](crate::ComponentView)
11-
/// properties tree and then re-render the view using [`Self::to_value()`].
12-
///
13-
/// - It is not recommended to use [`self`] "as-is" in assertions.
14-
/// - It is recommended to use [`Self::to_value()`] in assertions.
15-
///
16-
/// The fields on this struct are **intentionally private**.
178
#[derive(Deserialize, Serialize, Debug, Default)]
18-
pub struct ComponentViewProperties {
19-
si: serde_json::Value,
9+
pub struct ComponentProperties {
10+
pub(crate) si: serde_json::Value,
2011
#[serde(skip_serializing_if = "Option::is_none")]
21-
domain: Option<serde_json::Value>,
12+
pub(crate) domain: Option<serde_json::Value>,
2213
#[serde(skip_serializing_if = "Option::is_none")]
23-
resource: Option<ResourceProperties>,
14+
pub(crate) resource: Option<ResourceProperties>,
2415
#[serde(skip_serializing_if = "Option::is_none")]
25-
code: Option<serde_json::Value>,
16+
pub(crate) code: Option<serde_json::Value>,
2617
#[serde(skip_serializing_if = "Option::is_none")]
27-
qualification: Option<serde_json::Value>,
18+
pub(crate) qualification: Option<serde_json::Value>,
2819
}
2920

3021
/// This _private_ struct provides the ability to drop fields for the "/root/resource" tree at a
3122
/// more granular level than [`ComponentViewProperties`].
3223
#[derive(Deserialize, Serialize, Debug, Default, Clone)]
33-
struct ResourceProperties {
24+
pub struct ResourceProperties {
3425
#[serde(skip_serializing_if = "Option::is_none")]
3526
status: Option<serde_json::Value>,
3627
#[serde(skip_serializing_if = "Option::is_none")]
@@ -43,13 +34,7 @@ struct ResourceProperties {
4334
last_synced: Option<serde_json::Value>,
4435
}
4536

46-
impl ComponentViewProperties {
47-
/// Create a new [`ComponentViewProperties`] object by using [`Self::try_from`] with a
48-
/// [`ComponentView`].
49-
pub fn new(view: ComponentView) -> ComponentViewResult<Self> {
50-
Self::try_from(view)
51-
}
52-
37+
impl ComponentProperties {
5338
pub fn drop_private(&mut self) -> &mut Self {
5439
*self = Self {
5540
si: self.si.take(),
@@ -79,18 +64,12 @@ impl ComponentViewProperties {
7964
}
8065
self
8166
}
82-
83-
/// Converts [`self`](ComponentViewProperties) into a serialized [`Value`](serde_json::Value).
84-
pub fn to_value(&self) -> ComponentViewResult<serde_json::Value> {
85-
let value = serde_json::to_value(self)?;
86-
Ok(value)
87-
}
8867
}
8968

90-
impl TryFrom<ComponentView> for ComponentViewProperties {
91-
type Error = ComponentViewError;
69+
impl TryFrom<serde_json::Value> for ComponentProperties {
70+
type Error = ComponentError;
9271

93-
fn try_from(view: ComponentView) -> Result<Self, Self::Error> {
94-
Ok(serde_json::from_value(view.properties)?)
72+
fn try_from(view: Value) -> Result<Self, Self::Error> {
73+
Ok(serde_json::from_value(view)?)
9574
}
9675
}

0 commit comments

Comments
 (0)