Skip to content

Commit

Permalink
merge: #4065
Browse files Browse the repository at this point in the history
4065: Chainsaw for Funcs Part 1 - Func Authoring Parity with New Routes r=vbustamante a=britmyerss

**Changes in this PR**

**New front end objects for Function Authoring**
- `FuncSummary` includes details about the function, the `func_id`, `FuncKind`, `display_name`, `name`, all function arguments, and all bindings for that Function
- `FuncBinding` - is the evolution of `FuncAssociations` and represents the intersection of the Func metadata and all of the required information for that Function to be configured and used by a Schema Variant (or Component)
- `FuncCode` is the actual code body and all the correct type information for type checking when authoring

**New Routes for Function Authoring**
All routes for func authoring follow the same pattern of `api/v2/workspaces/{workspace_id}/change-sets/{change_set_id}/funcs`

Reorganized the payloads for the routes to deduplicate how the front end is getting data, following the pattern we adopted for Func Arguments and Attribute Bindings

Abolished the `save_func` hammer and created separate CRUD routes for creating, modifying and deleting FuncBindings for Auth, Qualifications, Actions, and Code Gen Funcs. 

**`FuncBindings` in the Dal**
This enum encapsulates the logic for creating, updating, and deleting the various prototypes and related configuration metadata for how functions relate to Schema Variants/Components. 

I duplicated the existing tests to exercise the new code, but this is an area that we will definitely expand integration tests as the immutability for schema variants and functions come into play. 

This is set up to support the ability to add bindings for intrinsics (including setting default values) via the UI, but that work will be a follow on. 

** New WS Events** 
This is still very WIP as I work with `@jobelenus` on the necessary shape for these

For now, I've left all of the existing code/routes in tact so this is effectively toggled, but once the front end consumes these new routes I'll be able to remove what's been duplicated. 

Huge shoutout to `@nickgerace` for the work on porting authoring to the new engine - I was able to largely use the existing FuncAuthoringClient for the function specific authoring work! 

<div><img src="https://media4.giphy.com/media/eMRmnt6MIhfcJsMexH/200.gif?cid=5a38a5a2369ozkmc3tb3tljaj85un52xuzs846z80bww1jis&amp;ep=v1_gifs_search&amp;rid=200.gif&amp;ct=g" style="border:0;height:168px;width:300px"/><br/>via <a href="https://giphy.com/family-guy/">Family Guy</a> on <a href="https://giphy.com/gifs/family-guy-family-guy-peter-chainsaw-eMRmnt6MIhfcJsMexH">GIPHY</a></div>


Co-authored-by: Brit Myers <[email protected]>
  • Loading branch information
