Skip to main content

jellyflow_runtime/runtime/
create_node.rs

1//! Adapter-facing helpers for schema-driven node creation.
2
3use serde::{Deserialize, Serialize};
4
5use crate::runtime::store::{DispatchError, DispatchOutcome, NodeGraphStore};
6use crate::schema::{NodeInstantiation, NodeInstantiationError, NodeRegistry};
7use jellyflow_core::core::{CanvasPoint, NodeId, NodeKindKey, PortId};
8
9/// Default transaction label for schema-driven create-node commits.
10pub const CREATE_NODE_TRANSACTION_LABEL: &str = "create node";
11
12/// Canvas-space request for creating one node from a registered schema.
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub struct CreateNodeRequest {
15    /// Node kind or alias selected by the adapter palette.
16    pub kind: NodeKindKey,
17    /// Top-left position in canvas space.
18    pub pos: CanvasPoint,
19}
20
21impl CreateNodeRequest {
22    pub fn new(kind: NodeKindKey, pos: CanvasPoint) -> Self {
23        Self { kind, pos }
24    }
25}
26
27/// Result of a store create-node commit.
28#[derive(Debug, Clone)]
29pub struct CreateNodeOutcome {
30    /// Instantiated graph records before profile-derived edits are applied.
31    pub instantiation: NodeInstantiation,
32    /// Store dispatch result, including the committed transaction patch.
33    pub dispatch: DispatchOutcome,
34}
35
36impl CreateNodeOutcome {
37    pub fn node_id(&self) -> NodeId {
38        self.instantiation.node_id
39    }
40
41    pub fn port_ids(&self) -> impl Iterator<Item = PortId> + '_ {
42        self.instantiation.ports.iter().map(|(id, _)| *id)
43    }
44}
45
46/// Error returned when schema-driven node creation cannot be committed.
47#[derive(Debug, thiserror::Error)]
48pub enum CreateNodeError {
49    #[error(transparent)]
50    Schema(#[from] NodeInstantiationError),
51    #[error(transparent)]
52    Dispatch(#[from] DispatchError),
53}
54
55impl NodeGraphStore {
56    /// Instantiates a schema node without mutating the store.
57    pub fn plan_create_node_from_schema(
58        &self,
59        registry: &NodeRegistry,
60        request: CreateNodeRequest,
61    ) -> Result<NodeInstantiation, NodeInstantiationError> {
62        registry.instantiate_node(&request.kind, request.pos)
63    }
64
65    /// Instantiates and commits a schema node through the normal store dispatch path.
66    pub fn apply_create_node_from_schema(
67        &mut self,
68        registry: &NodeRegistry,
69        request: CreateNodeRequest,
70    ) -> Result<CreateNodeOutcome, CreateNodeError> {
71        let instantiation = self.plan_create_node_from_schema(registry, request)?;
72        let tx = instantiation
73            .clone()
74            .into_labeled_transaction(CREATE_NODE_TRANSACTION_LABEL);
75        let dispatch = self.dispatch_transaction(&tx)?;
76
77        Ok(CreateNodeOutcome {
78            instantiation,
79            dispatch,
80        })
81    }
82}