feat: Add v2 product types endpoints (#6880)

Also adjusts the product type module APIs to follow the conventions
This commit is contained in:
Stevche Radevski
2024-03-29 20:27:10 +01:00
committed by GitHub
parent 1bcb13f892
commit 1a48fe0282
21 changed files with 833 additions and 41 deletions

View File

@@ -0,0 +1,8 @@
---
"@medusajs/product": minor
"@medusajs/medusa": minor
"@medusajs/types": minor
"@medusajs/core-flows": patch
---
Add v2 product type endpoints and adjust the product module

View File

@@ -0,0 +1,30 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IProductModuleService, ProductTypes } from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
export const createProductTypesStepId = "create-product-types"
export const createProductTypesStep = createStep(
createProductTypesStepId,
async (data: ProductTypes.CreateProductTypeDTO[], { container }) => {
const service = container.resolve<IProductModuleService>(
ModuleRegistrationName.PRODUCT
)
const created = await service.createTypes(data)
return new StepResponse(
created,
created.map((productType) => productType.id)
)
},
async (createdIds, { container }) => {
if (!createdIds?.length) {
return
}
const service = container.resolve<IProductModuleService>(
ModuleRegistrationName.PRODUCT
)
await service.deleteTypes(createdIds)
}
)

View File

@@ -0,0 +1,27 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IProductModuleService } from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
export const deleteProductTypesStepId = "delete-product-types"
export const deleteProductTypesStep = createStep(
deleteProductTypesStepId,
async (ids: string[], { container }) => {
const service = container.resolve<IProductModuleService>(
ModuleRegistrationName.PRODUCT
)
await service.softDeleteTypes(ids)
return new StepResponse(void 0, ids)
},
async (prevIds, { container }) => {
if (!prevIds?.length) {
return
}
const service = container.resolve<IProductModuleService>(
ModuleRegistrationName.PRODUCT
)
await service.restoreTypes(prevIds)
}
)

View File

@@ -13,3 +13,6 @@ export * from "./delete-product-variants"
export * from "./create-collections"
export * from "./update-collections"
export * from "./delete-collections"
export * from "./create-product-types"
export * from "./update-product-types"
export * from "./delete-product-types"

View File

@@ -0,0 +1,42 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IProductModuleService, ProductTypes } from "@medusajs/types"
import { getSelectsAndRelationsFromObjectArray } from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
type UpdateProductTypesStepInput = {
selector: ProductTypes.FilterableProductTypeProps
update: ProductTypes.UpdateProductTypeDTO
}
export const updateProductTypesStepId = "update-product-types"
export const updateProductTypesStep = createStep(
updateProductTypesStepId,
async (data: UpdateProductTypesStepInput, { container }) => {
const service = container.resolve<IProductModuleService>(
ModuleRegistrationName.PRODUCT
)
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
data.update,
])
const prevData = await service.listTypes(data.selector, {
select: selects,
relations,
})
const productTypes = await service.updateTypes(data.selector, data.update)
return new StepResponse(productTypes, prevData)
},
async (prevData, { container }) => {
if (!prevData?.length) {
return
}
const service = container.resolve<IProductModuleService>(
ModuleRegistrationName.PRODUCT
)
await service.upsertTypes(prevData)
}
)

View File

@@ -0,0 +1,15 @@
import { ProductTypes } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { createProductTypesStep } from "../steps"
type WorkflowInput = { product_types: ProductTypes.CreateProductTypeDTO[] }
export const createProductTypesWorkflowId = "create-product-types"
export const createProductTypesWorkflow = createWorkflow(
createProductTypesWorkflowId,
(
input: WorkflowData<WorkflowInput>
): WorkflowData<ProductTypes.ProductTypeDTO[]> => {
return createProductTypesStep(input.product_types)
}
)

View File

@@ -0,0 +1,12 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { deleteProductTypesStep } from "../steps"
type WorkflowInput = { ids: string[] }
export const deleteProductTypesWorkflowId = "delete-product-types"
export const deleteProductTypesWorkflow = createWorkflow(
deleteProductTypesWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
return deleteProductTypesStep(input.ids)
}
)

View File

@@ -10,3 +10,6 @@ export * from "./update-product-variants"
export * from "./create-collections"
export * from "./delete-collections"
export * from "./update-collections"
export * from "./create-product-types"
export * from "./delete-product-types"
export * from "./update-product-types"

View File

