Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(index): Provide a similar API to Query #9193

Merged
merged 16 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 69 additions & 40 deletions integration-tests/modules/__tests__/index/search.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,23 +58,33 @@ medusaIntegrationTestRunner({
// Timeout to allow indexing to finish
await setTimeout(2000)

const [results, count] = await indexEngine.queryAndCount(
{
select: {
const [results, count] = await indexEngine.queryAndCount<"product">({
fields: [
"product.*",
"product.variants.*",
"product.variants.prices.*",
],
filters: {
product: {
variants: {
prices: {
amount: { $gt: 50 },
},
},
},
},
pagination: {
orderBy: {
product: {
variants: {
prices: true,
prices: {
amount: "DESC",
},
},
},
},
where: {
"product.variants.prices.amount": { $gt: 50 },
},
},
{
orderBy: [{ "product.variants.prices.amount": "DESC" }],
}
)
})

expect(count).toBe(1)

Expand Down Expand Up @@ -118,24 +128,34 @@ medusaIntegrationTestRunner({
// Timeout to allow indexing to finish
await setTimeout(2000)

const [results, count] = await indexEngine.queryAndCount(
{
select: {
product: {
variants: {
prices: true,
const [results, count] = await indexEngine.queryAndCount<"product">({
fields: [
"product.*",
"product.variants.*",
"product.variants.prices.*",
],
filters: {
product: {
variants: {
prices: {
amount: { $gt: 50 },
currency_code: { $eq: "AUD" },
},
},
},
where: {
"product.variants.prices.amount": { $gt: 50 },
"product.variants.prices.currency_code": { $eq: "AUD" },
pagination: {
orderBy: {
product: {
variants: {
prices: {
amount: "DESC",
},
},
},
},
},
},
{
orderBy: [{ "product.variants.prices.amount": "DESC" }],
}
)
})

expect(count).toBe(1)

Expand Down Expand Up @@ -179,30 +199,39 @@ medusaIntegrationTestRunner({

await setTimeout(5000)

const queryArgs = [
{
select: {
const queryArgs = {
fields: [
"product.*",
"product.variants.*",
"product.variants.prices.*",
],
filters: {
product: {
variants: {
prices: {
amount: { $gt: 50 },
currency_code: { $eq: "AUD" },
},
},
},
},
pagination: {
orderBy: {
product: {
variants: {
prices: true,
prices: {
amount: "DESC",
},
},
},
},
where: {
"product.variants.prices.amount": { $gt: 50 },
"product.variants.prices.currency_code": { $eq: "AUD" },
},
},
{
orderBy: [{ "product.variants.prices.amount": "DESC" }],
},
]
}

await indexEngine.queryAndCount(...queryArgs)
await indexEngine.queryAndCount<"product">(queryArgs)

const [results, count, perf] = await indexEngine.queryAndCount(
...queryArgs
)
const [results, count, perf] =
await indexEngine.queryAndCount<"product">(queryArgs)

console.log(perf)
})
Expand Down
20 changes: 13 additions & 7 deletions packages/core/modules-sdk/src/utils/gql-schema-to-types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MedusaModule } from "../medusa-module"
import { FileSystem } from "@medusajs/utils"
import { FileSystem, toCamelCase } from "@medusajs/utils"
import { GraphQLSchema } from "graphql/type"
import { parse, printSchema } from "graphql"
import { codegen } from "@graphql-codegen/core"
Expand All @@ -21,13 +21,13 @@ function buildEntryPointsTypeMap(

return aliases.flatMap((alias) => {
const names = Array.isArray(alias.name) ? alias.name : [alias.name]
const entity = alias.args?.["entity"]
const entity = alias?.["entity"]
return names.map((aliasItem) => {
return {
entryPoint: aliasItem,
entityType: entity
? schema.includes(`export type ${entity} `)
? alias.args?.["entity"]
? alias?.["entity"]
: "any"
: "any",
}
Expand All @@ -39,19 +39,23 @@ function buildEntryPointsTypeMap(

async function generateTypes({
outputDir,
filename,
config,
}: {
outputDir: string
filename: string
config: Parameters<typeof codegen>[0]
}) {
const fileSystem = new FileSystem(outputDir)

let output = await codegen(config)
const entryPoints = buildEntryPointsTypeMap(output)

const interfaceName = toCamelCase(filename)

const remoteQueryEntryPoints = `
declare module '@medusajs/types' {
interface RemoteQueryEntryPoints {
interface ${interfaceName} {
${entryPoints
.map((entry) => ` ${entry.entryPoint}: ${entry.entityType}`)
.join("\n")}
Expand All @@ -60,19 +64,21 @@ ${entryPoints

output += remoteQueryEntryPoints

await fileSystem.create("remote-query-types.d.ts", output)
await fileSystem.create(filename + ".d.ts", output)
await fileSystem.create(
"index.d.ts",
"export * as RemoteQueryTypes from './remote-query-types'"
`export * as ${interfaceName}Types from './${filename}'`
)
}

export async function gqlSchemaToTypes({
schema,
outputDir,
filename,
}: {
schema: GraphQLSchema
outputDir: string
filename: string
}) {
const config = {
documents: [],
Expand All @@ -98,5 +104,5 @@ export async function gqlSchemaToTypes({
},
}

await generateTypes({ outputDir, config })
await generateTypes({ outputDir, filename, config })
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
export type Maybe<T> = T | null
export type InputMaybe<T> = Maybe<T>
export type Exact<T extends { [key: string]: unknown }> = {
[K in keyof T]: T[K]
}
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & {
[SubKey in K]?: Maybe<T[SubKey]>
}
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & {
[SubKey in K]: Maybe<T[SubKey]>
}
export type MakeEmpty<
T extends { [key: string]: unknown },
K extends keyof T
> = { [_ in K]?: never }
export type Incremental<T> =
| T
| {
[P in keyof T]?: P extends " $fragmentName" | "__typename" ? T[P] : never
}
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: { input: string; output: string }
String: { input: string; output: string }
Boolean: { input: boolean; output: boolean }
Int: { input: number; output: number }
Float: { input: number; output: number }
}

export type Product = {
__typename?: "Product"
id?: Maybe<Scalars["String"]["output"]>
title?: Maybe<Scalars["String"]["output"]>
variants?: Maybe<Array<Maybe<ProductVariant>>>
}

export type ProductVariant = {
__typename?: "ProductVariant"
id?: Maybe<Scalars["String"]["output"]>
product_id?: Maybe<Scalars["String"]["output"]>
sku?: Maybe<Scalars["String"]["output"]>
prices?: Maybe<Array<Maybe<Price>>>
}

export type Price = {
__typename?: "Price"
amount?: Maybe<Scalars["Int"]["output"]>
}

export interface FixtureEntryPoints {
product_variant: ProductVariant
product_variants: ProductVariant
variant: ProductVariant
variants: ProductVariant
product: Product
products: Product
price: Price
prices: Price
}

declare module "../index-service-entry-points" {
interface IndexServiceEntryPoints extends FixtureEntryPoints {}
}
59 changes: 59 additions & 0 deletions packages/core/types/src/index/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { expectTypeOf } from "expect-type"
import "../__fixtures__/index-service-entry-points"
import { OperatorMap } from "../operator-map"
import { IndexQueryConfig, OrderBy } from "../query-config"

describe("IndexQueryConfig", () => {
it("should infer the config types properly", async () => {
type IndexConfig = IndexQueryConfig<"product">

expectTypeOf<IndexConfig["fields"]>().toEqualTypeOf<
(
| "id"
| "title"
| "variants.*"
| "variants.id"
| "variants.product_id"
| "variants.sku"
| "variants.prices.*"
| "variants.prices.amount"
)[]
>()

expectTypeOf<IndexConfig["filters"]>().toEqualTypeOf<
| {
id?: string | string[] | OperatorMap<string>
title?: string | string[] | OperatorMap<string>
variants?: {
id?: string | string[] | OperatorMap<string>
product_id?: string | string[] | OperatorMap<string>
sku?: string | string[] | OperatorMap<string>
prices?: {
amount?: number | number[] | OperatorMap<number>
}
}
}
| undefined
>()

expectTypeOf<IndexConfig["pagination"]>().toEqualTypeOf<
| {
skip?: number
take?: number
orderBy?: {
id?: OrderBy
title?: OrderBy
variants?: {
id?: OrderBy
product_id?: OrderBy
sku?: OrderBy
prices?: {
amount?: OrderBy
}
}
}
}
| undefined
>()
})
})
4 changes: 4 additions & 0 deletions packages/core/types/src/index/index-service-entry-points.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Bucket filled with map of entry point -> types that are autogenerated by the codegen from the config schema
*/
export interface IndexServiceEntryPoints {}
3 changes: 3 additions & 0 deletions packages/core/types/src/index/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export * from "./service"
export * from "./index-service-entry-points"
export * from "./query-config"
export * from "./operator-map"
12 changes: 12 additions & 0 deletions packages/core/types/src/index/operator-map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type OperatorMap<T> = {
$eq: T
$lt: T
$lte: T
$gt: T
$gte: T
$ne: T
$in: T
$is: T
$like: T
$ilike: T
}
9 changes: 9 additions & 0 deletions packages/core/types/src/index/query-config/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Prettify } from "../../common"

export type ExcludedProps = "__typename"
export type Depth = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
export type CleanupObject<T> = Prettify<Omit<Exclude<T, symbol>, ExcludedProps>>
export type OmitNever<T extends object> = {
[K in keyof T as TypeOnly<T[K]> extends never ? never : K]: T[K]
}
export type TypeOnly<T> = Required<Exclude<T, null | undefined>>
4 changes: 4 additions & 0 deletions packages/core/types/src/index/query-config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./query-input-config"
export * from "./query-input-config-fields"
export * from "./query-input-config-filters"
export * from "./query-input-config-order-by"
Loading
Loading