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

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

# {metadata.title}

In this chapter, you’ll 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. It’s 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 Medusa’s commerce modules.

<Note type="check">

- [Enable the isQueryable configuration of the module](../module-links/page.mdx#prerequisite-isqueryable-configuration)

</Note>

---

## 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 model’s 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 model’s 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>
    <TabsTrigger value="basic">Basic Usage</TabsTrigger>
    <TabsTrigger value="filters">Apply Filters</TabsTrigger>
    <TabsTrigger value="sort">Sort Records</TabsTrigger>
    <TabsTrigger value="pagination">Apply Pagination</TabsTrigger>
  </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 object’s key is the property’s 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>
