feat: Update the signatures for variants and options to follow convention (#6748)
This commit is contained in:
1 parent
a859b7895e
commit
05e857d256
9 files changed
+574
-117
No files matched your search
+2
-2
@@ -242,7 +242,7 @@ moduleIntegrationTestRunner({
|
||||
const optionId = "option-1"
|
||||
|
||||
it("should update the title of the option successfully", async () => {
|
||||
await service.updateOptions([
|
||||
await service.upsertOptions([
|
||||
{
|
||||
id: optionId,
|
||||
title: "new test",
|
||||
@@ -258,7 +258,7 @@ moduleIntegrationTestRunner({
|
||||
let error
|
||||
|
||||
try {
|
||||
await service.updateOptions([
|
||||
await service.upsertOptions([
|
||||
{
|
||||
id: "does-not-exist",
|
||||
},
|
||||
|
||||
@@ -32,7 +32,6 @@ import {
|
||||
arrayDifference,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
isPresent,
|
||||
isString,
|
||||
kebabCase,
|
||||
MedusaContext,
|
||||
@@ -50,6 +49,7 @@ import {
|
||||
ProductCollectionEventData,
|
||||
ProductCollectionEvents,
|
||||
UpdateProductVariantInput,
|
||||
UpdateProductOptionInput,
|
||||
} from "../types"
|
||||
import { entityNameToLinkableKeysMap, joinerConfig } from "./../joiner-config"
|
||||
import { ProductStatus } from "@medusajs/utils"
|
||||
@@ -197,58 +197,158 @@ export default class ProductModuleService<
|
||||
return joinerConfig
|
||||
}
|
||||
|
||||
// TODO: Add options validation, among other things
|
||||
createVariants(
|
||||
data: ProductTypes.CreateProductVariantDTO[],
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductVariantDTO[]>
|
||||
createVariants(
|
||||
data: ProductTypes.CreateProductVariantDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductVariantDTO>
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async createVariants(
|
||||
data:
|
||||
| ProductTypes.CreateProductVariantDTO[]
|
||||
| ProductTypes.CreateProductVariantDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<
|
||||
ProductTypes.ProductVariantDTO[] | ProductTypes.ProductVariantDTO
|
||||
> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
|
||||
const variants = await this.createVariants_(input, sharedContext)
|
||||
|
||||
const createdVariants = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductVariantDTO[]
|
||||
>(variants, { populate: true })
|
||||
|
||||
return Array.isArray(data) ? createdVariants : createdVariants[0]
|
||||
}
|
||||
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
protected async createVariants_(
|
||||
data: ProductTypes.CreateProductVariantDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ProductTypes.ProductVariantDTO[]> {
|
||||
const productVariantsWithOptions = await promiseAll(
|
||||
data.map(async (variant) => {
|
||||
if (!isPresent(variant.options)) {
|
||||
return variant
|
||||
}
|
||||
): Promise<ProductVariant[]> {
|
||||
if (data.some((v) => !v.product_id)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Tried to create variants without specifying a product_id"
|
||||
)
|
||||
}
|
||||
|
||||
const productOptions = await this.productOptionService_.list(
|
||||
{ product_id: variant.product_id },
|
||||
{
|
||||
take: null,
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return ProductModuleService.assignOptionsToVariants(
|
||||
[variant],
|
||||
productOptions
|
||||
)[0]
|
||||
})
|
||||
)
|
||||
|
||||
const productVariants = await this.productVariantService_.create(
|
||||
productVariantsWithOptions,
|
||||
const productOptions = await this.productOptionService_.list(
|
||||
{
|
||||
product_id: [...new Set<string>(data.map((v) => v.product_id!))],
|
||||
},
|
||||
{
|
||||
take: null,
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductVariantDTO[]
|
||||
>(productVariants)
|
||||
const productVariantsWithOptions =
|
||||
ProductModuleService.assignOptionsToVariants(data, productOptions)
|
||||
|
||||
return await this.productVariantService_.create(
|
||||
productVariantsWithOptions,
|
||||
sharedContext
|
||||
)
|
||||
}
|
||||
|
||||
async upsertVariants(
|
||||
data: ProductTypes.UpsertProductVariantDTO[],
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductVariantDTO[]>
|
||||
async upsertVariants(
|
||||
data: ProductTypes.UpsertProductVariantDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductVariantDTO>
|
||||
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
async upsertVariants(
|
||||
data:
|
||||
| ProductTypes.UpsertProductVariantDTO[]
|
||||
| ProductTypes.UpsertProductVariantDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<
|
||||
ProductTypes.ProductVariantDTO[] | ProductTypes.ProductVariantDTO
|
||||
> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter(
|
||||
(variant): variant is UpdateProductVariantInput => !!variant.id
|
||||
)
|
||||
const forCreate = input.filter(
|
||||
(variant): variant is ProductTypes.CreateProductVariantDTO => !variant.id
|
||||
)
|
||||
|
||||
let created: ProductVariant[] = []
|
||||
let updated: ProductVariant[] = []
|
||||
|
||||
if (forCreate.length) {
|
||||
created = await this.createVariants_(forCreate, sharedContext)
|
||||
}
|
||||
if (forUpdate.length) {
|
||||
updated = await this.updateVariants_(forUpdate, sharedContext)
|
||||
}
|
||||
|
||||
const result = [...created, ...updated]
|
||||
const allVariants = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductVariantDTO[] | ProductTypes.ProductVariantDTO
|
||||
>(result)
|
||||
|
||||
return Array.isArray(data) ? allVariants : allVariants[0]
|
||||
}
|
||||
|
||||
updateVariants(
|
||||
id: string,
|
||||
data: ProductTypes.UpdateProductVariantDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductVariantDTO>
|
||||
updateVariants(
|
||||
selector: ProductTypes.FilterableProductVariantProps,
|
||||
data: ProductTypes.UpdateProductVariantDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductVariantDTO[]>
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async updateVariants(
|
||||
data: ProductTypes.UpdateProductVariantDTO[],
|
||||
idOrSelector: string | ProductTypes.FilterableProductVariantProps,
|
||||
data: ProductTypes.UpdateProductVariantDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ProductTypes.ProductVariantDTO[]> {
|
||||
const productVariants = await this.updateVariants_(data, sharedContext)
|
||||
): Promise<
|
||||
ProductTypes.ProductVariantDTO[] | ProductTypes.ProductVariantDTO
|
||||
> {
|
||||
let normalizedInput: UpdateProductVariantInput[] = []
|
||||
if (isString(idOrSelector)) {
|
||||
normalizedInput = [{ id: idOrSelector, ...data }]
|
||||
} else {
|
||||
const variants = await this.productVariantService_.list(
|
||||
idOrSelector,
|
||||
{},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
normalizedInput = variants.map((variant) => ({
|
||||
id: variant.id,
|
||||
...data,
|
||||
}))
|
||||
}
|
||||
|
||||
const variants = await this.updateVariants_(normalizedInput, sharedContext)
|
||||
|
||||
const updatedVariants = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductVariantDTO[]
|
||||
>(productVariants)
|
||||
>(variants)
|
||||
|
||||
return updatedVariants
|
||||
return isString(idOrSelector) ? updatedVariants[0] : updatedVariants
|
||||
}
|
||||
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
protected async updateVariants_(
|
||||
data: ProductTypes.UpdateProductVariantDTO[],
|
||||
data: UpdateProductVariantInput[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TProductVariant[]> {
|
||||
// Validation step
|
||||
@@ -280,7 +380,7 @@ export default class ProductModuleService<
|
||||
const productOptions = await this.productOptionService_.list(
|
||||
{
|
||||
product_id: Array.from(
|
||||
new Set(variantsWithProductId.map((v) => v.product_id))
|
||||
new Set(variantsWithProductId.map((v) => v.product_id!))
|
||||
),
|
||||
},
|
||||
{ take: null },
|
||||
@@ -294,8 +394,8 @@ export default class ProductModuleService<
|
||||
)
|
||||
}
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async diffVariants_(
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
protected async diffVariants_(
|
||||
data: UpdateProductVariantInput[],
|
||||
productOptions: ProductOption[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -427,11 +527,45 @@ export default class ProductModuleService<
|
||||
})
|
||||
}
|
||||
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
createOptions(
|
||||
data: ProductTypes.CreateProductOptionDTO[],
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductOptionDTO[]>
|
||||
createOptions(
|
||||
data: ProductTypes.CreateProductOptionDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductOptionDTO>
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async createOptions(
|
||||
data:
|
||||
| ProductTypes.CreateProductOptionDTO[]
|
||||
| ProductTypes.CreateProductOptionDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ProductTypes.ProductOptionDTO[] | ProductTypes.ProductOptionDTO> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
|
||||
const options = await this.createOptions_(input, sharedContext)
|
||||
|
||||
const createdOptions = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductOptionDTO[]
|
||||
>(options, { populate: true })
|
||||
|
||||
return Array.isArray(data) ? createdOptions : createdOptions[0]
|
||||
}
|
||||
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
protected async createOptions_(
|
||||
data: ProductTypes.CreateProductOptionDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
): Promise<ProductOption[]> {
|
||||
if (data.some((v) => !v.product_id)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Tried to create options without specifying a product_id"
|
||||
)
|
||||
}
|
||||
|
||||
const normalizedInput = data.map((opt) => {
|
||||
return {
|
||||
...opt,
|
||||
@@ -441,21 +575,102 @@ export default class ProductModuleService<
|
||||
}
|
||||
})
|
||||
|
||||
const productOptions = await this.productOptionService_.create(
|
||||
return await this.productOptionService_.create(
|
||||
normalizedInput,
|
||||
sharedContext
|
||||
)
|
||||
}
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
async upsertOptions(
|
||||
data: ProductTypes.UpsertProductOptionDTO[],
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductOptionDTO[]>
|
||||
async upsertOptions(
|
||||
data: ProductTypes.UpsertProductOptionDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductOptionDTO>
|
||||
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
async upsertOptions(
|
||||
data:
|
||||
| ProductTypes.UpsertProductOptionDTO[]
|
||||
| ProductTypes.UpsertProductOptionDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ProductTypes.ProductOptionDTO[] | ProductTypes.ProductOptionDTO> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter(
|
||||
(option): option is UpdateProductOptionInput => !!option.id
|
||||
)
|
||||
const forCreate = input.filter(
|
||||
(option): option is ProductTypes.CreateProductOptionDTO => !option.id
|
||||
)
|
||||
|
||||
let created: ProductOption[] = []
|
||||
let updated: ProductOption[] = []
|
||||
|
||||
if (forCreate.length) {
|
||||
created = await this.createOptions_(forCreate, sharedContext)
|
||||
}
|
||||
if (forUpdate.length) {
|
||||
updated = await this.updateOptions_(forUpdate, sharedContext)
|
||||
}
|
||||
|
||||
const result = [...created, ...updated]
|
||||
const allOptions = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductOptionDTO[] | ProductTypes.ProductOptionDTO
|
||||
>(result)
|
||||
|
||||
return Array.isArray(data) ? allOptions : allOptions[0]
|
||||
}
|
||||
|
||||
updateOptions(
|
||||
id: string,
|
||||
data: ProductTypes.UpdateProductOptionDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductOptionDTO>
|
||||
updateOptions(
|
||||
selector: ProductTypes.FilterableProductOptionProps,
|
||||
data: ProductTypes.UpdateProductOptionDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductOptionDTO[]>
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async updateOptions(
|
||||
idOrSelector: string | ProductTypes.FilterableProductOptionProps,
|
||||
data: ProductTypes.UpdateProductOptionDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ProductTypes.ProductOptionDTO[] | ProductTypes.ProductOptionDTO> {
|
||||
let normalizedInput: UpdateProductOptionInput[] = []
|
||||
if (isString(idOrSelector)) {
|
||||
normalizedInput = [{ id: idOrSelector, ...data }]
|
||||
} else {
|
||||
const options = await this.productOptionService_.list(
|
||||
idOrSelector,
|
||||
{},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
normalizedInput = options.map((option) => ({
|
||||
id: option.id,
|
||||
...data,
|
||||
}))
|
||||
}
|
||||
|
||||
const options = await this.updateOptions_(normalizedInput, sharedContext)
|
||||
|
||||
const updatedOptions = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductOptionDTO[]
|
||||
>(productOptions)
|
||||
>(options)
|
||||
|
||||
return isString(idOrSelector) ? updatedOptions[0] : updatedOptions
|
||||
}
|
||||
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
async updateOptions(
|
||||
data: ProductTypes.UpdateProductOptionDTO[],
|
||||
protected async updateOptions_(
|
||||
data: UpdateProductOptionInput[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
): Promise<ProductOption[]> {
|
||||
// Validation step
|
||||
const normalizedInput = data.map((opt) => {
|
||||
return {
|
||||
...opt,
|
||||
@@ -466,7 +681,7 @@ export default class ProductModuleService<
|
||||
}),
|
||||
}
|
||||
: {}),
|
||||
} as ProductTypes.UpdateProductOptionDTO
|
||||
} as UpdateProductOptionInput
|
||||
})
|
||||
|
||||
if (normalizedInput.some((option) => !option.id)) {
|
||||
@@ -481,15 +696,13 @@ export default class ProductModuleService<
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductOptionDTO[]
|
||||
>(productOptions)
|
||||
return productOptions
|
||||
}
|
||||
|
||||
// TODO: Do validation
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
async diffOptions_(
|
||||
data: ProductTypes.UpdateProductOptionDTO[],
|
||||
protected async diffOptions_(
|
||||
data: UpdateProductOptionInput[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
const toCreate = data.filter((o) => !o.id)
|
||||
@@ -740,7 +953,7 @@ export default class ProductModuleService<
|
||||
}
|
||||
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
async updateCollections_(
|
||||
protected async updateCollections_(
|
||||
data: UpdateCollectionInput[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TProductCollection[]> {
|
||||
|
||||
@@ -54,5 +54,10 @@ export type UpdateCollectionInput = ProductTypes.UpdateProductCollectionDTO & {
|
||||
}
|
||||
|
||||
export type UpdateProductVariantInput = ProductTypes.UpdateProductVariantDTO & {
|
||||
product_id: string
|
||||
id: string
|
||||
product_id?: string
|
||||
}
|
||||
|
||||
export type UpdateProductOptionInput = ProductTypes.UpdateProductOptionDTO & {
|
||||
id: string
|
||||
}
|
||||
Reference in new issue
Block a user