feat(medusa): Simplify the transaction base service (#2007)

**What**
Simplify the transaction base service.

**How**

In fact, it does not need to be template and reduce the extensibility as the type is internally enforce. Now, the type is deduced by this which can be any derived class.
This commit is contained in:
Adrien de Peretti
2022-08-12 11:17:39 +02:00
committed by GitHub
parent cbe2b7f687
commit 79acc38a57
46 changed files with 82 additions and 115 deletions

View File

@@ -31,7 +31,7 @@ import { IsString } from "class-validator"
* description: The Download URL of the file
*/
export default async (req, res) => {
const fileService: AbstractFileService<any> = req.scope.resolve("fileService")
const fileService: AbstractFileService = req.scope.resolve("fileService")
const url = await fileService.getPresignedDownloadUrl({
fileKey: (req.validatedBody as AdminPostUploadsDownloadUrlReq).file_key,

View File

@@ -4,7 +4,7 @@ import { TransactionBaseService } from "../transaction-base-service"
describe("TransactionBaseService", () => {
it("should cloned the child class withTransaction", () => {
class Child extends TransactionBaseService<Child> {
class Child extends TransactionBaseService {
protected manager_!: EntityManager
protected transactionManager_!: EntityManager

View File

@@ -4,8 +4,7 @@ import { ProductExportBatchJob } from "../strategies/batch-jobs/product"
import { BatchJobService } from "../services"
import { BatchJob } from "../models"
export interface IBatchJobStrategy<T extends TransactionBaseService<never>>
extends TransactionBaseService<T> {
export interface IBatchJobStrategy extends TransactionBaseService {
/**
* Method for preparing a batch job for processing
*/
@@ -30,12 +29,9 @@ export interface IBatchJobStrategy<T extends TransactionBaseService<never>>
buildTemplate(): Promise<string>
}
export abstract class AbstractBatchJobStrategy<
T extends TransactionBaseService<never, TContainer>,
TContainer = unknown
>
extends TransactionBaseService<T, TContainer>
implements IBatchJobStrategy<T>
export abstract class AbstractBatchJobStrategy
extends TransactionBaseService
implements IBatchJobStrategy
{
static identifier: string
static batchType: string
@@ -113,6 +109,6 @@ export abstract class AbstractBatchJobStrategy<
export function isBatchJobStrategy(
object: unknown
): object is IBatchJobStrategy<never> {
): object is IBatchJobStrategy {
return object instanceof AbstractBatchJobStrategy
}

View File

@@ -30,8 +30,7 @@ export type UploadStreamDescriptorType = {
[x: string]: unknown
}
export interface IFileService<T extends TransactionBaseService<any>>
extends TransactionBaseService<T> {
export interface IFileService extends TransactionBaseService {
/**
* upload file to fileservice
* @param file Multer file from express multipart/form-data
@@ -69,9 +68,9 @@ export interface IFileService<T extends TransactionBaseService<any>>
* */
getPresignedDownloadUrl(fileData: GetUploadedFileType): Promise<string>
}
export abstract class AbstractFileService<T extends TransactionBaseService<any>>
extends TransactionBaseService<T>
implements IFileService<T>
export abstract class AbstractFileService
extends TransactionBaseService
implements IFileService
{
abstract upload(
fileData: Express.Multer.File

View File

@@ -7,8 +7,7 @@ type ReturnedData = {
data: Record<string, unknown>
}
export interface INotificationService<T extends TransactionBaseService<never>>
extends TransactionBaseService<T> {
export interface INotificationService extends TransactionBaseService {
sendNotification(
event: string,
data: unknown,
@@ -22,11 +21,9 @@ export interface INotificationService<T extends TransactionBaseService<never>>
): Promise<ReturnedData>
}
export abstract class AbstractNotificationService<
T extends TransactionBaseService<never>
>
extends TransactionBaseService<T>
implements INotificationService<T>
export abstract class AbstractNotificationService
extends TransactionBaseService
implements INotificationService
{
static identifier: string

View File

@@ -12,8 +12,8 @@ export type Data = Record<string, unknown>
export type PaymentData = Data
export type PaymentSessionData = Data
export interface PaymentService<T extends TransactionBaseService<never>>
extends TransactionBaseService<T> {
export interface PaymentService<T extends TransactionBaseService>
extends TransactionBaseService {
getIdentifier(): string
getPaymentData(paymentSession: PaymentSession): Promise<PaymentData>
@@ -50,10 +50,8 @@ export interface PaymentService<T extends TransactionBaseService<never>>
getStatus(data: Data): Promise<PaymentSessionStatus>
}
export abstract class AbstractPaymentService<
T extends TransactionBaseService<never>
>
extends TransactionBaseService<T>
export abstract class AbstractPaymentService<T extends TransactionBaseService>
extends TransactionBaseService
implements PaymentService<T>
{
protected constructor(container: unknown, config?: Record<string, unknown>) {

View File

@@ -1,7 +1,7 @@
import { TransactionBaseService } from "./transaction-base-service"
import { SearchService } from "medusa-interfaces"
export interface ISearchService<T extends TransactionBaseService<never>> {
export interface ISearchService {
options: Record<string, unknown>
/**
@@ -72,11 +72,9 @@ export interface ISearchService<T extends TransactionBaseService<never>> {
updateSettings(indexName: string, settings: unknown): unknown
}
export abstract class AbstractSearchService<
T extends TransactionBaseService<never>
>
extends TransactionBaseService<T>
implements ISearchService<T>
export abstract class AbstractSearchService
extends TransactionBaseService
implements ISearchService
{
abstract readonly isDefault
protected readonly options_: Record<string, unknown>

View File

@@ -1,34 +1,31 @@
import { EntityManager } from "typeorm"
import { IsolationLevel } from "typeorm/driver/types/IsolationLevel"
export abstract class TransactionBaseService<
TChild extends TransactionBaseService<TChild, TContainer>,
TContainer = unknown
> {
export abstract class TransactionBaseService {
protected abstract manager_: EntityManager
protected abstract transactionManager_: EntityManager | undefined
protected constructor(
protected readonly container: TContainer,
protected readonly configModule?: Record<string, unknown>
protected readonly __container__: any,
protected readonly __configModule__?: Record<string, unknown>
) {}
withTransaction(transactionManager?: EntityManager): this | TChild {
withTransaction(transactionManager?: EntityManager): this {
if (!transactionManager) {
return this
}
const cloned = new (<any>this.constructor)(
{
...this.container,
...this.__container__,
manager: transactionManager,
},
this.configModule
this.__configModule__
)
cloned.transactionManager_ = transactionManager
return cloned as TChild
return cloned
}
protected shouldRetryTransaction_(

View File

@@ -22,7 +22,7 @@ export default async ({
container: MedusaContainer
}): Promise<void> => {
const searchService =
container.resolve<AbstractSearchService<never>>("searchService")
container.resolve<AbstractSearchService>("searchService")
const logger = container.resolve<Logger>("logger")
if (searchService.isDefault) {
logger.warn(

View File

@@ -16,7 +16,7 @@ type InjectedDependencies = {
* Can authenticate a user based on email password combination
* @extends BaseService
*/
class AuthService extends TransactionBaseService<AuthService> {
class AuthService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined
protected readonly userService_: UserService

View File

@@ -23,7 +23,7 @@ type InjectedDependencies = {
strategyResolverService: StrategyResolverService
}
class BatchJobService extends TransactionBaseService<BatchJobService> {
class BatchJobService extends TransactionBaseService {
static readonly Events = {
CREATED: "batch.created",
UPDATED: "batch.updated",

View File

@@ -83,7 +83,7 @@ type TotalsConfig = {
/* Provides layer to manipulate carts.
* @implements BaseService
*/
class CartService extends TransactionBaseService<CartService> {
class CartService extends TransactionBaseService {
static readonly Events = {
CUSTOMER_UPDATED: "cart.customer_updated",
CREATED: "cart.created",

View File

@@ -11,7 +11,7 @@ import { buildQuery, setMetadata } from "../utils"
import EventBusService from "./event-bus"
import LineItemService from "./line-item"
class ClaimItemService extends BaseService<ClaimItemService> {
class ClaimItemService extends BaseService {
static Events = {
CREATED: "claim_item.created",
UPDATED: "claim_item.updated",

View File

@@ -49,10 +49,7 @@ type InjectedDependencies = {
totalsService: TotalsService
}
export default class ClaimService extends TransactionBaseService<
ClaimService,
InjectedDependencies
> {
export default class ClaimService extends TransactionBaseService {
static readonly Events = {
CREATED: "claim.created",
UPDATED: "claim.updated",

View File

@@ -11,7 +11,7 @@ type InjectedDependencies = {
manager: EntityManager
customShippingOptionRepository: typeof CustomShippingOptionRepository
}
class CustomShippingOptionService extends TransactionBaseService<CustomShippingOptionService> {
class CustomShippingOptionService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined
protected customShippingOptionRepository_: typeof CustomShippingOptionRepository

View File

@@ -22,7 +22,7 @@ type InjectedDependencies = {
/**
* Provides layer to manipulate customers.
*/
class CustomerService extends TransactionBaseService<CustomerService> {
class CustomerService extends TransactionBaseService {
protected readonly customerRepository_: typeof CustomerRepository
protected readonly addressRepository_: typeof AddressRepository
protected readonly eventBusService_: EventBusService

View File

@@ -27,7 +27,7 @@ type InjectedDependencies = {
* Provides layer to manipulate discount conditions.
* @implements {BaseService}
*/
class DiscountConditionService extends TransactionBaseService<DiscountConditionService> {
class DiscountConditionService extends TransactionBaseService {
protected readonly discountConditionRepository_: typeof DiscountConditionRepository
protected readonly eventBus_: EventBusService

View File

@@ -44,7 +44,7 @@ import { buildQuery, setMetadata } from "../utils"
* Provides layer to manipulate discounts.
* @implements {BaseService}
*/
class DiscountService extends TransactionBaseService<DiscountService> {
class DiscountService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined

View File

@@ -30,7 +30,7 @@ type InjectedDependencies = {
* Handles draft orders
* @implements {BaseService}
*/
class DraftOrderService extends TransactionBaseService<DraftOrderService> {
class DraftOrderService extends TransactionBaseService {
static readonly Events = {
CREATED: "draft_order.created",
UPDATED: "draft_order.updated",

View File

@@ -8,7 +8,7 @@ import {
UploadStreamDescriptorType,
} from "../interfaces"
class DefaultFileService extends AbstractFileService<any> {
class DefaultFileService extends AbstractFileService {
upload(fileData: Express.Multer.File): Promise<FileServiceUploadResult> {
throw new MedusaError(
MedusaError.Types.UNEXPECTED_STATE,

View File

@@ -32,7 +32,7 @@ type InjectedDependencies = {
/**
* Handles Fulfillments
*/
class FulfillmentService extends TransactionBaseService<FulfillmentService> {
class FulfillmentService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined

View File

@@ -30,7 +30,7 @@ type InjectedDependencies = {
/**
* Provides layer to manipulate gift cards.
*/
class GiftCardService extends TransactionBaseService<GiftCardService> {
class GiftCardService extends TransactionBaseService {
protected readonly giftCardRepository_: typeof GiftCardRepository
protected readonly giftCardTransactionRepo_: typeof GiftCardTransactionRepository
protected readonly regionService_: RegionService

View File

@@ -13,7 +13,7 @@ type InjectedDependencies = {
idempotencyKeyRepository: typeof IdempotencyKeyRepository
}
class IdempotencyKeyService extends TransactionBaseService<IdempotencyKeyService> {
class IdempotencyKeyService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined

View File

@@ -9,7 +9,7 @@ type InventoryServiceProps = {
manager: EntityManager
productVariantService: ProductVariantService
}
class InventoryService extends TransactionBaseService<InventoryService> {
class InventoryService extends TransactionBaseService {
protected readonly productVariantService_: ProductVariantService
protected manager_: EntityManager

View File

@@ -14,7 +14,7 @@ type InjectedDependencies = {
eventBusService: EventBusService
}
class NoteService extends TransactionBaseService<NoteService> {
class NoteService extends TransactionBaseService {
static readonly Events = {
CREATED: "note.created",
UPDATED: "note.updated",

View File

@@ -19,14 +19,14 @@ type InjectedDependencies = {
}
type NotificationProviderKey = `noti_${string}`
class NotificationService extends TransactionBaseService<NotificationService> {
class NotificationService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined
protected subscribers_ = {}
protected attachmentGenerator_: unknown = null
protected readonly container_: InjectedDependencies & {
[key in `${NotificationProviderKey}`]: AbstractNotificationService<never>
[key in `${NotificationProviderKey}`]: AbstractNotificationService
}
protected readonly logger_: Logger
protected readonly notificationRepository_: typeof NotificationRepository
@@ -151,7 +151,7 @@ class NotificationService extends TransactionBaseService<NotificationService> {
* @param id - the id of the provider
* @return the notification provider
*/
protected retrieveProvider_(id: string): AbstractNotificationService<never> {
protected retrieveProvider_(id: string): AbstractNotificationService {
try {
return this.container_[`noti_${id}`]
} catch (err) {

View File

@@ -15,7 +15,7 @@ type InjectedDependencies = MedusaContainer & {
oauthRepository: typeof OauthRepository
}
class Oauth extends TransactionBaseService<Oauth> {
class Oauth extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined
static Events = {

View File

@@ -64,7 +64,7 @@ type InjectedDependencies = {
eventBusService: EventBusService
}
class OrderService extends TransactionBaseService<OrderService> {
class OrderService extends TransactionBaseService {
static readonly Events = {
GIFT_CARD_CREATED: "order.gift_card_created",
PAYMENT_CAPTURED: "order.payment_captured",

View File

@@ -33,7 +33,7 @@ type InjectedDependencies = {
/**
* Helps retrieve payment providers
*/
export default class PaymentProviderService extends TransactionBaseService<PaymentProviderService> {
export default class PaymentProviderService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined
protected readonly container_: InjectedDependencies

View File

@@ -40,7 +40,7 @@ type PriceListConstructorProps = {
* Provides layer to manipulate product tags.
* @extends BaseService
*/
class PriceListService extends TransactionBaseService<PriceListService> {
class PriceListService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined

View File

@@ -29,7 +29,7 @@ type InjectedDependencies = {
* Allows retrieval of prices.
* @extends BaseService
*/
class PricingService extends TransactionBaseService<PricingService> {
class PricingService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined
protected readonly regionService: RegionService

View File

@@ -7,7 +7,7 @@ import { ProductCollectionRepository } from "../repositories/product-collection"
import { ExtendedFindConfig, FindConfig, QuerySelector } from "../types/common"
import {
CreateProductCollection,
UpdateProductCollection
UpdateProductCollection,
} from "../types/product-collection"
import { buildQuery, setMetadata } from "../utils"
import { formatException } from "../utils/exception-formatter"
@@ -23,7 +23,7 @@ type InjectedDependencies = {
/**
* Provides layer to manipulate product collections.
*/
class ProductCollectionService extends TransactionBaseService<ProductCollectionService> {
class ProductCollectionService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined

View File

@@ -47,10 +47,7 @@ type InjectedDependencies = {
featureFlagRouter: FlagRouter
}
class ProductService extends TransactionBaseService<
ProductService,
InjectedDependencies
> {
class ProductService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined

View File

@@ -12,7 +12,7 @@ type InjectedDependencies = {
returnReasonRepository: typeof ReturnReasonRepository
}
class ReturnReasonService extends TransactionBaseService<ReturnReasonService> {
class ReturnReasonService extends TransactionBaseService {
protected readonly retReasonRepo_: typeof ReturnReasonRepository
protected manager_: EntityManager

View File

@@ -20,7 +20,7 @@ type InjectedDependencies = {
storeService: StoreService
}
class SalesChannelService extends TransactionBaseService<SalesChannelService> {
class SalesChannelService extends TransactionBaseService {
static Events = {
UPDATED: "sales_channel.updated",
CREATED: "sales_channel.created",

View File

@@ -7,7 +7,7 @@ type InjectedDependencies = {
manager: EntityManager
}
export default class DefaultSearchService extends AbstractSearchService<DefaultSearchService> {
export default class DefaultSearchService extends AbstractSearchService {
isDefault = true
protected manager_: EntityManager

View File

@@ -26,7 +26,7 @@ import RegionService from "./region"
/**
* Provides layer to manipulate profiles.
*/
class ShippingOptionService extends TransactionBaseService<ShippingOptionService> {
class ShippingOptionService extends TransactionBaseService {
protected readonly providerService_: FulfillmentProviderService
protected readonly regionService_: RegionService
protected readonly requirementRepository_: typeof ShippingOptionRequirementRepository

View File

@@ -32,7 +32,7 @@ type InjectedDependencies = {
* @constructor
* @implements {BaseService}
*/
class ShippingProfileService extends TransactionBaseService<ShippingProfileService> {
class ShippingProfileService extends TransactionBaseService {
protected readonly productService_: ProductService
protected readonly shippingOptionService_: ShippingOptionService
protected readonly customShippingOptionService_: CustomShippingOptionService

View File

@@ -21,7 +21,7 @@ type InjectedDependencies = {
* Provides layer to manipulate store settings.
* @extends BaseService
*/
class StoreService extends TransactionBaseService<StoreService> {
class StoreService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager

View File

@@ -7,26 +7,19 @@ type InjectedDependencies = {
[key: string]: unknown
}
export default class StrategyResolver extends TransactionBaseService<
StrategyResolver,
InjectedDependencies
> {
export default class StrategyResolver extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined
constructor(container: InjectedDependencies) {
constructor(protected readonly container: InjectedDependencies) {
super(container)
this.manager_ = container.manager
}
resolveBatchJobByType<T extends TransactionBaseService<never>>(
type: string
): AbstractBatchJobStrategy<T> {
let resolved: AbstractBatchJobStrategy<T>
resolveBatchJobByType(type: string): AbstractBatchJobStrategy {
let resolved: AbstractBatchJobStrategy
try {
resolved = this.container[
`batchType_${type}`
] as AbstractBatchJobStrategy<T>
resolved = this.container[`batchType_${type}`] as AbstractBatchJobStrategy
} catch (e) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,

View File

@@ -38,7 +38,7 @@ type RegionDetails = {
/**
* Finds tax providers and assists in tax related operations.
*/
class TaxProviderService extends TransactionBaseService<TaxProviderService> {
class TaxProviderService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager

View File

@@ -90,7 +90,7 @@ type CalculationContextOptions = {
* A service that calculates total and subtotals for orders, carts etc..
* @implements {BaseService}
*/
class TotalsService extends TransactionBaseService<TotalsService> {
class TotalsService extends TransactionBaseService {
protected manager_: EntityManager
protected transactionManager_: EntityManager

View File

@@ -24,7 +24,7 @@ type UserServiceProps = {
* Provides layer to manipulate users.
* @extends BaseService
*/
class UserService extends TransactionBaseService<UserService> {
class UserService extends TransactionBaseService {
static Events = {
PASSWORD_RESET: "user.password_reset",
CREATED: "user.created",
@@ -51,9 +51,7 @@ class UserService extends TransactionBaseService<UserService> {
* @return {string} the validated email
*/
validateEmail_(email: string): string {
const schema = Validator.string()
.email()
.required()
const schema = Validator.string().email().required()
const { value, error } = schema.validate(email)
if (error) {
throw new MedusaError(

View File

@@ -18,14 +18,14 @@ import SalesChannelFeatureFlag from "../../../loaders/feature-flags/sales-channe
import { FindConfig } from "../../../types/common"
type InjectedDependencies = {
fileService: IFileService<never>
fileService: IFileService
orderService: OrderService
batchJobService: BatchJobService
manager: EntityManager
featureFlagRouter: FlagRouter
}
class OrderExportStrategy extends AbstractBatchJobStrategy<OrderExportStrategy> {
class OrderExportStrategy extends AbstractBatchJobStrategy {
public static identifier = "order-export-strategy"
public static batchType = "order-export"
@@ -37,7 +37,7 @@ class OrderExportStrategy extends AbstractBatchJobStrategy<OrderExportStrategy>
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined
protected readonly fileService_: IFileService<any>
protected readonly fileService_: IFileService
protected readonly batchJobService_: BatchJobService
protected readonly orderService_: OrderService
protected readonly featureFlagRouter_: FlagRouter
@@ -258,7 +258,7 @@ class OrderExportStrategy extends AbstractBatchJobStrategy<OrderExportStrategy>
await this.fileService_
.withTransaction(transactionManager)
.delete({ key: fileKey })
.delete({ fileKey: fileKey })
return
}

View File

@@ -20,14 +20,11 @@ type InjectedDependencies = {
manager: EntityManager
batchJobService: BatchJobService
productService: ProductService
fileService: IFileService<never>
fileService: IFileService
featureFlagRouter: FlagRouter
}
export default class ProductExportStrategy extends AbstractBatchJobStrategy<
ProductExportStrategy,
InjectedDependencies
> {
export default class ProductExportStrategy extends AbstractBatchJobStrategy {
public static identifier = "product-export-strategy"
public static batchType = "product-export"
@@ -36,7 +33,7 @@ export default class ProductExportStrategy extends AbstractBatchJobStrategy<
protected readonly batchJobService_: BatchJobService
protected readonly productService_: ProductService
protected readonly fileService_: IFileService<never>
protected readonly fileService_: IFileService
protected readonly featureFlagRouter_: FlagRouter
protected readonly defaultRelations_ = [

View File

@@ -7,13 +7,13 @@ import { ISearchService } from "../interfaces"
type InjectedDependencies = {
eventBusService: EventBusService
searchService: ISearchService<never>
searchService: ISearchService
productService: ProductService
}
class SearchIndexingSubscriber {
private readonly eventBusService_: EventBusService
private readonly searchService_: ISearchService<never>
private readonly searchService_: ISearchService
private readonly productService_: ProductService
constructor({