use std::{
collections::{
HashMap,
HashSet,
},
sync::Arc,
};
use async_trait::async_trait;
use petgraph::prelude::*;
use serde::{
Deserialize,
Serialize,
};
use si_events::{
ContentHash,
WorkspaceSnapshotAddress,
merkle_tree_hash::MerkleTreeHash,
workspace_snapshot::{
Change,
EntityKind,
},
};
use si_id::{
ApprovalRequirementDefinitionId,
AttributePrototypeArgumentId,
AttributePrototypeId,
AttributeValueId,
ComponentId,
EntityId,
FuncId,
InputSocketId,
PropId,
SchemaId,
SchemaVariantId,
UserPk,
ViewId,
ulid::Ulid,
};
use strum::{
EnumDiscriminants,
EnumString,
};
use super::{
CycleCheckGuard,
DependentValueRoot,
EntityKindExt,
InputSocketExt,
SchemaVariantExt,
WorkspaceSnapshot,
WorkspaceSnapshotError,
WorkspaceSnapshotResult,
graph::LineageId,
node_weight::{
NodeWeight,
category_node_weight::CategoryNodeKind,
},
split_snapshot::SplitSnapshot,
};
use crate::{
DalContext,
EdgeWeight,
EdgeWeightKind,
EdgeWeightKindDiscriminants,
InputSocket,
approval_requirement::{
ApprovalRequirement,
ApprovalRequirementApprover,
ApprovalRequirementDefinition,
},
attribute::{
prototype::{
AttributePrototypeResult,
argument::AttributePrototypeArgumentResult,
},
value::AttributeValueResult,
},
component::ComponentResult,
entity_kind::EntityKindResult,
func::FuncResult,
prop::PropResult,
workspace_snapshot::{
node_weight::CategoryNodeWeight,
traits::{
approval_requirement::ApprovalRequirementExt,
attribute_prototype::AttributePrototypeExt,
attribute_prototype_argument::AttributePrototypeArgumentExt,
attribute_value::AttributeValueExt,
component::ComponentExt,
diagram::view::ViewExt,
func::FuncExt,
prop::PropExt,
},
},
};
/// The `WorkspaceSnapshotSelector` enum acts as a dispatcher for workspace snapshot methods
/// between the legacy `WorkspaceSnapshot` and the new `SplitSnapshot` implementations.
///
/// This approach provides a unified interface to work with both snapshot types without
/// requiring dynamic dispatch through trait objects (`dyn Trait`). Instead, it uses
/// pattern matching on the enum variants to route method calls to the appropriate
/// implementation, which is theoretically more performant than dynamic dispatch / v-table.
///
/// By wrapping both snapshot types in a single enum, code that interacts with workspace
/// snapshots can remain implementation-agnostic and work with either snapshot type
/// without needing to be aware of the underlying differences.
#[derive(Clone, Debug, EnumDiscriminants)]
#[strum_discriminants(derive(strum::Display, Serialize, Deserialize, EnumString))]
pub enum WorkspaceSnapshotSelector {
LegacySnapshot(Arc<WorkspaceSnapshot>),
SplitSnapshot(Arc<SplitSnapshot>),
}
impl WorkspaceSnapshotSelector {
pub async fn address(&self) -> WorkspaceSnapshotAddress {
match self {
Self::LegacySnapshot(snap) => snap.id().await,
Self::SplitSnapshot(snap) => snap.id().await,
}
}
pub fn as_legacy_snapshot(&self) -> WorkspaceSnapshotResult<Arc<WorkspaceSnapshot>> {
match self {
Self::LegacySnapshot(snap) => Ok(snap.clone()),
_ => Err(WorkspaceSnapshotError::UnexpectedSnapshotKind(self.into())),
}
}
pub fn as_split_snapshot(&self) -> WorkspaceSnapshotResult<Arc<SplitSnapshot>> {
match self {
Self::SplitSnapshot(snap) => Ok(snap.clone()),
_ => Err(WorkspaceSnapshotError::UnexpectedSnapshotKind(self.into())),
}
}
pub async fn write(
&self,
ctx: &DalContext,
) -> WorkspaceSnapshotResult<WorkspaceSnapshotAddress> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.write(ctx).await,
Self::SplitSnapshot(snapshot) => snapshot.write(ctx).await,
}
}
pub async fn subgraph_count(&self) -> usize {
match self {
Self::LegacySnapshot(_) => 1,
Self::SplitSnapshot(snapshot) => snapshot.subgraph_count().await,
}
}
pub async fn id(&self) -> WorkspaceSnapshotAddress {
match self {
Self::LegacySnapshot(snapshot) => snapshot.id().await,
Self::SplitSnapshot(snapshot) => snapshot.id().await,
}
}
pub async fn root(&self) -> WorkspaceSnapshotResult<Ulid> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.root().await,
Self::SplitSnapshot(snapshot) => snapshot.root().await,
}
}
pub async fn generate_ulid(&self) -> WorkspaceSnapshotResult<Ulid> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.generate_ulid().await,
Self::SplitSnapshot(_) => Ok(Ulid::new()),
}
}
pub async fn enable_cycle_check(&self) -> CycleCheckGuard {
match self {
Self::LegacySnapshot(snapshot) => snapshot.enable_cycle_check().await,
Self::SplitSnapshot(snapshot) => snapshot.enable_cycle_check().await,
}
}
pub async fn disable_cycle_check(&self) {
match self {
Self::LegacySnapshot(snapshot) => snapshot.disable_cycle_check().await,
Self::SplitSnapshot(snapshot) => snapshot.disable_cycle_check().await,
}
}
pub async fn cycle_check(&self) -> bool {
match self {
Self::LegacySnapshot(snapshot) => snapshot.cycle_check().await,
Self::SplitSnapshot(snapshot) => snapshot.cycle_check().await,
}
}
pub async fn is_acyclic_directed(&self) -> bool {
match self {
Self::LegacySnapshot(snapshot) => snapshot.is_acyclic_directed().await,
Self::SplitSnapshot(snapshot) => snapshot.is_acyclic_directed().await,
}
}
pub async fn add_or_replace_node(&self, node: NodeWeight) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.add_or_replace_node(node).await,
Self::SplitSnapshot(snapshot) => snapshot.add_or_replace_node(node).await,
}
}
pub async fn add_ordered_node(&self, node: NodeWeight) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.add_ordered_node(node).await,
Self::SplitSnapshot(snapshot) => snapshot.add_ordered_node(node).await,
}
}
pub async fn update_content(
&self,
id: Ulid,
new_content_hash: ContentHash,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.update_content(id, new_content_hash).await,
Self::SplitSnapshot(snapshot) => snapshot.update_content(id, new_content_hash).await,
}
}
pub async fn add_edge(
&self,
from_node_id: impl Into<Ulid>,
edge_weight: EdgeWeight,
to_node_id: impl Into<Ulid>,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.add_edge(from_node_id, edge_weight, to_node_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.add_edge(from_node_id, edge_weight, to_node_id)
.await
}
}
}
pub async fn add_ordered_edge(
&self,
from_node_id: impl Into<Ulid>,
edge_weight: EdgeWeight,
to_node_id: impl Into<Ulid>,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.add_ordered_edge(from_node_id, edge_weight, to_node_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.add_ordered_edge(from_node_id, edge_weight, to_node_id)
.await
}
}
}
pub async fn import_component_subgraph(
&self,
other: &WorkspaceSnapshotSelector,
component_id: ComponentId,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => {
let other = other.as_legacy_snapshot()?;
snapshot
.import_component_subgraph(&other, component_id)
.await
}
Self::SplitSnapshot(snapshot) => {
let other = other.as_split_snapshot()?;
snapshot
.import_component_subgraph(&other, component_id)
.await
}
}
}
pub async fn get_node_weight(
&self,
id: impl Into<Ulid>,
) -> WorkspaceSnapshotResult<NodeWeight> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.get_node_weight(id).await,
Self::SplitSnapshot(snapshot) => snapshot.get_node_weight(id).await,
}
}
pub async fn get_node_weight_opt(&self, id: impl Into<Ulid>) -> Option<NodeWeight> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.get_node_weight_opt(id).await,
Self::SplitSnapshot(snapshot) => snapshot.get_node_weight_opt(id).await,
}
}
pub async fn cleanup(&self) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.cleanup().await,
Self::SplitSnapshot(snapshot) => snapshot.cleanup().await,
}
}
pub async fn cleanup_and_merkle_tree_hash(&self) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.cleanup_and_merkle_tree_hash().await,
Self::SplitSnapshot(snapshot) => snapshot.cleanup_and_merkle_tree_hash().await,
}
}
pub async fn nodes(&self) -> WorkspaceSnapshotResult<Vec<NodeWeight>> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.nodes().await,
Self::SplitSnapshot(snapshot) => snapshot.nodes().await,
}
}
pub async fn edges(&self) -> WorkspaceSnapshotResult<Vec<(EdgeWeight, Ulid, Ulid)>> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.edges().await,
Self::SplitSnapshot(snapshot) => snapshot.edges().await,
}
}
pub async fn node_exists(&self, id: impl Into<Ulid>) -> bool {
match self {
Self::LegacySnapshot(snapshot) => snapshot.node_exists(id).await,
Self::SplitSnapshot(snapshot) => snapshot.node_exists(id).await,
}
}
pub async fn get_category_node_or_err(
&self,
kind: CategoryNodeKind,
) -> WorkspaceSnapshotResult<Ulid> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.get_category_node_or_err(kind).await,
Self::SplitSnapshot(snapshot) => snapshot.get_category_node_or_err(kind).await,
}
}
pub async fn get_category_node(
&self,
kind: CategoryNodeKind,
) -> WorkspaceSnapshotResult<Option<Ulid>> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.get_category_node(kind).await,
Self::SplitSnapshot(snapshot) => snapshot.get_category_node(kind).await,
}
}
/// Create category nodes on demand. Only works for For category node kinds
/// with static ids. If a category node kind without a static id is
/// requested, and does not yet exist, this will produce an error.
pub async fn get_or_create_static_category_node(
&self,
kind: CategoryNodeKind,
) -> WorkspaceSnapshotResult<Ulid> {
Ok(match self.get_category_node(kind).await? {
Some(id) => id,
None => {
let Some(static_id) = kind.static_id() else {
return Err(WorkspaceSnapshotError::CannotCreateOnDemandCategoryNode(
kind,
));
};
let node_weight = CategoryNodeWeight::new(
static_id,
static_id,
CategoryNodeKind::DefaultSubscriptionSources,
);
self.add_or_replace_node(super::NodeWeight::Category(node_weight))
.await?;
let root_id = self.root().await?;
self.add_edge(
root_id,
EdgeWeight::new(EdgeWeightKind::new_use()),
static_id,
)
.await?;
static_id
}
})
}
pub async fn edges_directed(
&self,
id: impl Into<Ulid>,
direction: Direction,
) -> WorkspaceSnapshotResult<Vec<(EdgeWeight, Ulid, Ulid)>> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.edges_directed(id, direction).await,
Self::SplitSnapshot(snapshot) => snapshot.edges_directed(id, direction).await,
}
}
/// Get edges for a specific direction and edge weight kind
/// (edge_weight, source_id, target_id)
pub async fn edges_directed_for_edge_weight_kind(
&self,
id: impl Into<Ulid>,
direction: Direction,
edge_kind: EdgeWeightKindDiscriminants,
) -> WorkspaceSnapshotResult<Vec<(EdgeWeight, Ulid, Ulid)>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.edges_directed_for_edge_weight_kind(id, direction, edge_kind)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.edges_directed_for_edge_weight_kind(id, direction, edge_kind)
.await
}
}
}
pub async fn remove_all_edges(&self, id: impl Into<Ulid>) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.remove_all_edges(id).await,
Self::SplitSnapshot(snapshot) => snapshot.remove_all_edges(id).await,
}
}
pub async fn incoming_sources_for_edge_weight_kind(
&self,
id: impl Into<Ulid>,
edge_weight_kind_discrim: impl Into<EdgeWeightKindDiscriminants>,
) -> WorkspaceSnapshotResult<Vec<Ulid>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.incoming_sources_for_edge_weight_kind(id, edge_weight_kind_discrim.into())
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.incoming_sources_for_edge_weight_kind(id, edge_weight_kind_discrim.into())
.await
}
}
}
pub async fn source_opt(
&self,
id: impl Into<Ulid>,
edge_weight_kind_discrim: impl Into<EdgeWeightKindDiscriminants>,
) -> WorkspaceSnapshotResult<Option<Ulid>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.source_opt(id, edge_weight_kind_discrim.into())
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.source_opt(id, edge_weight_kind_discrim.into())
.await
}
}
}
pub async fn outgoing_targets_for_edge_weight_kind(
&self,
id: impl Into<Ulid>,
edge_weight_kind_discrim: impl Into<EdgeWeightKindDiscriminants>,
) -> WorkspaceSnapshotResult<Vec<Ulid>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.outgoing_targets_for_edge_weight_kind(id, edge_weight_kind_discrim.into())
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.outgoing_targets_for_edge_weight_kind(id, edge_weight_kind_discrim.into())
.await
}
}
}
pub async fn all_outgoing_targets(
&self,
id: impl Into<Ulid>,
) -> WorkspaceSnapshotResult<Vec<NodeWeight>> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.all_outgoing_targets(id).await,
Self::SplitSnapshot(snapshot) => snapshot.all_outgoing_targets(id).await,
}
}
pub async fn all_incoming_sources(
&self,
id: impl Into<Ulid>,
) -> WorkspaceSnapshotResult<Vec<NodeWeight>> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.all_incoming_sources(id).await,
Self::SplitSnapshot(snapshot) => snapshot.all_incoming_sources(id).await,
}
}
pub async fn remove_incoming_edges_of_kind(
&self,
target_id: impl Into<Ulid>,
kind: EdgeWeightKindDiscriminants,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.remove_incoming_edges_of_kind(target_id, kind)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.remove_incoming_edges_of_kind(target_id, kind)
.await
}
}
}
pub async fn remove_outgoing_edges_of_kind(
&self,
source_id: impl Into<Ulid>,
kind: EdgeWeightKindDiscriminants,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.remove_outgoing_edges_of_kind(source_id, kind)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.remove_outgoing_edges_of_kind(source_id, kind)
.await
}
}
}
pub async fn get_edges_between_nodes(
&self,
from_node_id: Ulid,
to_node_id: Ulid,
) -> WorkspaceSnapshotResult<Vec<EdgeWeight>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.get_edges_between_nodes(from_node_id, to_node_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.get_edges_between_nodes(from_node_id, to_node_id)
.await
}
}
}
pub async fn remove_node_by_id(&self, id: impl Into<Ulid>) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.remove_node_by_id(id).await,
Self::SplitSnapshot(snapshot) => snapshot.remove_node_by_id(id).await,
}
}
pub async fn remove_edge(
&self,
source_id: impl Into<Ulid>,
target_id: impl Into<Ulid>,
edge_kind: EdgeWeightKindDiscriminants,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot.remove_edge(source_id, target_id, edge_kind).await
}
Self::SplitSnapshot(snapshot) => {
snapshot.remove_edge(source_id, target_id, edge_kind).await
}
}
}
pub async fn find_edge(
&self,
from_id: impl Into<Ulid>,
to_id: impl Into<Ulid>,
edge_weight_kind: EdgeWeightKindDiscriminants,
) -> Option<EdgeWeight> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot.find_edge(from_id, to_id, edge_weight_kind).await
}
Self::SplitSnapshot(snapshot) => {
snapshot.find_edge(from_id, to_id, edge_weight_kind).await
}
}
}
/// If the `new_id` for the node is the id of an existing node weight (for example if you
/// are creating a new thing and want to "swap it" back in for the old thing), then you
/// *MUST* remove the existing node *before* issuing the update_node_id call.
pub async fn update_node_id(
&self,
current_id: impl Into<Ulid>,
new_id: impl Into<Ulid>,
new_lineage_id: LineageId,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.update_node_id(current_id, new_id, new_lineage_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.update_node_id(current_id, new_id, new_lineage_id)
.await
}
}
}
pub async fn ordered_children_for_node(
&self,
id: impl Into<Ulid>,
) -> WorkspaceSnapshotResult<Option<Vec<Ulid>>> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.ordered_children_for_node(id).await,
Self::SplitSnapshot(snapshot) => snapshot.ordered_children_for_node(id).await,
}
}
pub async fn dvu_root_check(&self, root: DependentValueRoot) -> bool {
match self {
Self::LegacySnapshot(snapshot) => snapshot.dvu_root_check(root).await,
Self::SplitSnapshot(snapshot) => snapshot.dvu_root_check(root).await,
}
}
pub async fn schema_variant_id_for_component_id(
&self,
component_id: ComponentId,
) -> ComponentResult<SchemaVariantId> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.schema_variant_id_for_component_id(component_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.schema_variant_id_for_component_id(component_id)
.await
}
}
}
pub async fn prop_suggestions_cache(
&self,
ctx: &DalContext,
) -> WorkspaceSnapshotResult<&crate::workspace_snapshot::PropSuggestionsCache> {
match self {
Self::LegacySnapshot(snap) => snap.prop_suggestions_cache(ctx).await,
Self::SplitSnapshot(snap) => snap.prop_suggestions_cache(ctx).await,
}
}
pub async fn prop_suggestions_cache_no_populate(
&self,
) -> WorkspaceSnapshotResult<&crate::workspace_snapshot::PropSuggestionsCache> {
match self {
Self::LegacySnapshot(snap) => snap.prop_suggestions_cache_no_populate().await,
Self::SplitSnapshot(snap) => snap.prop_suggestions_cache_no_populate().await,
}
}
pub async fn clear_prop_suggestions_cache(&self) {
match self {
Self::LegacySnapshot(snapshot) => snapshot.clear_prop_suggestions_cache(),
Self::SplitSnapshot(snapshot) => snapshot.clear_prop_suggestions_cache(),
}
}
pub async fn revert(&self) {
match self {
Self::LegacySnapshot(snapshot) => snapshot.revert().await,
Self::SplitSnapshot(snapshot) => snapshot.revert().await,
}
}
}
#[async_trait]
impl ApprovalRequirementExt for WorkspaceSnapshotSelector {
async fn new_definition(
&self,
ctx: &DalContext,
entity_id: Ulid,
minimum_approvers_count: usize,
approvers: HashSet<ApprovalRequirementApprover>,
) -> WorkspaceSnapshotResult<ApprovalRequirementDefinitionId> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.new_definition(ctx, entity_id, minimum_approvers_count, approvers)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.new_definition(ctx, entity_id, minimum_approvers_count, approvers)
.await
}
}
}
async fn remove_definition(
&self,
approval_requirement_definition_id: ApprovalRequirementDefinitionId,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.remove_definition(approval_requirement_definition_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.remove_definition(approval_requirement_definition_id)
.await
}
}
}
async fn add_individual_approver_for_definition(
&self,
ctx: &DalContext,
id: ApprovalRequirementDefinitionId,
user_id: UserPk,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.add_individual_approver_for_definition(ctx, id, user_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.add_individual_approver_for_definition(ctx, id, user_id)
.await
}
}
}
async fn remove_individual_approver_for_definition(
&self,
ctx: &DalContext,
id: ApprovalRequirementDefinitionId,
user_id: UserPk,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.remove_individual_approver_for_definition(ctx, id, user_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.remove_individual_approver_for_definition(ctx, id, user_id)
.await
}
}
}
async fn approval_requirements_for_changes(
&self,
ctx: &DalContext,
changes: &[Change],
) -> WorkspaceSnapshotResult<(Vec<ApprovalRequirement>, HashMap<EntityId, MerkleTreeHash>)>
{
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.approval_requirements_for_changes(ctx, changes)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.approval_requirements_for_changes(ctx, changes)
.await
}
}
}
async fn approval_requirement_definitions_for_entity_id_opt(
&self,
ctx: &DalContext,
entity_id: EntityId,
) -> WorkspaceSnapshotResult<Option<Vec<ApprovalRequirementDefinition>>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.approval_requirement_definitions_for_entity_id_opt(ctx, entity_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.approval_requirement_definitions_for_entity_id_opt(ctx, entity_id)
.await
}
}
}
async fn entity_id_for_approval_requirement_definition_id(
&self,
id: ApprovalRequirementDefinitionId,
) -> WorkspaceSnapshotResult<EntityId> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.entity_id_for_approval_requirement_definition_id(id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.entity_id_for_approval_requirement_definition_id(id)
.await
}
}
}
async fn get_approval_requirement_definition_by_id(
&self,
ctx: &DalContext,
id: ApprovalRequirementDefinitionId,
) -> WorkspaceSnapshotResult<ApprovalRequirementDefinition> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.get_approval_requirement_definition_by_id(ctx, id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.get_approval_requirement_definition_by_id(ctx, id)
.await
}
}
}
}
#[async_trait]
impl InputSocketExt for WorkspaceSnapshotSelector {
async fn get_input_socket(
&self,
ctx: &DalContext,
id: InputSocketId,
) -> WorkspaceSnapshotResult<InputSocket> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.get_input_socket(ctx, id).await,
Self::SplitSnapshot(snapshot) => snapshot.get_input_socket(ctx, id).await,
}
}
async fn get_input_socket_by_name_opt(
&self,
ctx: &DalContext,
name: &str,
schema_variant_id: SchemaVariantId,
) -> WorkspaceSnapshotResult<Option<InputSocket>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.get_input_socket_by_name_opt(ctx, name, schema_variant_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.get_input_socket_by_name_opt(ctx, name, schema_variant_id)
.await
}
}
}
async fn list_input_socket_ids_for_schema_variant(
&self,
schema_variant_id: SchemaVariantId,
) -> WorkspaceSnapshotResult<Vec<InputSocketId>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.list_input_socket_ids_for_schema_variant(schema_variant_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.list_input_socket_ids_for_schema_variant(schema_variant_id)
.await
}
}
}
async fn list_input_sockets(
&self,
ctx: &DalContext,
schema_variant_id: SchemaVariantId,
) -> WorkspaceSnapshotResult<Vec<InputSocket>> {
let mut result = match self {
Self::LegacySnapshot(snapshot) => {
snapshot.list_input_sockets(ctx, schema_variant_id).await
}
Self::SplitSnapshot(snapshot) => {
snapshot.list_input_sockets(ctx, schema_variant_id).await
}
}?;
result.sort_by_key(|socket| socket.id());
Ok(result)
}
async fn all_attribute_value_ids_everywhere_for_input_socket_id(
&self,
input_socket_id: InputSocketId,
) -> WorkspaceSnapshotResult<Vec<AttributeValueId>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.all_attribute_value_ids_everywhere_for_input_socket_id(input_socket_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.all_attribute_value_ids_everywhere_for_input_socket_id(input_socket_id)
.await
}
}
}
async fn component_attribute_value_id_for_input_socket_id(
&self,
input_socket_id: InputSocketId,
component_id: ComponentId,
) -> WorkspaceSnapshotResult<AttributeValueId> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.component_attribute_value_id_for_input_socket_id(input_socket_id, component_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.component_attribute_value_id_for_input_socket_id(input_socket_id, component_id)
.await
}
}
}
async fn input_socket_id_find_for_attribute_value_id(
&self,
attribute_value_id: AttributeValueId,
) -> WorkspaceSnapshotResult<Option<InputSocketId>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.input_socket_id_find_for_attribute_value_id(attribute_value_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.input_socket_id_find_for_attribute_value_id(attribute_value_id)
.await
}
}
}
}
#[async_trait]
impl SchemaVariantExt for WorkspaceSnapshotSelector {
async fn schema_id_for_schema_variant_id(
&self,
schema_variant_id: SchemaVariantId,
) -> WorkspaceSnapshotResult<SchemaId> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.schema_id_for_schema_variant_id(schema_variant_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.schema_id_for_schema_variant_id(schema_variant_id)
.await
}
}
}
async fn schema_variant_add_edge_to_input_socket(
&self,
schema_variant_id: SchemaVariantId,
input_socket_id: InputSocketId,
) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.schema_variant_add_edge_to_input_socket(schema_variant_id, input_socket_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.schema_variant_add_edge_to_input_socket(schema_variant_id, input_socket_id)
.await
}
}
}
}
#[async_trait]
impl EntityKindExt for WorkspaceSnapshotSelector {
async fn get_entity_kind_for_id(&self, id: EntityId) -> EntityKindResult<EntityKind> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.get_entity_kind_for_id(id).await,
Self::SplitSnapshot(snapshot) => snapshot.get_entity_kind_for_id(id).await,
}
}
}
#[async_trait]
impl ViewExt for WorkspaceSnapshotSelector {
async fn view_remove(&self, view_id: ViewId) -> WorkspaceSnapshotResult<()> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.view_remove(view_id).await,
Self::SplitSnapshot(snapshot) => snapshot.view_remove(view_id).await,
}
}
async fn list_for_component_id(&self, id: ComponentId) -> WorkspaceSnapshotResult<Vec<ViewId>> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.list_for_component_id(id).await,
Self::SplitSnapshot(snapshot) => snapshot.list_for_component_id(id).await,
}
}
}
#[async_trait]
impl PropExt for WorkspaceSnapshotSelector {
async fn prop_default_value(
&self,
ctx: &DalContext,
prop_id: PropId,
) -> PropResult<Option<serde_json::Value>> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.prop_default_value(ctx, prop_id).await,
Self::SplitSnapshot(snapshot) => snapshot.prop_default_value(ctx, prop_id).await,
}
}
async fn prop_prototype_id(&self, prop_id: PropId) -> PropResult<AttributePrototypeId> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.prop_prototype_id(prop_id).await,
Self::SplitSnapshot(snapshot) => snapshot.prop_prototype_id(prop_id).await,
}
}
async fn ts_type(&self, prop_id: PropId) -> PropResult<String> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.ts_type(prop_id).await,
Self::SplitSnapshot(snapshot) => snapshot.ts_type(prop_id).await,
}
}
async fn build_prop_schema_tree(
&self,
ctx: &DalContext,
root_prop_id: PropId,
) -> PropResult<si_frontend_mv_types::prop_schema::PropSchemaV1> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot.build_prop_schema_tree(ctx, root_prop_id).await
}
Self::SplitSnapshot(snapshot) => {
snapshot.build_prop_schema_tree(ctx, root_prop_id).await
}
}
}
}
#[async_trait]
impl ComponentExt for WorkspaceSnapshotSelector {
async fn root_attribute_value(
&self,
component_id: ComponentId,
) -> ComponentResult<AttributeValueId> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.root_attribute_value(component_id).await,
Self::SplitSnapshot(snapshot) => snapshot.root_attribute_value(component_id).await,
}
}
async fn external_source_count(&self, id: ComponentId) -> ComponentResult<usize> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.external_source_count(id).await,
Self::SplitSnapshot(snapshot) => snapshot.external_source_count(id).await,
}
}
}
#[async_trait]
impl AttributeValueExt for WorkspaceSnapshotSelector {
async fn attribute_value_view(
&self,
ctx: &DalContext,
attribute_value_id: AttributeValueId,
) -> AttributeValueResult<Option<serde_json::Value>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot.attribute_value_view(ctx, attribute_value_id).await
}
Self::SplitSnapshot(snapshot) => {
snapshot.attribute_value_view(ctx, attribute_value_id).await
}
}
}
async fn component_prototype_id(
&self,
id: AttributeValueId,
) -> AttributeValueResult<Option<AttributePrototypeId>> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.component_prototype_id(id).await,
Self::SplitSnapshot(snapshot) => snapshot.component_prototype_id(id).await,
}
}
}
#[async_trait]
impl AttributePrototypeExt for WorkspaceSnapshotSelector {
async fn attribute_prototype_arguments(
&self,
attribute_prototype_id: AttributePrototypeId,
) -> AttributePrototypeResult<Vec<AttributePrototypeArgumentId>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.attribute_prototype_arguments(attribute_prototype_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.attribute_prototype_arguments(attribute_prototype_id)
.await
}
}
}
async fn attribute_prototype_func_id(
&self,
attribute_prototype_id: AttributePrototypeId,
) -> AttributePrototypeResult<FuncId> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.attribute_prototype_func_id(attribute_prototype_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.attribute_prototype_func_id(attribute_prototype_id)
.await
}
}
}
}
#[async_trait]
impl AttributePrototypeArgumentExt for WorkspaceSnapshotSelector {
async fn attribute_prototype_argument_static_value(
&self,
ctx: &DalContext,
attribute_prototype_argument_id: AttributePrototypeArgumentId,
) -> AttributePrototypeArgumentResult<Option<serde_json::Value>> {
match self {
Self::LegacySnapshot(snapshot) => {
snapshot
.attribute_prototype_argument_static_value(ctx, attribute_prototype_argument_id)
.await
}
Self::SplitSnapshot(snapshot) => {
snapshot
.attribute_prototype_argument_static_value(ctx, attribute_prototype_argument_id)
.await
}
}
}
}
#[async_trait]
impl FuncExt for WorkspaceSnapshotSelector {
async fn func_is_dynamic(&self, func_id: FuncId) -> FuncResult<bool> {
match self {
Self::LegacySnapshot(snapshot) => snapshot.func_is_dynamic(func_id).await,
Self::SplitSnapshot(snapshot) => snapshot.func_is_dynamic(func_id).await,
}
}
}