diff --git a/.changeset/fresh-snakes-judge.md b/.changeset/fresh-snakes-judge.md new file mode 100644 index 0000000000..ab51fe994e --- /dev/null +++ b/.changeset/fresh-snakes-judge.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +Convert CollectionService to TypeScript diff --git a/packages/medusa/src/api/routes/admin/collections/add-products.ts b/packages/medusa/src/api/routes/admin/collections/add-products.ts index a7a859ef25..d1925f2f10 100644 --- a/packages/medusa/src/api/routes/admin/collections/add-products.ts +++ b/packages/medusa/src/api/routes/admin/collections/add-products.ts @@ -1,6 +1,6 @@ import { ArrayNotEmpty, IsString } from "class-validator" import { Request, Response } from "express" -import { EntityManager } from "typeorm"; +import { EntityManager } from "typeorm" import ProductCollectionService from "../../../../services/product-collection" @@ -39,7 +39,9 @@ import ProductCollectionService from "../../../../services/product-collection" */ export default async (req: Request, res: Response) => { const { id } = req.params - const { validatedBody } = req as { validatedBody: AdminPostProductsToCollectionReq } + const { validatedBody } = req as { + validatedBody: AdminPostProductsToCollectionReq + } const productCollectionService: ProductCollectionService = req.scope.resolve( "productCollectionService" @@ -47,10 +49,9 @@ export default async (req: Request, res: Response) => { const manager: EntityManager = req.scope.resolve("manager") const collection = await manager.transaction(async (transactionManager) => { - return await productCollectionService.withTransaction(transactionManager).addProducts( - id, - validatedBody.product_ids - ) + return await productCollectionService + .withTransaction(transactionManager) + .addProducts(id, validatedBody.product_ids) }) res.status(200).json({ collection }) diff --git a/packages/medusa/src/api/routes/admin/collections/create-collection.ts b/packages/medusa/src/api/routes/admin/collections/create-collection.ts index d70e7b3cef..415a7299d6 100644 --- a/packages/medusa/src/api/routes/admin/collections/create-collection.ts +++ b/packages/medusa/src/api/routes/admin/collections/create-collection.ts @@ -1,7 +1,7 @@ import { IsNotEmpty, IsObject, IsOptional, IsString } from "class-validator" import ProductCollectionService from "../../../../services/product-collection" import { Request, Response } from "express" -import { EntityManager } from "typeorm"; +import { EntityManager } from "typeorm" /** * @oas [post] /collections @@ -38,7 +38,7 @@ import { EntityManager } from "typeorm"; * $ref: "#/components/schemas/product_collection" */ export default async (req: Request, res: Response) => { - const { validatedBody } = req + const { validatedBody } = req as { validatedBody: AdminPostCollectionsReq } const productCollectionService: ProductCollectionService = req.scope.resolve( "productCollectionService" @@ -46,7 +46,9 @@ export default async (req: Request, res: Response) => { const manager: EntityManager = req.scope.resolve("manager") const created = await manager.transaction(async (transactionManager) => { - return await productCollectionService.withTransaction(transactionManager).create(validatedBody) + return await productCollectionService + .withTransaction(transactionManager) + .create(validatedBody) }) const collection = await productCollectionService.retrieve(created.id) @@ -65,5 +67,5 @@ export class AdminPostCollectionsReq { @IsObject() @IsOptional() - metadata?: object + metadata?: Record } diff --git a/packages/medusa/src/api/routes/admin/collections/update-collection.ts b/packages/medusa/src/api/routes/admin/collections/update-collection.ts index 84a3c020d1..d7773136e6 100644 --- a/packages/medusa/src/api/routes/admin/collections/update-collection.ts +++ b/packages/medusa/src/api/routes/admin/collections/update-collection.ts @@ -1,6 +1,5 @@ import { IsObject, IsOptional, IsString } from "class-validator" import { Request, Response } from "express" - import { EntityManager } from "typeorm"; import ProductCollectionService from "../../../../services/product-collection" @@ -40,7 +39,9 @@ import ProductCollectionService from "../../../../services/product-collection" */ export default async (req: Request, res: Response) => { const { id } = req.params - const { validatedBody } = req + const { validatedBody } = req as { + validatedBody: AdminPostCollectionsCollectionReq + } const productCollectionService: ProductCollectionService = req.scope.resolve( "productCollectionService" @@ -48,7 +49,9 @@ export default async (req: Request, res: Response) => { const manager: EntityManager = req.scope.resolve("manager") const updated = await manager.transaction(async (transactionManager) => { - return await productCollectionService.withTransaction(transactionManager).update(id, validatedBody) + return await productCollectionService + .withTransaction(transactionManager) + .update(id, validatedBody) }) const collection = await productCollectionService.retrieve(updated.id) @@ -67,5 +70,5 @@ export class AdminPostCollectionsCollectionReq { @IsObject() @IsOptional() - metadata?: object + metadata?: Record } diff --git a/packages/medusa/src/services/product-collection.js b/packages/medusa/src/services/product-collection.ts similarity index 51% rename from packages/medusa/src/services/product-collection.js rename to packages/medusa/src/services/product-collection.ts index 53422a5e2f..c95e17ef10 100644 --- a/packages/medusa/src/services/product-collection.js +++ b/packages/medusa/src/services/product-collection.ts @@ -1,65 +1,71 @@ import { MedusaError } from "medusa-core-utils" -import { BaseService } from "medusa-interfaces" -import { Brackets, ILike } from "typeorm" +import { Brackets, EntityManager, ILike } from "typeorm" +import { TransactionBaseService } from "../interfaces" +import { ProductCollection } from "../models" +import { ProductRepository } from "../repositories/product" +import { ProductCollectionRepository } from "../repositories/product-collection" +import { ExtendedFindConfig, FindConfig, QuerySelector } from "../types/common" +import { + CreateProductCollection, + UpdateProductCollection +} from "../types/product-collection" +import { buildQuery, setMetadata } from "../utils" import { formatException } from "../utils/exception-formatter" +import EventBusService from "./event-bus" + +type InjectedDependencies = { + manager: EntityManager + eventBusService: EventBusService + productRepository: typeof ProductRepository + productCollectionRepository: typeof ProductCollectionRepository +} /** * Provides layer to manipulate product collections. - * @extends BaseService */ -class ProductCollectionService extends BaseService { +class ProductCollectionService extends TransactionBaseService { + protected manager_: EntityManager + protected transactionManager_: EntityManager | undefined + + protected readonly eventBus_: EventBusService + + protected readonly productCollectionRepository_: typeof ProductCollectionRepository + protected readonly productRepository_: typeof ProductRepository + constructor({ manager, productCollectionRepository, productRepository, eventBusService, - }) { - super() - - /** @private @const {EntityManager} */ + }: InjectedDependencies) { + super({ + manager, + productCollectionRepository, + productRepository, + eventBusService, + }) this.manager_ = manager - /** @private @const {ProductCollectionRepository} */ this.productCollectionRepository_ = productCollectionRepository - - /** @private @const {ProductRepository} */ this.productRepository_ = productRepository - - /** @private @const {EventBus} */ this.eventBus_ = eventBusService } - withTransaction(transactionManager) { - if (!transactionManager) { - return this - } - - const cloned = new ProductCollectionService({ - manager: transactionManager, - productCollectionRepository: this.productCollectionRepository_, - productRepository: this.productRepository_, - eventBusService: this.eventBus_, - }) - - cloned.transactionManager_ = transactionManager - - return cloned - } - /** * Retrieves a product collection by id. - * @param {string} collectionId - the id of the collection to retrieve. - * @param {Object} config - the config of the collection to retrieve. - * @return {Promise} the collection. + * @param collectionId - the id of the collection to retrieve. + * @param config - the config of the collection to retrieve. + * @return the collection. */ - async retrieve(collectionId, config = {}) { + async retrieve( + collectionId: string, + config: FindConfig = {} + ): Promise { const collectionRepo = this.manager_.getCustomRepository( this.productCollectionRepository_ ) - const validatedId = this.validateId_(collectionId) - - const query = this.buildQuery_({ id: validatedId }, config) + const query = buildQuery({ id: collectionId }, config) const collection = await collectionRepo.findOne(query) if (!collection) { @@ -74,16 +80,19 @@ class ProductCollectionService extends BaseService { /** * Retrieves a product collection by id. - * @param {string} collectionHandle - the handle of the collection to retrieve. - * @param {object} config - query config for request - * @return {Promise} the collection. + * @param collectionHandle - the handle of the collection to retrieve. + * @param config - query config for request + * @return the collection. */ - async retrieveByHandle(collectionHandle, config = {}) { + async retrieveByHandle( + collectionHandle: string, + config: FindConfig = {} + ): Promise { const collectionRepo = this.manager_.getCustomRepository( this.productCollectionRepository_ ) - const query = this.buildQuery_({ handle: collectionHandle }, config) + const query = buildQuery({ handle: collectionHandle }, config) const collection = await collectionRepo.findOne(query) if (!collection) { @@ -98,11 +107,13 @@ class ProductCollectionService extends BaseService { /** * Creates a product collection - * @param {object} collection - the collection to create - * @return {Promise} created collection + * @param collection - the collection to create + * @return created collection */ - async create(collection) { - return this.atomicPhase_(async (manager) => { + async create( + collection: CreateProductCollection + ): Promise { + return await this.atomicPhase_(async (manager) => { const collectionRepo = manager.getCustomRepository( this.productCollectionRepository_ ) @@ -118,12 +129,15 @@ class ProductCollectionService extends BaseService { /** * Updates a product collection - * @param {string} collectionId - id of collection to update - * @param {object} update - update object - * @return {Promise} update collection + * @param collectionId - id of collection to update + * @param update - update object + * @return update collection */ - async update(collectionId, update) { - return this.atomicPhase_(async (manager) => { + async update( + collectionId: string, + update: UpdateProductCollection + ): Promise { + return await this.atomicPhase_(async (manager) => { const collectionRepo = manager.getCustomRepository( this.productCollectionRepository_ ) @@ -133,7 +147,7 @@ class ProductCollectionService extends BaseService { const { metadata, ...rest } = update if (metadata) { - collection.metadata = this.setMetadata_(collection, metadata) + collection.metadata = setMetadata(collection, metadata) } for (const [key, value] of Object.entries(rest)) { @@ -146,11 +160,11 @@ class ProductCollectionService extends BaseService { /** * Deletes a product collection idempotently - * @param {string} collectionId - id of collection to delete - * @return {Promise} empty promise + * @param collectionId - id of collection to delete + * @return empty promise */ - async delete(collectionId) { - return this.atomicPhase_(async (manager) => { + async delete(collectionId: string): Promise { + return await this.atomicPhase_(async (manager) => { const productCollectionRepo = manager.getCustomRepository( this.productCollectionRepository_ ) @@ -167,8 +181,11 @@ class ProductCollectionService extends BaseService { }) } - async addProducts(collectionId, productIds) { - return this.atomicPhase_(async (manager) => { + async addProducts( + collectionId: string, + productIds: string[] + ): Promise { + return await this.atomicPhase_(async (manager) => { const productRepo = manager.getCustomRepository(this.productRepository_) try { @@ -185,8 +202,11 @@ class ProductCollectionService extends BaseService { }) } - async removeProducts(collectionId, productIds) { - return this.atomicPhase_(async (manager) => { + async removeProducts( + collectionId: string, + productIds: string[] + ): Promise { + return await this.atomicPhase_(async (manager) => { const productRepo = manager.getCustomRepository(this.productRepository_) const { id } = await this.retrieve(collectionId, { select: ["id"] }) @@ -199,26 +219,32 @@ class ProductCollectionService extends BaseService { /** * Lists product collections - * @param {Object} selector - the query object for find - * @param {Object} config - the config to be used for find - * @return {Promise} the result of the find operation + * @param selector - the query object for find + * @param config - the config to be used for find + * @return the result of the find operation */ - async list(selector = {}, config = { skip: 0, take: 20 }) { + async list( + selector = {}, + config = { skip: 0, take: 20 } + ): Promise { const productCollectionRepo = this.manager_.getCustomRepository( this.productCollectionRepository_ ) - const query = this.buildQuery_(selector, config) + const query = buildQuery(selector, config) return await productCollectionRepo.find(query) } /** * Lists product collections and add count. - * @param {Object} selector - the query object for find - * @param {Object} config - the config to be used for find - * @return {Promise} the result of the find operation + * @param selector - the query object for find + * @param config - the config to be used for find + * @return the result of the find operation */ - async listAndCount(selector = {}, config = { skip: 0, take: 20 }) { + async listAndCount( + selector: QuerySelector = {}, + config: FindConfig = { skip: 0, take: 20 } + ): Promise<[ProductCollection[], number]> { const productCollectionRepo = this.manager_.getCustomRepository( this.productCollectionRepository_ ) @@ -229,7 +255,12 @@ class ProductCollectionService extends BaseService { delete selector.q } - const query = this.buildQuery_(selector, config) + const query = buildQuery( + selector, + config + ) as ExtendedFindConfig & { + where: (qb: any) => void + } if (q) { const where = query.where @@ -239,7 +270,7 @@ class ProductCollectionService extends BaseService { delete where.created_at delete where.updated_at - query.where = (qb) => { + query.where = (qb): void => { qb.where(where) qb.andWhere( diff --git a/packages/medusa/src/types/product-collection.ts b/packages/medusa/src/types/product-collection.ts new file mode 100644 index 0000000000..17dca44e03 --- /dev/null +++ b/packages/medusa/src/types/product-collection.ts @@ -0,0 +1,11 @@ +export type CreateProductCollection = { + title: string + handle?: string + metadata?: Record +} + +export type UpdateProductCollection = { + title?: string + handle?: string + metadata?: Record +}