si-bors-ng[bot] and britmyerss authored Jul 1, 2024
2 parents 7e8709f + bf23144 commit 99d248b
Show file tree
Hide file tree
Showing 59 changed files with 5,455 additions and 210 deletions.
1 change: 1 addition & 0 deletions lib/dal/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ rust_test(
"//lib/rebaser-core:rebaser-core",
"//lib/rebaser-server:rebaser-server",
"//lib/si-events-rs:si-events",
"//lib/si-frontend-types-rs:si-frontend-types",
"//lib/si-pkg:si-pkg",
"//lib/veritech-client:veritech-client",
"//third-party/rust:chrono",
Expand Down
13 changes: 12 additions & 1 deletion lib/dal/src/action/prototype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub enum ActionPrototypeError {
pub type ActionPrototypeResult<T> = Result<T, ActionPrototypeError>;

#[remain::sorted]
#[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Display)]
#[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Display, Hash)]
pub enum ActionKind {
/// Create the "outside world" version of the modeled object.
Create,
Expand All @@ -92,6 +92,17 @@ impl From<ActionKind> for si_events::ActionKind {
}
}
}
impl From<si_events::ActionKind> for ActionKind {
fn from(value: si_events::ActionKind) -> Self {
match value {
si_events::ActionKind::Create => ActionKind::Create,
si_events::ActionKind::Destroy => ActionKind::Destroy,
si_events::ActionKind::Manual => ActionKind::Refresh,
si_events::ActionKind::Refresh => ActionKind::Refresh,
si_events::ActionKind::Update => ActionKind::Update,
}
}
}

impl From<ActionFuncSpecKind> for ActionKind {
fn from(value: ActionFuncSpecKind) -> Self {
Expand Down
21 changes: 15 additions & 6 deletions lib/dal/src/attribute/prototype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub type AttributePrototypeResult<T> = Result<T, AttributePrototypeError>;
#[remain::sorted]
#[derive(Debug, Clone, Copy, EnumDiscriminants)]
pub enum AttributePrototypeEventualParent {
Component(ComponentId),
Component(ComponentId, AttributeValueId),
SchemaVariantFromInputSocket(SchemaVariantId, InputSocketId),
SchemaVariantFromOutputSocket(SchemaVariantId, OutputSocketId),
SchemaVariantFromProp(SchemaVariantId, PropId),
Expand All @@ -105,6 +105,12 @@ pub enum AttributePrototypeEventualParent {
// that the argument is a new one.
pk!(AttributePrototypeId);

impl From<AttributePrototypeId> for si_events::AttributePrototypeId {
fn from(value: AttributePrototypeId) -> Self {
si_events::AttributePrototypeId::from_raw_id(value.into())
}
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct AttributePrototype {
pub id: AttributePrototypeId,
Expand Down Expand Up @@ -544,11 +550,14 @@ impl AttributePrototype {
let node_weight_id = node_weight.id();

let eventual_parent = match node_weight {
NodeWeight::AttributeValue(_) => AttributePrototypeEventualParent::Component(
AttributeValue::component_id(ctx, node_weight_id.into())
.await
.map_err(Box::new)?,
),
NodeWeight::AttributeValue(attribute_value_id) => {
AttributePrototypeEventualParent::Component(
AttributeValue::component_id(ctx, node_weight_id.into())
.await
.map_err(Box::new)?,
attribute_value_id.id().into(),
)
}
NodeWeight::Prop(_) => AttributePrototypeEventualParent::SchemaVariantFromProp(
SchemaVariant::find_for_prop_id(ctx, node_weight_id.into())
.await
Expand Down
12 changes: 12 additions & 0 deletions lib/dal/src/attribute/prototype/argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ pub mod value_source;
// that the argument is a new one.
pk!(AttributePrototypeArgumentId);

impl From<si_events::AttributePrototypeArgumentId> for AttributePrototypeArgumentId {
fn from(value: si_events::AttributePrototypeArgumentId) -> Self {
Self(value.into_raw_id())
}
}

impl From<AttributePrototypeArgumentId> for si_events::AttributePrototypeArgumentId {
fn from(value: AttributePrototypeArgumentId) -> Self {
Self::from_raw_id(value.0)
}
}

#[remain::sorted]
#[derive(Error, Debug)]
pub enum AttributePrototypeArgumentError {
Expand Down
6 changes: 6 additions & 0 deletions lib/dal/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ impl From<ComponentId> for si_events::ComponentId {
}
}

impl From<si_events::ComponentId> for ComponentId {
fn from(value: si_events::ComponentId) -> Self {
Self(value.into_raw_id())
}
}

#[derive(Clone, Debug)]
pub struct IncomingConnection {
pub attribute_prototype_argument_id: AttributePrototypeArgumentId,
Expand Down
101 changes: 100 additions & 1 deletion lib/dal/src/func.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use argument::{FuncArgument, FuncArgumentError};
use authoring::FuncAuthoringError;
use base64::{engine::general_purpose, Engine};
use binding::{FuncBindings, FuncBindingsError};
use serde::{Deserialize, Serialize};
use si_events::CasValue;
use si_events::{ulid::Ulid, ContentHash};
use si_frontend_types::FuncSummary;
use std::collections::HashMap;
use std::string::FromUtf8Error;
use std::sync::Arc;
Expand Down Expand Up @@ -31,6 +35,7 @@ use self::backend::{FuncBackendKind, FuncBackendResponseType};
pub mod argument;
pub mod authoring;
pub mod backend;
pub mod binding;
pub mod intrinsics;
pub mod runner;
pub mod summary;
Expand Down Expand Up @@ -58,8 +63,14 @@ pub enum FuncError {
ChronoParse(#[from] chrono::ParseError),
#[error("edge weight error: {0}")]
EdgeWeight(#[from] EdgeWeightError),
#[error("func argument error: {0}")]
FuncArgument(#[from] Box<FuncArgumentError>),
#[error("func associations error: {0}")]
FuncAssociations(#[from] Box<FuncAssociationsError>),
#[error("func authoring client error: {0}")]
FuncAuthoringClient(#[from] Box<FuncAuthoringError>),
#[error("func bindings error: {0}")]
FuncBindings(#[from] Box<FuncBindingsError>),
#[error("func name already in use {0}")]
FuncNameInUse(String),
#[error("func to be deleted has associations: {0}")]
Expand Down Expand Up @@ -630,14 +641,56 @@ impl Func {

Ok(duplicated_func)
}

pub async fn into_frontend_type(&self, ctx: &DalContext) -> FuncResult<FuncSummary> {
let args = FuncArgument::list_for_func(ctx, self.id)
.await
.map_err(Box::new)?;
let mut arguments = vec![];
for arg in args {
arguments.push(si_frontend_types::FuncArgument {
id: Some(arg.id.into()),
name: arg.name.clone(),
kind: arg.kind.into(),
element_kind: arg.element_kind.map(Into::into),
timestamp: arg.timestamp.into(),
});
}
let bindings = FuncBindings::from_func_id(ctx, self.id)
.await
.map_err(Box::new)?
.into_frontend_type();
Ok(FuncSummary {
func_id: self.id.into(),
kind: self.kind.into(),
name: self.name.clone(),
display_name: self.display_name.clone(),
is_locked: false,
arguments,
bindings,
})
}
}

#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq)]
#[derive(Clone, Deserialize, Serialize, Debug, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct FuncWsEventPayload {
func_id: FuncId,
change_set_id: ChangeSetId,
}
#[derive(Clone, Deserialize, Serialize, Debug, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct FuncWsEventFuncSummary {
change_set_id: ChangeSetId,
func_summary: si_frontend_types::FuncSummary,
types: String,
}
#[derive(Clone, Deserialize, Serialize, Debug, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct FuncWsEventCodeSaved {
change_set_id: ChangeSetId,
func_code: si_frontend_types::FuncCode,
}

impl WsEvent {
pub async fn func_arguments_saved(ctx: &DalContext, func_id: FuncId) -> WsEventResult<Self> {
Expand Down Expand Up @@ -672,4 +725,50 @@ impl WsEvent {
)
.await
}

pub async fn func_updated(
ctx: &DalContext,
func_summary: si_frontend_types::FuncSummary,
types: String,
) -> WsEventResult<Self> {
WsEvent::new(
ctx,
WsPayload::FuncUpdated(FuncWsEventFuncSummary {
change_set_id: ctx.change_set_id(),
func_summary,
types,
}),
)
.await
}

pub async fn func_created(
ctx: &DalContext,
func_summary: si_frontend_types::FuncSummary,
types: String,
) -> WsEventResult<Self> {
WsEvent::new(
ctx,
WsPayload::FuncUpdated(FuncWsEventFuncSummary {
change_set_id: ctx.change_set_id(),
func_summary,
types,
}),
)
.await
}

pub async fn func_code_saved(
ctx: &DalContext,
func_code: si_frontend_types::FuncCode,
) -> WsEventResult<Self> {
WsEvent::new(
ctx,
WsPayload::FuncCodeSaved(FuncWsEventCodeSaved {
change_set_id: ctx.change_set_id(),
func_code,
}),
)
.await
}
}
42 changes: 42 additions & 0 deletions lib/dal/src/func/argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,50 @@ impl From<FuncArgumentKind> for PkgFuncArgumentKind {
}
}

impl From<si_frontend_types::FuncArgumentKind> for FuncArgumentKind {
fn from(value: si_frontend_types::FuncArgumentKind) -> Self {
match value {
si_frontend_types::FuncArgumentKind::Any => FuncArgumentKind::Any,
si_frontend_types::FuncArgumentKind::Array => FuncArgumentKind::Array,
si_frontend_types::FuncArgumentKind::Boolean => FuncArgumentKind::Boolean,
si_frontend_types::FuncArgumentKind::Integer => FuncArgumentKind::Integer,
si_frontend_types::FuncArgumentKind::Json => FuncArgumentKind::Json,
si_frontend_types::FuncArgumentKind::Map => FuncArgumentKind::Map,
si_frontend_types::FuncArgumentKind::Object => FuncArgumentKind::Object,
si_frontend_types::FuncArgumentKind::String => FuncArgumentKind::String,
}
}
}

id!(FuncArgumentId);

impl From<si_events::FuncArgumentId> for FuncArgumentId {
fn from(value: si_events::FuncArgumentId) -> Self {
Self(value.into_raw_id())
}
}

impl From<FuncArgumentId> for si_events::FuncArgumentId {
fn from(value: FuncArgumentId) -> Self {
Self::from_raw_id(value.0)
}
}

impl From<FuncArgumentKind> for si_frontend_types::FuncArgumentKind {
fn from(value: FuncArgumentKind) -> Self {
match value {
FuncArgumentKind::Any => si_frontend_types::FuncArgumentKind::Any,
FuncArgumentKind::Array => si_frontend_types::FuncArgumentKind::Array,
FuncArgumentKind::Boolean => si_frontend_types::FuncArgumentKind::Boolean,
FuncArgumentKind::Integer => si_frontend_types::FuncArgumentKind::Integer,
FuncArgumentKind::Json => si_frontend_types::FuncArgumentKind::Json,
FuncArgumentKind::Map => si_frontend_types::FuncArgumentKind::Map,
FuncArgumentKind::Object => si_frontend_types::FuncArgumentKind::Object,
FuncArgumentKind::String => si_frontend_types::FuncArgumentKind::String,
}
}
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct FuncArgument {
pub id: FuncArgumentId,
Expand Down
18 changes: 14 additions & 4 deletions lib/dal/src/func/associations.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashMap;

use itertools::Itertools;
use serde::{Deserialize, Serialize};
use strum::EnumDiscriminants;
use telemetry::prelude::*;
Expand Down Expand Up @@ -87,8 +88,17 @@ impl FuncAssociations {
) -> FuncAssociationsResult<(Option<Self>, String)> {
let (associations, input_type) = match func.kind {
FuncKind::Action => {
let schema_variant_ids = SchemaVariant::list_for_action_func(ctx, func.id).await?;
let action_prototype_ids = ActionPrototype::list_for_func_id(ctx, func.id).await?;
let schemas_and_prototypes =
SchemaVariant::list_for_action_func(ctx, func.id).await?;
let schema_variant_ids = schemas_and_prototypes
.clone()
.into_iter()
.map(|(sv, _)| sv)
.collect_vec();
let action_prototype_ids = schemas_and_prototypes
.into_iter()
.map(|(_, ap)| ap)
.collect_vec();

// TODO(nick): right now, we just grab the first one and it decides the action kind for all of them.
// This should be configurable on a "per prototype" basis in the future.
Expand Down Expand Up @@ -154,7 +164,7 @@ impl FuncAssociations {
AttributePrototype::eventual_parent(ctx, attribute_prototype_id).await?;

match eventual_parent {
AttributePrototypeEventualParent::Component(component_id) => {
AttributePrototypeEventualParent::Component(component_id, _) => {
component_ids.push(component_id)
}
AttributePrototypeEventualParent::SchemaVariantFromInputSocket(
Expand Down Expand Up @@ -200,7 +210,7 @@ impl FuncAssociations {
let eventual_parent =
AttributePrototype::eventual_parent(ctx, attribute_prototype_id).await?;
match eventual_parent {
AttributePrototypeEventualParent::Component(component_id) => {
AttributePrototypeEventualParent::Component(component_id, _) => {
component_ids.push(component_id)
}
AttributePrototypeEventualParent::SchemaVariantFromInputSocket(
Expand Down
2 changes: 1 addition & 1 deletion lib/dal/src/func/associations/bags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl AttributePrototypeBag {
) -> FuncAssociationsResult<Self> {
let eventual_parent = AttributePrototype::eventual_parent(ctx, id).await?;
let (component_id, schema_variant_id, prop_id, output_socket_id) = match eventual_parent {
AttributePrototypeEventualParent::Component(component_id) => {
AttributePrototypeEventualParent::Component(component_id, _) => {
(Some(component_id), None, None, None)
}
AttributePrototypeEventualParent::SchemaVariantFromInputSocket(
Expand Down
Loading

0 comments on commit 99d248b

Please sign in to comment.