chore: Adjusting the v2 product module to follow the v1 specs (#6618)
In this PR: 1. I added upsert support for the product 2. I updated the create and update signatures to match the latest interface standards 3. Small changes to make the v1 and v2 APIs compatible (WIP)
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
} from "@medusajs/utils"
|
||||
|
||||
import { ProductServiceTypes } from "../types/services"
|
||||
import { UpdateProductInput } from "src/types/services/product"
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory<Product>(
|
||||
@@ -120,7 +121,7 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory<Pr
|
||||
async update(
|
||||
data: {
|
||||
entity: Product
|
||||
update: WithRequiredProperty<ProductServiceTypes.UpdateProductDTO, "id">
|
||||
update: UpdateProductInput
|
||||
}[],
|
||||
context: Context = {}
|
||||
): Promise<Product[]> {
|
||||
@@ -136,7 +137,7 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory<Pr
|
||||
productData?.categories?.map((c) => c.id) || []
|
||||
)
|
||||
|
||||
tagIds = tagIds.concat(productData?.tags?.map((c) => c.id) || [])
|
||||
tagIds = tagIds.concat(productData?.tags?.map((c: any) => c.id) || [])
|
||||
|
||||
if (productData.collection_id) {
|
||||
collectionIds.push(productData.collection_id)
|
||||
@@ -204,7 +205,7 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory<Pr
|
||||
|
||||
const {
|
||||
categories: categoriesData = [],
|
||||
tags: tagsData = [],
|
||||
tags: tagsData = [] as any,
|
||||
collection_id: collectionId,
|
||||
type_id: typeId,
|
||||
} = updateData
|
||||
|
||||
@@ -49,7 +49,11 @@ import {
|
||||
ProductServiceTypes,
|
||||
ProductVariantServiceTypes,
|
||||
} from "@types"
|
||||
import { ProductEventData, ProductEvents } from "../types/services/product"
|
||||
import {
|
||||
ProductEventData,
|
||||
ProductEvents,
|
||||
UpdateProductInput,
|
||||
} from "../types/services/product"
|
||||
import {
|
||||
ProductCategoryEventData,
|
||||
ProductCategoryEvents,
|
||||
@@ -545,12 +549,23 @@ export default class ProductModuleService<
|
||||
})
|
||||
}
|
||||
|
||||
create(
|
||||
data: ProductTypes.CreateProductDTO[],
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductDTO[]>
|
||||
create(
|
||||
data: ProductTypes.CreateProductDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductDTO>
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async create(
|
||||
data: ProductTypes.CreateProductDTO[],
|
||||
data: ProductTypes.CreateProductDTO[] | ProductTypes.CreateProductDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ProductTypes.ProductDTO[]> {
|
||||
const products = await this.create_(data, sharedContext)
|
||||
): Promise<ProductTypes.ProductDTO[] | ProductTypes.ProductDTO> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
|
||||
const products = await this.create_(input, sharedContext)
|
||||
|
||||
const createdProducts = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductDTO[]
|
||||
@@ -563,15 +578,100 @@ export default class ProductModuleService<
|
||||
}))
|
||||
)
|
||||
|
||||
return createdProducts
|
||||
return Array.isArray(data) ? createdProducts : createdProducts[0]
|
||||
}
|
||||
|
||||
async upsert(
|
||||
data: ProductTypes.UpsertProductDTO[],
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductDTO[]>
|
||||
async upsert(
|
||||
data: ProductTypes.UpsertProductDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductDTO>
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
async upsert(
|
||||
data: ProductTypes.UpsertProductDTO[] | ProductTypes.UpsertProductDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ProductTypes.ProductDTO[] | ProductTypes.ProductDTO> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter(
|
||||
(product): product is UpdateProductInput => !!product.id
|
||||
)
|
||||
const forCreate = input.filter(
|
||||
(product): product is ProductTypes.CreateProductDTO => !product.id
|
||||
)
|
||||
|
||||
let created: Product[] = []
|
||||
let updated: Product[] = []
|
||||
|
||||
if (forCreate.length) {
|
||||
created = await this.create_(forCreate, sharedContext)
|
||||
}
|
||||
if (forUpdate.length) {
|
||||
updated = await this.update_(forUpdate, sharedContext)
|
||||
}
|
||||
|
||||
const result = [...created, ...updated]
|
||||
const allProducts = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductDTO[] | ProductTypes.ProductDTO
|
||||
>(Array.isArray(data) ? result : result[0])
|
||||
|
||||
if (created.length) {
|
||||
await this.eventBusModuleService_?.emit<ProductEventData>(
|
||||
created.map(({ id }) => ({
|
||||
eventName: ProductEvents.PRODUCT_CREATED,
|
||||
data: { id },
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
if (updated.length) {
|
||||
await this.eventBusModuleService_?.emit<ProductEventData>(
|
||||
updated.map(({ id }) => ({
|
||||
eventName: ProductEvents.PRODUCT_UPDATED,
|
||||
data: { id },
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
return allProducts
|
||||
}
|
||||
|
||||
update(
|
||||
id: string,
|
||||
data: ProductTypes.UpdateProductDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductDTO>
|
||||
update(
|
||||
selector: ProductTypes.FilterableProductProps,
|
||||
data: ProductTypes.UpdateProductDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductDTO[]>
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async update(
|
||||
data: ProductTypes.UpdateProductDTO[],
|
||||
idOrSelector: string | ProductTypes.FilterableProductProps,
|
||||
data: ProductTypes.UpdateProductDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ProductTypes.ProductDTO[]> {
|
||||
const products = await this.update_(data, sharedContext)
|
||||
): Promise<ProductTypes.ProductDTO[] | ProductTypes.ProductDTO> {
|
||||
let normalizedInput: UpdateProductInput[] = []
|
||||
if (isString(idOrSelector)) {
|
||||
normalizedInput = [{ id: idOrSelector, ...data }]
|
||||
} else {
|
||||
const products = await this.productService_.list(
|
||||
idOrSelector,
|
||||
{},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
normalizedInput = products.map((product) => ({
|
||||
id: product.id,
|
||||
...data,
|
||||
}))
|
||||
}
|
||||
|
||||
const products = await this.update_(normalizedInput, sharedContext)
|
||||
|
||||
const updatedProducts = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductDTO[]
|
||||
@@ -584,7 +684,7 @@ export default class ProductModuleService<
|
||||
}))
|
||||
)
|
||||
|
||||
return updatedProducts
|
||||
return isString(idOrSelector) ? updatedProducts[0] : updatedProducts
|
||||
}
|
||||
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
@@ -706,7 +806,7 @@ export default class ProductModuleService<
|
||||
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
protected async update_(
|
||||
data: ProductTypes.UpdateProductDTO[],
|
||||
data: UpdateProductInput[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TProduct[]> {
|
||||
const productIds = data.map((pd) => pd.id)
|
||||
@@ -734,10 +834,7 @@ export default class ProductModuleService<
|
||||
|
||||
const productVariantsMap = new Map<
|
||||
string,
|
||||
(
|
||||
| ProductTypes.CreateProductVariantDTO
|
||||
| ProductTypes.UpdateProductVariantDTO
|
||||
)[]
|
||||
ProductTypes.UpsertProductVariantDTO[]
|
||||
>()
|
||||
|
||||
const productOptionsMap = new Map<string, TProductOption[]>()
|
||||
@@ -781,7 +878,7 @@ export default class ProductModuleService<
|
||||
(productData.options ?? []) as TProductOption[]
|
||||
)
|
||||
|
||||
return productData as ProductServiceTypes.UpdateProductDTO
|
||||
return productData as UpdateProductInput
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ProductUtils } from "@medusajs/utils"
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
|
||||
export type ProductEventData = {
|
||||
id: string
|
||||
@@ -10,28 +10,6 @@ export enum ProductEvents {
|
||||
PRODUCT_DELETED = "product.deleted",
|
||||
}
|
||||
|
||||
export interface UpdateProductDTO {
|
||||
export type UpdateProductInput = ProductTypes.UpdateProductDTO & {
|
||||
id: string
|
||||
title?: string
|
||||
subtitle?: string
|
||||
description?: string
|
||||
is_giftcard?: boolean
|
||||
discountable?: boolean
|
||||
images?: { id?: string; url: string }[]
|
||||
thumbnail?: string
|
||||
handle?: string
|
||||
status?: ProductUtils.ProductStatus
|
||||
collection_id?: string
|
||||
width?: number
|
||||
height?: number
|
||||
length?: number
|
||||
weight?: number
|
||||
origin_country?: string
|
||||
hs_code?: string
|
||||
material?: string
|
||||
mid_code?: string
|
||||
metadata?: Record<string, unknown>
|
||||
tags?: { id: string }[]
|
||||
categories?: { id: string }[]
|
||||
type_id?: string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user