docs: document when-then name

This commit is contained in:
Shahed Nasser
2024-12-11 11:00:25 +02:00
parent fad85a9d29
commit fd23f13cfd
10 changed files with 2082 additions and 4880 deletions
@@ -8,19 +8,17 @@ In this chapter, you'll learn how to execute an action based on a condition in a
## Why If-Conditions Aren't Allowed in Workflows?
Medusa creates an internal representation of the workflow definition you pass to `createWorkflow` to track and store its steps.
At that point, variables in the workflow don't have any values. They only do when you execute the workflow.
Medusa creates an internal representation of the workflow definition you pass to `createWorkflow` to track and store its steps. At that point, variables in the workflow don't have any values. They only do when you execute the workflow.
So, you can't use an if-condition that checks a variable's value, as the condition will be evaluated when Medusa creates the internal representation of the workflow, rather than during execution.
Instead, use when-then from the Workflows SDK.
Instead, use when-then from the Workflows SDK. It allows you to perform steps in a workflow only if a condition that you specify is satisified.
---
## What is the When-Then Utility?
## How to use When-Then?
when-then from the Workflows SDK executes an action if a condition is satisfied. The `when` function accepts as a parameter a function that returns a boolean value, and the `then` function is chained to `when`. `then` accepts as a parameter a function that's executed if `when`'s parameter function returns a `true` value.
The Workflows SDK provides a `when` function that is used to check whether a condition is true. You chain a `then` function to `when` that specifies the steps to execute if the condition in `when` is satisfied.
For example:
@@ -77,4 +75,101 @@ In this code snippet, you execute the `isActiveStep` only if the `input.is_activ
To specify the action to perform if the condition is satisfied, chain a `then` function to `when` and pass it a callback function.
The callback function is only executed if `when`'s second parameter function returns a `true` value.
The callback function is only executed if `when`'s second parameter function returns a `true` value.
---
## Implementing If-Else with When-Then
when-then doesn't support if-else conditions. Instead, use two `when-then` conditions in your workflow.
For example:
export const ifElseHighlights = [
["7", "when", "This when-then block acts as an if condition."],
["16", "when", "This when-then block acts as an else condiiton."]
]
```ts highlights={ifElseHighlights}
const workflow = createWorkflow(
"workflow",
function (input: {
is_active: boolean
}) {
const isActiveResult = when(
input,
(input) => {
return input.is_active
}
).then(() => {
return isActiveStep()
})
const notIsActiveResult = when(
input,
(input) => {
return input.is_active
}
).then(() => {
return notIsActiveStep()
})
// ...
}
)
```
In the above workflow, you use two `when-then` blocks. The first one performs a step if `input.is_active` is `true`, and the second performs a step if `input.is_active` is `false`, acting as an else condition.
---
## Specify Name for When-Then
Internally, `when-then` blocks have a unique name similar to a step. When you return a step's result in a `when-then` block, the block's name is derived from the step's name. For example:
```ts
const isActiveResult = when(
input,
(input) => {
return input.is_active
}
).then(() => {
return isActiveStep()
})
```
This `when-then` block's internal name will be `when-then-is-active`, where `is-active` is the step's name.
However, if you need to return in your `when-then` block something other than a step's result, you need to specify a unique step name for that block. Otherwise, Medusa will generate a random name for it which can cause unexpected errors in production.
You pass a name for `when-then` as a first parameter of `when`, whose signature can accept three parameters in this case. For example:
export const nameHighlights = [
["2", `"check-is-active"`, "The when-then block's name."],
["10", "return", "`then` returns a value other than the step's result."]
]
```ts highlights={nameHighlights}
const { isActive } = when(
"check-is-active",
input,
(input) => {
return input.is_active
}
).then(() => {
const isActive = isActiveStep()
return {
isActive
}
})
```
Since `then` returns a value different than the step's result, you pass to the `when` function the following parameters:
1. A unique name to be assigned to the `when-then` block.
2. Either an object or the workflow's input. This data is passed as a parameter to the function in `when`'s second parameter.
3. A function that returns a boolean indicating whether to execute the action in `then`.
The second and third parameters are the same as the parameters you previously passed to `when`.
@@ -157,6 +157,8 @@ const myWorkflow = createWorkflow(
})
```
You can also pair multiple `when-then` blocks to implement an `if-else` condition as explained in [this chapter](../conditions/page.mdx).
### No Conditional Operators
You can't use conditional operators in a workflow, such as `??` or `||`.
+2 -2
View File
@@ -32,11 +32,11 @@ export const generatedEditDates = {
"app/learn/fundamentals/data-models/default-properties/page.mdx": "2024-10-21T13:30:21.368Z",
"app/learn/fundamentals/workflows/advanced-example/page.mdx": "2024-09-11T10:46:59.975Z",
"app/learn/fundamentals/events-and-subscribers/emit-event/page.mdx": "2024-11-25T16:19:32.168Z",
"app/learn/fundamentals/workflows/conditions/page.mdx": "2024-12-09T15:55:51.565Z",
"app/learn/fundamentals/workflows/conditions/page.mdx": "2024-12-11T08:44:00.239Z",
"app/learn/fundamentals/modules/module-link-directions/page.mdx": "2024-07-24T09:16:01+02:00",
"app/learn/fundamentals/admin/page.mdx": "2024-10-23T07:08:55.898Z",
"app/learn/fundamentals/workflows/long-running-workflow/page.mdx": "2024-12-04T07:37:59.822Z",
"app/learn/fundamentals/workflows/constructor-constraints/page.mdx": "2024-12-09T14:43:35.160Z",
"app/learn/fundamentals/workflows/constructor-constraints/page.mdx": "2024-12-11T08:36:08.282Z",
"app/learn/fundamentals/data-models/write-migration/page.mdx": "2024-11-11T15:27:59.794Z",
"app/learn/fundamentals/data-models/manage-relationships/page.mdx": "2024-10-28T04:22:21.328Z",
"app/learn/fundamentals/modules/remote-query/page.mdx": "2024-07-21T21:20:24+02:00",
@@ -599,7 +599,7 @@ export const subscriptionWorkflow1Highlights = [
["16", "createWorkflow", "Create a workflow."],
["23", "transform", "Set the customer ID to an empty string if not provided."],
["28", "when", "If email is not set, try to retrieve customer by its ID."],
["44", "transform", "Set the email either to the one in the input or the specified customer's email."],
["48", "transform", "Set the email either to the one in the input or the specified customer's email."],
]
```ts title="src/workflows/create-restock-subscription/index.ts" highlights={subscriptionWorkflow1Highlights}
@@ -630,9 +630,13 @@ export const createRestockSubscriptionWorkflow = createWorkflow(
}, (data) => {
return data.customer.customer_id || ""
})
const retrievedCustomer = when({ customer }, ({ customer }) => {
return !customer.email
}).then(() => {
const retrievedCustomer = when(
"retrieve-customer-by-id",
{ customer },
({ customer }) => {
return !customer.email
}
).then(() => {
// @ts-ignore
const { data } = useQueryGraphStep({
entity: "customer",
@@ -1669,11 +1669,11 @@ export const createDpoWorkflowHighlights = [
["27", "completeCartWorkflow", "Create an order for the cart."],
["33", "useQueryGraphStep", "Retrieve the order's items and their associated variants and linked digital products."],
["57", "when", "Check whether the order has any digital products."],
["60", "then", "Perform the callback function if an order has digital products."],
["63", "createDigitalProductOrderStep", "Create the digital product order."],
["67", "createRemoteLinkStep", "Link the digital product order to the Medusa order."],
["76", "createOrderFulfillmentWorkflow", "Create a fulfillment for the digital products in the order."],
["90", "emitEventStep", "Emit the `digital_product_order.created` event."]
["63", "then", "Perform the callback function if an order has digital products."],
["66", "createDigitalProductOrderStep", "Create the digital product order."],
["70", "createRemoteLinkStep", "Link the digital product order to the Medusa order."],
["79", "createOrderFulfillmentWorkflow", "Create a fulfillment for the digital products in the order."],
["93", "emitEventStep", "Emit the `digital_product_order.created` event."]
]
```ts title="src/workflows/create-digital-product-order/index.ts" highlights={createDpoWorkflowHighlights} collapsibleLines="1-17" expandMoreLabel="Show Imports"
@@ -1733,10 +1733,13 @@ const createDigitalProductOrderWorkflow = createWorkflow(
}
)
const digital_product_order = when(itemsWithDigitalProducts, (itemsWithDigitalProducts) => {
return itemsWithDigitalProducts.length
})
.then(() => {
const digital_product_order = when(
"create-digital-product-order-condition",
itemsWithDigitalProducts,
(itemsWithDigitalProducts) => {
return itemsWithDigitalProducts.length
}
).then(() => {
const {
digital_product_order,
} = createDigitalProductOrderStep({
@@ -0,0 +1,24 @@
export const metadata = {
title: `Workflow Errors`,
}
# {metadata.title}
## When-Then Error: Handler for action X Not Found
The following error may occur in production if you use a `when-then` block in your workflow:
```plain
custom-workflow:when-then-01JE8Z0M1FXSE2NCK1G04S0RR2:invoke - Handler for action \"when-then-01JE8Z0M1FXSE2NCK1G04S0RR2\" not found...
```
This occurs if the `when-then` block doesn't return a step's result and doesn't have a name specified. You can resolve it by passing a name as a first parameter of `when`:
```ts
const result = when(
"custom-when-condition",
// ... rest of the parameters
)
```
Learn more about passing a name for `when-then` in [this documentation](!docs!/learn/fundamentals/workflows/conditions#specify-name-for-when-then)
+3 -2
View File
@@ -126,7 +126,7 @@ export const generatedEditDates = {
"app/nextjs-starter/page.mdx": "2024-12-10T08:44:33.783Z",
"app/recipes/b2b/page.mdx": "2024-10-03T13:07:44.153Z",
"app/recipes/commerce-automation/page.mdx": "2024-10-16T08:52:01.585Z",
"app/recipes/digital-products/examples/standard/page.mdx": "2024-12-09T16:18:45.973Z",
"app/recipes/digital-products/examples/standard/page.mdx": "2024-12-11T08:46:17.435Z",
"app/recipes/digital-products/page.mdx": "2024-10-03T13:07:44.147Z",
"app/recipes/ecommerce/page.mdx": "2024-10-22T11:01:01.218Z",
"app/recipes/integrate-ecommerce-stack/page.mdx": "2024-12-09T13:03:35.846Z",
@@ -5687,5 +5687,6 @@ export const generatedEditDates = {
"references/modules/sales_channel_models/page.mdx": "2024-12-10T14:55:13.205Z",
"references/types/DmlTypes/types/types.DmlTypes.KnownDataTypes/page.mdx": "2024-12-10T14:54:55.434Z",
"references/types/DmlTypes/types/types.DmlTypes.RelationshipTypes/page.mdx": "2024-12-10T14:54:55.435Z",
"app/recipes/commerce-automation/restock-notification/page.mdx": "2024-12-10T14:15:39.178Z"
"app/recipes/commerce-automation/restock-notification/page.mdx": "2024-12-11T08:47:27.471Z",
"app/troubleshooting/workflow-errors/page.mdx": "2024-12-11T08:44:36.598Z"
}
File diff suppressed because it is too large Load Diff
+8
View File
@@ -9309,6 +9309,14 @@ export const generatedSidebar = [
"path": "/troubleshooting/dist-imports",
"title": "Importing from /dist",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/troubleshooting/workflow-errors",
"title": "Workflow Errors",
"children": []
}
]
},
+5
View File
@@ -2249,6 +2249,11 @@ export const sidebar = sidebarAttachHrefCommonOptions([
path: "/troubleshooting/dist-imports",
title: "Importing from /dist",
},
{
type: "link",
path: "/troubleshooting/workflow-errors",
title: "Workflow Errors",
},
],
},
{