|
|
|
|
@@ -0,0 +1,211 @@
|
|
|
|
|
export const metadata = {
|
|
|
|
|
title: `${pageNumber} Query Context`,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# {metadata.title}
|
|
|
|
|
|
|
|
|
|
In this chapter, you'll learn how to pass contexts when retrieving data with [Query](../query/page.mdx).
|
|
|
|
|
|
|
|
|
|
## What is Query Context?
|
|
|
|
|
|
|
|
|
|
Query context is a way to pass additional information when retrieving data with Query. This data can be useful when applying custom transformations to the retrieved data based on the current context.
|
|
|
|
|
|
|
|
|
|
For example, consider you have a Blog Module with posts and authors. You can accept the user's language as a context and return the posts in the user's language. Another example is how Medusa uses Query Context to [retrieve product variants' prices based on the customer's currency](!resources!/commerce-modules/product/guides/price).
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## How to Use Query Context
|
|
|
|
|
|
|
|
|
|
The `query.graph` method accepts an optional `context` parameter that can be used to pass additional context either to the data model you're retrieving (for example, `post`), or its related and linked models (for example, `author`).
|
|
|
|
|
|
|
|
|
|
You initialize a context using `QueryContext` from the Modules SDK. It accepts an object of contexts as an argument.
|
|
|
|
|
|
|
|
|
|
For example, to retrieve posts using Query while passing the user's language as a context:
|
|
|
|
|
|
|
|
|
|
export const highlights1 = [
|
|
|
|
|
["4", "context", "Pass additional context to the query."],
|
|
|
|
|
["4", "QueryContext", "Create a query context."]
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
const { data } = await query.graph({
|
|
|
|
|
entity: "post",
|
|
|
|
|
fields: ["*"],
|
|
|
|
|
context: QueryContext({
|
|
|
|
|
lang: "es",
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In this example, you pass in the context a `lang` property whose value is `es`.
|
|
|
|
|
|
|
|
|
|
Then, to handle the context while retrieving records of the data model, in the associated module's service you override the generated `list` method of the data model.
|
|
|
|
|
|
|
|
|
|
For example, continuing the example above, you can override the `listPosts` method of the Blog Module's service to handle the context:
|
|
|
|
|
|
|
|
|
|
export const highlights2 = [
|
|
|
|
|
["11", "listPosts", "Override the generated listPosts method."],
|
|
|
|
|
["16", "context", "The context is passed as part of `filters`."],
|
|
|
|
|
["19", "super", "Use the parent's `listPosts` method to retrieve the posts."],
|
|
|
|
|
["21", "", "If the language is set in the context, you transform the titles of the posts."]
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
```ts highlights={highlights2}
|
|
|
|
|
import { MedusaContext, MedusaService } from "@medusajs/framework/utils"
|
|
|
|
|
import { Context, FindConfig } from "@medusajs/framework/types"
|
|
|
|
|
import Post from "./models/post"
|
|
|
|
|
import Author from "./models/author"
|
|
|
|
|
|
|
|
|
|
class BlogModuleService extends MedusaService({
|
|
|
|
|
Post,
|
|
|
|
|
Author
|
|
|
|
|
}){
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
async listPosts(
|
|
|
|
|
filters?: any,
|
|
|
|
|
config?: FindConfig<any> | undefined,
|
|
|
|
|
@MedusaContext() sharedContext?: Context | undefined
|
|
|
|
|
) {
|
|
|
|
|
const context = filters.context ?? {}
|
|
|
|
|
delete filters.context
|
|
|
|
|
|
|
|
|
|
let posts = await super.listPosts(filters, config, sharedContext)
|
|
|
|
|
|
|
|
|
|
if (context.lang === "es") {
|
|
|
|
|
posts = posts.map((post) => {
|
|
|
|
|
return {
|
|
|
|
|
...post,
|
|
|
|
|
title: post.title + " en español",
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return posts
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default BlogModuleService
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In the above example, you override the generated `listPosts` method. This method receives as a first parameter the filters passed to the query, but it also includes a `context` property that holds the context passed to the query.
|
|
|
|
|
|
|
|
|
|
You extract the context from `filters`, then retrieve the posts using the parent's `listPosts` method. After that, if the language is set in the context, you transform the titles of the posts.
|
|
|
|
|
|
|
|
|
|
All posts returned will now have their titles appended with "en español".
|
|
|
|
|
|
|
|
|
|
<Note title="Tip">
|
|
|
|
|
|
|
|
|
|
Learn more about the generated `list` method in [this reference](!resources!/service-factory-reference/methods/list).
|
|
|
|
|
|
|
|
|
|
</Note>
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Passing Query Context to Related Data Models
|
|
|
|
|
|
|
|
|
|
If you're retrieving a data model and you want to pass context to its associated model in the same module, you can pass them as part of `QueryContext`'s parameter, then handle them in the same `list` method.
|
|
|
|
|
|
|
|
|
|
<Note>
|
|
|
|
|
|
|
|
|
|
For linked data models, check out the [next section](#passing-query-context-to-linked-data-models).
|
|
|
|
|
|
|
|
|
|
</Note>
|
|
|
|
|
|
|
|
|
|
For example, to pass a context for the post's authors:
|
|
|
|
|
|
|
|
|
|
export const highlights3 = [
|
|
|
|
|
["6", "author", "Pass a context for the author."]
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
```ts highlights={highlights3}
|
|
|
|
|
const { data } = await query.graph({
|
|
|
|
|
entity: "post",
|
|
|
|
|
fields: ["*"],
|
|
|
|
|
context: QueryContext({
|
|
|
|
|
lang: "es",
|
|
|
|
|
author: QueryContext({
|
|
|
|
|
lang: "es",
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Then, in the `listPosts` method, you can handle the context for the post's authors:
|
|
|
|
|
|
|
|
|
|
export const highlights4 = [
|
|
|
|
|
["22", "context.author?.lang", "Access the author's context."]
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
```ts highlights={highlights4}
|
|
|
|
|
import { MedusaContext, MedusaService } from "@medusajs/framework/utils"
|
|
|
|
|
import { Context, FindConfig } from "@medusajs/framework/types"
|
|
|
|
|
import Post from "./models/post"
|
|
|
|
|
import Author from "./models/author"
|
|
|
|
|
|
|
|
|
|
class BlogModuleService extends MedusaService({
|
|
|
|
|
Post,
|
|
|
|
|
Author
|
|
|
|
|
}){
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
async listPosts(
|
|
|
|
|
filters?: any,
|
|
|
|
|
config?: FindConfig<any> | undefined,
|
|
|
|
|
@MedusaContext() sharedContext?: Context | undefined
|
|
|
|
|
) {
|
|
|
|
|
const context = filters.context ?? {}
|
|
|
|
|
delete filters.context
|
|
|
|
|
|
|
|
|
|
let posts = await super.listPosts(filters, config, sharedContext)
|
|
|
|
|
|
|
|
|
|
const isPostLangEs = context.lang === "es"
|
|
|
|
|
const isAuthorLangEs = context.author?.lang === "es"
|
|
|
|
|
|
|
|
|
|
if (isPostLangEs || isAuthorLangEs) {
|
|
|
|
|
posts = posts.map((post) => {
|
|
|
|
|
return {
|
|
|
|
|
...post,
|
|
|
|
|
title: isPostLangEs ? post.title + " en español" : post.title,
|
|
|
|
|
author: {
|
|
|
|
|
...post.author,
|
|
|
|
|
name: isAuthorLangEs ? post.author.name + " en español" : post.author.name,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return posts
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default BlogModuleService
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The context in `filters` will also have the context for `author`, which you can use to make transformations to the post's authors.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Passing Query Context to Linked Data Models
|
|
|
|
|
|
|
|
|
|
If you're retrieving a data model and you want to pass context to a linked model in a different module, pass to the `context` property an object instead, where its keys are the linked model's name and the values are the context for that linked model.
|
|
|
|
|
|
|
|
|
|
For example, consider the Product Module's `Product` data model is linked to the Blog Module's `Post` data model. You can pass context to the `Post` data model while retrieving products like so:
|
|
|
|
|
|
|
|
|
|
export const highlights5 = [
|
|
|
|
|
["5", "post", "Pass a context for posts."]
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
```ts highlights={highlights5}
|
|
|
|
|
const { data } = await query.graph({
|
|
|
|
|
entity: "product",
|
|
|
|
|
fields: ["*", "post.*"],
|
|
|
|
|
context: {
|
|
|
|
|
post: QueryContext({
|
|
|
|
|
lang: "es",
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In this example, you retrieve products and their associated posts. You also pass a context for `post`, indicating the customer's language.
|
|
|
|
|
|
|
|
|
|
To handle the context, you override the generated `listPosts` method of the Blog Module as explained [previously](#how-to-use-query-context).
|