Skip to content

Commit

Permalink
Merge pull request #10543 from medusajs/docs/when-then-name
Browse files Browse the repository at this point in the history
* docs: document when-then name

* update when-then blocks across docs

* fix lint errors
  • Loading branch information
shahednasser authored Dec 11, 2024
2 parents 16d27ea + 35a8224 commit fd77809
Show file tree
Hide file tree
Showing 18 changed files with 2,202 additions and 4,992 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ Add the `validateAndTransformQuery` middleware to the API route in the file `src
```ts title="src/api/middlewares.ts"
import {
validateAndTransformQuery,
defineMiddlewares
defineMiddlewares,
} from "@medusajs/framework/http"
import { PostStoreCustomSchema } from "./custom/validators"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ The first step is to use the `validateAndTransformQuery` middleware on the `GET`
```ts title="src/api/middlewares.ts"
import {
validateAndTransformQuery,
defineMiddlewares
defineMiddlewares,
} from "@medusajs/framework/http"
import { createFindParams } from "@medusajs/medusa/api/utils/validators"

Expand Down
109 changes: 102 additions & 7 deletions www/apps/book/app/learn/fundamentals/workflows/conditions/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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`.
Original file line number Diff line number Diff line change
Expand Up @@ -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 `||`.
Expand Down
4 changes: 2 additions & 2 deletions www/apps/book/generated/edit-dates.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
37 changes: 20 additions & 17 deletions www/apps/resources/app/commerce-modules/cart/extend/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -529,12 +529,15 @@ In the workflow, you retrieve the cart's linked `Custom` record using Query.
Next, replace the `TODO` with the following:

```ts title="src/workflows/update-custom-from-cart/index.ts"
const created = when({
input,
carts,
}, (data) =>
!data.carts[0].custom &&
data.input.additional_data?.custom_name?.length > 0
const created = when(
"create-cart-custom-link",
{
input,
carts,
},
(data) =>
!data.carts[0].custom &&
data.input.additional_data?.custom_name?.length > 0
)
.then(() => {
const custom = createCustomStep({
Expand Down Expand Up @@ -563,14 +566,16 @@ To create the `Custom` record, you use the `createCustomStep` you created in an
Next, replace the new `TODO` with the following:

```ts title="src/workflows/update-custom-from-cart/index.ts"
const deleted = when({
input,
carts,
}, (data) =>
data.carts[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
const deleted = when(
"delete-cart-custom-link",
{
input,
carts,
}, (data) =>
data.carts[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
)
.then(() => {
deleteCustomStep({
Expand Down Expand Up @@ -599,12 +604,10 @@ const updated = when({
carts,
}, (data) => data.carts[0].custom && data.input.additional_data?.custom_name?.length > 0)
.then(() => {
const custom = updateCustomStep({
return updateCustomStep({
id: carts[0].custom.id,
custom_name: input.additional_data.custom_name,
})

return custom
})

return new WorkflowResponse({
Expand Down
36 changes: 19 additions & 17 deletions www/apps/resources/app/commerce-modules/customer/extend/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -541,12 +541,14 @@ In the workflow, you retrieve the customer's linked `Custom` record using Query.
Next, replace the `TODO` with the following:

```ts title="src/workflows/update-custom-from-customer/index.ts"
const created = when({
input,
customers,
}, (data) =>
!data.customers[0].custom &&
data.input.additional_data?.custom_name?.length > 0
const created = when(
"create-customer-custom-link",
{
input,
customers,
}, (data) =>
!data.customers[0].custom &&
data.input.additional_data?.custom_name?.length > 0
)
.then(() => {
const custom = createCustomStep({
Expand Down Expand Up @@ -575,14 +577,16 @@ To create the `Custom` record, you use the `createCustomStep` you created in an
Next, replace the new `TODO` with the following:

```ts title="src/workflows/update-custom-from-customer/index.ts"
const deleted = when({
input,
customers,
}, (data) =>
data.customers[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
const deleted = when(
"delete-customer-custom-link",
{
input,
customers,
}, (data) =>
data.customers[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
)
.then(() => {
deleteCustomStep({
Expand Down Expand Up @@ -611,12 +615,10 @@ const updated = when({
customers,
}, (data) => data.customers[0].custom && data.input.additional_data?.custom_name?.length > 0)
.then(() => {
const custom = updateCustomStep({
return updateCustomStep({
id: customers[0].custom.id,
custom_name: input.additional_data.custom_name,
})

return custom
})

return new WorkflowResponse({
Expand Down
36 changes: 19 additions & 17 deletions www/apps/resources/app/commerce-modules/product/extend/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -547,12 +547,14 @@ In the workflow, you retrieve the product's linked `Custom` record using Query.
Next, replace the `TODO` with the following:

```ts title="src/workflows/update-custom-from-product/index.ts"
const created = when({
input,
products,
}, (data) =>
!data.products[0].custom &&
data.input.additional_data?.custom_name?.length > 0
const created = when(
"create-product-custom-link",
{
input,
products,
}, (data) =>
!data.products[0].custom &&
data.input.additional_data?.custom_name?.length > 0
)
.then(() => {
const custom = createCustomStep({
Expand Down Expand Up @@ -581,14 +583,16 @@ To create the `Custom` record, you use the `createCustomStep` you created in an
Next, replace the new `TODO` with the following:

```ts title="src/workflows/update-custom-from-product/index.ts"
const deleted = when({
input,
products,
}, (data) =>
data.products[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
const deleted = when(
"delete-product-custom-link",
{
input,
products,
}, (data) =>
data.products[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
)
.then(() => {
deleteCustomStep({
Expand Down Expand Up @@ -617,12 +621,10 @@ const updated = when({
products,
}, (data) => data.products[0].custom && data.input.additional_data?.custom_name?.length > 0)
.then(() => {
const custom = updateCustomStep({
return updateCustomStep({
id: products[0].custom.id,
custom_name: input.additional_data.custom_name,
})

return custom
})

return new WorkflowResponse({
Expand Down
Loading

0 comments on commit fd77809

Please sign in to comment.