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:
Stevche Radevski
2024-03-08 14:03:59 +00:00
committed by GitHub
parent c19d276458
commit a92cdeb01d
15 changed files with 648 additions and 395 deletions
+4 -3
View File
@@ -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
})
)
+2 -24
View File
@@ -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
}