chore: Abstract module service (#6188)

**What**
- Remove services that do not have any custom business and replace them with a simple interfaces
- Abstract module service provide the following base implementation
  - retrieve
  - list
  - listAndCount
  - delete
  - softDelete
  - restore

The above methods are created for the main model and also for each other models for which a config is provided

all method such as list, listAndCount, delete, softDelete and restore are pluralized with the model it refers to

**Migration**
- [x] product
- [x] pricing
- [x] promotion
- [x] cart
- [x] auth
- [x] customer
- [x] payment
- [x] Sales channel
- [x] Workflow-*


**Usage**

**Module**

The module service can now extend the ` ModulesSdkUtils.abstractModuleServiceFactory` which returns a class with the default implementation for each method and each model following the standard naming convention mentioned above.
This factory have 3 template arguments being the container, the main model DTO and an object representing the other model with a config object that contains at list the DTO and optionally a singular and plural property in case it needs to be set manually. It looks like the following:

```ts
export default class PricingModuleService</* ... */>
  extends ModulesSdkUtils.abstractModuleServiceFactory<
    InjectedDependencies,
    PricingTypes.PriceSetDTO,
    {
      Currency: { dto: PricingTypes.CurrencyDTO }
      MoneyAmount: { dto: PricingTypes.MoneyAmountDTO }
      PriceSetMoneyAmount: { dto: PricingTypes.PriceSetMoneyAmountDTO }
      PriceSetMoneyAmountRules: {
        dto: PricingTypes.PriceSetMoneyAmountRulesDTO
      }
      PriceRule: { dto: PricingTypes.PriceRuleDTO }
      RuleType: { dto: PricingTypes.RuleTypeDTO }
      PriceList: { dto: PricingTypes.PriceListDTO }
      PriceListRule: { dto: PricingTypes.PriceListRuleDTO }
    }
  >(PriceSet, generateMethodForModels, entityNameToLinkableKeysMap)
  implements PricingTypes.IPricingModuleService
{
// ...
}
```

In the above, the singular and plural can be inferred as there is no tricky naming. Also, the default implementation does not remove the fact that you need to provides all the overloads etc in your module service interface. The above will provide a default implementation following the interface `AbstractModuleService` which is also auto generated, hence you will have the following methods available:

**for the main model**
- list
- retrieve
- listAndCount 
- delete
- softDelete
- restore


**for the other models**
- list**MyModels**
- retrieve**MyModel**
- listAndCount**MyModels**
- delete**MyModels**
- softDelete**MyModels**
- restore**MyModels**

**Internal module service**

The internal module service can now extend `ModulesSdkUtils.internalModuleServiceFactory` which takes only one template argument which is the container type. 
All internal services provides a default implementation for all retrieve, list, listAndCount, create, update, delete, softDelete, restore methods which follow the following interface `ModulesSdkTypes.InternalModuleService`:

```ts
export interface InternalModuleService<
  TEntity extends {},
  TContainer extends object = object
> {
  get __container__(): TContainer

  retrieve(
    idOrObject: string,
    config?: FindConfig<any>,
    sharedContext?: Context
  ): Promise<TEntity>
  retrieve(
    idOrObject: object,
    config?: FindConfig<any>,
    sharedContext?: Context
  ): Promise<TEntity>

  list(
    filters?: FilterQuery<any> | BaseFilterable<FilterQuery<any>>,
    config?: FindConfig<any>,
    sharedContext?: Context
  ): Promise<TEntity[]>

  listAndCount(
    filters?: FilterQuery<any> | BaseFilterable<FilterQuery<any>>,
    config?: FindConfig<any>,
    sharedContext?: Context
  ): Promise<[TEntity[], number]>

  create(data: any[], sharedContext?: Context): Promise<TEntity[]>
  create(data: any, sharedContext?: Context): Promise<TEntity>

  update(data: any[], sharedContext?: Context): Promise<TEntity[]>
  update(data: any, sharedContext?: Context): Promise<TEntity>
  update(
    selectorAndData: {
      selector: FilterQuery<any> | BaseFilterable<FilterQuery<any>>
      data: any
    },
    sharedContext?: Context
  ): Promise<TEntity[]>
  update(
    selectorAndData: {
      selector: FilterQuery<any> | BaseFilterable<FilterQuery<any>>
      data: any
    }[],
    sharedContext?: Context
  ): Promise<TEntity[]>

  delete(idOrSelector: string, sharedContext?: Context): Promise<void>
  delete(idOrSelector: string[], sharedContext?: Context): Promise<void>
  delete(idOrSelector: object, sharedContext?: Context): Promise<void>
  delete(idOrSelector: object[], sharedContext?: Context): Promise<void>
  delete(
    idOrSelector: {
      selector: FilterQuery<any> | BaseFilterable<FilterQuery<any>>
    },
    sharedContext?: Context
  ): Promise<void>

  softDelete(
    idsOrFilter: string[] | InternalFilterQuery,
    sharedContext?: Context
  ): Promise<[TEntity[], Record<string, unknown[]>]>

  restore(
    idsOrFilter: string[] | InternalFilterQuery,
    sharedContext?: Context
  ): Promise<[TEntity[], Record<string, unknown[]>]>

  upsert(data: any[], sharedContext?: Context): Promise<TEntity[]>
  upsert(data: any, sharedContext?: Context): Promise<TEntity>
}
```

When a service is auto generated you can use that interface to type your class property representing the expected internal service.

**Repositories**

The repositories can now extend `DALUtils.mikroOrmBaseRepositoryFactory` which takes one template argument being the entity or the template entity and provides all the default implementation. If the repository is auto generated you can type it using the `RepositoryService` interface. Here is the new interface typings.

```ts
export interface RepositoryService<T = any> extends BaseRepositoryService<T> {
  find(options?: FindOptions<T>, context?: Context): Promise<T[]>

  findAndCount(
    options?: FindOptions<T>,
    context?: Context
  ): Promise<[T[], number]>

  create(data: any[], context?: Context): Promise<T[]>

  // Becareful here, if you have a custom internal service, the update data should never be the entity otherwise
 // both entity and update will point to the same ref and create issues with mikro orm
  update(data: { entity; update }[], context?: Context): Promise<T[]>

  delete(
    idsOrPKs: FilterQuery<T> & BaseFilterable<FilterQuery<T>>,
    context?: Context
  ): Promise<void>

  /**
   * Soft delete entities and cascade to related entities if configured.
   *
   * @param idsOrFilter
   * @param context
   *
   * @returns [T[], Record<string, string[]>] the second value being the map of the entity names and ids that were soft deleted
   */
  softDelete(
    idsOrFilter: string[] | InternalFilterQuery,
    context?: Context
  ): Promise<[T[], Record<string, unknown[]>]>

  restore(
    idsOrFilter: string[] | InternalFilterQuery,
    context?: Context
  ): Promise<[T[], Record<string, unknown[]>]>

  upsert(data: any[], context?: Context): Promise<T[]>
}
```
This commit is contained in:
Adrien de Peretti
2024-02-02 14:20:32 +00:00
committed by GitHub
parent abc30517cb
commit a7be5d7b6d
163 changed files with 2867 additions and 5080 deletions
+1 -1
View File
@@ -144,7 +144,7 @@ class Product {
@ManyToMany(() => ProductCategory, "products", {
owner: true,
pivotTable: "product_category_product",
cascade: ["soft-remove"] as any,
// TODO: rm cascade: ["soft-remove"] as any,
})
categories = new Collection<ProductCategory>(this)
@@ -14,6 +14,6 @@ export class ProductImageRepository extends DALUtils.mikroOrmBaseRepositoryFacto
async upsert(urls: string[], context: Context = {}): Promise<Image[]> {
const data = urls.map((url) => ({ url }))
return await super.upsert(data, context)
return (await super.upsert(data, context)) as Image[]
}
}
+8 -15
View File
@@ -17,8 +17,8 @@ import {
DALUtils,
isDefined,
MedusaError,
promiseAll,
ProductUtils,
promiseAll,
} from "@medusajs/utils"
import { ProductServiceTypes } from "../types/services"
@@ -118,7 +118,10 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory<Pr
}
async update(
data: WithRequiredProperty<ProductServiceTypes.UpdateProductDTO, "id">[],
data: {
entity: Product
update: WithRequiredProperty<ProductServiceTypes.UpdateProductDTO, "id">
}[],
context: Context = {}
): Promise<Product[]> {
let categoryIds: string[] = []
@@ -128,7 +131,7 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory<Pr
// TODO: use the getter method (getActiveManager)
const manager = this.getActiveManager<SqlEntityManager>(context)
data.forEach((productData) => {
data.forEach(({ update: productData }) => {
categoryIds = categoryIds.concat(
productData?.categories?.map((c) => c.id) || []
)
@@ -144,16 +147,6 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory<Pr
}
})
const productsToUpdate = await manager.find(
Product,
{
id: data.map((updateData) => updateData.id),
},
{
populate: ["tags", "categories"],
}
)
const collectionsToAssign = collectionIds.length
? await manager.find(ProductCollection, {
id: collectionIds,
@@ -195,11 +188,11 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory<Pr
)
const productsToUpdateMap = new Map<string, Product>(
productsToUpdate.map((product) => [product.id, product])
data.map(({ entity }) => [entity.id, entity])
)
const products = await promiseAll(
data.map(async (updateData) => {
data.map(async ({ update: updateData }) => {
const product = productsToUpdateMap.get(updateData.id)
if (!product) {
@@ -1,11 +1,8 @@
import { asClass, asValue, createContainer } from "awilix"
import { ProductService } from "@services"
import { asValue } from "awilix"
export const nonExistingProductId = "non-existing-id"
export const mockContainer = createContainer()
mockContainer.register({
transaction: asValue(async (task) => await task()),
export const productRepositoryMock = {
productRepository: asValue({
find: jest.fn().mockImplementation(async ({ where: { id } }) => {
if (id === nonExistingProductId) {
@@ -17,5 +14,4 @@ mockContainer.register({
findAndCount: jest.fn().mockResolvedValue([[], 0]),
getFreshManager: jest.fn().mockResolvedValue({}),
}),
productService: asClass(ProductService),
})
}
@@ -1,13 +1,28 @@
import { mockContainer, nonExistingProductId } from "../__fixtures__/product"
import {
nonExistingProductId,
productRepositoryMock,
} from "../__fixtures__/product"
import { createMedusaContainer } from "@medusajs/utils"
import { asValue } from "awilix"
import ContainerLoader from "../../loaders/container"
describe("Product service", function () {
beforeEach(function () {
let container
beforeEach(async function () {
jest.clearAllMocks()
container = createMedusaContainer()
container.register("manager", asValue({}))
await ContainerLoader({ container })
container.register(productRepositoryMock)
})
it("should retrieve a product", async function () {
const productService = mockContainer.resolve("productService")
const productRepository = mockContainer.resolve("productRepository")
const productService = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const productId = "existing-product"
await productService.retrieve(productId)
@@ -30,8 +45,8 @@ describe("Product service", function () {
})
it("should fail to retrieve a product", async function () {
const productService = mockContainer.resolve("productService")
const productRepository = mockContainer.resolve("productRepository")
const productService = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const err = await productService
.retrieve(nonExistingProductId)
@@ -59,8 +74,8 @@ describe("Product service", function () {
})
it("should list products", async function () {
const productService = mockContainer.resolve("productService")
const productRepository = mockContainer.resolve("productRepository")
const productService = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const filters = {}
const config = {
@@ -85,8 +100,8 @@ describe("Product service", function () {
})
it("should list products with filters", async function () {
const productService = mockContainer.resolve("productService")
const productRepository = mockContainer.resolve("productRepository")
const productService = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const filters = {
tags: {
@@ -123,8 +138,8 @@ describe("Product service", function () {
})
it("should list products with filters and relations", async function () {
const productService = mockContainer.resolve("productService")
const productRepository = mockContainer.resolve("productRepository")
const productService = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const filters = {
tags: {
@@ -161,8 +176,8 @@ describe("Product service", function () {
})
it("should list and count the products with filters and relations", async function () {
const productService = mockContainer.resolve("productService")
const productRepository = mockContainer.resolve("productRepository")
const productService = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const filters = {
tags: {
-2
View File
@@ -6,5 +6,3 @@ export { default as ProductTagService } from "./product-tag"
export { default as ProductVariantService } from "./product-variant"
export { default as ProductTypeService } from "./product-type"
export { default as ProductOptionService } from "./product-option"
export { default as ProductImageService } from "./product-image"
export { default as ProductOptionValueService } from "./product-option-value"
@@ -7,14 +7,7 @@ import {
} from "@medusajs/utils"
import { ProductCollection } from "@models"
import {
IProductCollectionRepository,
ProductCollectionServiceTypes,
} from "@types"
import {
CreateProductCollection,
UpdateProductCollection,
} from "../types/services/product-collection"
import { ProductCollectionServiceTypes } from "@types"
type InjectedDependencies = {
productCollectionRepository: DAL.RepositoryService
@@ -22,15 +15,11 @@ type InjectedDependencies = {
export default class ProductCollectionService<
TEntity extends ProductCollection = ProductCollection
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: CreateProductCollection
update: UpdateProductCollection
}
>(ProductCollection)<TEntity> {
> extends ModulesSdkUtils.internalModuleServiceFactory<InjectedDependencies>(
ProductCollection
)<TEntity> {
// eslint-disable-next-line max-len
protected readonly productCollectionRepository_: IProductCollectionRepository<TEntity>
protected readonly productCollectionRepository_: DAL.RepositoryService<TEntity>
constructor(container: InjectedDependencies) {
super(container)
@@ -38,9 +27,9 @@ export default class ProductCollectionService<
}
@InjectManager("productCollectionRepository_")
async list<TEntityMethod = ProductTypes.ProductCollectionDTO>(
async list(
filters: ProductTypes.FilterableProductCollectionProps = {},
config: FindConfig<TEntityMethod> = {},
config: FindConfig<TEntity> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return await this.productCollectionRepository_.find(
@@ -50,9 +39,9 @@ export default class ProductCollectionService<
}
@InjectManager("productCollectionRepository_")
async listAndCount<TEntityMethod = ProductTypes.ProductCollectionDTO>(
async listAndCount(
filters: ProductTypes.FilterableProductCollectionProps = {},
config: FindConfig<TEntityMethod> = {},
config: FindConfig<TEntity> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
return await this.productCollectionRepository_.findAndCount(
@@ -61,11 +50,9 @@ export default class ProductCollectionService<
)
}
protected buildListQueryOptions<
TEntityMethod = ProductTypes.ProductCollectionDTO
>(
protected buildListQueryOptions(
filters: ProductTypes.FilterableProductCollectionProps = {},
config: FindConfig<TEntityMethod> = {}
config: FindConfig<TEntity> = {}
): DAL.FindOptions<TEntity> {
const queryOptions = ModulesSdkUtils.buildQuery<TEntity>(filters, config)
@@ -80,12 +67,24 @@ export default class ProductCollectionService<
return queryOptions
}
create(
data: ProductCollectionServiceTypes.CreateProductCollection,
context?: Context
): Promise<TEntity>
create(
data: ProductCollectionServiceTypes.CreateProductCollection[],
context?: Context
): Promise<TEntity[]>
@InjectTransactionManager("productCollectionRepository_")
async create(
data: ProductCollectionServiceTypes.CreateProductCollection[],
data:
| ProductCollectionServiceTypes.CreateProductCollection
| ProductCollectionServiceTypes.CreateProductCollection[],
context: Context = {}
): Promise<TEntity[]> {
const productCollections = data.map((collectionData) => {
): Promise<TEntity | TEntity[]> {
const data_ = Array.isArray(data) ? data : [data]
const productCollections = data_.map((collectionData) => {
if (collectionData.product_ids) {
collectionData.products = collectionData.product_ids
@@ -98,12 +97,27 @@ export default class ProductCollectionService<
return super.create(productCollections, context)
}
@InjectTransactionManager("productCollectionRepository_")
async update(
// @ts-ignore
update(
data: ProductCollectionServiceTypes.UpdateProductCollection,
context?: Context
): Promise<TEntity>
// @ts-ignore
update(
data: ProductCollectionServiceTypes.UpdateProductCollection[],
context?: Context
): Promise<TEntity[]>
@InjectTransactionManager("productCollectionRepository_")
// @ts-ignore Do not implement all the expected overloads, see if we must do it
async update(
data:
| ProductCollectionServiceTypes.UpdateProductCollection
| ProductCollectionServiceTypes.UpdateProductCollection[],
context: Context = {}
): Promise<TEntity[]> {
const productCollections = data.map((collectionData) => {
): Promise<TEntity | TEntity[]> {
const data_ = Array.isArray(data) ? data : [data]
const productCollections = data_.map((collectionData) => {
if (collectionData.product_ids) {
collectionData.products = collectionData.product_ids
@@ -1,18 +0,0 @@
import { Image } from "@models"
import { DAL } from "@medusajs/types"
import { ModulesSdkUtils } from "@medusajs/utils"
type InjectedDependencies = {
productImageRepository: DAL.RepositoryService
}
export default class ProductImageService<
TEntity extends Image = Image
> extends ModulesSdkUtils.abstractServiceFactory<InjectedDependencies>(
Image
)<TEntity> {
constructor(container: InjectedDependencies) {
// @ts-ignore
super(...arguments)
}
}
@@ -2,13 +2,11 @@ import {
Context,
CreateProductOnlyDTO,
DAL,
FindConfig,
IEventBusModuleService,
InternalModuleDeclaration,
ModuleJoinerConfig,
ModulesSdkTypes,
ProductTypes,
RestoreReturn,
SoftDeleteReturn,
} from "@medusajs/types"
import {
Image,
@@ -25,22 +23,12 @@ import {
ProductCategoryService,
ProductCollectionService,
ProductOptionService,
ProductOptionValueService,
ProductService,
ProductTagService,
ProductTypeService,
ProductVariantService,
} from "@services"
import ProductImageService from "./product-image"
import {
ProductCategoryServiceTypes,
ProductCollectionServiceTypes,
ProductServiceTypes,
ProductVariantServiceTypes,
} from "@types"
import {
arrayDifference,
groupBy,
@@ -49,25 +37,24 @@ import {
isDefined,
isString,
kebabCase,
mapObjectTo,
MedusaContext,
MedusaError,
ModulesSdkUtils,
promiseAll,
} from "@medusajs/utils"
import { entityNameToLinkableKeysMap, joinerConfig } from "./../joiner-config"
import { ProductEventData, ProductEvents } from "../types/services/product"
import {
ProductCategoryEventData,
ProductCategoryEvents,
} from "../types/services/product-category"
import {
CreateProductOptionValueDTO,
UpdateProductOptionValueDTO,
} from "../types/services/product-option-value"
import {
entityNameToLinkableKeysMap,
joinerConfig,
LinkableKeys,
} from "./../joiner-config"
ProductCategoryServiceTypes,
ProductCollectionServiceTypes,
ProductOptionValueServiceTypes,
ProductServiceTypes,
ProductVariantServiceTypes,
} from "@types"
type InjectedDependencies = {
baseRepository: DAL.RepositoryService
@@ -76,24 +63,70 @@ type InjectedDependencies = {
productTagService: ProductTagService<any>
productCategoryService: ProductCategoryService<any>
productCollectionService: ProductCollectionService<any>
productImageService: ProductImageService<any>
productImageService: ModulesSdkTypes.InternalModuleService<any>
productTypeService: ProductTypeService<any>
productOptionService: ProductOptionService<any>
productOptionValueService: ProductOptionValueService<any>
productOptionValueService: ModulesSdkTypes.InternalModuleService<any>
eventBusModuleService?: IEventBusModuleService
}
const generateMethodForModels = [
{ model: ProductCategory, singular: "Category", plural: "Categories" },
{ model: ProductCollection, singular: "Collection", plural: "Collections" },
{ model: ProductOption, singular: "Option", plural: "Options" },
{ model: ProductTag, singular: "Tag", plural: "Tags" },
{ model: ProductType, singular: "Type", plural: "Types" },
{ model: ProductVariant, singular: "Variant", plural: "Variants" },
]
export default class ProductModuleService<
TProduct extends Product = Product,
TProductVariant extends ProductVariant = ProductVariant,
TProductTag extends ProductTag = ProductTag,
TProductCollection extends ProductCollection = ProductCollection,
TProductCategory extends ProductCategory = ProductCategory,
TProductImage extends Image = Image,
TProductType extends ProductType = ProductType,
TProductOption extends ProductOption = ProductOption,
TProductOptionValue extends ProductOptionValue = ProductOptionValue
> implements ProductTypes.IProductModuleService
TProduct extends Product = Product,
TProductVariant extends ProductVariant = ProductVariant,
TProductTag extends ProductTag = ProductTag,
TProductCollection extends ProductCollection = ProductCollection,
TProductCategory extends ProductCategory = ProductCategory,
TProductImage extends Image = Image,
TProductType extends ProductType = ProductType,
TProductOption extends ProductOption = ProductOption,
TProductOptionValue extends ProductOptionValue = ProductOptionValue
>
extends ModulesSdkUtils.abstractModuleServiceFactory<
InjectedDependencies,
ProductTypes.ProductDTO,
{
ProductCategory: {
dto: ProductTypes.ProductCategoryDTO
singular: "Category"
plural: "Categories"
}
ProductCollection: {
dto: ProductTypes.ProductCollectionDTO
singular: "Collection"
plural: "Collections"
}
ProductOption: {
dto: ProductTypes.ProductOptionDTO
singular: "Option"
plural: "Options"
}
ProductTag: {
dto: ProductTypes.ProductTagDTO
singular: "Tag"
plural: "Tags"
}
ProductType: {
dto: ProductTypes.ProductTypeDTO
singular: "Type"
plural: "Types"
}
ProductVariant: {
dto: ProductTypes.ProductVariantDTO
singular: "Variant"
plural: "Variants"
}
}
>(Product, generateMethodForModels, entityNameToLinkableKeysMap)
implements ProductTypes.IProductModuleService
{
protected baseRepository_: DAL.RepositoryService
protected readonly productService_: ProductService<TProduct>
@@ -107,11 +140,12 @@ export default class ProductModuleService<
protected readonly productTagService_: ProductTagService<TProductTag>
// eslint-disable-next-line max-len
protected readonly productCollectionService_: ProductCollectionService<TProductCollection>
protected readonly productImageService_: ProductImageService<TProductImage>
// eslint-disable-next-line max-len
protected readonly productImageService_: ModulesSdkTypes.InternalModuleService<TProductImage>
protected readonly productTypeService_: ProductTypeService<TProductType>
protected readonly productOptionService_: ProductOptionService<TProductOption>
// eslint-disable-next-line max-len
protected readonly productOptionValueService_: ProductOptionValueService<TProductOptionValue>
protected readonly productOptionValueService_: ModulesSdkTypes.InternalModuleService<TProductOptionValue>
protected readonly eventBusModuleService_?: IEventBusModuleService
constructor(
@@ -130,6 +164,10 @@ export default class ProductModuleService<
}: InjectedDependencies,
protected readonly moduleDeclaration: InternalModuleDeclaration
) {
// @ts-ignore
// eslint-disable-next-line prefer-rest-params
super(...arguments)
this.baseRepository_ = baseRepository
this.productService_ = productService
this.productVariantService_ = productVariantService
@@ -147,96 +185,6 @@ export default class ProductModuleService<
return joinerConfig
}
@InjectManager("baseRepository_")
async list(
filters: ProductTypes.FilterableProductProps = {},
config: FindConfig<ProductTypes.ProductDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductDTO[]> {
const products = await this.productService_.list(
filters,
config,
sharedContext
)
return JSON.parse(JSON.stringify(products))
}
@InjectManager("baseRepository_")
async retrieve(
productId: string,
config: FindConfig<ProductTypes.ProductDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductDTO> {
const product = await this.productService_.retrieve(
productId,
config,
sharedContext
)
return JSON.parse(JSON.stringify(product))
}
@InjectManager("baseRepository_")
async listAndCount(
filters: ProductTypes.FilterableProductProps = {},
config: FindConfig<ProductTypes.ProductDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[ProductTypes.ProductDTO[], number]> {
const [products, count] = await this.productService_.listAndCount(
filters,
config,
sharedContext
)
return [JSON.parse(JSON.stringify(products)), count]
}
@InjectManager("baseRepository_")
async retrieveVariant(
productVariantId: string,
config: FindConfig<ProductTypes.ProductVariantDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductVariantDTO> {
const productVariant = await this.productVariantService_.retrieve(
productVariantId,
config,
sharedContext
)
return JSON.parse(JSON.stringify(productVariant))
}
@InjectManager("baseRepository_")
async listVariants(
filters: ProductTypes.FilterableProductVariantProps = {},
config: FindConfig<ProductTypes.ProductVariantDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductVariantDTO[]> {
const variants = await this.productVariantService_.list(
filters,
config,
sharedContext
)
return JSON.parse(JSON.stringify(variants))
}
@InjectManager("baseRepository_")
async listAndCountVariants(
filters: ProductTypes.FilterableProductVariantProps = {},
config: FindConfig<ProductTypes.ProductVariantDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[ProductTypes.ProductVariantDTO[], number]> {
const [variants, count] = await this.productVariantService_.listAndCount(
filters,
config,
sharedContext
)
return [JSON.parse(JSON.stringify(variants)), count]
}
async createVariants(
data: ProductTypes.CreateProductVariantDTO[],
@MedusaContext() sharedContext: Context = {}
@@ -300,21 +248,6 @@ export default class ProductModuleService<
return productVariants as unknown as ProductTypes.ProductVariantDTO[]
}
@InjectTransactionManager("baseRepository_")
async deleteVariants(
productVariantIds: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productVariantService_.delete(productVariantIds, sharedContext)
await this.eventBusModuleService_?.emit<ProductEventData>(
productVariantIds.map((id) => ({
eventName: ProductEvents.PRODUCT_DELETED,
data: { id },
}))
)
}
@InjectManager("baseRepository_")
async updateVariants(
data: ProductTypes.UpdateProductVariantOnlyDTO[],
@@ -324,9 +257,7 @@ export default class ProductModuleService<
const updatedVariants = await this.baseRepository_.serialize<
ProductTypes.ProductVariantDTO[]
>(productVariants, {
populate: true,
})
>(productVariants)
return updatedVariants
}
@@ -357,8 +288,8 @@ export default class ProductModuleService<
}
const optionValuesToUpsert: (
| CreateProductOptionValueDTO
| UpdateProductOptionValueDTO
| ProductOptionValueServiceTypes.CreateProductOptionValueDTO
| ProductOptionValueServiceTypes.UpdateProductOptionValueDTO
)[] = []
const optionsValuesToDelete: string[] = []
@@ -413,11 +344,7 @@ export default class ProductModuleService<
const groups = groupBy(toUpdate, "product_id")
const [, , productVariants]: [
void,
TProductOptionValue[],
TProductVariant[][]
] = await promiseAll([
const [, , productVariants] = await promiseAll([
await this.productOptionValueService_.delete(
optionsValuesToDelete,
sharedContext
@@ -440,51 +367,6 @@ export default class ProductModuleService<
return productVariants.flat()
}
@InjectManager("baseRepository_")
async retrieveTag(
tagId: string,
config: FindConfig<ProductTypes.ProductTagDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductTagDTO> {
const productTag = await this.productTagService_.retrieve(
tagId,
config,
sharedContext
)
return JSON.parse(JSON.stringify(productTag))
}
@InjectManager("baseRepository_")
async listTags(
filters: ProductTypes.FilterableProductTagProps = {},
config: FindConfig<ProductTypes.ProductTagDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductTagDTO[]> {
const tags = await this.productTagService_.list(
filters,
config,
sharedContext
)
return JSON.parse(JSON.stringify(tags))
}
@InjectManager("baseRepository_")
async listAndCountTags(
filters: ProductTypes.FilterableProductTagProps = {},
config: FindConfig<ProductTypes.ProductTagDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[ProductTypes.ProductTagDTO[], number]> {
const [tags, count] = await this.productTagService_.listAndCount(
filters,
config,
sharedContext
)
return [JSON.parse(JSON.stringify(tags)), count]
}
@InjectTransactionManager("baseRepository_")
async createTags(
data: ProductTypes.CreateProductTagDTO[],
@@ -511,59 +393,6 @@ export default class ProductModuleService<
return JSON.parse(JSON.stringify(productTags))
}
@InjectTransactionManager("baseRepository_")
async deleteTags(
productTagIds: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productTagService_.delete(productTagIds, sharedContext)
}
@InjectManager("baseRepository_")
async retrieveType(
typeId: string,
config: FindConfig<ProductTypes.ProductTypeDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductTypeDTO> {
const productType = await this.productTypeService_.retrieve(
typeId,
config,
sharedContext
)
return JSON.parse(JSON.stringify(productType))
}
@InjectManager("baseRepository_")
async listTypes(
filters: ProductTypes.FilterableProductTypeProps = {},
config: FindConfig<ProductTypes.ProductTypeDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductTypeDTO[]> {
const types = await this.productTypeService_.list(
filters,
config,
sharedContext
)
return JSON.parse(JSON.stringify(types))
}
@InjectManager("baseRepository_")
async listAndCountTypes(
filters: ProductTypes.FilterableProductTypeProps = {},
config: FindConfig<ProductTypes.ProductTypeDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[ProductTypes.ProductTypeDTO[], number]> {
const [types, count] = await this.productTypeService_.listAndCount(
filters,
config,
sharedContext
)
return [JSON.parse(JSON.stringify(types)), count]
}
@InjectTransactionManager("baseRepository_")
async createTypes(
data: ProductTypes.CreateProductTypeDTO[],
@@ -590,60 +419,6 @@ export default class ProductModuleService<
return JSON.parse(JSON.stringify(productTypes))
}
@InjectTransactionManager("baseRepository_")
async deleteTypes(
productTypeIds: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productTypeService_.delete(productTypeIds, sharedContext)
}
@InjectManager("baseRepository_")
async retrieveOption(
optionId: string,
config: FindConfig<ProductTypes.ProductOptionDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductOptionDTO> {
const productOptions = await this.productOptionService_.retrieve(
optionId,
config,
sharedContext
)
return JSON.parse(JSON.stringify(productOptions))
}
@InjectManager("baseRepository_")
async listOptions(
filters: ProductTypes.FilterableProductTypeProps = {},
config: FindConfig<ProductTypes.ProductOptionDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductOptionDTO[]> {
const productOptions = await this.productOptionService_.list(
filters,
config,
sharedContext
)
return JSON.parse(JSON.stringify(productOptions))
}
@InjectManager("baseRepository_")
async listAndCountOptions(
filters: ProductTypes.FilterableProductTypeProps = {},
config: FindConfig<ProductTypes.ProductOptionDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[ProductTypes.ProductOptionDTO[], number]> {
const [productOptions, count] =
await this.productOptionService_.listAndCount(
filters,
config,
sharedContext
)
return [JSON.parse(JSON.stringify(productOptions)), count]
}
@InjectTransactionManager("baseRepository_")
async createOptions(
data: ProductTypes.CreateProductOptionDTO[],
@@ -656,9 +431,7 @@ export default class ProductModuleService<
return await this.baseRepository_.serialize<
ProductTypes.ProductOptionDTO[]
>(productOptions, {
populate: true,
})
>(productOptions)
}
@InjectTransactionManager("baseRepository_")
@@ -673,62 +446,7 @@ export default class ProductModuleService<
return await this.baseRepository_.serialize<
ProductTypes.ProductOptionDTO[]
>(productOptions, {
populate: true,
})
}
@InjectTransactionManager("baseRepository_")
async deleteOptions(
productOptionIds: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productOptionService_.delete(productOptionIds, sharedContext)
}
@InjectManager("baseRepository_")
async retrieveCollection(
productCollectionId: string,
config: FindConfig<ProductTypes.ProductCollectionDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductCollectionDTO> {
const productCollection = await this.productCollectionService_.retrieve(
productCollectionId,
config,
sharedContext
)
return JSON.parse(JSON.stringify(productCollection))
}
@InjectManager("baseRepository_")
async listCollections(
filters: ProductTypes.FilterableProductCollectionProps = {},
config: FindConfig<ProductTypes.ProductCollectionDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductCollectionDTO[]> {
const collections = await this.productCollectionService_.list(
filters,
config,
sharedContext
)
return JSON.parse(JSON.stringify(collections))
}
@InjectManager("baseRepository_")
async listAndCountCollections(
filters: ProductTypes.FilterableProductCollectionProps = {},
config: FindConfig<ProductTypes.ProductCollectionDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[ProductTypes.ProductCollectionDTO[], number]> {
const collections = await this.productCollectionService_.listAndCount(
filters,
config,
sharedContext
)
return JSON.parse(JSON.stringify(collections))
>(productOptions)
}
@InjectTransactionManager("baseRepository_")
@@ -777,57 +495,6 @@ export default class ProductModuleService<
return JSON.parse(JSON.stringify(productCollections))
}
@InjectTransactionManager("baseRepository_")
async deleteCollections(
productCollectionIds: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productCollectionService_.delete(
productCollectionIds,
sharedContext
)
// eslint-disable-next-line max-len
await this.eventBusModuleService_?.emit<ProductCollectionServiceTypes.ProductCollectionEventData>(
productCollectionIds.map((id) => ({
eventName:
ProductCollectionServiceTypes.ProductCollectionEvents
.COLLECTION_DELETED,
data: { id },
}))
)
}
@InjectManager("baseRepository_")
async retrieveCategory(
productCategoryId: string,
config: FindConfig<ProductTypes.ProductCategoryDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductCategoryDTO> {
const productCategory = await this.productCategoryService_.retrieve(
productCategoryId,
config,
sharedContext
)
return JSON.parse(JSON.stringify(productCategory))
}
@InjectManager("baseRepository_")
async listCategories(
filters: ProductTypes.FilterableProductCategoryProps = {},
config: FindConfig<ProductTypes.ProductCategoryDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<ProductTypes.ProductCategoryDTO[]> {
const categories = await this.productCategoryService_.list(
filters,
config,
sharedContext
)
return JSON.parse(JSON.stringify(categories))
}
@InjectTransactionManager("baseRepository_")
async createCategory(
data: ProductCategoryServiceTypes.CreateProductCategoryDTO,
@@ -866,34 +533,6 @@ export default class ProductModuleService<
return JSON.parse(JSON.stringify(productCategory))
}
@InjectTransactionManager("baseRepository_")
async deleteCategory(
categoryId: string,
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productCategoryService_.delete(categoryId, sharedContext)
await this.eventBusModuleService_?.emit<ProductCategoryEventData>(
ProductCategoryEvents.CATEGORY_DELETED,
{ id: categoryId }
)
}
@InjectManager("baseRepository_")
async listAndCountCategories(
filters: ProductTypes.FilterableProductCategoryProps = {},
config: FindConfig<ProductTypes.ProductCategoryDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[ProductTypes.ProductCategoryDTO[], number]> {
const categories = await this.productCategoryService_.listAndCount(
filters,
config,
sharedContext
)
return JSON.parse(JSON.stringify(categories))
}
@InjectManager("baseRepository_")
async create(
data: ProductTypes.CreateProductDTO[],
@@ -902,9 +541,7 @@ export default class ProductModuleService<
const products = await this.create_(data, sharedContext)
const createdProducts = await this.baseRepository_.serialize<
ProductTypes.ProductDTO[]
>(products, {
populate: true,
})
>(products)
await this.eventBusModuleService_?.emit<ProductEventData>(
createdProducts.map(({ id }) => ({
@@ -925,9 +562,7 @@ export default class ProductModuleService<
const updatedProducts = await this.baseRepository_.serialize<
ProductTypes.ProductDTO[]
>(products, {
populate: true,
})
>(products)
await this.eventBusModuleService_?.emit<ProductEventData>(
updatedProducts.map(({ id }) => ({
@@ -1297,131 +932,15 @@ export default class ProductModuleService<
}
@InjectTransactionManager("baseRepository_")
async delete(
productIds: string[],
async deleteCategory(
categoryId: string,
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productService_.delete(productIds, sharedContext)
await this.productCategoryService_.delete(categoryId, sharedContext)
await this.eventBusModuleService_?.emit<ProductEventData>(
productIds.map((id) => ({
eventName: ProductEvents.PRODUCT_DELETED,
data: { id },
}))
await this.eventBusModuleService_?.emit<ProductCategoryEventData>(
ProductCategoryEvents.CATEGORY_DELETED,
{ id: categoryId }
)
}
@InjectManager("baseRepository_")
async softDelete<
TReturnableLinkableKeys extends string = Lowercase<
keyof typeof LinkableKeys
>
>(
productIds: string[],
{ returnLinkableKeys }: SoftDeleteReturn<TReturnableLinkableKeys> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<Record<Lowercase<keyof typeof LinkableKeys>, string[]> | void> {
const [products, cascadedEntitiesMap] = await this.softDelete_(
productIds,
sharedContext
)
const softDeletedProducts = await this.baseRepository_.serialize<
ProductTypes.ProductDTO[]
>(products, {
populate: true,
})
await this.eventBusModuleService_?.emit<ProductEventData>(
softDeletedProducts.map(({ id }) => ({
eventName: ProductEvents.PRODUCT_DELETED,
data: { id },
}))
)
let mappedCascadedEntitiesMap
if (returnLinkableKeys) {
// Map internal table/column names to their respective external linkable keys
// eg: product.id = product_id, variant.id = variant_id
mappedCascadedEntitiesMap = mapObjectTo<
Record<Lowercase<keyof typeof LinkableKeys>, string[]>
>(cascadedEntitiesMap, entityNameToLinkableKeysMap, {
pick: returnLinkableKeys,
})
}
return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0
}
@InjectTransactionManager("baseRepository_")
protected async softDelete_(
productIds: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<[TProduct[], Record<string, unknown[]>]> {
return await this.productService_.softDelete(productIds, sharedContext)
}
@InjectManager("baseRepository_")
async restore<
TReturnableLinkableKeys extends string = Lowercase<
keyof typeof LinkableKeys
>
>(
productIds: string[],
{ returnLinkableKeys }: RestoreReturn<TReturnableLinkableKeys> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<Record<Lowercase<keyof typeof LinkableKeys>, string[]> | void> {
const [_, cascadedEntitiesMap] = await this.restore_(
productIds,
sharedContext
)
let mappedCascadedEntitiesMap
if (returnLinkableKeys) {
// Map internal table/column names to their respective external linkable keys
// eg: product.id = product_id, variant.id = variant_id
mappedCascadedEntitiesMap = mapObjectTo<
Record<Lowercase<keyof typeof LinkableKeys>, string[]>
>(cascadedEntitiesMap, entityNameToLinkableKeysMap, {
pick: returnLinkableKeys,
})
}
return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0
}
@InjectTransactionManager("baseRepository_")
async restoreVariants<
TReturnableLinkableKeys extends string = Lowercase<
keyof typeof LinkableKeys
>
>(
variantIds: string[],
{ returnLinkableKeys }: RestoreReturn<TReturnableLinkableKeys> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<Record<Lowercase<keyof typeof LinkableKeys>, string[]> | void> {
const [_, cascadedEntitiesMap] = await this.productVariantService_.restore(
variantIds,
sharedContext
)
let mappedCascadedEntitiesMap
if (returnLinkableKeys) {
mappedCascadedEntitiesMap = mapObjectTo<
Record<Lowercase<keyof typeof LinkableKeys>, string[]>
>(cascadedEntitiesMap, entityNameToLinkableKeysMap, {
pick: returnLinkableKeys,
})
}
return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0
}
@InjectTransactionManager("baseRepository_")
async restore_(
productIds: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<[TProduct[], Record<string, unknown[]>]> {
return await this.productService_.restore(productIds, sharedContext)
}
}
@@ -1,23 +0,0 @@
import { ProductOptionValue } from "@models"
import { DAL } from "@medusajs/types"
import { ModulesSdkUtils } from "@medusajs/utils"
import { ProductOptionValueServiceTypes } from "@types"
type InjectedDependencies = {
productOptionValueRepository: DAL.RepositoryService
}
export default class ProductOptionValueService<
TEntity extends ProductOptionValue = ProductOptionValue
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductOptionValueServiceTypes.CreateProductOptionValueDTO
update: ProductOptionValueServiceTypes.UpdateProductOptionValueDTO
}
>(ProductOptionValue)<TEntity> {
constructor(container: InjectedDependencies) {
// @ts-ignore
super(...arguments)
}
}
+10 -15
View File
@@ -1,7 +1,6 @@
import { ProductOption } from "@models"
import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types"
import { InjectManager, MedusaContext, ModulesSdkUtils } from "@medusajs/utils"
import { IProductOptionRepository } from "@types"
type InjectedDependencies = {
productOptionRepository: DAL.RepositoryService
@@ -9,14 +8,10 @@ type InjectedDependencies = {
export default class ProductOptionService<
TEntity extends ProductOption = ProductOption
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductTypes.CreateProductOptionDTO
update: ProductTypes.UpdateProductOptionDTO
}
>(ProductOption)<TEntity> {
protected readonly productOptionRepository_: IProductOptionRepository<TEntity>
> extends ModulesSdkUtils.internalModuleServiceFactory<InjectedDependencies>(
ProductOption
)<TEntity> {
protected readonly productOptionRepository_: DAL.RepositoryService<TEntity>
constructor(container: InjectedDependencies) {
super(container)
@@ -24,9 +19,9 @@ export default class ProductOptionService<
}
@InjectManager("productOptionRepository_")
async list<TEntityMethod = ProductTypes.ProductOptionDTO>(
async list(
filters: ProductTypes.FilterableProductOptionProps = {},
config: FindConfig<TEntityMethod> = {},
config: FindConfig<TEntity> = {},
@MedusaContext() sharedContext?: Context
): Promise<TEntity[]> {
return await this.productOptionRepository_.find(
@@ -36,9 +31,9 @@ export default class ProductOptionService<
}
@InjectManager("productOptionRepository_")
async listAndCount<TEntityMethod = ProductTypes.ProductOptionDTO>(
async listAndCount(
filters: ProductTypes.FilterableProductOptionProps = {},
config: FindConfig<TEntityMethod> = {},
config: FindConfig<TEntity> = {},
@MedusaContext() sharedContext?: Context
): Promise<[TEntity[], number]> {
return await this.productOptionRepository_.findAndCount(
@@ -47,9 +42,9 @@ export default class ProductOptionService<
)
}
private buildQueryForList<TEntityMethod = ProductTypes.ProductOptionDTO>(
private buildQueryForList(
filters: ProductTypes.FilterableProductOptionProps = {},
config: FindConfig<TEntityMethod> = {}
config: FindConfig<TEntity> = {}
): DAL.FindOptions<TEntity> {
const queryOptions = ModulesSdkUtils.buildQuery<TEntity>(filters, config)
+10 -15
View File
@@ -1,7 +1,6 @@
import { ProductTag } from "@models"
import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types"
import { InjectManager, MedusaContext, ModulesSdkUtils } from "@medusajs/utils"
import { IProductTagRepository } from "@types"
type InjectedDependencies = {
productTagRepository: DAL.RepositoryService
@@ -9,23 +8,19 @@ type InjectedDependencies = {
export default class ProductTagService<
TEntity extends ProductTag = ProductTag
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductTypes.CreateProductTagDTO
update: ProductTypes.UpdateProductTagDTO
}
>(ProductTag)<TEntity> {
protected readonly productTagRepository_: IProductTagRepository<TEntity>
> extends ModulesSdkUtils.internalModuleServiceFactory<InjectedDependencies>(
ProductTag
)<TEntity> {
protected readonly productTagRepository_: DAL.RepositoryService<TEntity>
constructor(container: InjectedDependencies) {
super(container)
this.productTagRepository_ = container.productTagRepository
}
@InjectManager("productTagRepository_")
async list<TEntityMethod = ProductTypes.ProductTagDTO>(
async list(
filters: ProductTypes.FilterableProductTagProps = {},
config: FindConfig<TEntityMethod> = {},
config: FindConfig<TEntity> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return await this.productTagRepository_.find(
@@ -35,9 +30,9 @@ export default class ProductTagService<
}
@InjectManager("productTagRepository_")
async listAndCount<TEntityMethod = ProductTypes.ProductTagDTO>(
async listAndCount(
filters: ProductTypes.FilterableProductTagProps = {},
config: FindConfig<TEntityMethod> = {},
config: FindConfig<TEntity> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
return await this.productTagRepository_.findAndCount(
@@ -46,9 +41,9 @@ export default class ProductTagService<
)
}
private buildQueryForList<TEntityMethod = ProductTypes.ProductTagDTO>(
private buildQueryForList(
filters: ProductTypes.FilterableProductTagProps = {},
config: FindConfig<TEntityMethod> = {}
config: FindConfig<TEntity> = {}
): DAL.FindOptions<TEntity> {
const queryOptions = ModulesSdkUtils.buildQuery<TEntity>(filters, config)
+10 -15
View File
@@ -1,7 +1,6 @@
import { ProductType } from "@models"
import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types"
import { InjectManager, MedusaContext, ModulesSdkUtils } from "@medusajs/utils"
import { IProductTypeRepository } from "@types"
type InjectedDependencies = {
productTypeRepository: DAL.RepositoryService
@@ -9,14 +8,10 @@ type InjectedDependencies = {
export default class ProductTypeService<
TEntity extends ProductType = ProductType
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductTypes.CreateProductTypeDTO
update: ProductTypes.UpdateProductTypeDTO
}
>(ProductType)<TEntity> {
protected readonly productTypeRepository_: IProductTypeRepository<TEntity>
> extends ModulesSdkUtils.internalModuleServiceFactory<InjectedDependencies>(
ProductType
)<TEntity> {
protected readonly productTypeRepository_: DAL.RepositoryService<TEntity>
constructor(container: InjectedDependencies) {
super(container)
@@ -24,9 +19,9 @@ export default class ProductTypeService<
}
@InjectManager("productTypeRepository_")
async list<TEntityMethod = ProductTypes.ProductTypeDTO>(
async list(
filters: ProductTypes.FilterableProductTypeProps = {},
config: FindConfig<TEntityMethod> = {},
config: FindConfig<TEntity> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return await this.productTypeRepository_.find(
@@ -36,9 +31,9 @@ export default class ProductTypeService<
}
@InjectManager("productTypeRepository_")
async listAndCount<TEntityMethod = ProductTypes.ProductOptionDTO>(
async listAndCount(
filters: ProductTypes.FilterableProductTypeProps = {},
config: FindConfig<TEntityMethod> = {},
config: FindConfig<TEntity> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
return await this.productTypeRepository_.findAndCount(
@@ -47,9 +42,9 @@ export default class ProductTypeService<
)
}
private buildQueryForList<TEntityMethod = ProductTypes.ProductTypeDTO>(
private buildQueryForList(
filters: ProductTypes.FilterableProductTypeProps = {},
config: FindConfig<TEntityMethod> = {}
config: FindConfig<TEntity> = {}
): DAL.FindOptions<TEntity> {
const queryOptions = ModulesSdkUtils.buildQuery<TEntity>(filters, config)
@@ -7,7 +7,7 @@ import {
} from "@medusajs/utils"
import { Product, ProductVariant } from "@models"
import { IProductVariantRepository, ProductVariantServiceTypes } from "@types"
import { ProductVariantServiceTypes } from "@types"
import ProductService from "./product"
type InjectedDependencies = {
@@ -18,14 +18,10 @@ type InjectedDependencies = {
export default class ProductVariantService<
TEntity extends ProductVariant = ProductVariant,
TProduct extends Product = Product
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductTypes.CreateProductVariantOnlyDTO
update: ProductVariantServiceTypes.UpdateProductVariantDTO
}
>(ProductVariant)<TEntity> {
protected readonly productVariantRepository_: IProductVariantRepository<TEntity>
> extends ModulesSdkUtils.internalModuleServiceFactory<InjectedDependencies>(
ProductVariant
)<TEntity> {
protected readonly productVariantRepository_: DAL.RepositoryService<TEntity>
protected readonly productService_: ProductService<TProduct>
constructor({
@@ -92,8 +88,6 @@ export default class ProductVariantService<
const variantsData = [...data]
variantsData.forEach((variant) => Object.assign(variant, { product }))
return await this.productVariantRepository_.update(variantsData, {
transactionManager: sharedContext.transactionManager,
})
return await super.update(variantsData, sharedContext)
}
}
+10 -19
View File
@@ -1,7 +1,6 @@
import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types"
import { InjectManager, MedusaContext, ModulesSdkUtils } from "@medusajs/utils"
import { Product } from "@models"
import { IProductRepository, ProductServiceTypes } from "@types"
type InjectedDependencies = {
productRepository: DAL.RepositoryService
@@ -9,14 +8,10 @@ type InjectedDependencies = {
export default class ProductService<
TEntity extends Product = Product
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ProductTypes.CreateProductOnlyDTO
update: ProductServiceTypes.UpdateProductDTO
}
>(Product)<TEntity> {
protected readonly productRepository_: IProductRepository<TEntity>
> extends ModulesSdkUtils.internalModuleServiceFactory<InjectedDependencies>(
Product
)<TEntity> {
protected readonly productRepository_: DAL.RepositoryService<TEntity>
constructor({ productRepository }: InjectedDependencies) {
// @ts-ignore
@@ -27,9 +22,9 @@ export default class ProductService<
}
@InjectManager("productRepository_")
async list<TEntityMethod = ProductTypes.ProductDTO>(
async list(
filters: ProductTypes.FilterableProductProps = {},
config: FindConfig<TEntityMethod> = {},
config: FindConfig<TEntity> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
if (filters.category_id) {
@@ -45,13 +40,13 @@ export default class ProductService<
delete filters.category_id
}
return await super.list<TEntityMethod>(filters, config, sharedContext)
return await super.list(filters, config, sharedContext)
}
@InjectManager("productRepository_")
async listAndCount<TEntityMethod = ProductTypes.ProductDTO>(
async listAndCount(
filters: ProductTypes.FilterableProductProps = {},
config: FindConfig<TEntityMethod> = {},
config: FindConfig<any> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
if (filters.category_id) {
@@ -67,10 +62,6 @@ export default class ProductService<
delete filters.category_id
}
return await super.listAndCount<TEntityMethod>(
filters,
config,
sharedContext
)
return await super.listAndCount(filters, config, sharedContext)
}
}
-1
View File
@@ -6,4 +6,3 @@ export type InitializeModuleInjectableDependencies = {
}
export * from "./services"
export * from "./repositories"
-100
View File
@@ -1,100 +0,0 @@
import { DAL, ProductTypes, WithRequiredProperty } from "@medusajs/types"
import {
Image,
Product,
ProductCollection,
ProductOption,
ProductOptionValue,
ProductTag,
ProductType,
ProductVariant,
} from "@models"
import { UpdateProductDTO } from "./services/product"
import {
CreateProductCollection,
UpdateProductCollection,
} from "./services/product-collection"
import {
CreateProductOptionValueDTO,
UpdateProductOptionValueDTO,
} from "./services/product-option-value"
import { UpdateProductVariantDTO } from "./services/product-variant"
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IProductRepository<TEntity extends Product = Product>
extends DAL.RepositoryService<
TEntity,
{
create: WithRequiredProperty<ProductTypes.CreateProductOnlyDTO, "status">
update: WithRequiredProperty<UpdateProductDTO, "id">
}
> {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IProductCollectionRepository<
TEntity extends ProductCollection = ProductCollection
> extends DAL.RepositoryService<
TEntity,
{
create: CreateProductCollection
update: UpdateProductCollection
}
> {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IProductImageRepository<TEntity extends Image = Image>
extends DAL.RepositoryService<TEntity> {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IProductOptionRepository<
TEntity extends ProductOption = ProductOption
> extends DAL.RepositoryService<
TEntity,
{
create: ProductTypes.CreateProductOptionDTO
update: ProductTypes.UpdateProductOptionDTO
}
> {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IProductOptionValueRepository<
TEntity extends ProductOptionValue = ProductOptionValue
> extends DAL.RepositoryService<
TEntity,
{
create: CreateProductOptionValueDTO
update: UpdateProductOptionValueDTO
}
> {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IProductTagRepository<TEntity extends ProductTag = ProductTag>
extends DAL.RepositoryService<
TEntity,
{
create: ProductTypes.CreateProductTagDTO
update: ProductTypes.UpdateProductTagDTO
}
> {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IProductTypeRepository<
TEntity extends ProductType = ProductType
> extends DAL.RepositoryService<
TEntity,
{
create: ProductTypes.CreateProductTypeDTO
update: ProductTypes.UpdateProductTypeDTO
}
> {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IProductVariantRepository<
TEntity extends ProductVariant = ProductVariant
> extends DAL.RepositoryService<
TEntity,
{
create: ProductTypes.CreateProductVariantOnlyDTO
update: UpdateProductVariantDTO
}
> {}