chore(): Reorganize modules (#7210)

**What**
Move all modules to the modules directory
This commit is contained in:
Adrien de Peretti
2024-05-02 17:33:34 +02:00
committed by GitHub
parent 7a351eef09
commit 4eae25e1ef
870 changed files with 91 additions and 62 deletions

View File

@@ -0,0 +1,17 @@
import { asValue } from "awilix"
export const nonExistingProductId = "non-existing-id"
export const productRepositoryMock = {
productRepository: asValue({
find: jest.fn().mockImplementation(async ({ where: { id } }) => {
if (id === nonExistingProductId) {
return []
}
return [{}]
}),
findAndCount: jest.fn().mockResolvedValue([[], 0]),
getFreshManager: jest.fn().mockResolvedValue({}),
}),
}

View File

@@ -0,0 +1,227 @@
import {
nonExistingProductId,
productRepositoryMock,
} from "../__fixtures__/product"
import { createMedusaContainer } from "@medusajs/utils"
import { asValue } from "awilix"
import ContainerLoader from "../../loaders/container"
describe("Product service", 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 = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const productId = "existing-product"
await productService.retrieve(productId)
expect(productRepository.find).toHaveBeenCalledWith(
{
where: {
id: productId,
},
options: {
fields: undefined,
limit: undefined,
offset: 0,
populate: [],
withDeleted: undefined,
},
},
expect.any(Object)
)
})
it("should fail to retrieve a product", async function () {
const productService = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const err = await productService
.retrieve(nonExistingProductId)
.catch((e) => e)
expect(productRepository.find).toHaveBeenCalledWith(
{
where: {
id: nonExistingProductId,
},
options: {
fields: undefined,
limit: undefined,
offset: 0,
populate: [],
withDeleted: undefined,
},
},
expect.any(Object)
)
expect(err.message).toBe(
`Product with id: ${nonExistingProductId} was not found`
)
})
it("should list products", async function () {
const productService = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const filters = {}
const config = {
relations: [],
}
await productService.list(filters, config)
expect(productRepository.find).toHaveBeenCalledWith(
{
where: {},
options: {
fields: undefined,
limit: 15,
offset: 0,
orderBy: {
id: "ASC",
},
populate: [],
withDeleted: undefined,
},
},
expect.any(Object)
)
})
it("should list products with filters", async function () {
const productService = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const filters = {
tags: {
value: {
$in: ["test"],
},
},
}
const config = {
relations: [],
}
await productService.list(filters, config)
expect(productRepository.find).toHaveBeenCalledWith(
{
where: {
tags: {
value: {
$in: ["test"],
},
},
},
options: {
fields: undefined,
limit: 15,
offset: 0,
orderBy: {
id: "ASC",
},
populate: [],
withDeleted: undefined,
},
},
expect.any(Object)
)
})
it("should list products with filters and relations", async function () {
const productService = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const filters = {
tags: {
value: {
$in: ["test"],
},
},
}
const config = {
relations: ["tags"],
}
await productService.list(filters, config)
expect(productRepository.find).toHaveBeenCalledWith(
{
where: {
tags: {
value: {
$in: ["test"],
},
},
},
options: {
fields: undefined,
limit: 15,
offset: 0,
orderBy: {
id: "ASC",
},
withDeleted: undefined,
populate: ["tags"],
},
},
expect.any(Object)
)
})
it("should list and count the products with filters and relations", async function () {
const productService = container.resolve("productService")
const productRepository = container.resolve("productRepository")
const filters = {
tags: {
value: {
$in: ["test"],
},
},
}
const config = {
relations: ["tags"],
}
await productService.listAndCount(filters, config)
expect(productRepository.findAndCount).toHaveBeenCalledWith(
{
where: {
tags: {
value: {
$in: ["test"],
},
},
},
options: {
fields: undefined,
limit: 15,
offset: 0,
orderBy: {
id: "ASC",
},
withDeleted: undefined,
populate: ["tags"],
},
},
expect.any(Object)
)
})
})

View File

@@ -0,0 +1,3 @@
export { default as ProductService } from "./product"
export { default as ProductCategoryService } from "./product-category"
export { default as ProductModuleService } from "./product-module-service"

View File

