Skip to content

Commit

Permalink
Merge pull request #7174 from TouK/template-lazy-param-flink-creator
Browse files Browse the repository at this point in the history
Template parts handling approach change: expression level instead of LazyParameter level
  • Loading branch information
mslabek authored Nov 20, 2024
2 parents 8b8a412 + a1dccbd commit fb75e9a
Show file tree
Hide file tree
Showing 136 changed files with 1,875 additions and 893 deletions.
3 changes: 1 addition & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -1816,8 +1816,7 @@ lazy val flinkBaseComponentsTests = (project in flink("components/base-tests"))
)
.dependsOn(
flinkComponentsTestkit % Test,
flinkTableApiComponents % Test,
scenarioCompiler % "test->test"
flinkTableApiComponents % Test
)

lazy val flinkKafkaComponents = (project in flink("components/kafka"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
package pl.touk.nussknacker.engine.api.parameter

import io.circe.generic.extras.semiauto.{deriveUnwrappedDecoder, deriveUnwrappedEncoder}
import io.circe.{Decoder, Encoder, KeyDecoder, KeyEncoder}

final case class ParameterName(value: String) {
def withBranchId(branchId: String): ParameterName = ParameterName(s"$value for branch $branchId")
}

object ParameterName {
implicit val encoder: Encoder[ParameterName] = deriveUnwrappedEncoder
implicit val decoder: Decoder[ParameterName] = deriveUnwrappedDecoder

implicit val keyEncoder: KeyEncoder[ParameterName] = KeyEncoder.encodeKeyString.contramap(_.value)
implicit val keyDecoder: KeyDecoder[ParameterName] = KeyDecoder.decodeKeyString.map(ParameterName(_))
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package pl.touk.nussknacker.engine.api

import pl.touk.nussknacker.engine.api.LazyParameter.TemplateLazyParameter.TemplateExpression
import pl.touk.nussknacker.engine.api.LazyParameter.{Evaluate, MappedLazyParameter, ProductLazyParameter}
import pl.touk.nussknacker.engine.api.typed.typing.{Typed, TypingResult}

Expand Down Expand Up @@ -69,25 +68,6 @@ object LazyParameter {

trait CustomLazyParameter[+T <: AnyRef] extends LazyParameter[T]

trait TemplateLazyParameter[T <: AnyRef] extends LazyParameter[T] {
def templateExpression: TemplateExpression
}

object TemplateLazyParameter {
case class TemplateExpression(parts: List[TemplateExpressionPart])
sealed trait TemplateExpressionPart

object TemplateExpressionPart {
case class Literal(value: String) extends TemplateExpressionPart

trait Placeholder extends TemplateExpressionPart {
val evaluate: Evaluate[String]
}

}

}

final class ProductLazyParameter[T <: AnyRef, Y <: AnyRef](
val arg1: LazyParameter[T],
val arg2: LazyParameter[Y]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package pl.touk.nussknacker.engine.api

case class TemplateEvaluationResult(renderedParts: List[TemplateRenderedPart]) {
def renderedTemplate: String = renderedParts.map(_.value).mkString("")
}

sealed trait TemplateRenderedPart {
def value: String
}

object TemplateRenderedPart {
case class RenderedLiteral(value: String) extends TemplateRenderedPart

case class RenderedSubExpression(value: String) extends TemplateRenderedPart
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package pl.touk.nussknacker.engine.api.component

import io.circe.generic.JsonCodec
import pl.touk.nussknacker.engine.api.definition.FixedExpressionValue
import pl.touk.nussknacker.engine.api.parameter.{
ParameterName,
Expand All @@ -24,6 +25,7 @@ object AdditionalUIConfigProvider {
val empty = new DefaultAdditionalUIConfigProvider(Map.empty, Map.empty)
}

@JsonCodec
case class ComponentAdditionalConfig(
parameterConfigs: Map[ParameterName, ParameterAdditionalUIConfig],
icon: Option[String] = None,
Expand All @@ -32,6 +34,7 @@ case class ComponentAdditionalConfig(
disabled: Boolean = false
)

@JsonCodec
case class ParameterAdditionalUIConfig(
required: Boolean,
initialValue: Option[FixedExpressionValue],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package pl.touk.nussknacker.engine.api.component

import io.circe.generic.extras.semiauto.{deriveUnwrappedDecoder, deriveUnwrappedEncoder}
import io.circe.{Decoder, Encoder}
import io.circe.{Decoder, Encoder, KeyDecoder, KeyEncoder}

// TODO This class is used as a work around for the problem that the components are duplicated across processing types.
// We plan to get rid of this. After that, we could replace usages of this class by usage of ComponentId
Expand All @@ -14,6 +14,10 @@ object DesignerWideComponentId {
implicit val encoder: Encoder[DesignerWideComponentId] = deriveUnwrappedEncoder
implicit val decoder: Decoder[DesignerWideComponentId] = deriveUnwrappedDecoder

implicit val keyEncoder: KeyEncoder[DesignerWideComponentId] = KeyEncoder.encodeKeyString.contramap(_.value)
implicit val keyDecoder: KeyDecoder[DesignerWideComponentId] =
KeyDecoder.decodeKeyString.map(DesignerWideComponentId(_))

def apply(value: String): DesignerWideComponentId = new DesignerWideComponentId(value.toLowerCase)

def forBuiltInComponent(componentId: ComponentId): DesignerWideComponentId = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ object DatabaseQueryEnricher {

final val queryParamName: ParameterName = ParameterName("Query")

final val queryParamDeclaration =
ParameterDeclaration
.mandatory[String](queryParamName)
.withCreator(modify = _.copy(editor = Some(SqlParameterEditor)))
final val queryParam = Parameter[String](queryParamName).copy(editor = Some(SqlParameterEditor))

final val resultStrategyParamName: ParameterName = ParameterName("Result strategy")

Expand Down Expand Up @@ -132,7 +129,7 @@ class DatabaseQueryEnricher(val dbPoolConfig: DBPoolConfig, val dbMetaDataProvid
): ContextTransformationDefinition = { case TransformationStep(Nil, _) =>
NextParameters(parameters =
resultStrategyParamDeclaration.createParameter() ::
queryParamDeclaration.createParameter() ::
queryParam ::
cacheTTLParamDeclaration.createParameter() :: Nil
)
}
Expand All @@ -142,14 +139,15 @@ class DatabaseQueryEnricher(val dbPoolConfig: DBPoolConfig, val dbMetaDataProvid
): ContextTransformationDefinition = {
case TransformationStep(
(`resultStrategyParamName`, DefinedEagerParameter(strategyName: String, _)) ::
(`queryParamName`, DefinedEagerParameter(query: String, _)) ::
(`queryParamName`, DefinedEagerParameter(query: TemplateEvaluationResult, _)) ::
(`cacheTTLParamName`, _) :: Nil,
None
) =>
if (query.isEmpty) {
val renderedQuery = query.renderedTemplate
if (renderedQuery.isEmpty) {
FinalResults(context, errors = CustomNodeError("Query is missing", Some(queryParamName)) :: Nil, state = None)
} else {
parseQuery(context, dependencies, strategyName, query)
parseQuery(context, dependencies, strategyName, renderedQuery)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package pl.touk.nussknacker.sql.service

import pl.touk.nussknacker.engine.api.TemplateRenderedPart.RenderedLiteral
import pl.touk.nussknacker.engine.api.context.ProcessCompilationError.CustomNodeError
import pl.touk.nussknacker.engine.api.context.transformation.{DefinedEagerParameter, OutputVariableNameValue}
import pl.touk.nussknacker.engine.api.context.{OutputVar, ValidationContext}
import pl.touk.nussknacker.engine.api.typed.typing.{Typed, Unknown}
import pl.touk.nussknacker.engine.api.NodeId
import pl.touk.nussknacker.engine.api.{NodeId, TemplateEvaluationResult}
import pl.touk.nussknacker.sql.db.query.{ResultSetStrategy, SingleResultStrategy}
import pl.touk.nussknacker.sql.db.schema.MetaDataProviderFactory
import pl.touk.nussknacker.sql.utils.BaseHsqlQueryEnricherTest
Expand Down Expand Up @@ -32,8 +33,10 @@ class DatabaseQueryEnricherValidationTest extends BaseHsqlQueryEnricherTest {
service.TransformationStep(
List(
DatabaseQueryEnricher.resultStrategyParamName -> eagerValueParameter(SingleResultStrategy.name),
DatabaseQueryEnricher.queryParamName -> eagerValueParameter("select from"),
DatabaseQueryEnricher.cacheTTLParamName -> eagerValueParameter(Duration.ofMinutes(1)),
DatabaseQueryEnricher.queryParamName -> eagerValueParameter(
TemplateEvaluationResult(List(RenderedLiteral("select from")))
),
DatabaseQueryEnricher.cacheTTLParamName -> eagerValueParameter(Duration.ofMinutes(1)),
),
None
)
Expand Down Expand Up @@ -62,8 +65,10 @@ class DatabaseQueryEnricherValidationTest extends BaseHsqlQueryEnricherTest {
service.TransformationStep(
List(
DatabaseQueryEnricher.resultStrategyParamName -> eagerValueParameter(ResultSetStrategy.name),
DatabaseQueryEnricher.queryParamName -> eagerValueParameter("select * from persons"),
DatabaseQueryEnricher.cacheTTLParamName -> eagerValueParameter(Duration.ofMinutes(1)),
DatabaseQueryEnricher.queryParamName -> eagerValueParameter(
TemplateEvaluationResult(List(RenderedLiteral("select * from persons")))
),
DatabaseQueryEnricher.cacheTTLParamName -> eagerValueParameter(Duration.ofMinutes(1)),
),
None
)
Expand Down
4 changes: 1 addition & 3 deletions designer/client/cypress/e2e/description.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ describe("Description", () => {
it("should display markdown", () => {
cy.get(`[title="toggle description view"]`).should("not.exist");

cy.contains(/^properties$/i)
.should("be.enabled")
.dblclick();
cy.contains(/^properties$/i).click();
cy.get("[data-testid=window]").should("be.visible").as("window");

cy.get("[data-testid=window]").contains("Description").next().find(".ace_editor").should("be.visible").click("center")
Expand Down
3 changes: 2 additions & 1 deletion designer/client/src/actions/actionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ export type ActionTypes =
| "PROCESS_VERSIONS_LOADED"
| "UPDATE_BACKEND_NOTIFICATIONS"
| "MARK_BACKEND_NOTIFICATION_READ"
| "ARCHIVED";
| "ARCHIVED"
| "EDIT_PROPERTIES";
34 changes: 3 additions & 31 deletions designer/client/src/actions/nk/calculateProcessAfterChange.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,16 @@
import NodeUtils from "../../components/graph/NodeUtils";
import { fetchProcessDefinition } from "./processDefinitionData";
import { getProcessDefinitionData } from "../../reducers/selectors/settings";
import { mapProcessWithNewNode, replaceNodeOutputEdges } from "../../components/graph/utils/graphUtils";
import { alignFragmentWithSchema } from "../../components/graph/utils/fragmentSchemaAligner";
import { Edge, NodeType, ScenarioGraph, ProcessDefinitionData, ScenarioGraphWithName } from "../../types";
import { Edge, NodeType, ScenarioGraphWithName } from "../../types";
import { ThunkAction } from "../reduxTypes";
import { Scenario } from "../../components/Process/types";

function alignFragmentsNodeWithSchema(scenarioGraph: ScenarioGraph, processDefinitionData: ProcessDefinitionData): ScenarioGraph {
return {
...scenarioGraph,
nodes: scenarioGraph.nodes.map((node) => {
return node.type === "FragmentInput" ? alignFragmentWithSchema(processDefinitionData, node) : node;
}),
};
}

export function calculateProcessAfterChange(
scenario: Scenario,
before: NodeType,
after: NodeType,
outputEdges: Edge[],
): ThunkAction<Promise<ScenarioGraphWithName>> {
return async (dispatch, getState) => {
if (NodeUtils.nodeIsProperties(after)) {
const processDefinitionData = await dispatch(fetchProcessDefinition(scenario.processingType, scenario.isFragment));
const processWithNewFragmentSchema = alignFragmentsNodeWithSchema(scenario.scenarioGraph, processDefinitionData);
// TODO: We shouldn't keep scenario name in properties.id - it is a top-level scenario property
if (after.id !== before.id) {
dispatch({ type: "PROCESS_RENAME", name: after.id });
}

const { id, ...properties } = after;

return {
processName: after.id,
scenarioGraph: { ...processWithNewFragmentSchema, properties },
};
}

return async (_, getState) => {
let changedProcess = scenario.scenarioGraph;
if (outputEdges) {
const processDefinitionData = getProcessDefinitionData(getState());
Expand All @@ -54,7 +26,7 @@ export function calculateProcessAfterChange(
}

return {
processName: scenario.scenarioGraph.properties.id || scenario.name,
processName: scenario.name,
scenarioGraph: mapProcessWithNewNode(changedProcess, before, after),
};
};
Expand Down
4 changes: 0 additions & 4 deletions designer/client/src/actions/nk/editNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ export type EditNodeAction = {
validationResult: ValidationResult;
scenarioGraphAfterChange: ScenarioGraph;
};
export type RenameProcessAction = {
type: "PROCESS_RENAME";
name: string;
};

export type EditScenarioLabels = {
type: "EDIT_LABELS";
Expand Down
58 changes: 58 additions & 0 deletions designer/client/src/actions/nk/editProperties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { ProcessDefinitionData, PropertiesType, ScenarioGraph, ScenarioGraphWithName, ValidationResult } from "../../types";
import { alignFragmentWithSchema } from "../../components/graph/utils/fragmentSchemaAligner";
import { fetchProcessDefinition } from "./processDefinitionData";
import { Scenario } from "../../components/Process/types";
import HttpService from "../../http/HttpService";
import { ThunkAction } from "../reduxTypes";

type EditPropertiesAction = {
type: "EDIT_PROPERTIES";
validationResult: ValidationResult;
scenarioGraphAfterChange: ScenarioGraph;
};

type RenameProcessAction = {
type: "PROCESS_RENAME";
name: string;
};

export type PropertiesActions = EditPropertiesAction | RenameProcessAction;

// TODO: We synchronize fragment changes with a scenario in case of properties changes. We need to find a better way to hande it
function alignFragmentsNodeWithSchema(scenarioGraph: ScenarioGraph, processDefinitionData: ProcessDefinitionData): ScenarioGraph {
return {
...scenarioGraph,
nodes: scenarioGraph.nodes.map((node) => {
return node.type === "FragmentInput" ? alignFragmentWithSchema(processDefinitionData, node) : node;
}),
};
}

const calculateProperties = (scenario: Scenario, changedProperties: PropertiesType): ThunkAction<Promise<ScenarioGraphWithName>> => {
return async (dispatch) => {
const processDefinitionData = await dispatch(fetchProcessDefinition(scenario.processingType, scenario.isFragment));
const processWithNewFragmentSchema = alignFragmentsNodeWithSchema(scenario.scenarioGraph, processDefinitionData);

if (scenario.name !== changedProperties.name) {
dispatch({ type: "PROCESS_RENAME", name: changedProperties.name });
}

return {
processName: changedProperties.name,
scenarioGraph: { ...processWithNewFragmentSchema, properties: changedProperties },
};
};
};

export function editProperties(scenario: Scenario, changedProperties: PropertiesType): ThunkAction {
return async (dispatch) => {
const { processName, scenarioGraph } = await dispatch(calculateProperties(scenario, changedProperties));
const response = await HttpService.validateProcess(scenario.name, processName, scenarioGraph);

dispatch({
type: "EDIT_PROPERTIES",
validationResult: response.data,
scenarioGraphAfterChange: scenarioGraph,
});
};
}
1 change: 1 addition & 0 deletions designer/client/src/actions/nk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export * from "./ui/layout";
export * from "./zoom";
export * from "./nodeDetails";
export * from "./loadProcessToolbarsConfiguration";
export * from "./editProperties";
3 changes: 1 addition & 2 deletions designer/client/src/actions/nk/node.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Edge, EdgeType, NodeId, NodeType, ProcessDefinitionData, ValidationResult } from "../../types";
import { ThunkAction } from "../reduxTypes";
import { layoutChanged, Position } from "./ui/layout";
import { EditNodeAction, EditScenarioLabels, RenameProcessAction } from "./editNode";
import { EditNodeAction, EditScenarioLabels } from "./editNode";
import { getProcessDefinitionData } from "../../reducers/selectors/settings";
import { batchGroupBy } from "../../reducers/graph/batchGroupBy";
import NodeUtils from "../../components/graph/NodeUtils";
Expand Down Expand Up @@ -154,5 +154,4 @@ export type NodeActions =
| NodesWithEdgesAddedAction
| ValidationResultAction
| EditNodeAction
| RenameProcessAction
| EditScenarioLabels;
6 changes: 1 addition & 5 deletions designer/client/src/actions/nk/nodeDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,7 @@ const validate = debounce(
validationRequestData: ValidationRequest,
callback: (nodeId: NodeId, data?: ValidationData | void) => void,
) => {
const validate = (node: NodeType) =>
NodeUtils.nodeIsProperties(node)
? //NOTE: we don't validationRequestData contains processProperties, but they are refreshed only on modal open
HttpService.validateProperties(processName, { additionalFields: node.additionalFields, name: node.id })
: HttpService.validateNode(processName, { ...validationRequestData, nodeData: node });
const validate = (node: NodeType) => HttpService.validateNode(processName, { ...validationRequestData, nodeData: node });

const nodeId = validationRequestData.nodeData.id;
const nodeWithChangedName = applyIdFromFakeName(validationRequestData.nodeData);
Expand Down
5 changes: 3 additions & 2 deletions designer/client/src/actions/reduxTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AnyAction, Reducer as ReduxReducer } from "redux";
import { ThunkAction as TA, ThunkDispatch as TD } from "redux-thunk";

import { ActionTypes } from "./actionTypes";
import { CountsActions, NodeActions, ScenarioActions, SelectionActions, NodeDetailsActions } from "./nk";
import { CountsActions, NodeActions, ScenarioActions, SelectionActions, NodeDetailsActions, PropertiesActions } from "./nk";
import { UserSettingsActions } from "./nk/userSettings";
import { UiActions } from "./nk/ui/uiActions";
import { SettingsActions } from "./settingsActions";
Expand All @@ -25,7 +25,8 @@ type TypedAction =
| NotificationActions
| DisplayTestResultsDetailsAction
| CountsActions
| ScenarioActions;
| ScenarioActions
| PropertiesActions;

interface UntypedAction extends AnyAction {
type: Exclude<ActionTypes, TypedAction["type"]>;
Expand Down
Loading

0 comments on commit fb75e9a

Please sign in to comment.