chore(modules-sdk,orchestration): to remote joiner query (#4974)

Helper function to transform js/json object into RemoteJoinerQuery format.

```typescript
toRemoteJoinerQuery({
  product: {
    fields: ["id", "title"],
    __args: {
      skip: 0,
    },
    variants: {
      fields: ["id", "title", "handle", "sku"],
      shipping_profile: {
        profile: {
          fields: ["id", "name"],
        },
      },
    },
    collections: {
      fields: ["id", "title"],
    },
  },
})
```

outputs:
```
{
  alias: "product",
  fields: ["id", "title"],
  expands: [
    {
      property: "product.variants",
      fields: ["id", "title", "handle", "sku"],
    },
    {
      property: "product.variants.shipping_profile",
    },
    {
      property: "product.variants.shipping_profile.profile",
      fields: ["id", "name"],
    },
    {
      property: "product.collections",
      fields: ["id", "title"],
    },
  ],
  args: [
    {
      name: "skip",
      value: 0,
    },
  ],
};
```
This commit is contained in:
Carlos R. L. Rodrigues
2023-09-10 10:26:50 -03:00
committed by GitHub
parent 7a12aa04ac
commit d8649bacaa
5 changed files with 225 additions and 6 deletions

View File

@@ -0,0 +1,6 @@
---
"@medusajs/orchestration": minor
"@medusajs/modules-sdk": minor
---
object to remote joiner query

View File

@@ -1,3 +1,8 @@
import {
RemoteFetchDataCallback,
RemoteJoiner,
toRemoteJoinerQuery,
} from "@medusajs/orchestration"
import {
JoinerRelationship,
JoinerServiceConfig,
@@ -6,8 +11,6 @@ import {
RemoteExpandProperty,
RemoteJoinerQuery,
} from "@medusajs/types"
import { RemoteFetchDataCallback, RemoteJoiner } from "@medusajs/orchestration"
import { isString, toPascalCase } from "@medusajs/utils"
import { MedusaModule } from "./medusa-module"
@@ -213,12 +216,16 @@ export class RemoteQuery {
}
public async query(
query: string | RemoteJoinerQuery,
query: string | RemoteJoinerQuery | object,
variables?: Record<string, unknown>
): Promise<any> {
const finalQuery = isString(query)
? RemoteJoiner.parseQuery(query, variables)
: query
let finalQuery: RemoteJoinerQuery = query as RemoteJoinerQuery
if (isString(query)) {
finalQuery = RemoteJoiner.parseQuery(query, variables)
} else if (!isString(finalQuery?.service) && !isString(finalQuery?.alias)) {
finalQuery = toRemoteJoinerQuery(query)
}
return await this.remoteJoiner.query(finalQuery)
}

View File

@@ -0,0 +1,147 @@
import { toRemoteJoinerQuery } from "../../joiner/helpers"
describe("toRemoteJoinerQuery", () => {
beforeEach(() => {
jest.clearAllMocks()
})
it("should transform a simple object to a Remote Joiner Query format", async () => {
const obj = {
product: {
fields: ["id", "title", "handle"],
},
}
const rjQuery = toRemoteJoinerQuery(obj)
expect(rjQuery).toEqual({
alias: "product",
fields: ["id", "title", "handle"],
expands: [],
})
})
it("should transform a nested object to a Remote Joiner Query format", async () => {
const obj = {
product: {
fields: ["id", "title", "handle"],
variants: {
fields: ["sku"],
shipping_profiles: {
profile: {
fields: ["id", "name"],
},
},
options: {
fields: ["value"],
},
},
options: {
fields: ["value", "name"],
},
},
}
const rjQuery = toRemoteJoinerQuery(obj)
expect(rjQuery).toEqual({
alias: "product",
fields: ["id", "title", "handle"],
expands: [
{
property: "product.variants",
fields: ["sku"],
},
{
property: "product.variants.shipping_profiles",
},
{
property: "product.variants.shipping_profiles.profile",
fields: ["id", "name"],
},
{
property: "product.variants.options",
fields: ["value"],
},
{
property: "product.options",
fields: ["value", "name"],
},
],
})
})
it("should transform a nested object with arguments and directives to a Remote Joiner Query format", async () => {
const obj = {
product: {
fields: ["id", "title", "handle"],
__args: {
limit: 10,
offset: 0,
},
variants: {
fields: ["sku"],
__directives: {
directiveName: "value",
},
shipping_profiles: {
profile: {
fields: ["id", "name"],
__args: {
context: {
customer_group: "cg_123",
region_id: "US",
},
},
},
},
},
},
}
const rjQuery = toRemoteJoinerQuery(obj)
expect(rjQuery).toEqual({
alias: "product",
fields: ["id", "title", "handle"],
expands: [
{
property: "product.variants",
directives: [
{
name: "directiveName",
value: "value",
},
],
fields: ["sku"],
},
{
property: "product.variants.shipping_profiles",
},
{
property: "product.variants.shipping_profiles.profile",
args: [
{
name: "context",
value: {
customer_group: "cg_123",
region_id: "US",
},
},
],
fields: ["id", "name"],
},
],
args: [
{
name: "limit",
value: 10,
},
{
name: "offset",
value: 0,
},
],
})
})
})

View File

@@ -0,0 +1,58 @@
import { RemoteJoinerQuery } from "@medusajs/types"
export function toRemoteJoinerQuery(obj: any): RemoteJoinerQuery {
const remoteJoinerQuery: RemoteJoinerQuery = {
alias: "",
fields: [],
expands: [],
}
function extractRecursive(obj, parentName = "") {
for (const key in obj) {
const value = obj[key]
const canExpand =
typeof value === "object" &&
!["fields", "__args", "__directives"].includes(key)
if (canExpand) {
const entityName = parentName ? `${parentName}.${key}` : key
const expandObj: any = {
property: entityName,
}
const isEntryPoint = parentName === ""
const reference = isEntryPoint ? remoteJoinerQuery : expandObj
if (value.__args) {
reference.args = Object.entries(value.__args).map(
([name, value]) => ({
name,
value,
})
)
}
if (value.__directives) {
reference.directives = Object.entries(value.__directives).map(
([name, value]) => ({ name, value })
)
}
reference.fields = value.fields
if (isEntryPoint) {
remoteJoinerQuery.alias = key
} else {
remoteJoinerQuery.expands!.push(expandObj)
}
extractRecursive(value, entityName)
}
}
return remoteJoinerQuery
}
return extractRecursive(obj)
}

View File

@@ -1 +1,2 @@
export * from "./helpers"
export * from "./remote-joiner"