import { TypeList, Tabs, TabsList, TabsTriggerVertical, TabsContent, TabsContentWrapper } from "docs-ui"

export const metadata = {
  title: `${pageNumber} Query`,
}

# {metadata.title}

In this chapter, you’ll 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. It’s 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 Medusa’s 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 model’s 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 model’s 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" />