@@ -0,0 +1,20 @@
import { ProductTypes } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { updateProductTypesStep } from "../steps"
type UpdateProductTypesStepInput = {
selector: ProductTypes.FilterableProductTypeProps
update: ProductTypes.UpdateProductTypeDTO
}
type WorkflowInput = UpdateProductTypesStepInput
export const updateProductTypesWorkflowId = "update-product-types"
export const updateProductTypesWorkflow = createWorkflow(
updateProductTypesWorkflowId,
(
input: WorkflowData<WorkflowInput>
): WorkflowData<ProductTypes.ProductTypeDTO[]> => {
return updateProductTypesStep(input)
}
)

View File

@@ -0,0 +1,78 @@
import {
deleteProductTypesWorkflow,
updateProductTypesWorkflow,
} from "@medusajs/core-flows"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../types/routing"
import { UpdateProductTypeDTO } from "@medusajs/types"
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { refetchProductType } from "../helpers"
export const GET = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse
) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const variables = { id: req.params.id }
const queryObject = remoteQueryObjectFromString({
entryPoint: "product_type",
variables,
fields: req.remoteQueryConfig.fields,
})
const [product_type] = await remoteQuery(queryObject)
res.status(200).json({ product_type })
}
export const POST = async (
req: AuthenticatedMedusaRequest<UpdateProductTypeDTO>,
res: MedusaResponse
) => {
const { result, errors } = await updateProductTypesWorkflow(req.scope).run({
input: {
selector: { id: req.params.id },
update: req.validatedBody,
},
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const productType = await refetchProductType(
result[0].id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ product_type: productType })
}
export const DELETE = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse
) => {
const id = req.params.id
const { errors } = await deleteProductTypesWorkflow(req.scope).run({
input: { ids: [id] },
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
res.status(200).json({
id,
object: "product_type",
deleted: true,
})
}

View File

@@ -0,0 +1,20 @@
import { MedusaContainer } from "@medusajs/types"
import { remoteQueryObjectFromString } from "@medusajs/utils"
export const refetchProductType = async (
productTypeId: string,
scope: MedusaContainer,
fields: string[]
) => {
const remoteQuery = scope.resolve("remoteQuery")
const queryObject = remoteQueryObjectFromString({
entryPoint: "product_type",
variables: {
filters: { id: productTypeId },
},
fields: fields,
})
const productTypes = await remoteQuery(queryObject)
return productTypes[0]
}

View File

@@ -0,0 +1,69 @@
import * as QueryConfig from "./query-config"
import {
AdminGetProductTypesProductTypeParams,
AdminGetProductTypesParams,
AdminPostProductTypesProductTypeReq,
AdminPostProductTypesReq,
} from "./validators"
import { transformBody, transformQuery } from "../../../api/middlewares"
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
import { authenticate } from "../../../utils/authenticate-middleware"
export const adminProductTypeRoutesMiddlewares: MiddlewareRoute[] = [
{
method: ["ALL"],
matcher: "/admin/product-types/*",
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
},
{
method: ["GET"],
matcher: "/admin/product-types",
middlewares: [
transformQuery(
AdminGetProductTypesParams,
QueryConfig.listProductTypesTransformQueryConfig
),
],
},
{
method: ["GET"],
matcher: "/admin/product-types/:id",
middlewares: [
transformQuery(
AdminGetProductTypesProductTypeParams,
QueryConfig.retrieveProductTypeTransformQueryConfig
),
],
},
// Create/update/delete methods are new in v2
{
method: ["POST"],
matcher: "/admin/product-types",
middlewares: [
transformBody(AdminPostProductTypesReq),
transformQuery(
AdminGetProductTypesParams,
QueryConfig.retrieveProductTypeTransformQueryConfig
),
],
},
{
method: ["POST"],
matcher: "/admin/product-types/:id",
middlewares: [
transformBody(AdminPostProductTypesProductTypeReq),
transformQuery(
AdminGetProductTypesProductTypeParams,
QueryConfig.retrieveProductTypeTransformQueryConfig
),
],
},
{
method: ["DELETE"],
matcher: "/admin/product-types/:id",
middlewares: [],
},
]

View File

@@ -0,0 +1,17 @@
export const defaultAdminProductTypeFields = [
"id",
"value",
"created_at",
"updated_at",
]
export const retrieveProductTypeTransformQueryConfig = {
defaults: defaultAdminProductTypeFields,
isList: false,
}
export const listProductTypesTransformQueryConfig = {
...retrieveProductTypeTransformQueryConfig,
defaultLimit: 20,
isList: true,
}

View File

@@ -0,0 +1,63 @@
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../types/routing"
import {
ContainerRegistrationKeys,
remoteQueryObjectFromString,
} from "@medusajs/utils"
import {
AdminGetProductTypesParams,
AdminPostProductTypesReq,
} from "./validators"
import { createProductTypesWorkflow } from "@medusajs/core-flows"
import { refetchProductType } from "./helpers"
export const GET = async (
req: AuthenticatedMedusaRequest<AdminGetProductTypesParams>,
res: MedusaResponse
) => {
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const queryObject = remoteQueryObjectFromString({
entryPoint: "product",
variables: {
filters: req.filterableFields,
...req.remoteQueryConfig.pagination,
},
fields: req.remoteQueryConfig.fields,
})
const { rows: product_types, metadata } = await remoteQuery(queryObject)
res.json({
product_types: product_types,
count: metadata.count,
offset: metadata.skip,
limit: metadata.take,
})
}
export const POST = async (
req: AuthenticatedMedusaRequest<AdminPostProductTypesReq>,
res: MedusaResponse
) => {
const input = [req.validatedBody]
const { result, errors } = await createProductTypesWorkflow(req.scope).run({
input: { product_types: input },
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const productType = await refetchProductType(
result[0].id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ product_type: productType })
}

View File

@@ -0,0 +1,113 @@
import { OperatorMap } from "@medusajs/types"
import { Type } from "class-transformer"
import {
IsNotEmpty,
IsObject,
IsOptional,
IsString,
ValidateNested,
} from "class-validator"
import { FindParams, extendedFindParamsMixin } from "../../../types/common"
import { OperatorMapValidator } from "../../../types/validators/operator-map"
export class AdminGetProductTypesProductTypeParams extends FindParams {}
/**
* Parameters used to filter and configure the pagination of the retrieved product types.
*/
export class AdminGetProductTypesParams extends extendedFindParamsMixin({
limit: 10,
offset: 0,
}) {
/**
* Term to search product product types by their title and handle.
*/
@IsString()
@IsOptional()
q?: string
/**
* Id to filter product product types by.
*/
@IsOptional()
@IsString()
id?: string | string[]
/**
* Title to filter product product types by.
*/
@IsOptional()
@IsString()
value?: string | string[] | OperatorMap<string>
/**
* Handle to filter product product types by.
*/
@IsOptional()
@IsString()
handle?: string | string[]
/**
* Date filters to apply on the product product types' `created_at` date.
*/
@IsOptional()
@ValidateNested()
@Type(() => OperatorMapValidator)
created_at?: OperatorMap<string>
/**
* Date filters to apply on the product product types' `updated_at` date.
*/
@IsOptional()
@ValidateNested()
@Type(() => OperatorMapValidator)
updated_at?: OperatorMap<string>
/**
* Date filters to apply on the product product types' `deleted_at` date.
*/
@ValidateNested()
@IsOptional()
@Type(() => OperatorMapValidator)
deleted_at?: OperatorMap<string>
// TODO: To be added in next iteration
// /**
// * Filter product types by their associated discount condition's ID.
// */
// @IsString()
// @IsOptional()
// discount_condition_id?: string
// Note: These are new in v2
// Additional filters from BaseFilterable
@IsOptional()
@ValidateNested({ each: true })
@Type(() => AdminGetProductTypesParams)
$and?: AdminGetProductTypesParams[]
@IsOptional()
@ValidateNested({ each: true })
@Type(() => AdminGetProductTypesParams)
$or?: AdminGetProductTypesParams[]
}
export class AdminPostProductTypesReq {
@IsString()
@IsNotEmpty()
value: string
@IsObject()
@IsOptional()
metadata?: Record<string, unknown>
}
export class AdminPostProductTypesProductTypeReq {
@IsString()
@IsOptional()
value?: string
@IsObject()
@IsOptional()
metadata?: Record<string, unknown>
}

View File

@@ -12,6 +12,7 @@ import { adminPaymentRoutesMiddlewares } from "./admin/payments/middlewares"
import { adminPriceListsRoutesMiddlewares } from "./admin/price-lists/middlewares"
import { adminPricingRoutesMiddlewares } from "./admin/pricing/middlewares"
import { adminProductRoutesMiddlewares } from "./admin/products/middlewares"
import { adminProductTypeRoutesMiddlewares } from "./admin/product-types/middlewares"
import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
import { adminRegionRoutesMiddlewares } from "./admin/regions/middlewares"
import { adminSalesChannelRoutesMiddlewares } from "./admin/sales-channels/middlewares"
@@ -59,5 +60,6 @@ export const config: MiddlewaresConfig = {
...adminFulfillmentRoutesMiddlewares,
...adminSalesChannelRoutesMiddlewares,
...adminStockLocationRoutesMiddlewares,
...adminProductTypeRoutesMiddlewares,
],
}

View File

@@ -211,12 +211,9 @@ moduleIntegrationTestRunner({
const typeId = "type-1"
it("should update the value of the type successfully", async () => {
await service.updateTypes([
{
id: typeId,
value: "UK",
},
])
await service.updateTypes(typeId, {
value: "UK",
})
const productType = await service.retrieveType(typeId)
@@ -227,18 +224,15 @@ moduleIntegrationTestRunner({
let error
try {
await service.updateTypes([
{
id: "does-not-exist",
value: "UK",
},
])
await service.updateTypes("does-not-exist", {
value: "UK",
})
} catch (e) {
error = e
}
expect(error.message).toEqual(
'ProductType with id "does-not-exist" not found'
"ProductType with id: does-not-exist was not found"
)
})
})

View File

@@ -51,6 +51,7 @@ import {
UpdateProductInput,
UpdateProductOptionInput,
UpdateProductVariantInput,
UpdateTypeInput,
} from "../types"
import { entityNameToLinkableKeysMap, joinerConfig } from "./../joiner-config"
@@ -425,34 +426,118 @@ export default class ProductModuleService<
return await this.baseRepository_.serialize(productTags)
}
@InjectTransactionManager("baseRepository_")
async createTypes(
createTypes(
data: ProductTypes.CreateProductTypeDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductTypeDTO[]> {
const productTypes = await this.productTypeService_.create(
data,
sharedContext
)
sharedContext?: Context
): Promise<ProductTypes.ProductTypeDTO[]>
createTypes(
data: ProductTypes.CreateProductTypeDTO,
sharedContext?: Context
): Promise<ProductTypes.ProductTypeDTO>
return await this.baseRepository_.serialize(productTypes, {
populate: true,
})
@InjectManager("baseRepository_")
async createTypes(
data:
| ProductTypes.CreateProductTypeDTO[]
| ProductTypes.CreateProductTypeDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductTypeDTO[] | ProductTypes.ProductTypeDTO> {
const input = Array.isArray(data) ? data : [data]
const types = await this.productTypeService_.create(input, sharedContext)
const createdTypes = await this.baseRepository_.serialize<
ProductTypes.ProductTypeDTO[]
>(types)
return Array.isArray(data) ? createdTypes : createdTypes[0]
}
async upsertTypes(
data: ProductTypes.UpsertProductTypeDTO[],
sharedContext?: Context
): Promise<ProductTypes.ProductTypeDTO[]>
async upsertTypes(
data: ProductTypes.UpsertProductTypeDTO,
sharedContext?: Context
): Promise<ProductTypes.ProductTypeDTO>
@InjectTransactionManager("baseRepository_")
async updateTypes(
data: ProductTypes.UpdateProductTypeDTO[],
async upsertTypes(
data:
| ProductTypes.UpsertProductTypeDTO[]
| ProductTypes.UpsertProductTypeDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductTypeDTO[]> {
const productTypes = await this.productTypeService_.update(
data,
): Promise<ProductTypes.ProductTypeDTO[] | ProductTypes.ProductTypeDTO> {
const input = Array.isArray(data) ? data : [data]
const forUpdate = input.filter((type): type is UpdateTypeInput => !!type.id)
const forCreate = input.filter(
(type): type is ProductTypes.CreateProductTypeDTO => !type.id
)
let created: ProductType[] = []
let updated: ProductType[] = []
if (forCreate.length) {
created = await this.productTypeService_.create(forCreate, sharedContext)
}
if (forUpdate.length) {
updated = await this.productTypeService_.update(forUpdate, sharedContext)
}
const result = [...created, ...updated]
const allTypes = await this.baseRepository_.serialize<
ProductTypes.ProductTypeDTO[] | ProductTypes.ProductTypeDTO
>(result)
return Array.isArray(data) ? allTypes : allTypes[0]
}
updateTypes(
id: string,
data: ProductTypes.UpdateProductTypeDTO,
sharedContext?: Context
): Promise<ProductTypes.ProductTypeDTO>
updateTypes(
selector: ProductTypes.FilterableProductTypeProps,
data: ProductTypes.UpdateProductTypeDTO,
sharedContext?: Context
): Promise<ProductTypes.ProductTypeDTO[]>
@InjectManager("baseRepository_")
async updateTypes(
idOrSelector: string | ProductTypes.FilterableProductTypeProps,
data: ProductTypes.UpdateProductTypeDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductTypeDTO[] | ProductTypes.ProductTypeDTO> {
let normalizedInput: UpdateTypeInput[] = []
if (isString(idOrSelector)) {
// Check if the type exists in the first place
await this.productTypeService_.retrieve(idOrSelector, {}, sharedContext)
normalizedInput = [{ id: idOrSelector, ...data }]
} else {
const types = await this.productTypeService_.list(
idOrSelector,
{},
sharedContext
)
normalizedInput = types.map((type) => ({
id: type.id,
...data,
}))
}
const types = await this.productTypeService_.update(
normalizedInput,
sharedContext
)
return await this.baseRepository_.serialize(productTypes, {
populate: true,
})
const updatedTypes = await this.baseRepository_.serialize<
ProductTypes.ProductTypeDTO[]
>(types)
return isString(idOrSelector) ? updatedTypes[0] : updatedTypes
}
createOptions(

View File

@@ -53,6 +53,10 @@ export type UpdateCollectionInput = ProductTypes.UpdateProductCollectionDTO & {
id: string
}
export type UpdateTypeInput = ProductTypes.UpdateProductTypeDTO & {
id: string
}
export type UpdateProductVariantInput = ProductTypes.UpdateProductVariantDTO & {
id: string
product_id?: string | null

View File

@@ -1002,7 +1002,7 @@ export interface UpdateProductTypeDTO {
/**
* Holds custom data in key-value pairs.
*/
metadata?: Record<string, unknown>
metadata?: Record<string, unknown> | null
}
/**

View File

@@ -31,6 +31,7 @@ import {
UpsertProductCollectionDTO,
UpsertProductDTO,
UpsertProductOptionDTO,
UpsertProductTypeDTO,
UpsertProductVariantDTO,
} from "./common"
@@ -1202,32 +1203,150 @@ export interface IProductModuleService extends IModuleService {
): Promise<ProductTypeDTO[]>
/**
* This method is used to update a product type
* This method is used to create a product type.
*
* @param {UpdateProductTypeDTO[]} data - The product types to be updated, each having the attributes that should be updated in the product type.
* @param {CreateProductTypeDTO} data - The product type to be created.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<ProductTypeDTO[]>} The list of updated product types.
* @returns {Promise<ProductTypeDTO>} The created product type.
*
* @example
* import {
* initialize as initializeProductModule,
* } from "@medusajs/product"
*
* async function updateProductType (id: string, value: string) {
* async function createType (title: string) {
* const productModule = await initializeProductModule()
*
* const productTypes = await productModule.updateTypes([
* const type = await productModule.createTypes(
* {
* value
* }
* )
*
* // do something with the product type or return them
* }
*
*/
createTypes(
data: CreateProductTypeDTO,
sharedContext?: Context
): Promise<ProductTypeDTO>
/**
* This method updates existing types, or creates new ones if they don't exist.
*
* @param {UpsertProductTypeDTO[]} data - The attributes to update or create for each type.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<ProductTypeDTO[]>} The updated and created types.
*
* @example
* import {
* initialize as initializeProductModule,
* } from "@medusajs/product"
*
* async function upsertTypes (title: string) {
* const productModule = await initializeProductModule()
*
* const createdTypes = await productModule.upsertTypes([
* {
* id,
* value
* }
* ])
*
* // do something with the product types or return them
* // do something with the types or return them
* }
*/
upsertTypes(
data: UpsertProductTypeDTO[],
sharedContext?: Context
): Promise<ProductTypeDTO[]>
/**
* This method updates an existing type, or creates a new one if it doesn't exist.
*
* @param {UpsertProductTypeDTO} data - The attributes to update or create for the type.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<ProductTypeDTO>} The updated or created type.
*
* @example
* import {
* initialize as initializeProductModule,
* } from "@medusajs/product"
*
* async function upsertType (title: string) {
* const productModule = await initializeProductModule()
*
* const createdType = await productModule.upsertTypes(
* {
* value
* }
* )
*
* // do something with the type or return it
* }
*/
upsertTypes(
data: UpsertProductTypeDTO,
sharedContext?: Context
): Promise<ProductTypeDTO>
/**
* This method is used to update a type.
*
* @param {string} id - The ID of the type to be updated.
* @param {UpdateProductTypeDTO} data - The attributes of the type to be updated
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<ProductTypeDTO>} The updated type.
*
* @example
* import {
* initialize as initializeProductModule,
* } from "@medusajs/product"
*
* async function updateType (id: string, title: string) {
* const productModule = await initializeProductModule()
*
* const type = await productModule.updateTypes(id, {
* value
* }
* )
*
* // do something with the type or return it
* }
*/
updateTypes(
data: UpdateProductTypeDTO[],
id: string,
data: UpdateProductTypeDTO,
sharedContext?: Context
): Promise<ProductTypeDTO>
/**
* This method is used to update a list of types determined by the selector filters.
*
* @param {FilterableProductTypeProps} selector - The filters that will determine which types will be updated.
* @param {UpdateProductTypeDTO} data - The attributes to be updated on the selected types
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<ProductTypeDTO[]>} The updated types.
*
* @example
* import {
* initialize as initializeProductModule,
* } from "@medusajs/product"
*
* async function updateTypes(ids: string[], title: string) {
* const productModule = await initializeProductModule()
*
* const types = await productModule.updateTypes({id: ids}, {
* value
* }
* )
*
* // do something with the types or return them
* }
*/
updateTypes(
selector: FilterableProductTypeProps,
data: UpdateProductTypeDTO,
sharedContext?: Context
): Promise<ProductTypeDTO[]>
@@ -1251,6 +1370,74 @@ export interface IProductModuleService extends IModuleService {
*/
deleteTypes(productTypeIds: string[], sharedContext?: Context): Promise<void>
/**
* This method is used to delete types. Unlike the {@link delete} method, this method won't completely remove the type. It can still be accessed or retrieved using methods like {@link retrieve} if you pass the `withDeleted` property to the `config` object parameter.
*
* The soft-deleted types can be restored using the {@link restore} method.
*
* @param {string[]} typeIds - The IDs of the types to soft-delete.
* @param {SoftDeleteReturn<TReturnableLinkableKeys>} config -
* Configurations determining which relations to soft delete along with the each of the types. You can pass to its `returnLinkableKeys`
* property any of the type's relation attribute names.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<Record<string, string[]> | void>}
* An object that includes the IDs of related records that were also soft deleted. The object's keys are the ID attribute names of the type entity's relations, and its value is an array of strings, each being the ID of a record associated with the type through this relation.
*
* If there are no related records, the promise resolved to `void`.
*
* @example
* import {
* initialize as initializeProductModule,
* } from "@medusajs/product"
*
* async function deleteTypes (ids: string[]) {
* const productModule = await initializeProductModule()
*
* const cascadedEntities = await productModule.softDeleteTypes(ids)
*
* // do something with the returned cascaded entity IDs or return them
* }
*/
softDeleteTypes<TReturnableLinkableKeys extends string = string>(
typeIds: string[],
config?: SoftDeleteReturn<TReturnableLinkableKeys>,
sharedContext?: Context
): Promise<Record<string, string[]> | void>
/**
* This method is used to restore types which were deleted using the {@link softDelete} method.
*
* @param {string[]} typeIds - The IDs of the types to restore.
* @param {RestoreReturn<TReturnableLinkableKeys>} config -
* Configurations determining which relations to restore along with each of the types. You can pass to its `returnLinkableKeys`
* property any of the type's relation attribute names.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<Record<string, string[]> | void>}
* An object that includes the IDs of related records that were restored. The object's keys are the ID attribute names of the type entity's relations, and its value is an array of strings, each being the ID of the record associated with the type through this relation.
*
* If there are no related records that were restored, the promise resolved to `void`.
*
* @example
* import {
* initialize as initializeProductModule,
* } from "@medusajs/product"
*
* async function restoreTypes (ids: string[]) {
* const productModule = await initializeProductModule()
*
* const cascadedEntities = await productModule.restoreTypes(ids, {
* returnLinkableKeys: []
* })
*
* // do something with the returned cascaded entity IDs or return them
* }
*/
restoreTypes<TReturnableLinkableKeys extends string = string>(
typeIds: string[],
config?: RestoreReturn<TReturnableLinkableKeys>,
sharedContext?: Context
): Promise<Record<string, string[]> | void>
/**
* This method is used to retrieve a product option by its ID.
*