chore: query graph api (#9125)
CLOSES: FRMW-2704 **What** Re-structure the Query graph API as well as introduce dynamic typing from schemas on the filters and better handling of relation treatment for fields/filters inference Co-authored-by: Adrien de Peretti <25098370+adrien2p@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
3e97a64b21
commit
8829f89402
@@ -48,7 +48,7 @@ declare module "@medusajs/types" {
|
||||
[ContainerRegistrationKeys.CONFIG_MODULE]: ConfigModule
|
||||
[ContainerRegistrationKeys.PG_CONNECTION]: Knex<any>
|
||||
[ContainerRegistrationKeys.REMOTE_QUERY]: RemoteQueryFunction
|
||||
[ContainerRegistrationKeys.QUERY]: RemoteQueryFunction
|
||||
[ContainerRegistrationKeys.QUERY]: Omit<RemoteQueryFunction, symbol>
|
||||
[ContainerRegistrationKeys.LOGGER]: Logger
|
||||
}
|
||||
}
|
||||
@@ -520,7 +520,7 @@ async function MedusaApp_({
|
||||
onApplicationStart,
|
||||
modules: allModules,
|
||||
link: remoteLink,
|
||||
query: createQuery(remoteQuery),
|
||||
query: createQuery(remoteQuery) as any, // TODO: rm any once we remove the old RemoteQueryFunction and rely on the Query object instead,
|
||||
entitiesMap: schema.getTypeMap(),
|
||||
gqlSchema: schema,
|
||||
notFound,
|
||||
|
||||
@@ -0,0 +1,454 @@
|
||||
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 }
|
||||
DateTime: { input: Date | string; output: Date | string }
|
||||
JSON: { input: Record<string, unknown>; output: Record<string, unknown> }
|
||||
}
|
||||
|
||||
export type SimpleProduct = {
|
||||
id: Scalars["ID"]["output"]
|
||||
handle: string
|
||||
title?: Scalars["String"]["output"]
|
||||
variants?: Maybe<Array<Maybe<Pick<ProductVariant, "id">>>>
|
||||
sales_channels_link?: Array<
|
||||
Pick<LinkProductSalesChannel, "product_id" | "sales_channel_id">
|
||||
>
|
||||
sales_channels?: Array<Pick<SalesChannel, "id" | "name">>
|
||||
}
|
||||
|
||||
export type Product = {
|
||||
__typename?: "Product"
|
||||
id: Scalars["ID"]["output"]
|
||||
handle: Scalars["String"]["output"]
|
||||
title: Scalars["String"]["output"]
|
||||
description?: Scalars["String"]["output"]
|
||||
variants?: Array<ProductVariant>
|
||||
sales_channels_link?: Array<LinkProductSalesChannel>
|
||||
sales_channels?: Array<SalesChannel>
|
||||
metadata?: Maybe<Scalars["JSON"]["output"]>
|
||||
}
|
||||
|
||||
export type ProductVariant = {
|
||||
__typename?: "ProductVariant"
|
||||
id: Scalars["ID"]["output"]
|
||||
handle: Scalars["String"]["output"]
|
||||
title: Scalars["String"]["output"]
|
||||
sku: Scalars["String"]["output"]
|
||||
product?: Maybe<Product>
|
||||
}
|
||||
|
||||
export type ProductCategory = {
|
||||
__typename?: "ProductCategory"
|
||||
id: Scalars["ID"]["output"]
|
||||
handle: Scalars["String"]["output"]
|
||||
title?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type SalesChannel = {
|
||||
__typename?: "SalesChannel"
|
||||
id: Scalars["ID"]["output"]
|
||||
name?: Maybe<Scalars["String"]["output"]>
|
||||
description?: Maybe<Scalars["String"]["output"]>
|
||||
created_at?: Maybe<Scalars["DateTime"]["output"]>
|
||||
updated_at?: Maybe<Scalars["DateTime"]["output"]>
|
||||
products_link?: Maybe<Array<Maybe<LinkProductSalesChannel>>>
|
||||
api_keys_link?: Maybe<Array<Maybe<LinkPublishableApiKeySalesChannel>>>
|
||||
locations_link?: Maybe<Array<Maybe<LinkSalesChannelStockLocation>>>
|
||||
}
|
||||
|
||||
export type LinkCartPaymentCollection = {
|
||||
__typename?: "LinkCartPaymentCollection"
|
||||
cart_id: Scalars["String"]["output"]
|
||||
payment_collection_id: Scalars["String"]["output"]
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkCartPromotion = {
|
||||
__typename?: "LinkCartPromotion"
|
||||
cart_id: Scalars["String"]["output"]
|
||||
promotion_id: Scalars["String"]["output"]
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkLocationFulfillmentProvider = {
|
||||
__typename?: "LinkLocationFulfillmentProvider"
|
||||
stock_location_id: Scalars["String"]["output"]
|
||||
fulfillment_provider_id: Scalars["String"]["output"]
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkLocationFulfillmentSet = {
|
||||
__typename?: "LinkLocationFulfillmentSet"
|
||||
stock_location_id: Scalars["String"]["output"]
|
||||
fulfillment_set_id: Scalars["String"]["output"]
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkOrderCart = {
|
||||
__typename?: "LinkOrderCart"
|
||||
order_id: Scalars["String"]["output"]
|
||||
cart_id: Scalars["String"]["output"]
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkOrderFulfillment = {
|
||||
__typename?: "LinkOrderFulfillment"
|
||||
order_id: Scalars["String"]["output"]
|
||||
fulfillment_id: Scalars["String"]["output"]
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkOrderPaymentCollection = {
|
||||
__typename?: "LinkOrderPaymentCollection"
|
||||
order_id: Scalars["String"]["output"]
|
||||
payment_collection_id: Scalars["String"]["output"]
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkOrderPromotion = {
|
||||
__typename?: "LinkOrderPromotion"
|
||||
order_id: Scalars["String"]["output"]
|
||||
promotion_id: Scalars["String"]["output"]
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkReturnFulfillment = {
|
||||
__typename?: "LinkReturnFulfillment"
|
||||
return_id: Scalars["String"]["output"]
|
||||
fulfillment_id: Scalars["String"]["output"]
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkProductSalesChannel = {
|
||||
__typename?: "LinkProductSalesChannel"
|
||||
product_id: Scalars["String"]["output"]
|
||||
sales_channel_id: Scalars["String"]["output"]
|
||||
product?: Maybe<Product>
|
||||
sales_channel?: Maybe<SalesChannel>
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkProductVariantInventoryItem = {
|
||||
__typename?: "LinkProductVariantInventoryItem"
|
||||
variant_id: Scalars["String"]["output"]
|
||||
inventory_item_id: Scalars["String"]["output"]
|
||||
required_quantity: Scalars["Int"]["output"]
|
||||
variant?: Maybe<Product>
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkProductVariantPriceSet = {
|
||||
__typename?: "LinkProductVariantPriceSet"
|
||||
variant_id: Scalars["String"]["output"]
|
||||
price_set_id: Scalars["String"]["output"]
|
||||
variant?: Maybe<Product>
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkPublishableApiKeySalesChannel = {
|
||||
__typename?: "LinkPublishableApiKeySalesChannel"
|
||||
publishable_key_id: Scalars["String"]["output"]
|
||||
sales_channel_id: Scalars["String"]["output"]
|
||||
sales_channel?: Maybe<SalesChannel>
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkRegionPaymentProvider = {
|
||||
__typename?: "LinkRegionPaymentProvider"
|
||||
region_id: Scalars["String"]["output"]
|
||||
payment_provider_id: Scalars["String"]["output"]
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkSalesChannelStockLocation = {
|
||||
__typename?: "LinkSalesChannelStockLocation"
|
||||
sales_channel_id: Scalars["String"]["output"]
|
||||
stock_location_id: Scalars["String"]["output"]
|
||||
sales_channel?: Maybe<SalesChannel>
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export type LinkShippingOptionPriceSet = {
|
||||
__typename?: "LinkShippingOptionPriceSet"
|
||||
shipping_option_id: Scalars["String"]["output"]
|
||||
price_set_id: Scalars["String"]["output"]
|
||||
createdAt: Scalars["String"]["output"]
|
||||
updatedAt: Scalars["String"]["output"]
|
||||
deletedAt?: Maybe<Scalars["String"]["output"]>
|
||||
}
|
||||
|
||||
export interface FixtureEntryPoints {
|
||||
file: any
|
||||
files: any
|
||||
workflow_execution: any
|
||||
workflow_executions: any
|
||||
inventory_items: any
|
||||
inventory_item: any
|
||||
inventory: any
|
||||
reservation: any
|
||||
reservations: any
|
||||
reservation_item: any
|
||||
reservation_items: any
|
||||
inventory_level: any
|
||||
inventory_levels: any
|
||||
stock_location_address: any
|
||||
stock_location_addresses: any
|
||||
stock_location: any
|
||||
stock_locations: any
|
||||
price_set: any
|
||||
price_sets: any
|
||||
price_list: any
|
||||
price_lists: any
|
||||
price: any
|
||||
prices: any
|
||||
price_preference: any
|
||||
price_preferences: any
|
||||
product_variant: ProductVariant
|
||||
product_variants: ProductVariant
|
||||
variant: ProductVariant
|
||||
variants: ProductVariant
|
||||
product: Product
|
||||
products: Product
|
||||
simple_product: SimpleProduct
|
||||
product_option: any
|
||||
product_options: any
|
||||
product_type: any
|
||||
product_types: any
|
||||
product_image: any
|
||||
product_images: any
|
||||
product_tag: any
|
||||
product_tags: any
|
||||
product_collection: any
|
||||
product_collections: any
|
||||
product_category: ProductCategory
|
||||
product_categories: ProductCategory
|
||||
sales_channel: SalesChannel
|
||||
sales_channels: SalesChannel
|
||||
customer_address: any
|
||||
customer_addresses: any
|
||||
customer_group_customer: any
|
||||
customer_group_customers: any
|
||||
customer_group: any
|
||||
customer_groups: any
|
||||
customer: any
|
||||
customers: any
|
||||
cart: any
|
||||
carts: any
|
||||
address: any
|
||||
addresses: any
|
||||
line_item: any
|
||||
line_items: any
|
||||
line_item_adjustment: any
|
||||
line_item_adjustments: any
|
||||
line_item_tax_line: any
|
||||
line_item_tax_lines: any
|
||||
shipping_method: any
|
||||
shipping_methods: any
|
||||
shipping_method_adjustment: any
|
||||
shipping_method_adjustments: any
|
||||
shipping_method_tax_line: any
|
||||
shipping_method_tax_lines: any
|
||||
promotion: any
|
||||
promotions: any
|
||||
campaign: any
|
||||
campaigns: any
|
||||
promotion_rule: any
|
||||
promotion_rules: any
|
||||
api_key: any
|
||||
api_keys: any
|
||||
tax_rate: any
|
||||
tax_rates: any
|
||||
tax_region: any
|
||||
tax_regions: any
|
||||
tax_rate_rule: any
|
||||
tax_rate_rules: any
|
||||
tax_provider: any
|
||||
tax_providers: any
|
||||
store: any
|
||||
stores: any
|
||||
store_currency: any
|
||||
store_currencies: any
|
||||
user: any
|
||||
users: any
|
||||
invite: any
|
||||
invites: any
|
||||
auth_identity: any
|
||||
auth_identities: any
|
||||
order: any
|
||||
orders: any
|
||||
order_address: any
|
||||
order_addresses: any
|
||||
order_line_item: any
|
||||
order_line_items: any
|
||||
order_line_item_adjustment: any
|
||||
order_line_item_adjustments: any
|
||||
order_line_item_tax_line: any
|
||||
order_line_item_tax_lines: any
|
||||
order_shipping_method: any
|
||||
order_shipping_methods: any
|
||||
order_shipping_method_adjustment: any
|
||||
order_shipping_method_adjustments: any
|
||||
order_shipping_method_tax_line: any
|
||||
order_shipping_method_tax_lines: any
|
||||
order_transaction: any
|
||||
order_transactions: any
|
||||
order_change: any
|
||||
order_changes: any
|
||||
order_change_action: any
|
||||
order_change_actions: any
|
||||
order_item: any
|
||||
order_items: any
|
||||
order_summary: any
|
||||
order_summaries: any
|
||||
order_shipping: any
|
||||
order_shippings: any
|
||||
return_reason: any
|
||||
return_reasons: any
|
||||
return: any
|
||||
returns: any
|
||||
return_item: any
|
||||
return_items: any
|
||||
order_claim: any
|
||||
order_claims: any
|
||||
order_claim_item: any
|
||||
order_claim_items: any
|
||||
order_claim_item_image: any
|
||||
order_claim_item_images: any
|
||||
order_exchange: any
|
||||
order_exchanges: any
|
||||
order_exchange_item: any
|
||||
order_exchange_items: any
|
||||
payment: any
|
||||
payments: any
|
||||
payment_collection: any
|
||||
payment_collections: any
|
||||
payment_provider: any
|
||||
payment_providers: any
|
||||
payment_session: any
|
||||
payment_sessions: any
|
||||
refund_reason: any
|
||||
refund_reasons: any
|
||||
fulfillment_address: any
|
||||
fulfillment_addresses: any
|
||||
fulfillment_item: any
|
||||
fulfillment_items: any
|
||||
fulfillment_label: any
|
||||
fulfillment_labels: any
|
||||
fulfillment_provider: any
|
||||
fulfillment_providers: any
|
||||
fulfillment_set: any
|
||||
fulfillment_sets: any
|
||||
fulfillment: any
|
||||
fulfillments: any
|
||||
geo_zone: any
|
||||
geo_zones: any
|
||||
service_zone: any
|
||||
service_zones: any
|
||||
shipping_option_rule: any
|
||||
shipping_option_rules: any
|
||||
shipping_option_type: any
|
||||
shipping_option_types: any
|
||||
shipping_option: any
|
||||
shipping_options: any
|
||||
shipping_profile: any
|
||||
shipping_profiles: any
|
||||
notification: any
|
||||
notifications: any
|
||||
region: any
|
||||
regions: any
|
||||
country: any
|
||||
countries: any
|
||||
currency: any
|
||||
currencies: any
|
||||
cart_payment_collection: LinkCartPaymentCollection
|
||||
cart_payment_collections: LinkCartPaymentCollection
|
||||
cart_promotion: LinkCartPromotion
|
||||
cart_promotions: LinkCartPromotion
|
||||
location_fulfillment_provider: LinkLocationFulfillmentProvider
|
||||
location_fulfillment_providers: LinkLocationFulfillmentProvider
|
||||
location_fulfillment_set: LinkLocationFulfillmentSet
|
||||
location_fulfillment_sets: LinkLocationFulfillmentSet
|
||||
order_cart: LinkOrderCart
|
||||
order_carts: LinkOrderCart
|
||||
order_fulfillment: LinkOrderFulfillment
|
||||
order_fulfillments: LinkOrderFulfillment
|
||||
order_payment_collection: LinkOrderPaymentCollection
|
||||
order_payment_collections: LinkOrderPaymentCollection
|
||||
order_promotion: LinkOrderPromotion
|
||||
order_promotions: LinkOrderPromotion
|
||||
return_fulfillment: LinkReturnFulfillment
|
||||
return_fulfillments: LinkReturnFulfillment
|
||||
product_sales_channel: LinkProductSalesChannel
|
||||
product_sales_channels: LinkProductSalesChannel
|
||||
product_variant_inventory_item: LinkProductVariantInventoryItem
|
||||
product_variant_inventory_items: LinkProductVariantInventoryItem
|
||||
product_variant_price_set: LinkProductVariantPriceSet
|
||||
product_variant_price_sets: LinkProductVariantPriceSet
|
||||
publishable_api_key_sales_channel: LinkPublishableApiKeySalesChannel
|
||||
publishable_api_key_sales_channels: LinkPublishableApiKeySalesChannel
|
||||
region_payment_provider: LinkRegionPaymentProvider
|
||||
region_payment_providers: LinkRegionPaymentProvider
|
||||
sales_channel_location: LinkSalesChannelStockLocation
|
||||
sales_channel_locations: LinkSalesChannelStockLocation
|
||||
shipping_option_price_set: LinkShippingOptionPriceSet
|
||||
shipping_option_price_sets: LinkShippingOptionPriceSet
|
||||
}
|
||||
|
||||
declare module "@medusajs/types" {
|
||||
export interface RemoteQueryEntryPoints extends FixtureEntryPoints {}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
import { QueryContext, QueryFilter } from "@medusajs/utils"
|
||||
import "../__fixtures__/remote-query-type"
|
||||
import { toRemoteQuery } from "../to-remote-query"
|
||||
|
||||
describe("toRemoteQuery", () => {
|
||||
it("should transform a query with top level filtering", () => {
|
||||
const format = toRemoteQuery({
|
||||
entity: "product",
|
||||
fields: ["id", "handle", "description"],
|
||||
filters: QueryFilter<"product">({
|
||||
handle: {
|
||||
$ilike: "abc%",
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
expect(format).toEqual({
|
||||
product: {
|
||||
__fields: ["id", "handle", "description"],
|
||||
__args: {
|
||||
filters: {
|
||||
handle: {
|
||||
$ilike: "abc%",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("should transform a query with pagination", () => {
|
||||
const format = toRemoteQuery({
|
||||
entity: "product",
|
||||
fields: ["id", "handle", "description"],
|
||||
pagination: {
|
||||
skip: 5,
|
||||
take: 10,
|
||||
},
|
||||
})
|
||||
|
||||
expect(format).toEqual({
|
||||
product: {
|
||||
__fields: ["id", "handle", "description"],
|
||||
__args: {
|
||||
skip: 5,
|
||||
take: 10,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("should transform a query with top level filtering and pagination", () => {
|
||||
const format = toRemoteQuery({
|
||||
entity: "product",
|
||||
fields: ["id", "handle", "description"],
|
||||
pagination: {
|
||||
skip: 5,
|
||||
take: 10,
|
||||
},
|
||||
filters: QueryFilter<"product">({
|
||||
handle: {
|
||||
$ilike: "abc%",
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
expect(format).toEqual({
|
||||
product: {
|
||||
__fields: ["id", "handle", "description"],
|
||||
__args: {
|
||||
skip: 5,
|
||||
take: 10,
|
||||
filters: {
|
||||
handle: {
|
||||
$ilike: "abc%",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("should transform a query with filters and context into remote query input [1]", () => {
|
||||
const format = toRemoteQuery({
|
||||
entity: "product",
|
||||
fields: [
|
||||
"id",
|
||||
"description",
|
||||
"variants.title",
|
||||
"variants.calculated_price",
|
||||
"variants.options.*",
|
||||
],
|
||||
filters: {
|
||||
variants: QueryFilter<"variants">({
|
||||
sku: {
|
||||
$ilike: "abc%",
|
||||
},
|
||||
}),
|
||||
},
|
||||
context: {
|
||||
variants: {
|
||||
calculated_price: QueryContext({
|
||||
region_id: "reg_123",
|
||||
currency_code: "usd",
|
||||
}),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(format).toEqual({
|
||||
product: {
|
||||
__fields: ["id", "description"],
|
||||
variants: {
|
||||
__args: {
|
||||
filters: {
|
||||
sku: {
|
||||
$ilike: "abc%",
|
||||
},
|
||||
},
|
||||
},
|
||||
calculated_price: {
|
||||
__args: {
|
||||
context: {
|
||||
region_id: "reg_123",
|
||||
currency_code: "usd",
|
||||
},
|
||||
},
|
||||
},
|
||||
__fields: ["title", "calculated_price"],
|
||||
options: {
|
||||
__fields: ["*"],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("should transform a query with filters and context into remote query input [2]", () => {
|
||||
const langContext = QueryContext({
|
||||
context: {
|
||||
lang: "pt-br",
|
||||
},
|
||||
})
|
||||
|
||||
const format = toRemoteQuery({
|
||||
entity: "product",
|
||||
fields: [
|
||||
"id",
|
||||
"title",
|
||||
"description",
|
||||
"product_translation.*",
|
||||
"categories.*",
|
||||
"categories.category_translation.*",
|
||||
"variants.*",
|
||||
"variants.variant_translation.*",
|
||||
],
|
||||
filters: QueryFilter<"product">({
|
||||
id: "prod_01J742X0QPFW3R2ZFRTRC34FS8",
|
||||
}),
|
||||
context: {
|
||||
product_translation: langContext,
|
||||
categories: {
|
||||
category_translation: langContext,
|
||||
},
|
||||
variants: {
|
||||
variant_translation: langContext,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(format).toEqual({
|
||||
product: {
|
||||
__fields: ["id", "title", "description"],
|
||||
__args: {
|
||||
filters: {
|
||||
id: "prod_01J742X0QPFW3R2ZFRTRC34FS8",
|
||||
},
|
||||
},
|
||||
product_translation: {
|
||||
__args: {
|
||||
context: {
|
||||
context: {
|
||||
lang: "pt-br",
|
||||
},
|
||||
},
|
||||
},
|
||||
__fields: ["*"],
|
||||
},
|
||||
categories: {
|
||||
category_translation: {
|
||||
__args: {
|
||||
context: {
|
||||
context: {
|
||||
lang: "pt-br",
|
||||
},
|
||||
},
|
||||
},
|
||||
__fields: ["*"],
|
||||
},
|
||||
__fields: ["*"],
|
||||
},
|
||||
variants: {
|
||||
variant_translation: {
|
||||
__args: {
|
||||
context: {
|
||||
context: {
|
||||
lang: "pt-br",
|
||||
},
|
||||
},
|
||||
},
|
||||
__fields: ["*"],
|
||||
},
|
||||
__fields: ["*"],
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,10 +1,10 @@
|
||||
import { RemoteQuery } from "./remote-query"
|
||||
import {
|
||||
GraphResultSet,
|
||||
RemoteJoinerOptions,
|
||||
RemoteJoinerQuery,
|
||||
RemoteQueryFunction,
|
||||
RemoteQueryFunctionReturnPagination,
|
||||
RemoteQueryInput,
|
||||
RemoteQueryObjectConfig,
|
||||
RemoteQueryObjectFromStringResult,
|
||||
} from "@medusajs/types"
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
MedusaError,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import { RemoteQuery } from "./remote-query"
|
||||
import { toRemoteQuery } from "./to-remote-query"
|
||||
|
||||
/**
|
||||
* API wrapper around the remoteQuery
|
||||
@@ -25,7 +27,7 @@ export class Query {
|
||||
*/
|
||||
static traceGraphQuery?: (
|
||||
queryFn: () => Promise<any>,
|
||||
queryOptions: RemoteQueryObjectConfig<any>
|
||||
queryOptions: RemoteQueryInput<any>
|
||||
) => Promise<any>
|
||||
|
||||
/**
|
||||
@@ -58,14 +60,16 @@ export class Query {
|
||||
|
||||
#unwrapQueryConfig(
|
||||
config:
|
||||
| RemoteQueryObjectConfig<any>
|
||||
| RemoteQueryObjectFromStringResult<any>
|
||||
| RemoteQueryObjectConfig<any>
|
||||
| RemoteJoinerQuery
|
||||
): object {
|
||||
let normalizedQuery: any = config
|
||||
|
||||
if ("__value" in config) {
|
||||
normalizedQuery = config.__value
|
||||
} else if ("entity" in normalizedQuery) {
|
||||
normalizedQuery = toRemoteQuery(normalizedQuery)
|
||||
} else if (
|
||||
"entryPoint" in normalizedQuery ||
|
||||
"service" in normalizedQuery
|
||||
@@ -95,6 +99,7 @@ export class Query {
|
||||
|
||||
async query(
|
||||
queryOptions:
|
||||
| RemoteQueryInput<any>
|
||||
| RemoteQueryObjectConfig<any>
|
||||
| RemoteQueryObjectFromStringResult<any>
|
||||
| RemoteJoinerQuery,
|
||||
@@ -110,7 +115,7 @@ export class Query {
|
||||
const config = this.#unwrapQueryConfig(queryOptions)
|
||||
if (Query.traceRemoteQuery) {
|
||||
return await Query.traceRemoteQuery(
|
||||
async () => this.#remoteQuery.query(config, undefined, options),
|
||||
async () => await this.#remoteQuery.query(config, undefined, options),
|
||||
queryOptions
|
||||
)
|
||||
}
|
||||
@@ -133,10 +138,10 @@ export class Query {
|
||||
* returns a result set
|
||||
*/
|
||||
async graph<const TEntry extends string>(
|
||||
queryOptions: RemoteQueryObjectConfig<TEntry>,
|
||||
queryOptions: RemoteQueryInput<TEntry>,
|
||||
options?: RemoteJoinerOptions
|
||||
): Promise<GraphResultSet<TEntry>> {
|
||||
const normalizedQuery = remoteQueryObjectFromString(queryOptions).__value
|
||||
const normalizedQuery = toRemoteQuery<TEntry>(queryOptions)
|
||||
let response:
|
||||
| any[]
|
||||
| { rows: any[]; metadata: RemoteQueryFunctionReturnPagination }
|
||||
@@ -148,8 +153,8 @@ export class Query {
|
||||
if (Query.traceGraphQuery) {
|
||||
response = await Query.traceGraphQuery(
|
||||
async () =>
|
||||
this.#remoteQuery.query(normalizedQuery, undefined, options),
|
||||
queryOptions
|
||||
await this.#remoteQuery.query(normalizedQuery, undefined, options),
|
||||
queryOptions as RemoteQueryInput<any>
|
||||
)
|
||||
} else {
|
||||
response = await this.#remoteQuery.query(
|
||||
@@ -167,7 +172,7 @@ export class Query {
|
||||
* API wrapper around the remoteQuery with backward compatibility support
|
||||
* @param remoteQuery
|
||||
*/
|
||||
export function createQuery(remoteQuery: RemoteQuery): RemoteQueryFunction {
|
||||
export function createQuery(remoteQuery: RemoteQuery) {
|
||||
const query = new Query(remoteQuery)
|
||||
|
||||
function backwardCompatibleQuery(...args: any[]) {
|
||||
@@ -177,5 +182,5 @@ export function createQuery(remoteQuery: RemoteQuery): RemoteQueryFunction {
|
||||
backwardCompatibleQuery.graph = query.graph.bind(query)
|
||||
backwardCompatibleQuery.gql = query.gql.bind(query)
|
||||
|
||||
return backwardCompatibleQuery
|
||||
return backwardCompatibleQuery as Omit<RemoteQueryFunction, symbol>
|
||||
}
|
||||
|
||||
120
packages/core/modules-sdk/src/remote-query/to-remote-query.ts
Normal file
120
packages/core/modules-sdk/src/remote-query/to-remote-query.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import {
|
||||
RemoteQueryEntryPoints,
|
||||
RemoteQueryFilters,
|
||||
RemoteQueryGraph,
|
||||
RemoteQueryObjectConfig,
|
||||
} from "@medusajs/types"
|
||||
import { QueryContext, QueryFilter, isObject } from "@medusajs/utils"
|
||||
|
||||
const FIELDS = "__fields"
|
||||
const ARGUMENTS = "__args"
|
||||
|
||||
/**
|
||||
* convert a specific API configuration to a remote query object
|
||||
*
|
||||
* @param config
|
||||
*
|
||||
* @example
|
||||
* const remoteQueryObject = toRemoteQuery({
|
||||
* entity: "product",
|
||||
* fields,
|
||||
* filters: { variants: QueryFilter({ sku: "abc" }) },
|
||||
* context: {
|
||||
* variants: { calculated_price: QueryContext({ region_id: "reg_123" }) }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* console.log(remoteQueryObject);
|
||||
*/
|
||||
|
||||
export function toRemoteQuery<const TEntity extends string>(config: {
|
||||
entity: TEntity | keyof RemoteQueryEntryPoints
|
||||
fields: RemoteQueryObjectConfig<TEntity>["fields"]
|
||||
filters?: RemoteQueryFilters<TEntity>
|
||||
pagination?: {
|
||||
skip?: number
|
||||
take?: number
|
||||
}
|
||||
context?: Record<string, any>
|
||||
}): RemoteQueryGraph<TEntity> {
|
||||
const { entity, fields = [], filters = {}, context = {} } = config
|
||||
|
||||
const joinerQuery: Record<string, any> = {
|
||||
[entity]: {
|
||||
__fields: [],
|
||||
},
|
||||
}
|
||||
|
||||
function processNestedObjects(
|
||||
target: any,
|
||||
source: Record<string, any>,
|
||||
topLevel = true
|
||||
) {
|
||||
for (const key in source) {
|
||||
const src = topLevel ? source : source[key]
|
||||
|
||||
if (!isObject(src)) {
|
||||
target[key] = src
|
||||
continue
|
||||
}
|
||||
|
||||
if (QueryContext.isQueryContext(src) || QueryFilter.isQueryFilter(src)) {
|
||||
const normalizedFilters = { ...src } as any
|
||||
delete normalizedFilters.__type
|
||||
|
||||
const prop = QueryFilter.isQueryFilter(src) ? "filters" : "context"
|
||||
|
||||
if (topLevel) {
|
||||
target[ARGUMENTS] ??= {}
|
||||
target[ARGUMENTS][prop] = normalizedFilters
|
||||
} else {
|
||||
target[key] ??= {}
|
||||
target[key][ARGUMENTS] ??= {}
|
||||
target[key][ARGUMENTS][prop] = normalizedFilters
|
||||
}
|
||||
} else {
|
||||
if (!topLevel) {
|
||||
target[key] ??= {}
|
||||
}
|
||||
|
||||
const nextTarget = topLevel ? target : target[key]
|
||||
processNestedObjects(nextTarget, src, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process filters and context recursively
|
||||
processNestedObjects(joinerQuery[entity], filters)
|
||||
processNestedObjects(joinerQuery[entity], context)
|
||||
|
||||
for (const field of fields) {
|
||||
const fieldAsString = field as string
|
||||
if (!fieldAsString.includes(".")) {
|
||||
joinerQuery[entity][FIELDS].push(field)
|
||||
continue
|
||||
}
|
||||
|
||||
const fieldSegments = fieldAsString.split(".")
|
||||
const fieldProperty = fieldSegments.pop()
|
||||
|
||||
let combinedPath = ""
|
||||
const deepConfigRef = fieldSegments.reduce((acc, curr) => {
|
||||
combinedPath = combinedPath ? combinedPath + "." + curr : curr
|
||||
acc[curr] ??= {}
|
||||
return acc[curr]
|
||||
}, joinerQuery[entity])
|
||||
|
||||
deepConfigRef[FIELDS] ??= []
|
||||
deepConfigRef[FIELDS].push(fieldProperty)
|
||||
}
|
||||
|
||||
if (config.pagination) {
|
||||
joinerQuery[entity][ARGUMENTS] ??= {}
|
||||
joinerQuery[entity][ARGUMENTS] = {
|
||||
...joinerQuery[entity][ARGUMENTS],
|
||||
...config.pagination,
|
||||
}
|
||||
}
|
||||
|
||||
return joinerQuery as RemoteQueryGraph<TEntity>
|
||||
}
|
||||
@@ -78,8 +78,11 @@ export async function gqlSchemaToTypes({
|
||||
documents: [],
|
||||
config: {
|
||||
scalars: {
|
||||
DateTime: { output: "Date | string" },
|
||||
JSON: { output: "Record<any, unknown>" },
|
||||
DateTime: { input: "Date | string", output: "Date | string" },
|
||||
JSON: {
|
||||
input: "Record<string, unknown>",
|
||||
output: "Record<string, unknown>",
|
||||
},
|
||||
},
|
||||
},
|
||||
filename: "",
|
||||
|
||||
@@ -17,7 +17,7 @@ export function toRemoteJoinerQuery(
|
||||
|
||||
const canExpand =
|
||||
typeof value === "object" &&
|
||||
!["fields", "__args", "__directives"].includes(key)
|
||||
!["fields", "__fields", "__args", "__directives"].includes(key) // TODO: deprecate "fields"
|
||||
|
||||
if (!canExpand) {
|
||||
continue
|
||||
@@ -65,8 +65,8 @@ export function toRemoteJoinerQuery(
|
||||
)
|
||||
}
|
||||
|
||||
if (value.fields) {
|
||||
reference.fields = value.fields
|
||||
if (value.__fields || value.fields) {
|
||||
reference.fields = value.__fields ?? value.fields
|
||||
}
|
||||
|
||||
if (isEntryPoint) {
|
||||
|
||||
@@ -26,25 +26,23 @@ export type Scalars = {
|
||||
Boolean: { input: boolean; output: boolean }
|
||||
Int: { input: number; output: number }
|
||||
Float: { input: number; output: number }
|
||||
DateTime: {
|
||||
input: { output: "Date | string" }
|
||||
output: { output: "Date | string" }
|
||||
}
|
||||
JSON: {
|
||||
input: { output: "Record<any, unknown>" }
|
||||
output: { output: "Record<any, unknown>" }
|
||||
}
|
||||
DateTime: { input: Date | string; output: Date | string }
|
||||
JSON: { input: Record<string, unknown>; output: Record<string, unknown> }
|
||||
}
|
||||
|
||||
export type SimpleProduct = {
|
||||
__typename?: "SimpleProduct"
|
||||
id: Scalars["ID"]["output"]
|
||||
handle: string
|
||||
title?: Scalars["String"]["output"]
|
||||
variants?: Maybe<Array<Maybe<Pick<ProductVariant, "id">>>>
|
||||
variants?: Maybe<Array<Maybe<Pick<ProductVariant, "id" | "__typename">>>>
|
||||
sales_channels_link?: Array<
|
||||
Pick<LinkProductSalesChannel, "product_id" | "sales_channel_id">
|
||||
Pick<
|
||||
LinkProductSalesChannel,
|
||||
"product_id" | "sales_channel_id" | "__typename"
|
||||
>
|
||||
>
|
||||
sales_channels?: Array<Pick<SalesChannel, "id" | "name">>
|
||||
sales_channels?: Array<Pick<SalesChannel, "id" | "name" | "__typename">>
|
||||
}
|
||||
|
||||
export type Product = {
|
||||
|
||||
@@ -9,11 +9,13 @@ describe("ObjectToRemoteQueryFields", () => {
|
||||
description: string
|
||||
date: Date
|
||||
variants: {
|
||||
__typename: string
|
||||
id: string
|
||||
sku: string
|
||||
title: string
|
||||
}[]
|
||||
sales_channel: {
|
||||
__typename: string
|
||||
id: string
|
||||
name: string
|
||||
value: string
|
||||
@@ -51,12 +53,14 @@ describe("ObjectToRemoteQueryFields", () => {
|
||||
date: Date
|
||||
variants: Maybe<
|
||||
Maybe<{
|
||||
__typename: string
|
||||
id: string
|
||||
sku: string
|
||||
title: string
|
||||
}>[]
|
||||
>
|
||||
sales_channel?: Maybe<{
|
||||
__typename: string
|
||||
id: string
|
||||
name: string
|
||||
value: string
|
||||
|
||||
@@ -10,7 +10,7 @@ describe("Query", () => {
|
||||
it("should infer return type of a known entry", async () => {
|
||||
const graph = (() => {}) as unknown as QueryGraphFunction
|
||||
const result = await graph({
|
||||
entryPoint: "product",
|
||||
entity: "product",
|
||||
fields: ["handle", "id"],
|
||||
})
|
||||
|
||||
@@ -23,7 +23,7 @@ describe("Query", () => {
|
||||
it("should infer as any for an known entry", async () => {
|
||||
const graph = (() => {}) as unknown as QueryGraphFunction
|
||||
const result = await graph({
|
||||
entryPoint: "foo",
|
||||
entity: "foo",
|
||||
fields: ["handle", "id"],
|
||||
})
|
||||
|
||||
|
||||
@@ -4,11 +4,18 @@ import { MedusaContainer } from "../common"
|
||||
import { RepositoryService } from "../dal"
|
||||
import { Logger } from "../logger"
|
||||
import {
|
||||
RemoteQueryGraph,
|
||||
RemoteQueryInput,
|
||||
RemoteQueryObjectConfig,
|
||||
RemoteQueryObjectFromStringResult,
|
||||
} from "./remote-query-object-from-string"
|
||||
|
||||
export { RemoteQueryObjectConfig, RemoteQueryObjectFromStringResult }
|
||||
export {
|
||||
RemoteQueryGraph,
|
||||
RemoteQueryInput,
|
||||
RemoteQueryObjectConfig,
|
||||
RemoteQueryObjectFromStringResult,
|
||||
}
|
||||
|
||||
export type Constructor<T> = new (...args: any[]) => T | (new () => T)
|
||||
|
||||
@@ -17,6 +24,8 @@ export * from "./medusa-internal-service"
|
||||
export * from "./module-provider"
|
||||
export * from "./remote-query"
|
||||
export * from "./remote-query-entry-points"
|
||||
export * from "./to-remote-query"
|
||||
export * from "./query-filter"
|
||||
|
||||
export type LogLevel =
|
||||
| "query"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
type Marker = [never, 0, 1, 2, 3, 4]
|
||||
|
||||
type ExcludedProps = ["__typename"]
|
||||
type SpecialNonRelationProps = ["metadata"]
|
||||
type ExcludedProps = "__typename"
|
||||
type RawBigNumberPrefix = "raw_"
|
||||
|
||||
type ExpandStarSelector<
|
||||
@@ -26,12 +25,9 @@ export type ObjectToRemoteQueryFields<
|
||||
? {
|
||||
[K in keyof T]: K extends // handle big number
|
||||
`${RawBigNumberPrefix}${string}`
|
||||
? Exclude<K, symbol>
|
||||
: // handle metadata
|
||||
K extends SpecialNonRelationProps[number]
|
||||
? Exclude<K, symbol>
|
||||
: // Special props that should be excluded
|
||||
K extends ExcludedProps[number]
|
||||
K extends ExcludedProps
|
||||
? never
|
||||
: // Prevent recursive reference to itself
|
||||
K extends Exclusion[number]
|
||||
@@ -39,21 +35,25 @@ export type ObjectToRemoteQueryFields<
|
||||
: TypeOnly<T[K]> extends Array<infer R>
|
||||
? TypeOnly<R> extends Date
|
||||
? Exclude<K, symbol>
|
||||
: TypeOnly<R> extends object
|
||||
: TypeOnly<R> extends { __typename: any }
|
||||
? `${Exclude<K, symbol>}.${ExpandStarSelector<
|
||||
TypeOnly<R>,
|
||||
Marker[Depth],
|
||||
[K & string, ...Exclusion]
|
||||
>}`
|
||||
: TypeOnly<R> extends object
|
||||
? Exclude<K, symbol>
|
||||
: never
|
||||
: TypeOnly<T[K]> extends Date
|
||||
? Exclude<K, symbol>
|
||||
: TypeOnly<T[K]> extends object
|
||||
: TypeOnly<T[K]> extends { __typename: any }
|
||||
? `${Exclude<K, symbol>}.${ExpandStarSelector<
|
||||
TypeOnly<T[K]>,
|
||||
Marker[Depth],
|
||||
[K & string, ...Exclusion]
|
||||
>}`
|
||||
: T[K] extends object
|
||||
? Exclude<K, symbol>
|
||||
: Exclude<K, symbol>
|
||||
}[keyof T]
|
||||
: never
|
||||
|
||||
9
packages/core/types/src/modules-sdk/query-filter.ts
Normal file
9
packages/core/types/src/modules-sdk/query-filter.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { RemoteQueryFilters } from "./to-remote-query"
|
||||
|
||||
export type QueryFilterType = {
|
||||
<TEntry extends string>(
|
||||
query: RemoteQueryFilters<TEntry>
|
||||
): RemoteQueryFilters<TEntry> & { __type: "QueryFilter" }
|
||||
|
||||
isQueryFilter: (obj: any) => boolean
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { RemoteQueryEntryPoints } from "./remote-query-entry-points"
|
||||
import { ObjectToRemoteQueryFields } from "./object-to-remote-query-fields"
|
||||
import { RemoteQueryEntryPoints } from "./remote-query-entry-points"
|
||||
import { RemoteQueryFilters } from "./to-remote-query"
|
||||
|
||||
export type RemoteQueryObjectConfig<TEntry extends string> = {
|
||||
// service: string This property is still supported under the hood but part of the type due to types missmatch towards fields
|
||||
@@ -20,3 +21,25 @@ export type RemoteQueryObjectFromStringResult<
|
||||
__TConfig: TConfig
|
||||
__value: object
|
||||
}
|
||||
|
||||
export type RemoteQueryInput<TEntry extends string> = {
|
||||
// service: string This property is still supported under the hood but part of the type due to types missmatch towards fields
|
||||
entity: TEntry | keyof RemoteQueryEntryPoints
|
||||
fields: ObjectToRemoteQueryFields<
|
||||
RemoteQueryEntryPoints[TEntry & keyof RemoteQueryEntryPoints]
|
||||
> extends never
|
||||
? string[]
|
||||
: ObjectToRemoteQueryFields<
|
||||
RemoteQueryEntryPoints[TEntry & keyof RemoteQueryEntryPoints]
|
||||
>[]
|
||||
pagination?: {
|
||||
skip: number
|
||||
take?: number
|
||||
}
|
||||
filters?: RemoteQueryFilters<TEntry>
|
||||
context?: any
|
||||
}
|
||||
|
||||
export type RemoteQueryGraph<TEntry extends string> = {
|
||||
__TConfig: RemoteQueryObjectConfig<TEntry>
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Prettify } from "../common"
|
||||
import { RemoteJoinerOptions, RemoteJoinerQuery } from "../joiner"
|
||||
import { RemoteQueryEntryPoints } from "./remote-query-entry-points"
|
||||
import {
|
||||
RemoteQueryInput,
|
||||
RemoteQueryObjectConfig,
|
||||
RemoteQueryObjectFromStringResult,
|
||||
} from "./remote-query-object-from-string"
|
||||
@@ -32,7 +33,7 @@ export type GraphResultSet<TEntry extends string> = {
|
||||
*/
|
||||
export type QueryGraphFunction = {
|
||||
<const TEntry extends string>(
|
||||
queryConfig: RemoteQueryObjectConfig<TEntry>,
|
||||
queryConfig: RemoteQueryInput<TEntry>,
|
||||
options?: RemoteJoinerOptions
|
||||
): Promise<Prettify<GraphResultSet<TEntry>>>
|
||||
}
|
||||
|
||||
72
packages/core/types/src/modules-sdk/to-remote-query.ts
Normal file
72
packages/core/types/src/modules-sdk/to-remote-query.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { Prettify } from "../common"
|
||||
import { OperatorMap } from "../dal"
|
||||
import { RemoteQueryEntryPoints } from "./remote-query-entry-points"
|
||||
|
||||
type ExcludedProps = "__typename"
|
||||
type Depth = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
type CleanupObject<T> = Prettify<Omit<Exclude<T, symbol>, ExcludedProps>>
|
||||
type OmitNever<T extends object> = {
|
||||
[K in keyof T as T[K] extends never ? never : K]: T[K]
|
||||
}
|
||||
type TypeOnly<T> = Required<Exclude<T, null | undefined>>
|
||||
|
||||
type ExtractFiltersOperators<
|
||||
MaybeT,
|
||||
Lim extends number = Depth[2],
|
||||
Exclusion extends string[] = [],
|
||||
T = TypeOnly<MaybeT>
|
||||
> = {
|
||||
[Key in keyof T]?: Key extends Exclusion[number]
|
||||
? never
|
||||
: Key extends ExcludedProps
|
||||
? never
|
||||
: T[Key] extends string | number | boolean | Date
|
||||
? T[Key] | OperatorMap<T[Key] | T[Key][]>
|
||||
: T[Key] extends Array<infer R>
|
||||
? TypeOnly<R> extends { __typename: any }
|
||||
? RemoteQueryFilters<
|
||||
Key & string,
|
||||
T,
|
||||
[Key & string, ...Exclusion],
|
||||
Depth[Lim]
|
||||
>
|
||||
: R extends object
|
||||
? CleanupObject<R>
|
||||
: never
|
||||
: T[Key] extends { __typename: any }
|
||||
? RemoteQueryFilters<
|
||||
Key & string,
|
||||
T[Key],
|
||||
[Key & string, ...Exclusion],
|
||||
Depth[Lim]
|
||||
>
|
||||
: T[Key] extends object
|
||||
? CleanupObject<T[Key]>
|
||||
: never
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all available filters from a remote entry point deeply
|
||||
*/
|
||||
export type RemoteQueryFilters<
|
||||
TEntry extends string,
|
||||
RemoteQueryEntryPointsLevel = RemoteQueryEntryPoints,
|
||||
Exclusion extends string[] = [],
|
||||
Lim extends number = Depth[3]
|
||||
> = Lim extends number
|
||||
? TEntry extends keyof RemoteQueryEntryPointsLevel
|
||||
? TypeOnly<RemoteQueryEntryPointsLevel[TEntry]> extends Array<infer V>
|
||||
? Prettify<
|
||||
OmitNever<ExtractFiltersOperators<V, Lim, [TEntry, ...Exclusion]>>
|
||||
>
|
||||
: Prettify<
|
||||
OmitNever<
|
||||
ExtractFiltersOperators<
|
||||
RemoteQueryEntryPointsLevel[TEntry],
|
||||
Lim,
|
||||
[TEntry, ...Exclusion]
|
||||
>
|
||||
>
|
||||
>
|
||||
: Record<string, any>
|
||||
: never
|
||||
1157
packages/core/utils/src/modules-sdk/_remote-joiner.ts
Normal file
1157
packages/core/utils/src/modules-sdk/_remote-joiner.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
export * from "./build-query"
|
||||
export * from "./create-pg-connection"
|
||||
export * from "./decorators"
|
||||
export * from "./define-link"
|
||||
export * from "./definition"
|
||||
export * from "./event-builder-factory"
|
||||
export * from "./joiner-config-builder"
|
||||
@@ -14,4 +15,5 @@ export * from "./medusa-service"
|
||||
export * from "./migration-scripts"
|
||||
export * from "./mikro-orm-cli-config-builder"
|
||||
export * from "./module"
|
||||
export * from "./define-link"
|
||||
export * from "./query-context"
|
||||
export * from "./query-filter"
|
||||
|
||||
19
packages/core/utils/src/modules-sdk/query-context.ts
Normal file
19
packages/core/utils/src/modules-sdk/query-context.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
type QueryContextType = {
|
||||
(query: Record<string, unknown>): Record<string, unknown>
|
||||
isQueryContext: (obj: any) => boolean
|
||||
}
|
||||
|
||||
const __type = "QueryContext"
|
||||
|
||||
function QueryContextFn(query: Record<string, unknown>) {
|
||||
return {
|
||||
...query,
|
||||
__type,
|
||||
}
|
||||
}
|
||||
|
||||
QueryContextFn.isQueryContext = (obj: any) => {
|
||||
return obj.__type === __type
|
||||
}
|
||||
|
||||
export const QueryContext: QueryContextType = QueryContextFn
|
||||
18
packages/core/utils/src/modules-sdk/query-filter.ts
Normal file
18
packages/core/utils/src/modules-sdk/query-filter.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { RemoteQueryFilters } from "@medusajs/types"
|
||||
|
||||
const __type = "QueryFilter"
|
||||
|
||||
export function QueryFilterFn<TEntry extends string>(
|
||||
query: RemoteQueryFilters<TEntry>
|
||||
): RemoteQueryFilters<TEntry> & { __type: "QueryFilter" } {
|
||||
return {
|
||||
...query,
|
||||
__type,
|
||||
}
|
||||
}
|
||||
|
||||
QueryFilterFn.isQueryFilter = (obj: any) => {
|
||||
return obj.__type === __type
|
||||
}
|
||||
|
||||
export const QueryFilter = QueryFilterFn
|
||||
@@ -1,14 +1,14 @@
|
||||
import { snakeCase } from "lodash"
|
||||
import { NodeSDK } from "@opentelemetry/sdk-node"
|
||||
import { Resource } from "@opentelemetry/resources"
|
||||
import { Query, RoutesLoader, Tracer } from "@medusajs/framework"
|
||||
import { SpanStatusCode } from "@opentelemetry/api"
|
||||
import { RoutesLoader, Tracer, Query } from "@medusajs/framework"
|
||||
import {
|
||||
type SpanExporter,
|
||||
SimpleSpanProcessor,
|
||||
} from "@opentelemetry/sdk-trace-node"
|
||||
import { PgInstrumentation } from "@opentelemetry/instrumentation-pg"
|
||||
import type { Instrumentation } from "@opentelemetry/instrumentation"
|
||||
import { PgInstrumentation } from "@opentelemetry/instrumentation-pg"
|
||||
import { Resource } from "@opentelemetry/resources"
|
||||
import { NodeSDK } from "@opentelemetry/sdk-node"
|
||||
import {
|
||||
SimpleSpanProcessor,
|
||||
type SpanExporter,
|
||||
} from "@opentelemetry/sdk-trace-node"
|
||||
import { snakeCase } from "lodash"
|
||||
|
||||
import start from "../commands/start"
|
||||
|
||||
@@ -132,7 +132,7 @@ export function instrumentRemoteQuery() {
|
||||
|
||||
Query.instrument.graphQuery(async function (queryFn, queryOptions) {
|
||||
return await QueryTracer.trace(
|
||||
`query.graph: ${queryOptions.entryPoint}`,
|
||||
`query.graph: ${queryOptions.entity}`,
|
||||
async (span) => {
|
||||
span.setAttributes({
|
||||
"query.fields": queryOptions.fields,
|
||||
|
||||
Reference in New Issue
Block a user