docs: update query usage across docs (#9120)

WIP
This commit is contained in:
Shahed Nasser
2024-09-16 15:46:26 +03:00
committed by GitHub
parent 35ffaf73d7
commit 0bcdcccbe2
7 changed files with 123 additions and 144 deletions

View File

@@ -8,9 +8,9 @@ export const metadata = {
In this chapter, youll learn about the Query utility and how to use it to fetch data from modules. In this chapter, youll learn about the Query utility and how to use it to fetch data from modules.
<Note> <Note type="soon" title="In Development">
Remote Query is now deprecated in favor of Query. Follow this documentation to see the difference in the usage. Query is in development and is subject to change in future releases.
</Note> </Note>
@@ -29,7 +29,7 @@ For example, create the route `src/api/store/query/route.ts` with the following
export const exampleHighlights = [ export const exampleHighlights = [
["13", "", "Resolve Query from the Medusa container."], ["13", "", "Resolve Query from the Medusa container."],
["15", "graph", "Run a query to retrieve data."], ["15", "graph", "Run a query to retrieve data."],
["16", "entryPoint", "The name of the data model you're querying."], ["16", "entity", "The name of the data model you're querying."],
["17", "fields", "An array of the data models properties to retrieve in the result."], ["17", "fields", "An array of the data models properties to retrieve in the result."],
] ]
@@ -49,7 +49,7 @@ export const GET = async (
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY) const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const { data: myCustoms } = await query.graph({ const { data: myCustoms } = await query.graph({
entryPoint: "my_custom", entity: "my_custom",
fields: ["id", "name"], fields: ["id", "name"],
}) })
@@ -61,7 +61,7 @@ In the above example, you resolve Query from the Medusa container using the `Con
Then, you run a query using its `graph` method. This method accepts as a parameter an object with the following required properties: 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. - `entity`: 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. - `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: The method returns an object that has a `data` property, which holds an array of the retrieved data. For example:
@@ -79,6 +79,14 @@ The method returns an object that has a `data` property, which holds an array of
--- ---
## Querying the Graph
When you use the `query.graph` method, you're running a query through an internal graph that the Medusa application creates.
This graph collects data models of all modules in your application, including commerce and custom modules, and identifies relations and links between them.
---
## Retrieve Linked Records ## Retrieve Linked Records
Retrieve the records of a linked data model by passing in `fields` the data model's name suffixed with `.*`. Retrieve the records of a linked data model by passing in `fields` the data model's name suffixed with `.*`.
@@ -87,7 +95,7 @@ For example:
```ts highlights={[["6"]]} ```ts highlights={[["6"]]}
const { data: myCustoms } = await query.graph({ const { data: myCustoms } = await query.graph({
entryPoint: "my_custom", entity: "my_custom",
fields: [ fields: [
"id", "id",
"name", "name",
@@ -110,7 +118,7 @@ For example:
```ts highlights={[["6"]]} ```ts highlights={[["6"]]}
const { data: myCustoms } = await query.graph({ const { data: myCustoms } = await query.graph({
entryPoint: "my_custom", entity: "my_custom",
fields: [ fields: [
"id", "id",
"name", "name",
@@ -125,54 +133,36 @@ const { data: myCustoms } = await query.graph({
```ts highlights={[["6"], ["7"], ["8"], ["9"]]} ```ts highlights={[["6"], ["7"], ["8"], ["9"]]}
const { data: myCustoms } = await query.graph({ const { data: myCustoms } = await query.graph({
entryPoint: "my_custom", entity: "my_custom",
fields: ["id", "name"], fields: ["id", "name"],
variables: { filters: {
filters: { id: [
id: [ "mc_01HWSVWR4D2XVPQ06DQ8X9K7AX",
"mc_01HWSVWR4D2XVPQ06DQ8X9K7AX", "mc_01HWSVWK3KYHKQEE6QGS2JC3FX",
"mc_01HWSVWK3KYHKQEE6QGS2JC3FX", ],
],
},
}, },
}) })
``` ```
The `query.graph` function accepts a `filters` property. You can use this property to filter retrieved records.
In the example above, you filter the `my_custom` records by multiple IDs.
<Note> <Note>
Filters don't apply on fields of linked data models from other modules. Filters don't apply on fields of linked data models from other modules.
</Note> </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 ## Sort Records
```ts highlights={[["5"], ["6"], ["7"]]} ```ts highlights={[["5"], ["6"], ["7"]]}
const { data: myCustoms } = await query.graph({ const { data: myCustoms } = await query.graph({
entryPoint: "my_custom", entity: "my_custom",
fields: ["id", "name"], fields: ["id", "name"],
variables: { pagination: {
order: { order: {
name: "DESC", name: "DESC",
}, },
@@ -186,7 +176,9 @@ Sorting doesn't work on fields of linked data models from other modules.
</Note> </Note>
To sort returned records, pass an `order` property to `variables`. The `graph` method's object parameter accepts a `pagination` property to configure the pagination of retrieved records.
To sort returned records, pass an `order` property to `pagination`.
The `order` property is an object whose keys are property names, and values are either: The `order` property is an object whose keys are property names, and values are either:
@@ -202,16 +194,16 @@ const {
data: myCustoms, data: myCustoms,
metadata: { count, take, skip }, metadata: { count, take, skip },
} = await query.graph({ } = await query.graph({
entryPoint: "my_custom", entity: "my_custom",
fields: ["id", "name"], fields: ["id", "name"],
variables: { pagination: {
skip: 0, skip: 0,
take: 10, take: 10,
}, },
}) })
``` ```
To paginate the returned records, pass the following properties to `variables`: To paginate the returned records, pass the following properties to `pagination`:
- `skip`: (required to apply pagination) The number of records to skip before fetching the results. - `skip`: (required to apply pagination) The number of records to skip before fetching the results.
- `take`: The number of records to fetch. - `take`: The number of records to fetch.

View File

@@ -38,23 +38,27 @@ const taxModuleService = container.resolve(
After resolving the resources, use 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 ```ts
import { QueryContext } from "@medusajs/utils"
// ...
const { data: products } = await query.graph({ const { data: products } = await query.graph({
entryPoint: "product", entity: "product",
fields: [ fields: [
"*", "*",
"variants.*", "variants.*",
"variants.calculated_price.*", "variants.calculated_price.*",
], ],
variables: { filters: {
filters: { id: "prod_123",
id: "prod_123", },
}, context: {
"variants.calculated_price": { variants: {
context: { calculated_price: QueryContext({
region_id: "region_123", region_id: "region_123",
currency_code: "usd", currency_code: "usd",
}, }),
}, }
}, },
}) })
``` ```

View File

@@ -26,18 +26,16 @@ For example:
```ts highlights={[["6"]]} ```ts highlights={[["6"]]}
const { data: products } = await query.graph({ const { data: products } = await query.graph({
entryPoint: "product", entity: "product",
fields: [ fields: [
"*", "*",
"variants.*", "variants.*",
"variants.prices.*", "variants.prices.*",
], ],
variables: { filters: {
filters: { id: [
id: [ "prod_123",
"prod_123", ],
],
},
}, },
}) })
``` ```
@@ -59,32 +57,38 @@ Learn more about prices calculation in [this Pricing Module documentation](../..
To retrieve calculated prices of variants based on a context, retrieve the products using 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 `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). - Pass a `context` property in the object parameter. Its value is an object of objects to sets the context for the retrieved fields.
For example: For example:
```ts highlights={[["6"], ["12"], ["13"], ["14"], ["15"], ["16"], ["17"]]} ```ts highlights={[["6"], ["12"], ["13"], ["14"], ["15"], ["16"], ["17"]]}
import { QueryContext } from "@medusajs/utils"
// ...
const { data: products } = await query.graph({ const { data: products } = await query.graph({
entryPoint: "product", entity: "product",
fields: [ fields: [
"*", "*",
"variants.*", "variants.*",
"variants.calculated_price.*", "variants.calculated_price.*",
], ],
variables: { filters: {
filters: { id: "prod_123",
id: "prod_123", },
}, context: {
"variants.calculated_price": { variants: {
context: { calculated_price: QueryContext({
region_id: "reg_01J3MRPDNXXXDSCC76Y6YCZARS", region_id: "reg_01J3MRPDNXXXDSCC76Y6YCZARS",
currency_code: "eur", currency_code: "eur",
}, }),
}, },
}, },
}) })
``` ```
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. For the context of the product variant's calculated price, you pass an object to `context` with the property `variants`, whose value is another object with the property `calculated_price`.
`calculated_price`'s value is created using the `QueryContext` utility function, passing it a [calculation context object](../../../pricing/price-calculation/page.mdx#calculation-context).
Each variant in the retrieved products has a `calculated_price` object. Learn more about its properties in [this Pricing Module guide](../../../pricing/price-calculation/page.mdx#returned-price-object). Each variant in the retrieved products has a `calculated_price` object. Learn more about its properties in [this Pricing Module guide](../../../pricing/price-calculation/page.mdx#returned-price-object).

View File

@@ -305,14 +305,14 @@ export const GET = async (
data: digitalProducts, data: digitalProducts,
metadata: { count, take, skip }, metadata: { count, take, skip },
} = await query.graph({ } = await query.graph({
entryPoint: "digital_product", entity: "digital_product",
fields: [ fields: [
"*", "*",
"medias.*", "medias.*",
"product_variant.*", "product_variant.*",
...(fields || []), ...(fields || []),
], ],
variables: { pagination: {
skip: offset, skip: offset,
take: limit, take: limit,
}, },
@@ -1858,17 +1858,15 @@ async function digitalProductOrderCreatedHandler({
) )
const { data: [digitalProductOrder] } = await query.graph({ const { data: [digitalProductOrder] } = await query.graph({
entryPoint: "digital_product_order", entity: "digital_product_order",
fields: [ fields: [
"*", "*",
"products.*", "products.*",
"products.medias.*", "products.medias.*",
"order.*", "order.*",
], ],
variables: { filters: {
filters: { id: data.id,
id: data.id,
},
}, },
}) })
@@ -2046,15 +2044,13 @@ export const GET = async (
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY) const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const { data: [customer] } = await query.graph({ const { data: [customer] } = await query.graph({
entryPoint: "customer", entity: "customer",
fields: [ fields: [
"orders.digital_product_order.products.*", "orders.digital_product_order.products.*",
"orders.digital_product_order.products.medias.*", "orders.digital_product_order.products.medias.*",
], ],
variables: { filters: {
filters: { id: req.auth_context.actor_id,
id: req.auth_context.actor_id,
},
}, },
}) })
@@ -2109,14 +2105,12 @@ export const POST = async (
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY) const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const { data: [customer] } = await query.graph({ const { data: [customer] } = await query.graph({
entryPoint: "customer", entity: "customer",
fields: [ fields: [
"orders.digital_product_order.*", "orders.digital_product_order.*",
], ],
variables: { filters: {
filters: { id: req.auth_context.actor_id,
id: req.auth_context.actor_id,
},
}, },
}) })
@@ -2125,14 +2119,12 @@ export const POST = async (
.map((order) => order.digital_product_order.id) .map((order) => order.digital_product_order.id)
const { data: dpoResult } = await query.graph({ const { data: dpoResult } = await query.graph({
entryPoint: "digital_product_order", entity: "digital_product_order",
fields: [ fields: [
"products.medias.*", "products.medias.*",
], ],
variables: { filters: {
filters: { id: customerDigitalOrderIds,
id: customerDigitalOrderIds,
},
}, },
}) })

View File

@@ -627,7 +627,10 @@ In the file `src/api/restaurants/route.ts` add the following API route:
```ts title="src/api/restaurants/route.ts" ```ts title="src/api/restaurants/route.ts"
// other imports... // other imports...
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import { ContainerRegistrationKeys } from "@medusajs/utils" import {
ContainerRegistrationKeys,
QueryContext
} from "@medusajs/utils"
// ... // ...
@@ -637,7 +640,7 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY) const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const { data: restaurants } = await query.graph({ const { data: restaurants } = await query.graph({
entryPoint: "restaurants", entity: "restaurants",
fields: [ fields: [
"id", "id",
"handle", "handle",
@@ -652,11 +655,13 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
"products.variants.*", "products.variants.*",
"products.variants.calculated_price.*", "products.variants.calculated_price.*",
], ],
variables: { filters: queryFilters,
filters: queryFilters, context: {
"products.variants.calculated_price": { products: {
context: { variants: {
currency_code, calculated_price: QueryContext({
currency_code,
})
}, },
}, },
}, },
@@ -1690,11 +1695,9 @@ export const notifyRestaurantStep = createStep(
const query = container.resolve(ContainerRegistrationKeys.QUERY) const query = container.resolve(ContainerRegistrationKeys.QUERY)
const { data: [delivery] } = await query.graph({ const { data: [delivery] } = await query.graph({
entryPoint: "deliveries", entity: "deliveries",
variables: { filters: {
filters: { id: deliveryId,
id: deliveryId,
},
}, },
fields: ["id", "restaurant.id"], fields: ["id", "restaurant.id"],
}) })
@@ -1772,12 +1775,7 @@ export const createOrderStep = createStep(
const query = container.resolve(ContainerRegistrationKeys.QUERY) const query = container.resolve(ContainerRegistrationKeys.QUERY)
const { data: [delivery] } = await query.graph({ const { data: [delivery] } = await query.graph({
entryPoint: "deliveries", entity: "deliveries",
variables: {
filters: {
id: deliveryId,
},
},
fields: [ fields: [
"id", "id",
"cart.*", "cart.*",
@@ -1786,6 +1784,9 @@ export const createOrderStep = createStep(
"cart.items.*", "cart.items.*",
"cart.shipping_methods.*", "cart.shipping_methods.*",
], ],
filters: {
id: deliveryId,
},
}) })
// TODO create order // TODO create order
@@ -2601,14 +2602,12 @@ export const isDeliveryRestaurant = async (
) )
const { data: [delivery] } = await query.graph({ const { data: [delivery] } = await query.graph({
entryPoint: "delivery", entity: "delivery",
fields: [ fields: [
"restaurant.*", "restaurant.*",
], ],
variables: { filters: {
filters: { id: req.params.id,
id: req.params.id,
},
}, },
}) })

View File

@@ -590,12 +590,10 @@ export const GET = async (
) )
const { data: [vendor] } = await query.graph({ const { data: [vendor] } = await query.graph({
entryPoint: "vendor", entity: "vendor",
fields: ["products.*"], fields: ["products.*"],
variables: { filters: {
filters: { id: [vendorAdmin.vendor.id],
id: [vendorAdmin.vendor.id],
},
}, },
}) })
@@ -830,12 +828,10 @@ const groupVendorItemsStep = createStep(
await Promise.all(cart.items?.map(async (item) => { await Promise.all(cart.items?.map(async (item) => {
const { data: [product] } = await query.graph({ const { data: [product] } = await query.graph({
entryPoint: "product", entity: "product",
fields: ["vendor.*"], fields: ["vendor.*"],
variables: { filters: {
filters: { id: [item.product_id],
id: [item.product_id],
},
}, },
}) })
@@ -1274,12 +1270,10 @@ export const GET = async (
) )
const { data: [vendor] } = await query.graph({ const { data: [vendor] } = await query.graph({
entryPoint: "vendor", entity: "vendor",
fields: ["orders.*"], fields: ["orders.*"],
variables: { filters: {
filters: { id: [vendorAdmin.vendor.id],
id: [vendorAdmin.vendor.id],
},
}, },
}) })

View File

@@ -677,14 +677,12 @@ export const POST = async (
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY) const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const { data: [cart] } = await query.graph({ const { data: [cart] } = await query.graph({
entryPoint: "cart", entity: "cart",
fields: [ fields: [
"metadata", "metadata",
], ],
variables: { filters: {
filters: { id: [req.params.id],
id: [req.params.id],
},
}, },
}) })
@@ -998,14 +996,14 @@ export const GET = async (
data: subscriptions, data: subscriptions,
metadata: { count, take, skip }, metadata: { count, take, skip },
} = await query.graph({ } = await query.graph({
entryPoint: "subscription", entity: "subscription",
fields: [ fields: [
"*", "*",
"orders.*", "orders.*",
"customer.*", "customer.*",
...(req.validatedQuery?.fields.split(",") || []), ...(req.validatedQuery?.fields.split(",") || []),
], ],
variables: { pagination: {
skip: offset, skip: offset,
take: limit, take: limit,
order: { order: {
@@ -1051,17 +1049,15 @@ export const GET = async (
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY) const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const { data: [subscription] } = await query.graph({ const { data: [subscription] } = await query.graph({
entryPoint: "subscription", entity: "subscription",
fields: [ fields: [
"*", "*",
"orders.*", "orders.*",
"customer.*", "customer.*",
...(req.validatedQuery?.fields.split(",") || []), ...(req.validatedQuery?.fields.split(",") || []),
], ],
variables: { filters: {
filters: { id: [req.params.id],
id: [req.params.id],
},
}, },
}) })
@@ -2134,14 +2130,12 @@ export const GET = async (
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY) const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const { data: [customer] } = await query.graph({ const { data: [customer] } = await query.graph({
entryPoint: "customer", entity: "customer",
fields: [ fields: [
"subscriptions.*", "subscriptions.*",
], ],
variables: { filters: {
filters: { id: [req.auth_context.actor_id],
id: [req.auth_context.actor_id],
},
}, },
}) })