docs: add Query documentation (#9079)

- Replace remote query documentation with new Query documentation
- Add redirect from old remote query to new query documentation
- Update remote query usages across docs to use new query usage.
This commit is contained in:
Shahed Nasser
2024-09-10 15:31:47 +03:00
committed by GitHub
parent 1d8dd54014
commit e9b5f76f9a
31 changed files with 437 additions and 635 deletions

View File

@@ -17,7 +17,7 @@ export const arrowHighlights = [
```ts highlights={arrowHighlights}
// Don't
function ProductWidget () {
function ProductWidget() {
// ...
}

View File

@@ -31,7 +31,7 @@ const ProductWidget = () => {
}
fetch(`/admin/products`, {
credentials: "include"
credentials: "include",
})
.then((res) => res.json())
.then(({ count }) => {

View File

@@ -256,7 +256,7 @@ import {
defineMiddlewares,
MedusaNextFunction,
MedusaRequest,
MedusaResponse
MedusaResponse,
} from "@medusajs/medusa"
import { MedusaError } from "@medusajs/utils"
@@ -268,9 +268,9 @@ export default defineMiddlewares({
next: MedusaNextFunction
) => {
res.status(400).json({
error: "Something happened."
error: "Something happened.",
})
}
},
})
```

View File

@@ -83,7 +83,7 @@ For example:
```ts title="src/api/admin/custom/route.ts" highlights={[["15"]]}
import type {
AuthenticatedMedusaRequest,
MedusaResponse
MedusaResponse,
} from "@medusajs/medusa"
export const GET = async (

View File

@@ -17,14 +17,14 @@ export const jsonHighlights = [
]
```ts title="src/api/store/custom/route.ts" highlights={jsonHighlights} apiTesting testApiUrl="http://localhost:9000/store/custom" testApiMethod="GET"
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
export const GET = async (
req: MedusaRequest,
res: MedusaResponse
) => {
res.json({
message: "Hello, World!"
message: "Hello, World!",
})
}
```
@@ -52,14 +52,14 @@ export const statusHighlight = [
]
```ts title="src/api/store/custom/route.ts" highlights={statusHighlight} apiTesting testApiUrl="http://localhost:9000/store/custom" testApiMethod="GET"
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
export const GET = async (
req: MedusaRequest,
res: MedusaResponse
) => {
res.status(201).json({
message: "Hello, World!"
message: "Hello, World!",
})
}
```
@@ -84,7 +84,7 @@ export const streamHighlights = [
]
```ts highlights={streamHighlights}
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
export const GET = async (
req: MedusaRequest,

View File

@@ -27,7 +27,7 @@ import { z } from "zod"
export const PostStoreCustomSchema = z.object({
a: z.number(),
b: z.number()
b: z.number(),
})
```
@@ -48,7 +48,7 @@ For example, create the file `src/api/middlewares.ts` with the following content
```ts title="src/api/middlewares.ts"
import { defineMiddlewares } from "@medusajs/medusa"
import {
validateAndTransformBody
validateAndTransformBody,
} from "@medusajs/medusa/dist/api/utils/validate-body"
import { PostStoreCustomSchema } from "./store/custom/validators"
@@ -58,7 +58,7 @@ export default defineMiddlewares({
matcher: "/store/custom",
method: "POST",
middlewares: [
validateAndTransformBody(PostStoreCustomSchema)
validateAndTransformBody(PostStoreCustomSchema),
],
},
],
@@ -87,9 +87,9 @@ export const routeHighlights = [
]
```ts title="src/api/store/custom/route.ts" highlights={routeHighlights}
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import { z } from "zod"
import { PostStoreCustomSchema } from "./validators";
import { PostStoreCustomSchema } from "./validators"
type PostStoreCustomSchemaType = z.infer<
typeof PostStoreCustomSchema
@@ -100,7 +100,7 @@ export const POST = async (
res: MedusaResponse
) => {
res.json({
sum: req.validatedBody.a + req.validatedBody.b
sum: req.validatedBody.a + req.validatedBody.b,
})
}
```

View File

@@ -84,7 +84,7 @@ export const retrieveHighlights = [
const product = await helloModuleService.retrieveProduct(
"123",
{
relations: ["orders"]
relations: ["orders"],
}
)
```

View File

@@ -22,10 +22,10 @@ export const highlights = [
```ts highlights={highlights}
import {
createWorkflow
createWorkflow,
} from "@medusajs/workflows-sdk"
import {
emitEventStep
emitEventStep,
} from "@medusajs/core-flows"
const helloWorldWorkflow = createWorkflow(
@@ -36,8 +36,8 @@ const helloWorldWorkflow = createWorkflow(
emitEventStep({
eventName: "custom.created",
data: {
id: "123"
}
id: "123",
},
})
}
)

View File

@@ -0,0 +1,237 @@
import { TypeList, Tabs, TabsList, TabsTriggerVertical, TabsContent, TabsContentWrapper } from "docs-ui"
export const metadata = {
title: `${pageNumber} Query`,
}
# {metadata.title}
In this chapter, youll learn about the Query utility and how to use it to fetch data from modules.
<Note>
Remote Query is now deprecated in favor of Query. Follow this documentation to see the difference in the usage.
</Note>
## What is Query?
Query fetches data across modules. Its a set of methods registered in the Medusa container under the `query` key.
In your resources, such as API routes or workflows, you can resolve Query to fetch data across custom modules and Medusas commerce modules.
---
## Query Example
For example, create the route `src/api/store/query/route.ts` with the following content:
export const exampleHighlights = [
["13", "", "Resolve Query from the Medusa container."],
["15", "graph", "Run a query to retrieve data."],
["16", "entryPoint", "The name of the data model you're querying."],
["17", "fields", "An array of the data models properties to retrieve in the result."],
]
```ts title="src/api/store/query/route.ts" highlights={exampleHighlights} apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query" collapsibleLines="1-8" expandButtonLabel="Show Imports"
import {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import {
ContainerRegistrationKeys,
} from "@medusajs/utils"
export const GET = async (
req: MedusaRequest,
res: MedusaResponse
) => {
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const { data: myCustoms } = await query.graph({
entryPoint: "my_custom",
fields: ["id", "name"],
})
res.json({ my_customs: myCustoms })
}
```
In the above example, you resolve Query from the Medusa container using the `ContainerRegistrationKeys.QUERY` (`query`) key.
Then, you run a query using its `graph` method. This method accepts as a parameter an object with the following required properties:
- `entryPoint`: The data model's name, as specified in the first parameter of the `model.define` method used for the data model's definition.
- `fields`: An array of the data models properties to retrieve in the result.
The method returns an object that has a `data` property, which holds an array of the retrieved data. For example:
```json title="Returned Data"
{
"data": [
{
"id": "123",
"name": "test"
}
]
}
```
---
## Retrieve Linked Records
Retrieve the records of a linked data model by passing in `fields` the data model's name suffixed with `.*`.
For example:
```ts highlights={[["6"]]}
const { data: myCustoms } = await query.graph({
entryPoint: "my_custom",
fields: [
"id",
"name",
"product.*",
],
})
```
<Note title="Tip">
`.*` means that all of data model's properties should be retrieved. To retrieve a specific property, replace the `*` with the property's name. For example, `product.title`.
</Note>
### Retrieve List Link Records
If the linked data model has `isList` enabled in the link definition, pass in `fields` the data model's plural name suffixed with `.*`.
For example:
```ts highlights={[["6"]]}
const { data: myCustoms } = await query.graph({
entryPoint: "my_custom",
fields: [
"id",
"name",
"products.*",
],
})
```
---
## Apply Filters
```ts highlights={[["6"], ["7"], ["8"], ["9"]]}
const { data: myCustoms } = await query.graph({
entryPoint: "my_custom",
fields: ["id", "name"],
variables: {
filters: {
id: [
"mc_01HWSVWR4D2XVPQ06DQ8X9K7AX",
"mc_01HWSVWK3KYHKQEE6QGS2JC3FX",
],
},
},
})
```
<Note>
Filters don't apply on fields of linked data models from other modules.
</Note>
The `query.graph` function accepts a `variables` property. You can use this property to filter retrieved records.
<TypeList
types={[
{
name: "variables",
type: "`object`",
description: "Variables to pass to the query.",
children: [
{
name: "filters",
type: "`object`",
description: "The filters to apply on any of the data model's properties."
}
]
},
]}
sectionTitle="Apply Filters"
/>
---
## Sort Records
```ts highlights={[["5"], ["6"], ["7"]]}
const { data: myCustoms } = await query.graph({
entryPoint: "my_custom",
fields: ["id", "name"],
variables: {
order: {
name: "DESC",
},
},
})
```
<Note>
Sorting doesn't work on fields of linked data models from other modules.
</Note>
To sort returned records, pass an `order` property to `variables`.
The `order` property is an object whose keys are property names, and values are either:
- `ASC` to sort records by that property in ascending order.
- `DESC` to sort records by that property in descending order.
---
## Apply Pagination
```ts highlights={[["8", "skip", "The number of records to skip before fetching the results."], ["9", "take", "The number of records to fetch."]]}
const {
data: myCustoms,
metadata: { count, take, skip },
} = await query.graph({
entryPoint: "my_custom",
fields: ["id", "name"],
variables: {
skip: 0,
take: 10,
},
})
```
To paginate the returned records, pass the following properties to `variables`:
- `skip`: (required to apply pagination) The number of records to skip before fetching the results.
- `take`: The number of records to fetch.
When you provide the pagination fields, the `query.graph` method's returned object has a `metadata` property. Its value is an object having the following properties:
<TypeList types={[
{
name: "skip",
type: "`number`",
description: "The number of records skipped."
},
{
name: "take",
type: "`number`",
description: "The number of records requested to fetch."
},
{
name: "count",
type: "`number`",
description: "The total number of records."
}
]} sectionTitle="Apply Pagination" />

View File

@@ -1,410 +0,0 @@
import { TypeList, Tabs, TabsList, TabsTriggerVertical, TabsContent, TabsContentWrapper } from "docs-ui"
export const metadata = {
title: `${pageNumber} Remote Query`,
}
# {metadata.title}
In this chapter, youll learn about the remote query and how to use it to fetch data from modules.
## What is the Remote Query?
The remote query fetches data across modules. Its a function registered in the Medusa container under the `remoteQuery` key.
In your resources, such as API routes or workflows, you can resolve the remote query to fetch data across custom modules and Medusas commerce modules.
---
## Remote Query Example
For example, create the route `src/api/store/query/route.ts` with the following content:
export const exampleHighlights = [
["18", "", "Resolve the remote query from the Medusa container."],
["21", "remoteQueryObjectFromString", "Utility function to build the query."],
["22", "entryPoint", "The name of the data model you're querying."],
["23", "fields", "An array of the data models properties to retrieve in the result."],
["27", "remoteQuery", "Run the query using the remote query."]
]
```ts title="src/api/store/query/route.ts" highlights={exampleHighlights} apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query" collapsibleLines="1-12" expandButtonLabel="Show Imports"
import {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import {
remoteQueryObjectFromString,
ContainerRegistrationKeys,
} from "@medusajs/utils"
import type {
RemoteQueryFunction,
} from "@medusajs/modules-sdk"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const remoteQuery: RemoteQueryFunction = req.scope.resolve(
ContainerRegistrationKeys.REMOTE_QUERY
)
const query = remoteQueryObjectFromString({
entryPoint: "my_custom",
fields: ["id", "name"],
})
res.json({
my_customs: await remoteQuery(query),
})
}
```
In the above example, you resolve `remoteQuery` from the Medusa container.
Then, you create a query using the `remoteQueryObjectFromString` utility function imported from `@medusajs/utils`. This function accepts as a parameter an object with the following required properties:
- `entryPoint`: The data model's name, as specified in the first parameter of the `model.define` method used for the data model's definition.
- `fields`: An array of the data models properties to retrieve in the result.
You then pass the query to the `remoteQuery` function to retrieve the results.
---
## Retrieve Linked Records
Retrieve the records of a linked data model by passing in `fields` the data model's name suffixed with `.*`.
For example:
```ts highlights={[["6"]]}
const query = remoteQueryObjectFromString({
entryPoint: "my_custom",
fields: [
"id",
"name",
"product.*",
],
})
```
<Note title="Tip">
`.*` means that all of data model's properties should be retrieved. To retrieve a specific property, replace the `*` with the property's name. For example, `product.title`.
</Note>
### Retrieve List Link Records
If the linked data model has `isList` enabled in the link definition, pass in `fields` the data model's plural name suffixed with `.*`.
For example:
```ts highlights={[["6"]]}
const query = remoteQueryObjectFromString({
entryPoint: "my_custom",
fields: [
"id",
"name",
"products.*",
],
})
```
---
## Apply Filters
```ts highlights={[["6"], ["7"], ["8"], ["9"]]}
const query = remoteQueryObjectFromString({
entryPoint: "my_custom",
fields: ["id", "name"],
variables: {
filters: {
id: [
"mc_01HWSVWR4D2XVPQ06DQ8X9K7AX",
"mc_01HWSVWK3KYHKQEE6QGS2JC3FX",
],
},
},
})
const result = await remoteQuery(query)
```
The `remoteQueryObjectFromString` function accepts a `variables` property. You can use this property to filter retrieved records.
<TypeList
types={[
{
name: "variables",
type: "`object`",
description: "Variables to pass to the query.",
children: [
{
name: "filters",
type: "`object`",
description: "The filters to apply on any of the data model's properties."
}
]
},
]}
sectionTitle="Apply Filters"
/>
---
## Sort Records
```ts highlights={[["5"], ["6"], ["7"]]}
const query = remoteQueryObjectFromString({
entryPoint: "my_custom",
fields: ["id", "name"],
variables: {
order: {
name: "DESC",
},
},
})
const result = await remoteQuery(query)
```
To sort returned records, pass an `order` property to `variables`.
The `order` property is an object whose keys are property names, and values are either:
- `ASC` to sort records by that property in ascending order.
- `DESC` to sort records by that property in descending order.
---
## Apply Pagination
```ts highlights={[["5", "skip", "The number of records to skip before fetching the results."], ["6", "take", "The number of records to fetch."]]}
const query = remoteQueryObjectFromString({
entryPoint: "my_custom",
fields: ["id", "name"],
variables: {
skip: 0,
take: 10,
},
})
const {
rows,
metadata: { count, take, skip },
} = await remoteQuery(query)
```
To paginate the returned records, pass the following properties to `variables`:
- `skip`: (required to apply pagination) The number of records to skip before fetching the results.
- `take`: The number of records to fetch.
When the pagination fields are provided, the `remoteQuery` returns an object having two properties:
<TypeList types={[
{
name: "rows",
type: "`array`",
description: "The returned records."
},
{
name: "metadata",
type: "`object`",
description: "The pagination details",
children: [
{
name: "skip",
type: "`number`",
description: "The number of records skipped."
},
{
name: "take",
type: "`number`",
description: "The number of records requested to fetch."
},
{
name: "count",
type: "`number`",
description: "The total number of records."
}
]
}
]} sectionTitle="Apply Pagination" />
---
## Using GraphQL
The remote query function alternatively accepts a string with GraphQL syntax as the query.
<Tabs defaultValue="basic" layoutType="vertical" className="mt-2">
<TabsList>
<TabsTriggerVertical value="basic">Basic Usage</TabsTriggerVertical>
<TabsTriggerVertical value="filters">Apply Filters</TabsTriggerVertical>
<TabsTriggerVertical value="sort">Sort Records</TabsTriggerVertical>
<TabsTriggerVertical value="pagination">Apply Pagination</TabsTriggerVertical>
</TabsList>
<TabsContentWrapper>
<TabsContent value="basic" className="[&_h3]:!mt-0">
### Basic GraphQL usage
```ts title="src/api/store/query/route.ts" apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query" collapsibleLines="1-10" expandButtonLabel="Show Imports"
import {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { ContainerRegistrationKeys } from "@medusajs/utils"
import type {
RemoteQueryFunction,
} from "@medusajs/modules-sdk"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const remoteQuery: RemoteQueryFunction = req.scope.resolve(
ContainerRegistrationKeys.REMOTE_QUERY
)
const query = `
query {
my_custom {
id
name
}
}
`
const result = await remoteQuery(query)
res.json({
my_customs: result,
})
}
```
</TabsContent>
<TabsContent value="filters" className="[&_h3]:!mt-0">
### Apply Filters with GraphQL
The `remoteQuery` function accepts as a second parameter an object of variables to reference in the GraphQL query.
```ts highlights={[["2"], ["3"], ["13"], ["14"], ["15"], ["16"]]}
const query = `
query($id: ID) {
my_custom(id: $id) {
id
name
}
}
`
const result = await remoteQuery(
query,
{
id: [
"mc_01HWSVWR4D2XVPQ06DQ8X9K7AX",
"mc_01HWSVWK3KYHKQEE6QGS2JC3FX",
]
}
)
```
</TabsContent>
<TabsContent value="sort" className="[&_h3]:!mt-0">
### Sort Records with GraphQL
To sort the records by a property, pass in the query an `order` argument whose value is an object. The objects key is the propertys name, and the value is either:
- `ASC` to sort items by that property in ascending order.
- `DESC` to sort items by that property in descending order.
For example:
```ts highlights={[["3"]]}
const query = `
query {
my_custom(order: {name: DESC}) {
id
name
}
}
`
const result = await remoteQuery(query)
```
</TabsContent>
<TabsContent value="pagination" className="[&_h3]:!mt-0">
### Pagination with GraphQL
To paginate the records retrieved, pass a `skip` and `take` records in your query, and pass their values in the second parameter of the `remoteQuery` function.
For example:
```ts highlights={[["2"], ["3"]]}
const query = `
query($skip: Int, $take: Int) {
my_custom(skip: $skip, take: $take) {
id
name
}
}
`
const {
rows,
metadata: { count, take, skip }
} = await remoteQuery(
query,
{
skip: 0,
take: 10
}
)
```
This skips no records and returns the first `10` records.
When the pagination fields are provided, the `remoteQuery` returns an object having two properties:
<TypeList types={[
{
name: "rows",
type: "`array`",
description: "The returned records."
},
{
name: "metadata",
type: "`object`",
description: "The pagination details",
children: [
{
name: "skip",
type: "`number`",
description: "The number of records skipped."
},
{
name: "take",
type: "`number`",
description: "The number of records requested to fetch."
},
{
name: "count",
type: "`number`",
description: "The total number of records."
}
]
}
]} sectionTitle="Pagination with GraphQL" />
</TabsContent>
</TabsContentWrapper>
</Tabs>

View File

@@ -94,7 +94,7 @@ This property is an object that holds additional data passed to the workflow.
To pass that additional data when executing the workflow, pass it as a parameter to the `.run` method of the workflow:
```ts highlights={[["10", "additional_data"]]}
import type { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
import type { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import { createProductsWorkflow } from "@medusajs/core-flows"
export async function POST(req: MedusaRequest, res: MedusaResponse) {
@@ -104,8 +104,8 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
// ...
],
additional_data: {
custom_field: "test"
}
custom_field: "test",
},
},
})
}

View File

@@ -29,7 +29,7 @@ export async function GET(
res: MedusaResponse
){
res.json({
message: "Hello, World!"
message: "Hello, World!",
})
}
```
@@ -58,7 +58,7 @@ medusaIntegrationTestRunner({
})
})
})
}
},
})
```
@@ -107,7 +107,7 @@ And consider that the file `src/api/store/custom/route.ts` defines another route
```ts title="src/api/store/custom/route.ts"
// other imports...
import HelloModuleService from "../../../modules/hello/service";
import HelloModuleService from "../../../modules/hello/service"
// ...
@@ -124,7 +124,7 @@ export async function POST(
)
res.json({
my_custom: myCustom
my_custom: myCustom,
})
}
```
@@ -155,7 +155,7 @@ medusaIntegrationTestRunner({
`/store/custom`,
{
id,
name: "Test"
name: "Test",
}
)
@@ -170,7 +170,7 @@ medusaIntegrationTestRunner({
})
})
})
}
},
})
```
@@ -210,7 +210,7 @@ medusaIntegrationTestRunner({
})
})
})
}
},
})
```
@@ -223,8 +223,8 @@ The `afterAll` hook resolves the `HelloModuleService` and use its `deleteMyCusto
Consider a `/store/custom/:id` API route created at `src/api/store/custom/[id]/route.ts`:
```ts title="src/api/store/custom/[id]/route.ts"
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
import HelloModuleService from "../../../modules/hello/service";
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import HelloModuleService from "../../../modules/hello/service"
export async function DELETE(
req: MedusaRequest,
@@ -237,7 +237,7 @@ export async function DELETE(
await helloModuleService.deleteMyCustoms(req.params.id)
res.json({
success: true
success: true,
})
}
```
@@ -266,7 +266,7 @@ medusaIntegrationTestRunner({
await helloModuleService.createMyCustoms({
id,
name: "Test"
name: "Test",
})
})
@@ -281,7 +281,7 @@ medusaIntegrationTestRunner({
})
})
})
}
},
})
```

View File

@@ -34,7 +34,7 @@ import { medusaIntegrationTestRunner } from "medusa-test-utils"
medusaIntegrationTestRunner({
testSuite: ({ api, getContainer }) => {
// TODO write tests...
}
},
})
```