@@ -0,0 +1,169 @@
import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types"
import {
FreeTextSearchFilterKey,
InjectManager,
InjectTransactionManager,
MedusaContext,
MedusaError,
ModulesSdkUtils,
isDefined,
} from "@medusajs/utils"
import { ProductCategory } from "@models"
import { ProductCategoryRepository } from "@repositories"
type InjectedDependencies = {
productCategoryRepository: DAL.TreeRepositoryService
}
export default class ProductCategoryService<
TEntity extends ProductCategory = ProductCategory
> {
protected readonly productCategoryRepository_: DAL.TreeRepositoryService
constructor({ productCategoryRepository }: InjectedDependencies) {
this.productCategoryRepository_ = productCategoryRepository
}
@InjectManager("productCategoryRepository_")
async retrieve(
productCategoryId: string,
config: FindConfig<ProductTypes.ProductCategoryDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity> {
if (!isDefined(productCategoryId)) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`"productCategoryId" must be defined`
)
}
const queryOptions = ModulesSdkUtils.buildQuery<ProductCategory>(
{
id: productCategoryId,
},
config
)
const transformOptions = {
includeDescendantsTree: true,
}
const productCategories = await this.productCategoryRepository_.find(
queryOptions,
transformOptions,
sharedContext
)
if (!productCategories?.length) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`ProductCategory with id: ${productCategoryId} was not found`
)
}
return productCategories[0] as TEntity
}
@InjectManager("productCategoryRepository_")
async list(
filters: ProductTypes.FilterableProductCategoryProps = {},
config: FindConfig<ProductTypes.ProductCategoryDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
const transformOptions = {
includeDescendantsTree: filters?.include_descendants_tree || false,
includeAncestorsTree: filters?.include_ancestors_tree || false,
}
delete filters.include_descendants_tree
delete filters.include_ancestors_tree
// Apply free text search filter
if (filters?.q) {
config.filters ??= {}
config.filters[FreeTextSearchFilterKey] = {
value: filters.q,
fromEntity: ProductCategory.name,
}
delete filters.q
}
const queryOptions = ModulesSdkUtils.buildQuery<ProductCategory>(
filters,
config
)
queryOptions.where ??= {}
return (await this.productCategoryRepository_.find(
queryOptions,
transformOptions,
sharedContext
)) as TEntity[]
}
@InjectManager("productCategoryRepository_")
async listAndCount(
filters: ProductTypes.FilterableProductCategoryProps = {},
config: FindConfig<ProductTypes.ProductCategoryDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
const transformOptions = {
includeDescendantsTree: filters?.include_descendants_tree || false,
includeAncestorsTree: filters?.include_ancestors_tree || false,
}
delete filters.include_descendants_tree
delete filters.include_ancestors_tree
// Apply free text search filter
if (filters?.q) {
config.filters ??= {}
config.filters[FreeTextSearchFilterKey] = {
value: filters.q,
fromEntity: ProductCategory.name,
}
delete filters.q
}
const queryOptions = ModulesSdkUtils.buildQuery<ProductCategory>(
filters,
config
)
queryOptions.where ??= {}
return (await this.productCategoryRepository_.findAndCount(
queryOptions,
transformOptions,
sharedContext
)) as [TEntity[], number]
}
@InjectTransactionManager("productCategoryRepository_")
async create(
data: ProductTypes.CreateProductCategoryDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity> {
return (await (
this.productCategoryRepository_ as unknown as ProductCategoryRepository
).create(data, sharedContext)) as TEntity
}
@InjectTransactionManager("productCategoryRepository_")
async update(
id: string,
data: ProductTypes.UpdateProductCategoryDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity> {
return (await (
this.productCategoryRepository_ as unknown as ProductCategoryRepository
).update(id, data, sharedContext)) as TEntity
}
@InjectTransactionManager("productCategoryRepository_")
async delete(
id: string,
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productCategoryRepository_.delete(id, sharedContext)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
import {
Context,
DAL,
FindConfig,
ProductTypes,
BaseFilterable,
FilterableProductProps,
} from "@medusajs/types"
import { InjectManager, MedusaContext, ModulesSdkUtils } from "@medusajs/utils"
import { Product } from "@models"
type InjectedDependencies = {
productRepository: DAL.RepositoryService
}
type NormalizedFilterableProductProps = ProductTypes.FilterableProductProps & {
categories?: {
id: string | { $in: string[] }
}
}
export default class ProductService<
TEntity extends Product = Product
> extends ModulesSdkUtils.internalModuleServiceFactory<InjectedDependencies>(
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 list(
filters: ProductTypes.FilterableProductProps = {},
config: FindConfig<TEntity> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return await super.list(
ProductService.normalizeFilters(filters),
config,
sharedContext
)
}
@InjectManager("productRepository_")
async listAndCount(
filters: ProductTypes.FilterableProductProps = {},
config: FindConfig<any> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
return await super.listAndCount(
ProductService.normalizeFilters(filters),
config,
sharedContext
)
}
protected static normalizeFilters(
filters: FilterableProductProps = {}
): NormalizedFilterableProductProps {
const normalized = filters as NormalizedFilterableProductProps
if (normalized.category_id) {
if (Array.isArray(normalized.category_id)) {
normalized.categories = {
id: { $in: normalized.category_id },
}
} else {
normalized.categories = {
id: normalized.category_id as string,
}
}
delete normalized.category_id
}
return normalized
}
}