chore: Abstract module services (#6087)

**What**
Create a service abstraction for the modules internal service layer. The objective is to reduce the effort of building new modules when the logic is the same or otherwise allow to override the default behavior.

Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Adrien de Peretti
2024-01-18 09:20:08 +00:00
committed by GitHub
co-authored by Oli Juhl
parent 80feb972cb
commit 130c641e5c
46 changed files with 857 additions and 2836 deletions
@@ -9,7 +9,7 @@ import {
MedusaError,
ModulesSdkUtils,
} from "@medusajs/utils"
import { ProductCategoryServiceTypes } from "../types"
import { ProductCategoryServiceTypes } from "@types"
type InjectedDependencies = {
productCategoryRepository: DAL.TreeRepositoryService
@@ -1,12 +1,5 @@
import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types"
import {
InjectManager,
InjectTransactionManager,
MedusaContext,
ModulesSdkUtils,
retrieveEntity,
} from "@medusajs/utils"
import { ProductCollectionRepository } from "../repositories"
import { InjectManager, MedusaContext, ModulesSdkUtils } from "@medusajs/utils"
import { ProductCollection } from "@models"
@@ -16,98 +9,61 @@ type InjectedDependencies = {
export default class ProductCollectionService<
TEntity extends ProductCollection = ProductCollection
> {
protected readonly productCollectionRepository_: DAL.RepositoryService
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductTypes.CreateProductCollectionDTO
update: ProductTypes.UpdateProductCollectionDTO
}
>(ProductCollection)<TEntity> {
// eslint-disable-next-line max-len
protected readonly productCollectionRepository_: DAL.RepositoryService<TEntity>
constructor({ productCollectionRepository }: InjectedDependencies) {
this.productCollectionRepository_ = productCollectionRepository
constructor(container: InjectedDependencies) {
super(container)
this.productCollectionRepository_ = container.productCollectionRepository
}
@InjectManager("productCollectionRepository_")
async retrieve(
productCollectionId: string,
config: FindConfig<ProductTypes.ProductCollectionDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity> {
return (await retrieveEntity<
ProductCollection,
ProductTypes.ProductCollectionDTO
>({
id: productCollectionId,
entityName: ProductCollection.name,
repository: this.productCollectionRepository_,
config,
sharedContext,
})) as TEntity
}
@InjectManager("productCollectionRepository_")
async list(
async list<TEntityMethod = ProductTypes.ProductCollectionDTO>(
filters: ProductTypes.FilterableProductCollectionProps = {},
config: FindConfig<ProductTypes.ProductCollectionDTO> = {},
config: FindConfig<TEntityMethod> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await this.productCollectionRepository_.find(
return await this.productCollectionRepository_.find(
this.buildListQueryOptions(filters, config),
sharedContext
)) as TEntity[]
)
}
@InjectManager("productCollectionRepository_")
async listAndCount(
async listAndCount<TEntityMethod = ProductTypes.ProductCollectionDTO>(
filters: ProductTypes.FilterableProductCollectionProps = {},
config: FindConfig<ProductTypes.ProductCollectionDTO> = {},
config: FindConfig<TEntityMethod> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
return (await this.productCollectionRepository_.findAndCount(
return await this.productCollectionRepository_.findAndCount(
this.buildListQueryOptions(filters, config),
sharedContext
)) as [TEntity[], number]
)
}
protected buildListQueryOptions(
protected buildListQueryOptions<
TEntityMethod = ProductTypes.ProductCollectionDTO
>(
filters: ProductTypes.FilterableProductCollectionProps = {},
config: FindConfig<ProductTypes.ProductCollectionDTO> = {}
) {
const queryOptions = ModulesSdkUtils.buildQuery<ProductCollection>(
filters,
config
)
config: FindConfig<TEntityMethod> = {}
): DAL.FindOptions<TEntity> {
const queryOptions = ModulesSdkUtils.buildQuery<TEntity>(filters, config)
queryOptions.where ??= {}
if (filters.title) {
queryOptions.where["title"] = { $like: filters.title }
queryOptions.where.title = {
$like: `%${filters.title}%`,
} as DAL.FindOptions<TEntity>["where"]["title"]
}
return queryOptions
}
@InjectTransactionManager("productCollectionRepository_")
async create(
data: ProductTypes.CreateProductCollectionDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (
this.productCollectionRepository_ as ProductCollectionRepository
).create(data, sharedContext)) as TEntity[]
}
@InjectTransactionManager("productCollectionRepository_")
async update(
data: ProductTypes.UpdateProductCollectionDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (
this.productCollectionRepository_ as ProductCollectionRepository
).update(data, sharedContext)) as TEntity[]
}
@InjectTransactionManager("productCollectionRepository_")
async delete(
ids: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productCollectionRepository_.delete(ids, sharedContext)
}
}
@@ -1,7 +1,6 @@
import { Image } from "@models"
import { Context, DAL } from "@medusajs/types"
import { InjectTransactionManager, MedusaContext } from "@medusajs/utils"
import { ProductImageRepository } from "@repositories"
type InjectedDependencies = {
productImageRepository: DAL.RepositoryService
@@ -19,7 +18,6 @@ export default class ProductImageService<TEntity extends Image = Image> {
urls: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (this.productImageRepository_ as ProductImageRepository)
.upsert!(urls, sharedContext)) as TEntity[]
return await this.productImageRepository_.upsert!(urls, sharedContext)
}
}
@@ -35,24 +35,11 @@ import {
import ProductImageService from "./product-image"
import {
CreateProductCategoryDTO,
ProductCategoryEventData,
ProductCategoryEvents,
UpdateProductCategoryDTO,
} from "../types/services/product-category"
import { UpdateProductVariantDTO } from "../types/services/product-variant"
import {
ProductCollectionEventData,
ProductCollectionEvents,
} from "../types/services/product-collection"
import {
ProductEventData,
ProductEvents,
UpdateProductDTO,
} from "../types/services/product"
ProductCategoryServiceTypes,
ProductCollectionServiceTypes,
ProductServiceTypes,
ProductVariantServiceTypes,
} from "@types"
import {
arrayDifference,
@@ -76,6 +63,11 @@ import {
joinerConfig,
LinkableKeys,
} from "./../joiner-config"
import {
ProductCategoryEventData,
ProductCategoryEvents,
} from "../types/services/product-category"
import { ProductEventData, ProductEvents } from "../types/services/product"
type InjectedDependencies = {
baseRepository: DAL.RepositoryService
@@ -373,7 +365,7 @@ export default class ProductModuleService<
const toUpdate = data.map(({ id, options, ...rest }) => {
const variant = variantsMap.get(id)!
const toUpdate: UpdateProductVariantDTO = {
const toUpdate: ProductVariantServiceTypes.UpdateProductVariantDTO = {
id,
product_id: variant.product_id,
}
@@ -749,9 +741,12 @@ export default class ProductModuleService<
sharedContext
)
await this.eventBusModuleService_?.emit<ProductCollectionEventData>(
// eslint-disable-next-line max-len
await this.eventBusModuleService_?.emit<ProductCollectionServiceTypes.ProductCollectionEventData>(
productCollections.map(({ id }) => ({
eventName: ProductCollectionEvents.COLLECTION_CREATED,
eventName:
ProductCollectionServiceTypes.ProductCollectionEvents
.COLLECTION_CREATED,
data: { id },
}))
)
@@ -769,9 +764,12 @@ export default class ProductModuleService<
sharedContext
)
await this.eventBusModuleService_?.emit<ProductCollectionEventData>(
// eslint-disable-next-line max-len
await this.eventBusModuleService_?.emit<ProductCollectionServiceTypes.ProductCollectionEventData>(
productCollections.map(({ id }) => ({
eventName: ProductCollectionEvents.COLLECTION_UPDATED,
eventName:
ProductCollectionServiceTypes.ProductCollectionEvents
.COLLECTION_UPDATED,
data: { id },
}))
)
@@ -789,9 +787,12 @@ export default class ProductModuleService<
sharedContext
)
await this.eventBusModuleService_?.emit<ProductCollectionEventData>(
// eslint-disable-next-line max-len
await this.eventBusModuleService_?.emit<ProductCollectionServiceTypes.ProductCollectionEventData>(
productCollectionIds.map((id) => ({
eventName: ProductCollectionEvents.COLLECTION_DELETED,
eventName:
ProductCollectionServiceTypes.ProductCollectionEvents
.COLLECTION_DELETED,
data: { id },
}))
)
@@ -829,7 +830,7 @@ export default class ProductModuleService<
@InjectTransactionManager("baseRepository_")
async createCategory(
data: CreateProductCategoryDTO,
data: ProductCategoryServiceTypes.CreateProductCategoryDTO,
@MedusaContext() sharedContext: Context = {}
) {
const productCategory = await this.productCategoryService_.create(
@@ -848,7 +849,7 @@ export default class ProductModuleService<
@InjectTransactionManager("baseRepository_")
async updateCategory(
categoryId: string,
data: UpdateProductCategoryDTO,
data: ProductCategoryServiceTypes.UpdateProductCategoryDTO,
@MedusaContext() sharedContext: Context = {}
) {
const productCategory = await this.productCategoryService_.update(
@@ -1124,7 +1125,7 @@ export default class ProductModuleService<
(productData.options ?? []) as TProductOption[]
)
return productData as UpdateProductDTO
return productData as ProductServiceTypes.UpdateProductDTO
})
)
@@ -1203,10 +1204,13 @@ export default class ProductModuleService<
})
productVariantsToUpdateMap.forEach((variants, productId) => {
const variants_ =
// eslint-disable-next-line max-len
variants as unknown as ProductVariantServiceTypes.UpdateProductVariantDTO[]
promises.push(
this.productVariantService_.update(
productByIdMap.get(productId)!,
variants as unknown as UpdateProductVariantDTO[],
variants_,
sharedContext
)
)
@@ -1,14 +1,7 @@
import { ProductOptionValue } from "@models"
import { Context, DAL } from "@medusajs/types"
import {
ProductOptionRepository,
ProductOptionValueRepository,
} from "@repositories"
import { InjectTransactionManager, MedusaContext } from "@medusajs/utils"
import {
CreateProductOptionValueDTO,
UpdateProductOptionValueDTO,
} from "../types/services/product-option-value"
import { ProductOptionValueServiceTypes } from "@types"
type InjectedDependencies = {
productOptionValueRepository: DAL.RepositoryService
@@ -17,11 +10,11 @@ type InjectedDependencies = {
export default class ProductOptionValueService<
TEntity extends ProductOptionValue = ProductOptionValue
> {
protected readonly productOptionValueRepository_: DAL.RepositoryService
// eslint-disable-next-line max-len
protected readonly productOptionValueRepository_: DAL.RepositoryService<TEntity>
constructor({ productOptionValueRepository }: InjectedDependencies) {
this.productOptionValueRepository_ =
productOptionValueRepository as ProductOptionRepository
this.productOptionValueRepository_ = productOptionValueRepository
}
@InjectTransactionManager("productOptionValueRepository_")
@@ -34,11 +27,12 @@ export default class ProductOptionValueService<
@InjectTransactionManager("productOptionValueRepository_")
async upsert(
data: (UpdateProductOptionValueDTO | CreateProductOptionValueDTO)[],
data: (
| ProductOptionValueServiceTypes.UpdateProductOptionValueDTO
| ProductOptionValueServiceTypes.CreateProductOptionValueDTO
)[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (
this.productOptionValueRepository_ as ProductOptionValueRepository
).upsert!(data, sharedContext)) as TEntity[]
return await this.productOptionValueRepository_.upsert!(data, sharedContext)
}
}
+27 -70
View File
@@ -1,12 +1,10 @@
import { ProductOption } from "@models"
import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types"
import { ProductOptionRepository } from "@repositories"
import {
InjectManager,
InjectTransactionManager,
MedusaContext,
ModulesSdkUtils,
retrieveEntity,
} from "@medusajs/utils"
type InjectedDependencies = {
@@ -15,99 +13,59 @@ type InjectedDependencies = {
export default class ProductOptionService<
TEntity extends ProductOption = ProductOption
> {
protected readonly productOptionRepository_: DAL.RepositoryService
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductTypes.CreateProductOptionDTO
update: ProductTypes.UpdateProductOptionDTO
}
>(ProductOption)<TEntity> {
protected readonly productOptionRepository_: DAL.RepositoryService<TEntity>
constructor({ productOptionRepository }: InjectedDependencies) {
this.productOptionRepository_ =
productOptionRepository as ProductOptionRepository
constructor(container: InjectedDependencies) {
super(container)
this.productOptionRepository_ = container.productOptionRepository
}
@InjectManager("productOptionRepository_")
async retrieve(
productOptionId: string,
config: FindConfig<ProductTypes.ProductOptionDTO> = {},
@MedusaContext() sharedContext?: Context
): Promise<TEntity> {
return (await retrieveEntity<ProductOption, ProductTypes.ProductOptionDTO>({
id: productOptionId,
entityName: ProductOption.name,
repository: this.productOptionRepository_,
config,
sharedContext,
})) as TEntity
}
@InjectManager("productOptionRepository_")
async list(
async list<TEntityMethod = ProductTypes.ProductOptionDTO>(
filters: ProductTypes.FilterableProductOptionProps = {},
config: FindConfig<ProductTypes.ProductOptionDTO> = {},
config: FindConfig<TEntityMethod> = {},
@MedusaContext() sharedContext?: Context
): Promise<TEntity[]> {
return (await this.productOptionRepository_.find(
return await this.productOptionRepository_.find(
this.buildQueryForList(filters, config),
sharedContext
)) as TEntity[]
)
}
@InjectManager("productOptionRepository_")
async listAndCount(
async listAndCount<TEntityMethod = ProductTypes.ProductOptionDTO>(
filters: ProductTypes.FilterableProductOptionProps = {},
config: FindConfig<ProductTypes.ProductOptionDTO> = {},
config: FindConfig<TEntityMethod> = {},
@MedusaContext() sharedContext?: Context
): Promise<[TEntity[], number]> {
return (await this.productOptionRepository_.findAndCount(
return await this.productOptionRepository_.findAndCount(
this.buildQueryForList(filters, config),
sharedContext
)) as [TEntity[], number]
)
}
private buildQueryForList(
private buildQueryForList<TEntityMethod = ProductTypes.ProductOptionDTO>(
filters: ProductTypes.FilterableProductOptionProps = {},
config: FindConfig<ProductTypes.ProductOptionDTO> = {}
) {
const queryOptions = ModulesSdkUtils.buildQuery<ProductOption>(
filters,
config
)
config: FindConfig<TEntityMethod> = {}
): DAL.FindOptions<TEntity> {
const queryOptions = ModulesSdkUtils.buildQuery<TEntity>(filters, config)
if (filters.title) {
queryOptions.where["title"] = { $ilike: filters.title }
queryOptions.where.title = {
$ilike: filters.title,
} as DAL.FindOptions<TEntity>["where"]["title"]
}
return queryOptions
}
@InjectTransactionManager("productOptionRepository_")
async create(
data: ProductTypes.CreateProductOptionOnlyDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (
this.productOptionRepository_ as ProductOptionRepository
).create(data, {
transactionManager: sharedContext.transactionManager,
})) as TEntity[]
}
@InjectTransactionManager("productOptionRepository_")
async update(
data: ProductTypes.UpdateProductOptionDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (
this.productOptionRepository_ as ProductOptionRepository
).update(data, sharedContext)) as TEntity[]
}
@InjectTransactionManager("productOptionRepository_")
async delete(
ids: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
return await this.productOptionRepository_.delete(ids, sharedContext)
}
@InjectTransactionManager("productOptionRepository_")
async upsert(
data:
@@ -115,7 +73,6 @@ export default class ProductOptionService<
| ProductTypes.UpdateProductOptionDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (this.productOptionRepository_ as ProductOptionRepository)
.upsert!(data, sharedContext)) as TEntity[]
return await this.productOptionRepository_.upsert!(data, sharedContext)
}
}
+26 -72
View File
@@ -1,11 +1,9 @@
import { ProductTag } from "@models"
import {
Context,
CreateProductTagDTO,
DAL,
FindConfig,
ProductTypes,
UpdateProductTagDTO,
UpsertProductTagDTO,
} from "@medusajs/types"
import {
@@ -13,11 +11,7 @@ import {
InjectTransactionManager,
MedusaContext,
ModulesSdkUtils,
retrieveEntity,
} from "@medusajs/utils"
import { ProductTagRepository } from "@repositories"
import { shouldForceTransaction } from "../utils"
type InjectedDependencies = {
productTagRepository: DAL.RepositoryService
@@ -25,103 +19,63 @@ type InjectedDependencies = {
export default class ProductTagService<
TEntity extends ProductTag = ProductTag
> {
protected readonly productTagRepository_: DAL.RepositoryService
constructor({ productTagRepository }: InjectedDependencies) {
this.productTagRepository_ = productTagRepository
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductTypes.CreateProductTagDTO
update: ProductTypes.UpdateProductTagDTO
}
>(ProductTag)<TEntity> {
protected readonly productTagRepository_: DAL.RepositoryService<TEntity>
@InjectManager("productTagRepository_")
async retrieve(
productTagId: string,
config: FindConfig<ProductTypes.ProductTagDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity> {
return (await retrieveEntity<ProductTag, ProductTypes.ProductTagDTO>({
id: productTagId,
entityName: ProductTag.name,
repository: this.productTagRepository_,
config,
sharedContext,
})) as TEntity
constructor(container: InjectedDependencies) {
super(container)
this.productTagRepository_ = container.productTagRepository
}
@InjectManager("productTagRepository_")
async list(
async list<TEntityMethod = ProductTypes.ProductTagDTO>(
filters: ProductTypes.FilterableProductTagProps = {},
config: FindConfig<ProductTypes.ProductTagDTO> = {},
config: FindConfig<TEntityMethod> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await this.productTagRepository_.find(
return await this.productTagRepository_.find(
this.buildQueryForList(filters, config),
sharedContext
)) as TEntity[]
)
}
@InjectManager("productTagRepository_")
async listAndCount(
async listAndCount<TEntityMethod = ProductTypes.ProductTagDTO>(
filters: ProductTypes.FilterableProductTagProps = {},
config: FindConfig<ProductTypes.ProductTagDTO> = {},
config: FindConfig<TEntityMethod> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
return (await this.productTagRepository_.findAndCount(
return await this.productTagRepository_.findAndCount(
this.buildQueryForList(filters, config),
sharedContext
)) as [TEntity[], number]
)
}
private buildQueryForList(
private buildQueryForList<TEntityMethod = ProductTypes.ProductTagDTO>(
filters: ProductTypes.FilterableProductTagProps = {},
config: FindConfig<ProductTypes.ProductTagDTO> = {}
) {
const queryOptions = ModulesSdkUtils.buildQuery<ProductTag>(filters, config)
config: FindConfig<TEntityMethod> = {}
): DAL.FindOptions<TEntity> {
const queryOptions = ModulesSdkUtils.buildQuery<TEntity>(filters, config)
if (filters.value) {
queryOptions.where["value"] = { $ilike: filters.value }
queryOptions.where.value = {
$ilike: filters.value,
} as DAL.FindOptions<TEntity>["where"]["value"]
}
return queryOptions
}
@InjectTransactionManager("productTagRepository_")
async create(
data: CreateProductTagDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (this.productTagRepository_ as ProductTagRepository).create(
data,
sharedContext
)) as TEntity[]
}
@InjectTransactionManager("productTagRepository_")
async update(
data: UpdateProductTagDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (this.productTagRepository_ as ProductTagRepository).update(
data,
sharedContext
)) as TEntity[]
}
@InjectTransactionManager("productTagRepository_")
async delete(
ids: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productTagRepository_.delete(ids, sharedContext)
}
@InjectTransactionManager("productTagRepository_")
async upsert(
data: UpsertProductTagDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (this.productTagRepository_ as ProductTagRepository).upsert!(
data,
sharedContext
)) as TEntity[]
return await this.productTagRepository_.upsert!(data, sharedContext)
}
}
+27 -73
View File
@@ -1,87 +1,72 @@
import { ProductType } from "@models"
import {
Context,
CreateProductTypeDTO,
DAL,
FindConfig,
ProductTypes,
UpdateProductTypeDTO,
UpsertProductTypeDTO,
} from "@medusajs/types"
import { ProductTypeRepository } from "@repositories"
import {
InjectManager,
InjectTransactionManager,
MedusaContext,
ModulesSdkUtils,
retrieveEntity,
} from "@medusajs/utils"
import { shouldForceTransaction } from "../utils"
type InjectedDependencies = {
productTypeRepository: DAL.RepositoryService
}
export default class ProductTypeService<
TEntity extends ProductType = ProductType
> {
protected readonly productTypeRepository_: DAL.RepositoryService
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductTypes.CreateProductTypeDTO
update: ProductTypes.UpdateProductTypeDTO
}
>(ProductType)<TEntity> {
protected readonly productTypeRepository_: DAL.RepositoryService<TEntity>
constructor({ productTypeRepository }: InjectedDependencies) {
this.productTypeRepository_ = productTypeRepository
constructor(container: InjectedDependencies) {
super(container)
this.productTypeRepository_ = container.productTypeRepository
}
@InjectManager("productTypeRepository_")
async retrieve(
productTypeId: string,
config: FindConfig<ProductTypes.ProductTypeDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity> {
return (await retrieveEntity<ProductType, ProductTypes.ProductTypeDTO>({
id: productTypeId,
entityName: ProductType.name,
repository: this.productTypeRepository_,
config,
sharedContext,
})) as TEntity
}
@InjectManager("productTypeRepository_")
async list(
async list<TEntityMethod = ProductTypes.ProductTypeDTO>(
filters: ProductTypes.FilterableProductTypeProps = {},
config: FindConfig<ProductTypes.ProductTypeDTO> = {},
config: FindConfig<TEntityMethod> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await this.productTypeRepository_.find(
return await this.productTypeRepository_.find(
this.buildQueryForList(filters, config),
sharedContext
)) as TEntity[]
)
}
@InjectManager("productTypeRepository_")
async listAndCount(
async listAndCount<TEntityMethod = ProductTypes.ProductOptionDTO>(
filters: ProductTypes.FilterableProductTypeProps = {},
config: FindConfig<ProductTypes.ProductTypeDTO> = {},
config: FindConfig<TEntityMethod> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
return (await this.productTypeRepository_.findAndCount(
return await this.productTypeRepository_.findAndCount(
this.buildQueryForList(filters, config),
sharedContext
)) as [TEntity[], number]
)
}
private buildQueryForList(
private buildQueryForList<TEntityMethod = ProductTypes.ProductTypeDTO>(
filters: ProductTypes.FilterableProductTypeProps = {},
config: FindConfig<ProductTypes.ProductTypeDTO> = {}
) {
const queryOptions = ModulesSdkUtils.buildQuery<ProductType>(
filters,
config
)
config: FindConfig<TEntityMethod> = {}
): DAL.FindOptions<TEntity> {
const queryOptions = ModulesSdkUtils.buildQuery<TEntity>(filters, config)
if (filters.value) {
queryOptions.where["value"] = { $ilike: filters.value }
queryOptions.where.value = {
$ilike: filters.value,
} as DAL.FindOptions<TEntity>["where"]["value"]
}
return queryOptions
@@ -92,37 +77,6 @@ export default class ProductTypeService<
types: UpsertProductTypeDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (this.productTypeRepository_ as ProductTypeRepository)
.upsert!(types, sharedContext)) as TEntity[]
}
@InjectTransactionManager("productTypeRepository_")
async create(
data: CreateProductTypeDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (this.productTypeRepository_ as ProductTypeRepository).create(
data,
sharedContext
)) as TEntity[]
}
@InjectTransactionManager("productTypeRepository_")
async update(
data: UpdateProductTypeDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (this.productTypeRepository_ as ProductTypeRepository).update(
data,
sharedContext
)) as TEntity[]
}
@InjectTransactionManager("productTypeRepository_")
async delete(
ids: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productTypeRepository_.delete(ids, sharedContext)
return await this.productTypeRepository_.upsert!(types, sharedContext)
}
}
@@ -1,16 +1,13 @@
import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types"
import { Context, DAL, ProductTypes } from "@medusajs/types"
import {
InjectManager,
InjectTransactionManager,
isString,
MedusaContext,
ModulesSdkUtils,
isString,
retrieveEntity,
} from "@medusajs/utils"
import { Product, ProductVariant } from "@models"
import { ProductVariantRepository } from "@repositories"
import { ProductVariantServiceTypes } from "../types/services"
import { ProductVariantServiceTypes } from "@types"
import ProductService from "./product"
type InjectedDependencies = {
@@ -21,72 +18,29 @@ type InjectedDependencies = {
export default class ProductVariantService<
TEntity extends ProductVariant = ProductVariant,
TProduct extends Product = Product
> {
protected readonly productVariantRepository_: DAL.RepositoryService
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductTypes.CreateProductVariantOnlyDTO
update: ProductVariantServiceTypes.UpdateProductVariantDTO
}
>(ProductVariant)<TEntity> {
protected readonly productVariantRepository_: DAL.RepositoryService<TEntity>
protected readonly productService_: ProductService<TProduct>
constructor({
productVariantRepository,
productService,
}: InjectedDependencies) {
// @ts-ignore
super(...arguments)
this.productVariantRepository_ = productVariantRepository
this.productService_ = productService
}
@InjectManager("productVariantRepository_")
async retrieve(
productVariantId: string,
config: FindConfig<ProductTypes.ProductVariantDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity> {
return (await retrieveEntity<
ProductVariant,
ProductTypes.ProductVariantDTO
>({
id: productVariantId,
entityName: ProductVariant.name,
repository: this.productVariantRepository_,
config,
sharedContext,
})) as TEntity
}
@InjectManager("productVariantRepository_")
async list(
filters: ProductTypes.FilterableProductVariantProps = {},
config: FindConfig<ProductTypes.ProductVariantDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
const queryOptions = ModulesSdkUtils.buildQuery<ProductVariant>(
filters,
config
)
return (await this.productVariantRepository_.find(
queryOptions,
sharedContext
)) as TEntity[]
}
@InjectManager("productVariantRepository_")
async listAndCount(
filters: ProductTypes.FilterableProductVariantProps = {},
config: FindConfig<ProductTypes.ProductVariantDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
const queryOptions = ModulesSdkUtils.buildQuery<ProductVariant>(
filters,
config
)
return (await this.productVariantRepository_.findAndCount(
queryOptions,
sharedContext
)) as [TEntity[], number]
}
@InjectTransactionManager("productVariantRepository_")
async create(
// @ts-ignore
override async create(
productOrId: TProduct | string,
data: ProductTypes.CreateProductVariantOnlyDTO[],
@MedusaContext() sharedContext: Context = {}
@@ -113,15 +67,14 @@ export default class ProductVariantService<
})
})
return (await (
this.productVariantRepository_ as ProductVariantRepository
).create(data_, {
return await this.productVariantRepository_.create(data_, {
transactionManager: sharedContext.transactionManager,
})) as TEntity[]
})
}
@InjectTransactionManager("productVariantRepository_")
async update(
// @ts-ignore
override async update(
productOrId: TProduct | string,
data: ProductVariantServiceTypes.UpdateProductVariantDTO[],
@MedusaContext() sharedContext: Context = {}
@@ -139,39 +92,7 @@ export default class ProductVariantService<
const variantsData = [...data]
variantsData.forEach((variant) => Object.assign(variant, { product }))
return (await (
this.productVariantRepository_ as ProductVariantRepository
).update(variantsData, {
transactionManager: sharedContext.transactionManager,
})) as TEntity[]
}
@InjectTransactionManager("productVariantRepository_")
async delete(
ids: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
return await this.productVariantRepository_.delete(ids, {
transactionManager: sharedContext.transactionManager,
})
}
@InjectTransactionManager("productVariantRepository_")
async softDelete(
ids: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productVariantRepository_.softDelete(ids, {
transactionManager: sharedContext.transactionManager,
})
}
@InjectTransactionManager("productVariantRepository_")
async restore(
ids: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], Record<string, unknown[]>]> {
return await this.productVariantRepository_.restore(ids, {
return await this.productVariantRepository_.update(variantsData, {
transactionManager: sharedContext.transactionManager,
})
}
+26 -135
View File
@@ -1,74 +1,35 @@
import {
Context,
DAL,
FindConfig,
ProductTypes,
WithRequiredProperty,
} from "@medusajs/types"
import {
InjectManager,
InjectTransactionManager,
isDefined,
MedusaContext,
MedusaError,
ModulesSdkUtils,
ProductUtils,
} from "@medusajs/utils"
import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types"
import { InjectManager, MedusaContext, ModulesSdkUtils } from "@medusajs/utils"
import { Product } from "@models"
import { ProductRepository } from "@repositories"
import { ProductServiceTypes } from "../types/services"
import { ProductServiceTypes } from "@types"
type InjectedDependencies = {
productRepository: DAL.RepositoryService
}
export default class ProductService<TEntity extends Product = Product> {
protected readonly productRepository_: DAL.RepositoryService
export default class ProductService<
TEntity extends Product = Product
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductTypes.CreateProductOnlyDTO
update: ProductServiceTypes.UpdateProductDTO
}
>(Product)<TEntity> {
protected readonly productRepository_: DAL.RepositoryService<TEntity>
constructor({ productRepository }: InjectedDependencies) {
// @ts-ignore
// eslint-disable-next-line prefer-rest-params
super(...arguments)
this.productRepository_ = productRepository
}
@InjectManager("productRepository_")
async retrieve(
productId: string,
config: FindConfig<ProductTypes.ProductDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity> {
if (!isDefined(productId)) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`"productId" must be defined`
)
}
const queryOptions = ModulesSdkUtils.buildQuery<Product>(
{
id: productId,
},
config
)
const product = await this.productRepository_.find(
queryOptions,
sharedContext
)
if (!product?.length) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`Product with id: ${productId} was not found`
)
}
return product[0] as TEntity
}
@InjectManager("productRepository_")
async list(
async list<TEntityMethod = ProductTypes.ProductDTO>(
filters: ProductTypes.FilterableProductProps = {},
config: FindConfig<ProductTypes.ProductDTO> = {},
config: FindConfig<TEntityMethod> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
if (filters.category_id) {
@@ -84,17 +45,13 @@ export default class ProductService<TEntity extends Product = Product> {
delete filters.category_id
}
const queryOptions = ModulesSdkUtils.buildQuery<Product>(filters, config)
return (await this.productRepository_.find(
queryOptions,
sharedContext
)) as TEntity[]
return await super.list<TEntityMethod>(filters, config, sharedContext)
}
@InjectManager("productRepository_")
async listAndCount(
async listAndCount<TEntityMethod = ProductTypes.ProductDTO>(
filters: ProductTypes.FilterableProductProps = {},
config: FindConfig<ProductTypes.ProductDTO> = {},
config: FindConfig<TEntityMethod> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
if (filters.category_id) {
@@ -110,76 +67,10 @@ export default class ProductService<TEntity extends Product = Product> {
delete filters.category_id
}
const queryOptions = ModulesSdkUtils.buildQuery<Product>(filters, config)
return (await this.productRepository_.findAndCount(
queryOptions,
return await super.listAndCount<TEntityMethod>(
filters,
config,
sharedContext
)) as [TEntity[], number]
}
@InjectTransactionManager("productRepository_")
async create(
data: ProductTypes.CreateProductOnlyDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
data.forEach((product) => {
product.status ??= ProductUtils.ProductStatus.DRAFT
})
return (await (this.productRepository_ as ProductRepository).create(
data as WithRequiredProperty<
ProductTypes.CreateProductOnlyDTO,
"status"
>[],
{
transactionManager: sharedContext.transactionManager,
}
)) as TEntity[]
}
@InjectTransactionManager("productRepository_")
async update(
data: ProductServiceTypes.UpdateProductDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (this.productRepository_ as ProductRepository).update(
data as WithRequiredProperty<
ProductServiceTypes.UpdateProductDTO,
"id"
>[],
{
transactionManager: sharedContext.transactionManager,
}
)) as TEntity[]
}
@InjectTransactionManager("productRepository_")
async delete(
ids: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productRepository_.delete(ids, {
transactionManager: sharedContext.transactionManager,
})
}
@InjectTransactionManager("productRepository_")
async softDelete(
productIds: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], Record<string, unknown[]>]> {
return await this.productRepository_.softDelete(productIds, {
transactionManager: sharedContext.transactionManager,
})
}
@InjectTransactionManager("productRepository_")
async restore(
productIds: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], Record<string, unknown[]>]> {
return await this.productRepository_.restore(productIds, {
transactionManager: sharedContext.transactionManager,
})
)
}
}