View File

@@ -26,7 +26,7 @@ import {
createWorkflow,
createStep,
StepResponse,
WorkflowResponse
WorkflowResponse,
} from "@medusajs/workflows-sdk"
const step1 = createStep("step-1", () => {
@@ -59,7 +59,7 @@ medusaIntegrationTestRunner({
expect(result).toEqual("Hello, World!")
})
})
}
},
})
```

View File

@@ -56,7 +56,7 @@ moduleIntegrationTestRunner<HelloModuleService>({
expect(message).toEqual("Hello, World!")
})
})
}
},
})
```

View File

@@ -35,7 +35,7 @@ moduleIntegrationTestRunner<HelloModuleService>({
resolve: "./modules/hello",
testSuite: ({ service }) => {
// TODO write tests
}
},
})
```
@@ -88,7 +88,7 @@ import HelloModuleService from "../service"
moduleIntegrationTestRunner<HelloModuleService>({
moduleOptions: {
apiKey: "123"
apiKey: "123",
},
// ...
})
@@ -108,7 +108,7 @@ import HelloModuleService from "../service"
import { model } from "@medusajs/utils"
const DummyModel = model.define("dummy_model", {
id: model.id().primaryKey()
id: model.id().primaryKey(),
})
moduleIntegrationTestRunner<HelloModuleService>({

View File

@@ -41,8 +41,8 @@ npm install --save-dev jest @types/jest @swc/jest
Then, create the file `jest.config.js` with the following content:
```js title="jest.config.js"
const { loadEnv } = require('@medusajs/utils')
loadEnv('test', process.cwd())
const { loadEnv } = require("@medusajs/utils")
loadEnv("test", process.cwd())
module.exports = {
transform: {

View File

@@ -6,7 +6,7 @@ export const generatedEditDates = {
"app/basics/modules-and-services/page.mdx": "2024-09-03T07:45:28.079Z",
"app/basics/commerce-modules/page.mdx": "2024-09-03T07:48:48.148Z",
"app/advanced-development/workflows/retry-failed-steps/page.mdx": "2024-07-31T17:01:33+03:00",
"app/advanced-development/workflows/workflow-hooks/page.mdx": "2024-08-13T09:55:37+03:00",
"app/advanced-development/workflows/workflow-hooks/page.mdx": "2024-09-10T11:39:51.168Z",
"app/cheatsheet/page.mdx": "2024-07-11T13:53:40+03:00",
"app/debugging-and-testing/logging/page.mdx": "2024-07-04T17:26:03+03:00",
"app/more-resources/page.mdx": "2024-07-04T17:26:03+03:00",
@@ -33,19 +33,19 @@ export const generatedEditDates = {
"app/advanced-development/admin/widgets/page.mdx": "2024-08-06T09:44:22+02:00",
"app/advanced-development/data-models/page.mdx": "2024-07-04T17:26:03+03:00",
"app/advanced-development/modules/remote-link/page.mdx": "2024-07-24T09:16:01+02:00",
"app/advanced-development/api-routes/protected-routes/page.mdx": "2024-09-04T10:11:25.860Z",
"app/advanced-development/api-routes/protected-routes/page.mdx": "2024-09-10T11:39:51.166Z",
"app/advanced-development/workflows/add-workflow-hook/page.mdx": "2024-08-13T09:55:37+03:00",
"app/advanced-development/events-and-subscribers/data-payload/page.mdx": "2024-07-16T17:12:05+01:00",
"app/advanced-development/data-models/default-properties/page.mdx": "2024-07-02T12:34:44+03:00",
"app/advanced-development/workflows/advanced-example/page.mdx": "2024-07-31T17:01:33+03:00",
"app/advanced-development/events-and-subscribers/emit-event/page.mdx": "2024-08-05T11:39:47+03:00",
"app/advanced-development/events-and-subscribers/emit-event/page.mdx": "2024-09-10T11:39:51.168Z",
"app/advanced-development/workflows/conditions/page.mdx": "2024-07-31T17:01:33+03:00",
"app/advanced-development/modules/module-link-directions/page.mdx": "2024-07-24T09:16:01+02:00",
"app/advanced-development/admin/page.mdx": "2024-05-29T13:50:19+03:00",
"app/advanced-development/workflows/long-running-workflow/page.mdx": "2024-07-31T17:01:33+03:00",
"app/advanced-development/workflows/constructor-constraints/page.mdx": "2024-07-17T13:19:51+01:00",
"app/advanced-development/data-models/write-migration/page.mdx": "2024-07-15T17:46:10+02:00",
"app/advanced-development/data-models/manage-relationships/page.mdx": "2024-08-15T16:30:00+03:00",
"app/advanced-development/data-models/manage-relationships/page.mdx": "2024-09-10T11:39:51.167Z",
"app/advanced-development/modules/remote-query/page.mdx": "2024-07-21T21:20:24+02:00",
"app/advanced-development/modules/options/page.mdx": "2024-08-05T07:23:49+00:00",
"app/advanced-development/data-models/relationships/page.mdx": "2024-08-15T16:30:00+03:00",
@@ -57,7 +57,7 @@ export const generatedEditDates = {
"app/advanced-development/scheduled-jobs/execution-number/page.mdx": "2024-07-02T09:41:15+00:00",
"app/advanced-development/api-routes/parameters/page.mdx": "2024-09-04T08:17:50.071Z",
"app/advanced-development/api-routes/http-methods/page.mdx": "2024-09-04T08:15:11.609Z",
"app/advanced-development/admin/tips/page.mdx": "2024-08-05T13:20:34+03:00",
"app/advanced-development/admin/tips/page.mdx": "2024-09-10T11:39:51.165Z",
"app/advanced-development/api-routes/cors/page.mdx": "2024-09-04T08:24:47.068Z",
"app/advanced-development/admin/ui-routes/page.mdx": "2024-08-06T09:44:22+02:00",
"app/advanced-development/api-routes/middlewares/page.mdx": "2024-09-04T09:45:12.441Z",
@@ -66,14 +66,18 @@ export const generatedEditDates = {
"app/advanced-development/data-models/index/page.mdx": "2024-07-04T17:26:03+03:00",
"app/advanced-development/custom-cli-scripts/page.mdx": "2024-07-04T17:26:03+03:00",
"app/advanced-development/data-models/property-types/page.mdx": "2024-07-04T17:26:03+03:00",
"app/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2024-09-02T10:57:08.040Z",
"app/debugging-and-testing/testing-tools/integration-tests/page.mdx": "2024-09-02T10:56:09.872Z",
"app/debugging-and-testing/testing-tools/integration-tests/workflows/page.mdx": "2024-09-02T10:57:04.202Z",
"app/debugging-and-testing/testing-tools/page.mdx": "2024-09-02T10:08:29.388Z",
"app/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2024-09-10T11:39:51.170Z",
"app/debugging-and-testing/testing-tools/integration-tests/page.mdx": "2024-09-10T11:39:51.170Z",
"app/debugging-and-testing/testing-tools/integration-tests/workflows/page.mdx": "2024-09-10T11:39:51.171Z",
"app/debugging-and-testing/testing-tools/page.mdx": "2024-09-10T11:39:51.172Z",
"app/debugging-and-testing/testing-tools/unit-tests/module-example/page.mdx": "2024-09-02T11:04:27.232Z",
"app/debugging-and-testing/testing-tools/unit-tests/page.mdx": "2024-09-02T11:03:26.997Z",
"app/advanced-development/api-routes/page.mdx": "2024-09-04T09:36:33.961Z",
"app/advanced-development/api-routes/responses/page.mdx": "2024-09-04T09:40:38.986Z",
"app/advanced-development/api-routes/validation/page.mdx": "2024-09-04T09:50:52.129Z",
"app/advanced-development/api-routes/errors/page.mdx": "2024-09-04T11:03:55.017Z"
"app/advanced-development/api-routes/responses/page.mdx": "2024-09-10T11:39:51.167Z",
"app/advanced-development/api-routes/validation/page.mdx": "2024-09-10T11:39:51.167Z",
"app/advanced-development/api-routes/errors/page.mdx": "2024-09-10T11:39:51.166Z",
"app/advanced-development/admin/constraints/page.mdx": "2024-09-10T11:39:51.165Z",
"app/advanced-development/modules/query/page.mdx": "2024-09-10T11:39:51.168Z",
"app/debugging-and-testing/testing-tools/modules-tests/module-example/page.mdx": "2024-09-10T11:39:51.171Z",
"app/debugging-and-testing/testing-tools/modules-tests/page.mdx": "2024-09-10T11:39:51.171Z"
}

View File

@@ -127,6 +127,15 @@ const nextConfig = {
],
}
},
async redirects() {
return [
{
source: "/advanced-development/modules/remote-query",
destination: "/advanced-development/modules/query",
permanent: true,
},
]
},
}
export default withMDX(nextConfig)

View File

@@ -172,8 +172,8 @@ export const sidebar = numberSidebarItems(
},
{
type: "link",
path: "/advanced-development/modules/remote-query",
title: "Remote Query",
path: "/advanced-development/modules/query",
title: "Query",
},
{
type: "link",

View File

@@ -14,17 +14,18 @@ In this document, you'll learn how to calculate a product variant's price with t
You'll need the following resources for the taxes calculation:
1. Remote query to retrieve the product's variants' prices for a context. Learn more about that in [this guide](../price/page.mdx).
1. Query to retrieve the product's variants' prices for a context. Learn more about that in [this guide](../price/page.mdx).
2. The Tax Module's main service to get the tax lines for each product.
```ts
// other imports...
import {
ModuleRegistrationName,
ContainerRegistrationKeys,
} from "@medusajs/utils"
// In an API route, workflow step, etc...
const remoteQuery = container.resolve("remoteQuery")
const query = container.resolve(ContainerRegistrationKeys.QUERY)
const taxModuleService = container.resolve(
ModuleRegistrationName.TAX
)
@@ -34,16 +35,10 @@ const taxModuleService = container.resolve(
## Step 1: Retrieve Prices for a Context
After resolving the resources, use the remote query to retrieve the products with the variants' prices for a context:
After resolving the resources, use Query to retrieve the products with the variants' prices for a context:
```ts
// other imports...
import {
remoteQueryObjectFromString,
} from "@medusajs/utils"
// ...
const query = remoteQueryObjectFromString({
const { data: products } = await query.graph({
entryPoint: "product",
fields: [
"*",
@@ -52,18 +47,16 @@ const query = remoteQueryObjectFromString({
],
variables: {
filters: {
id,
id: "prod_123",
},
"variants.calculated_price": {
context: {
region_id,
currency_code,
region_id: "region_123",
currency_code: "usd",
},
},
},
})
const products = await remoteQuery(query)
```
<Note>

View File

@@ -3,29 +3,29 @@ sidebar_label: "Get Product Variant Prices"
---
export const metadata = {
title: `Get Product Variant Prices using Remote Query`,
title: `Get Product Variant Prices using Query`,
}
# {metadata.title}
In this document, you'll learn how to retrieve product variant prices in the Medusa application using the [remote query](!docs!/advanced-development/modules/remote-query).
In this document, you'll learn how to retrieve product variant prices in the Medusa application using the [Query](!docs!/advanced-development/modules/query).
<Note title="Why use the Remote Query?">
<Note title="Why use Query?">
The Product Module doesn't provide pricing functionalities. The Medusa application links the Product Module's `ProductVariant` data model to the Pricing Module's `PriceSet` data model.
So, to retrieve data across the linked records of the two modules, you use the remote query.
So, to retrieve data across the linked records of the two modules, you use Query.
</Note>
## Retrieve All Product Variant Prices
To retrieve all product variant prices, retrieve the product using the remote query and include among its fields `variants.prices.*`.
To retrieve all product variant prices, retrieve the product using Query and include among its fields `variants.prices.*`.
For example:
```ts highlights={[["6"]]}
const query = remoteQueryObjectFromString({
const { data: products } = await query.graph({
entryPoint: "product",
fields: [
"*",
@@ -40,9 +40,6 @@ const query = remoteQueryObjectFromString({
},
},
})
// `result` is array of products
const result = await remoteQuery(query)
```
Each variant in the retrieved products has a `prices` array property with all the product variant prices. Each price object has the properties of the [Pricing Module's Price data model](/references/pricing/models/Price).
@@ -59,7 +56,7 @@ Learn more about prices calculation in [this Pricing Module documentation](../..
</Note>
To retrieve calculated prices of variants based on a context, retrieve the products using remote query and:
To retrieve calculated prices of variants based on a context, retrieve the products using Query and:
- Pass `variants.calculated_price.*` in the `fields` property.
- Pass in the `variables` property a `variants.calculated_price` property whose value is the [calculation context object](../../../pricing/price-calculation/page.mdx#calculation-context).
@@ -67,7 +64,7 @@ To retrieve calculated prices of variants based on a context, retrieve the produ
For example:
```ts highlights={[["6"], ["12"], ["13"], ["14"], ["15"], ["16"], ["17"]]}
const query = remoteQueryObjectFromString({
const { data: products } = await query.graph({
entryPoint: "product",
fields: [
"*",
@@ -76,7 +73,7 @@ const query = remoteQueryObjectFromString({
],
variables: {
filters: {
id,
id: "prod_123",
},
"variants.calculated_price": {
context: {
@@ -86,9 +83,6 @@ const query = remoteQueryObjectFromString({
},
},
})
// `result` is array of products
const result = await remoteQuery(query)
```
The `variants.calculated_price` property of `variables` is an object that has a `context` property. `context`'s value is an object whose keys are price rules, such as `region_id`, and value is the rule's value in this context, such as the customer's region's ID.

View File

@@ -8,6 +8,12 @@ export const metadata = {
This documentation page includes the list of resources registered in the Medusa container of your Medusa application.
<Note>
Use the `ContainerRegistrationKeys` enum imported from `@medusajs/utils` to resolve these resources' names.
</Note>
<Table>
<Table.Header>
<Table.Row>
@@ -43,7 +49,7 @@ This documentation page includes the list of resources registered in the Medusa
</Table.Cell>
<Table.Cell>
`configModule`
`configModule` or `ContainerRegistrationKeys.CONFIG_MODULE`
</Table.Cell>
</Table.Row>
@@ -61,7 +67,7 @@ This documentation page includes the list of resources registered in the Medusa
</Table.Cell>
<Table.Cell>
`logger`
`logger` or `ContainerRegistrationKeys.LOGGER`
</Table.Cell>
</Table.Row>
@@ -69,17 +75,17 @@ This documentation page includes the list of resources registered in the Medusa
<Table.Row>
<Table.Cell>
Remote Query
Query
</Table.Cell>
<Table.Cell>
The remote query function.
The Query utility methods.
</Table.Cell>
<Table.Cell>
`remoteQuery`
`query` or `ContainerRegistrationKeys.QUERY`
</Table.Cell>
</Table.Row>
@@ -97,7 +103,7 @@ This documentation page includes the list of resources registered in the Medusa
</Table.Cell>
<Table.Cell>
`remoteLink`
`remoteLink` or `ContainerRegistrationKeys.REMOTE_LINK`
</Table.Cell>
</Table.Row>

View File

@@ -288,7 +288,7 @@ import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { ContainerRegistrationKeys } from "@medusajs/utils"
export const GET = async (
req: AuthenticatedMedusaRequest,
@@ -299,9 +299,12 @@ export const GET = async (
limit = 20,
offset = 0,
} = req.validatedQuery || {}
const remoteQuery = req.scope.resolve("remoteQuery")
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const query = remoteQueryObjectFromString({
const {
data: digitalProducts,
metadata: { count, take, skip },
} = await query.graph({
entryPoint: "digital_product",
fields: [
"*",
@@ -315,13 +318,8 @@ export const GET = async (
},
})
const {
rows,
metadata: { count, take, skip },
} = await remoteQuery(query)
res.json({
digital_products: rows,
digital_products: digitalProducts,
count,
limit: take,
offset: skip,
@@ -331,7 +329,7 @@ export const GET = async (
This adds a `GET` API route at `/admin/digital-products`.
In the route handler, you use the remote query to retrieve the list of digital products and their relations. The route handler also supports pagination.
In the route handler, you use Query to retrieve the list of digital products and their relations. The route handler also supports pagination.
### Test API Route
@@ -364,7 +362,7 @@ Make sure to replace `{token}` with the JWT token you retrieved.
### Further Reads
- [How to Create an API Route](!docs!/basics/api-routes)
- [Learn more about the remote query](!docs!/advanced-development/modules/remote-query)
- [Learn more about Query](!docs!/advanced-development/modules/query)
---
@@ -1830,7 +1828,7 @@ Create the file `digital-product/src/subscribers/handle-digital-order.ts` with t
export const subscriberHighlight = [
["20", "notificationModuleService", "Resolve the Notification Module's service to use it later to send a notification."],
["22", "fileModuleService", "Resolve the File Module's service to use it later to retrieve a media's URL."],
["26", "query", "Assemble the query to retrieve the digital product order."]
["26", "query", "Run the query to retrieve the digital product order."]
]
```ts title="digital-product/src/subscribers/handle-digital-order.ts" highlights={subscriberHighlight} collapsibleLines="1-14" expandMoreLabel="Show Imports"
@@ -1844,7 +1842,7 @@ import {
} from "@medusajs/types"
import {
ModuleRegistrationName,
remoteQueryObjectFromString,
ContainerRegistrationKeys,
} from "@medusajs/utils"
import { MediaType } from "../modules/digital-product/types"
@@ -1852,14 +1850,14 @@ async function digitalProductOrderCreatedHandler({
event: { data },
container,
}: SubscriberArgs<{ id: string }>) {
const remoteQuery = container.resolve("remoteQuery")
const query = container.resolve(ContainerRegistrationKeys.QUERY)
const notificationModuleService: INotificationModuleService = container
.resolve(ModuleRegistrationName.NOTIFICATION)
const fileModuleService: IFileModuleService = container.resolve(
ModuleRegistrationName.FILE
)
const query = remoteQueryObjectFromString({
const { data: [digitalProductOrder] } = await query.graph({
entryPoint: "digital_product_order",
fields: [
"*",
@@ -1874,8 +1872,6 @@ async function digitalProductOrderCreatedHandler({
},
})
const digitalProductOrder = (await remoteQuery(query))[0]
// TODO format and send notification
}
@@ -2031,7 +2027,7 @@ You return in the response the preview files.
Create the file `src/api/store/customers/me/digital-products/route.ts` with the following content:
export const purchasedDpHighlights = [
["15", "remoteQueryObjectFromString", "Retrieve the customer's purchased digital products."]
["15", "graph", "Retrieve the customer's purchased digital products."]
]
```ts title="src/api/store/customers/me/digital-products/route.ts" highlights={purchasedDpHighlights} collapsibleLines="1-8" expandMoreLabel="Show Imports"
@@ -2040,16 +2036,16 @@ import {
MedusaResponse,
} from "@medusajs/medusa"
import {
remoteQueryObjectFromString,
ContainerRegistrationKeys,
} from "@medusajs/utils"
export const GET = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse
) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const query = remoteQueryObjectFromString({
const { data: [customer] } = await query.graph({
entryPoint: "customer",
fields: [
"orders.digital_product_order.products.*",
@@ -2062,11 +2058,9 @@ export const GET = async (
},
})
const result = await remoteQuery(query)
const digitalProducts = {}
result[0].orders.forEach((order) => {
customer.orders.forEach((order) => {
order.digital_product_order.products.forEach((product) => {
digitalProducts[product.id] = product
})
@@ -2076,23 +2070,22 @@ export const GET = async (
digital_products: Object.values(digitalProducts),
})
}
```
This adds a `GET` API route at `/store/customers/me/digital-products`. All API routes under `/store/customers/me` require customer authentication.
In the route handler, you use remote query to retrieve the customers orders and linked digital product orders, and return the purchased digital products in the response.
In the route handler, you use Query to retrieve the customers orders and linked digital product orders, and return the purchased digital products in the response.
### Get Digital Product Media Download URL API Route
Create the file `src/api/store/customers/me/digital-products/[mediaId]/download/route.ts` with the following content:
export const downloadUrlHighlights = [
["20", "remoteQueryObjectFromString", "Get the customer's orders and linked digital orders."],
["37", "remoteQueryObjectFromString", "Get the digital product orders of the customer and associated products and media."],
["62", "foundMedia", "Set `foundMedia` if the media's ID is equal to the ID passed as a route parameter."],
["68", "!foundMedia", "If `foundMedia` isn't set, throw an error."],
["75", "retrieveFile", "Retrieve the details of the media's file."]
["20", "query.graph", "Get the customer's orders and linked digital orders."],
["36", "query.graph", "Get the digital product orders of the customer and associated products and media."],
["56", "foundMedia", "Set `foundMedia` if the media's ID is equal to the ID passed as a route parameter."],
["65", "!foundMedia", "If `foundMedia` isn't set, throw an error."],
["72", "retrieveFile", "Retrieve the details of the media's file."]
]
```ts title="src/api/store/customers/me/digital-products/[mediaId]/download/route.ts" highlights={downloadUrlHighlights} collapsibleLines="1-10" expandMoreLabel="Show Imports"
@@ -2102,7 +2095,7 @@ import {
} from "@medusajs/medusa"
import {
ModuleRegistrationName,
remoteQueryObjectFromString,
ContainerRegistrationKeys,
MedusaError,
} from "@medusajs/utils"
@@ -2113,9 +2106,9 @@ export const POST = async (
const fileModuleService = req.scope.resolve(
ModuleRegistrationName.FILE
)
const remoteQuery = req.scope.resolve("remoteQuery")
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const customerQuery = remoteQueryObjectFromString({
const { data: [customer] } = await query.graph({
entryPoint: "customer",
fields: [
"orders.digital_product_order.*",
@@ -2127,12 +2120,11 @@ export const POST = async (
},
})
const customerResult = await remoteQuery(customerQuery)
const customerDigitalOrderIds = customerResult[0].orders
const customerDigitalOrderIds = customer.orders
.filter((order) => order.digital_product_order !== undefined)
.map((order) => order.digital_product_order.id)
const dpoQuery = remoteQueryObjectFromString({
const { data: dpoResult } = await query.graph({
entryPoint: "digital_product_order",
fields: [
"products.medias.*",
@@ -2144,8 +2136,6 @@ export const POST = async (
},
})
const dpoResult = await remoteQuery(dpoQuery)
if (!dpoResult.length) {
throw new MedusaError(
MedusaError.Types.NOT_ALLOWED,

View File

@@ -123,9 +123,9 @@ Create workflows to implement these flows, then utilize these workflows in other
## Manage Linked Records
If you've defined links between data models of two modules, you can manage them through two functions: remote link and remote query.
If you've defined links between data models of two modules, you can manage them through two functions: remote link and Query.
Use the remote link to create a link between two records, and use the remote query to fetch data across linked data models.
Use the remote link to create a link between two records, and use Query to fetch data across linked data models.
<CardList itemsPerRow={2} items={[
{
@@ -135,9 +135,9 @@ Use the remote link to create a link between two records, and use the remote que
icon: AcademicCapSolid,
},
{
href: "!docs!/advanced-development/modules/remote-query",
title: "How to Use the Remote Query",
text: "Learn how to fetch data across modules with remote query.",
href: "!docs!/advanced-development/modules/query",
title: "How to Use Query",
text: "Learn how to fetch data across modules with Medusa's Query.",
icon: AcademicCapSolid,
},
]} />

View File

@@ -627,16 +627,16 @@ In the file `src/api/restaurants/route.ts` add the following API route:
```ts title="src/api/restaurants/route.ts"
// other imports...
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { ContainerRegistrationKeys } from "@medusajs/utils"
// ...
export async function GET(req: MedusaRequest, res: MedusaResponse) {
const { currency_code = "eur", ...queryFilters } = req.query
const remoteQuery = req.scope.resolve("remoteQuery")
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const restaurantsQuery = remoteQueryObjectFromString({
const { data: restaurants } = await query.graph({
entryPoint: "restaurants",
fields: [
"id",
@@ -662,13 +662,11 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
},
})
const restaurants = await remoteQuery(restaurantsQuery)
return res.status(200).json({ restaurants })
}
```
This creates a `GET` API route at `/restaurants`. It uses remote query to retrieve a restaurant, its products, and the product variants prices for a specified currency.
This creates a `GET` API route at `/restaurants`. It uses Query to retrieve a restaurant, its products, and the product variants prices for a specified currency.
### Test it Out
@@ -682,7 +680,7 @@ This returns the list of restaurants in the response.
### Further Reads
- [What is Remote Query and how to use it](!docs!/advanced-development/modules/remote-query)
- [What is and how to use it](!docs!/advanced-development/modules/query)
- [How to Retrieve Prices for Product Variants](../../../../commerce-modules/product/guides/price/page.mdx)
---
@@ -1502,14 +1500,14 @@ Create the file `src/workflows/delivery/steps/notify-restaurant.ts` with the fol
export const notifyRestaurantStepHighlights = [
["11", "async", "Set the step as async."],
["18", "deliveryQuery", "Retrieve the delivery and its restaurant."],
["32", "emit", "Emit a custom event that can be used to notify the restaurant that a new delivery is created."]
["18", "graph", "Retrieve the delivery and its restaurant."],
["30", "emit", "Emit a custom event that can be used to notify the restaurant that a new delivery is created."]
]
```ts title="src/workflows/delivery/steps/notify-restaurant.ts" highlights={notifyRestaurantStepHighlights} collapsibleLines="1-6" expandButtonLabel="Show Imports"
import {
ModuleRegistrationName,
remoteQueryObjectFromString,
ContainerRegistrationKeys,
} from "@medusajs/utils"
import { createStep } from "@medusajs/workflows-sdk"
@@ -1522,9 +1520,9 @@ export const notifyRestaurantStep = createStep(
maxRetries: 2,
},
async function (deliveryId: string, { container }) {
const remoteQuery = container.resolve("remoteQuery")
const query = container.resolve(ContainerRegistrationKeys.QUERY)
const deliveryQuery = remoteQueryObjectFromString({
const { data: [delivery] } = await query.graph({
entryPoint: "deliveries",
variables: {
filters: {
@@ -1534,8 +1532,6 @@ export const notifyRestaurantStep = createStep(
fields: ["id", "restaurant.id"],
})
const delivery = await remoteQuery(deliveryQuery).then((res) => res[0])
const eventBus = container.resolve(ModuleRegistrationName.EVENT_BUS)
await eventBus.emit({
@@ -1547,7 +1543,6 @@ export const notifyRestaurantStep = createStep(
})
}
)
```
In this step, you:
@@ -1600,7 +1595,7 @@ import { CreateOrderShippingMethodDTO } from "@medusajs/types"
import {
ModuleRegistrationName,
Modules,
remoteQueryObjectFromString,
ContainerRegistrationKeys,
} from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
import { DELIVERY_MODULE } from "../../../modules/delivery"
@@ -1608,9 +1603,9 @@ import { DELIVERY_MODULE } from "../../../modules/delivery"
export const createOrderStep = createStep(
"create-order-step",
async function (deliveryId: string, { container }) {
const remoteQuery = container.resolve("remoteQuery")
const query = container.resolve(ContainerRegistrationKeys.QUERY)
const deliveryQuery = remoteQueryObjectFromString({
const { data: [delivery] } = await query.graph({
entryPoint: "deliveries",
variables: {
filters: {
@@ -1627,8 +1622,6 @@ export const createOrderStep = createStep(
],
})
const delivery = await remoteQuery(deliveryQuery).then((res) => res[0])
// TODO create order
},
async ({ orderId }, { container }) => {
@@ -2409,8 +2402,8 @@ Start by creating the file `src/api/utils/is-delivery-restaurant.ts` with the fo
export const isDeliveryRestaurantHighlights = [
["21", "restaurantAdmin", "Retrieve the logged-in restaurant admin."],
["28", "query", "Retrieve the delivery based on the ID in the path parameter."],
["42", "", "If the restaurant admin doesn't belong to the delivery's restaurant, return an unauthorized response."]
["28", "graph", "Retrieve the delivery based on the ID in the path parameter."],
["40", "", "If the restaurant admin doesn't belong to the delivery's restaurant, return an unauthorized response."]
]
```ts title="src/api/utils/is-delivery-restaurant.ts" highlights={isDeliveryRestaurantHighlights} collapsibleLines="1-10" expandButtonLabel="Show Imports"
@@ -2420,7 +2413,7 @@ import {
MedusaResponse,
} from "@medusajs/medusa"
import {
remoteQueryObjectFromString,
ContainerRegistrationKeys,
} from "@medusajs/utils"
import { RESTAURANT_MODULE } from "../../modules/restaurant"
@@ -2429,7 +2422,7 @@ export const isDeliveryRestaurant = async (
res: MedusaResponse,
next: MedusaNextFunction
) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const restaurantModuleService = req.scope.resolve(
RESTAURANT_MODULE
)
@@ -2441,7 +2434,7 @@ export const isDeliveryRestaurant = async (
}
)
const query = remoteQueryObjectFromString({
const { data: [delivery] } = await query.graph({
entryPoint: "delivery",
fields: [
"restaurant.*",
@@ -2453,9 +2446,7 @@ export const isDeliveryRestaurant = async (
},
})
const result = await remoteQuery(query)
if (result[0].restaurant.id !== restaurantAdmin.restaurant.id) {
if (delivery.restaurant.id !== restaurantAdmin.restaurant.id) {
return res.status(403).json({
message: "unauthorized",
})

View File

@@ -563,13 +563,13 @@ To create the API route that retrieves the vendors products, create the file
export const retrieveProductHighlights = [
["16", "retrieveVendorAdmin", "Retrive the vendor admin to retrieve its vendor's ID."],
["33", "remoteQuery", "Retrieve the vendor's products using remote query."]
["23", "graph", "Retrieve the vendor's products using Query."]
]
```ts title="src/api/vendors/products/route.ts" highlights={retrieveProductHighlights}
import { AuthenticatedMedusaRequest, MedusaResponse } from "@medusajs/medusa"
import {
remoteQueryObjectFromString,
ContainerRegistrationKeys,
} from "@medusajs/utils"
import MarketplaceModuleService from "../../../modules/marketplace/service"
import { MARKETPLACE_MODULE } from "../../../modules/marketplace"
@@ -578,7 +578,7 @@ export const GET = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse
) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const marketplaceModuleService: MarketplaceModuleService =
req.scope.resolve(MARKETPLACE_MODULE)
@@ -589,7 +589,7 @@ export const GET = async (
}
)
const query = remoteQueryObjectFromString({
const { data: [vendor] } = await query.graph({
entryPoint: "vendor",
fields: ["products.*"],
variables: {
@@ -599,15 +599,13 @@ export const GET = async (
},
})
const result = await remoteQuery(query)
res.json({
products: result[0].products,
products: vendor.products,
})
}
```
This adds a `GET` API route at `/vendors/products` that, using the remote query, retrieves the list of products of the vendor and returns them in the response.
This adds a `GET` API route at `/vendors/products` that, using Query, retrieves the list of products of the vendor and returns them in the response.
To add the create product API route, add to the same file the following:
@@ -782,7 +780,7 @@ curl 'http://localhost:9000/vendors/products' \
### Further Reads
- [How to use the Remote Query](!docs!/advanced-development/modules/remote-query)
- [How to use Query](!docs!/advanced-development/modules/query)
- [How to use the Remote Link](!docs!/advanced-development/modules/remote-link)
---
@@ -817,7 +815,7 @@ import {
StepResponse,
} from "@medusajs/workflows-sdk"
import { CartDTO, CartLineItemDTO } from "@medusajs/types"
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { ContainerRegistrationKeys } from "@medusajs/utils"
type StepInput = {
cart: CartDTO
@@ -826,12 +824,12 @@ type StepInput = {
const groupVendorItemsStep = createStep(
"group-vendor-items",
async ({ cart }: StepInput, { container }) => {
const remoteQuery = container.resolve("remoteQuery")
const query = container.resolve(ContainerRegistrationKeys.QUERY)
const vendorsItems: Record<string, CartLineItemDTO[]> = {}
await Promise.all(cart.items?.map(async (item) => {
const query = remoteQueryObjectFromString({
const { data: [product] } = await query.graph({
entryPoint: "product",
fields: ["vendor.*"],
variables: {
@@ -841,9 +839,7 @@ const groupVendorItemsStep = createStep(
},
})
const result = await remoteQuery(query)
const vendorId = result[0].vendor?.id
const vendorId = product.vendor?.id
if (!vendorId) {
return
@@ -1251,13 +1247,13 @@ Create the file `src/api/vendors/orders/route.ts` with the following content:
export const getOrderHighlights = [
["15", "retrieveVendorAdmin", "Retrive the vendor admin to retrieve its vendor's ID."],
["32", "remoteQuery", "Retrieve the orders of the vendor."],
["34", "getOrdersListWorkflow", "Use Medusa's workflow to retrieve the list of orders."],
["22", "graph", "Retrieve the orders of the vendor."],
["32", "getOrdersListWorkflow", "Use Medusa's workflow to retrieve the list of orders."],
]
```ts title="src/api/vendors/orders/route.ts" highlights={getOrderHighlights} collapsibleLines="1-6" expandMoreLabel="Show Imports"
import { AuthenticatedMedusaRequest, MedusaResponse } from "@medusajs/medusa"
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { ContainerRegistrationKeys } from "@medusajs/utils"
import { getOrdersListWorkflow } from "@medusajs/core-flows"
import MarketplaceModuleService from "../../../modules/marketplace/service"
import { MARKETPLACE_MODULE } from "../../../modules/marketplace"
@@ -1266,7 +1262,7 @@ export const GET = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse
) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const marketplaceModuleService: MarketplaceModuleService =
req.scope.resolve(MARKETPLACE_MODULE)
@@ -1277,7 +1273,7 @@ export const GET = async (
}
)
const query = remoteQueryObjectFromString({
const { data: [vendor] } = await query.graph({
entryPoint: "vendor",
fields: ["orders.*"],
variables: {
@@ -1287,8 +1283,6 @@ export const GET = async (
},
})
const result = await remoteQuery(query)
const { result: orders } = await getOrdersListWorkflow(req.scope)
.run({
input: {
@@ -1310,7 +1304,7 @@ export const GET = async (
],
variables: {
filters: {
id: result[0].orders.map((order) => order.id),
id: vendor.orders.map((order) => order.id),
},
},
},

View File

@@ -654,7 +654,7 @@ In this step, youll change what happens when the [Complete Cart API route](!a
Create the file `src/api/store/carts/[id]/complete/route.ts` with the following content:
export const completeCartHighlights = [
["17", "remoteQueryObjectFromString", "Retrieve the cart to retrieve the subscription details from the `metadata`."],
["17", "graph", "Retrieve the cart to retrieve the subscription details from the `metadata`."],
["31", "", "If the subscription data isn't set in the cart's `metadata`, throw an error"],
["38", "createSubscriptionWorkflow", "Execute the workflow created in the previous step."]
]
@@ -665,7 +665,7 @@ import {
MedusaResponse,
} from "@medusajs/medusa"
import {
remoteQueryObjectFromString,
ContainerRegistrationKeys,
MedusaError,
} from "@medusajs/utils"
import createSubscriptionWorkflow from "../../../../../workflows/create-subscription"
@@ -674,9 +674,9 @@ export const POST = async (
req: MedusaRequest,
res: MedusaResponse
) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const query = remoteQueryObjectFromString({
const { data: [cart] } = await query.graph({
entryPoint: "cart",
fields: [
"metadata",
@@ -688,7 +688,7 @@ export const POST = async (
},
})
const { metadata } = (await remoteQuery(query))[0]
const { metadata } = cart
if (!metadata?.subscription_interval || !metadata.subscription_period) {
throw new MedusaError(
@@ -973,7 +973,7 @@ In this step, youll add two API routes for admin users:
Create the file `src/api/admin/subscriptions/route.ts` with the following content:
export const listSubscriptionsAdminHighlight = [
["18", "remoteQueryObjectFromString", "Retrieve the subscriptions with their orders and customer."]
["21", "graph", "Retrieve the subscriptions with their orders and customer."]
]
```ts title="src/api/admin/subscriptions/route.ts" highlights={listSubscriptionsAdminHighlight}
@@ -981,20 +981,23 @@ import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { ContainerRegistrationKeys } from "@medusajs/utils"
export const GET = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse
) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const {
limit = 20,
offset = 0,
} = req.validatedQuery || {}
const query = remoteQueryObjectFromString({
const {
data: subscriptions,
metadata: { count, take, skip },
} = await query.graph({
entryPoint: "subscription",
fields: [
"*",
@@ -1011,13 +1014,8 @@ export const GET = async (
},
})
const {
rows,
metadata: { count, take, skip },
} = await remoteQuery(query)
res.json({
subscriptions: rows,
subscriptions,
count,
limit: take,
offset: skip,
@@ -1027,7 +1025,7 @@ export const GET = async (
This adds a `GET` API route at `/admin/subscriptions`.
In the route handler, you use the remote query to retrieve a subscription with its orders and customer.
In the route handler, you use Query to retrieve a subscription with its orders and customer.
The API route accepts pagination parameters to paginate the subscription list. It returns the subscriptions with pagination parameters in the response.
@@ -1036,7 +1034,7 @@ The API route accepts pagination parameters to paginate the subscription list. I
Create the file `src/api/admin/subscriptions/[id]/route.ts` with the following content:
export const getSubscriptionsAdminHighlight = [
["13", "remoteQueryObjectFromString", "Retrieve the subscription with its orders and customer."]
["13", "graph", "Retrieve the subscription with its orders and customer."]
]
```ts title="src/api/admin/subscriptions/[id]/route.ts" highlights={getSubscriptionsAdminHighlight}
@@ -1044,15 +1042,15 @@ import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { ContainerRegistrationKeys } from "@medusajs/utils"
export const GET = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse
) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const query = remoteQueryObjectFromString({
const { data: [subscription] } = await query.graph({
entryPoint: "subscription",
fields: [
"*",
@@ -1067,17 +1065,15 @@ export const GET = async (
},
})
const result = await remoteQuery(query)
res.json({
subscription: result[0],
subscription,
})
}
```
This adds a `GET` API route at `/admin/subscriptions/[id]`, where `[id]` is the ID of the subscription to retrieve.
In the route handler, you retrieve a subscription by its ID using the remote query and return it in the response.
In the route handler, you retrieve a subscription by its ID using Query and return it in the response.
In the next section, youll extend the Medusa admin and use these API routes to show the subscriptions.
@@ -2130,15 +2126,15 @@ import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { ContainerRegistrationKeys } from "@medusajs/utils"
export const GET = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse
) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const query = remoteQueryObjectFromString({
const { data: [customer] } = await query.graph({
entryPoint: "customer",
fields: [
"subscriptions.*",
@@ -2150,17 +2146,15 @@ export const GET = async (
},
})
const result = await remoteQuery(query)
res.json({
subscriptions: result[0].subscriptions,
subscriptions: customer.subscriptions,
})
}
```
This adds an API route at `/store/customers/me/subscriptions`.
In the route handler, you retrieve the authenticated customers subscriptions using the remote query and return them in the response.
In the route handler, you retrieve the authenticated customers subscriptions using Query and return them in the response.
### Cancel Subscription API Route

View File

@@ -48,7 +48,7 @@ The method returns an array of the first `15` records matching the filters.
<Note>
This applies to relations between data models of the same module. To retrieve linked records of different modules, use [remote query](!docs!/advanced-development/modules/remote-query).
This applies to relations between data models of the same module. To retrieve linked records of different modules, use [Query](!docs!/advanced-development/modules/query).
</Note>

View File

@@ -54,7 +54,7 @@ The method returns an array with two items:
<Note>
This applies to relations between data models of the same module. To retrieve linked records of different modules, use [remote query](!docs!/advanced-development/modules/remote-query).
This applies to relations between data models of the same module. To retrieve linked records of different modules, use [Query](!docs!/advanced-development/modules/query).
</Note>

View File

@@ -30,7 +30,7 @@ The method returns the record as an object.
<Note>
This applies to relations between data models of the same module. To retrieve linked records of different modules, use [remote query](!docs!/advanced-development/modules/remote-query).
This applies to relations between data models of the same module. To retrieve linked records of different modules, use [Query](!docs!/advanced-development/modules/query).
</Note>