Feat(modules-sdk,inventory,stock-location): modules isolated connection (#3329)

* feat: scoped container for modules
This commit is contained in:
Carlos R. L. Rodrigues
2023-03-15 12:09:45 -03:00
committed by GitHub
parent 8e78c533c4
commit 77d46220c2
65 changed files with 1116 additions and 1011 deletions
@@ -6,18 +6,13 @@ import {
IEventBusService,
setMetadata,
StockLocationAddressInput,
TransactionBaseService,
UpdateStockLocationInput,
} from "@medusajs/medusa"
import {
ConfigurableModuleDeclaration,
MODULE_RESOURCE_TYPE,
} from "@medusajs/modules-sdk"
import { InternalModuleDeclaration } from "@medusajs/modules-sdk"
import { SharedContext } from "@medusajs/types"
import { InjectEntityManager, MedusaContext } from "@medusajs/utils"
import { isDefined, MedusaError } from "medusa-core-utils"
import { EntityManager } from "typeorm"
import { StockLocation, StockLocationAddress } from "../models"
type InjectedDependencies = {
@@ -29,30 +24,22 @@ type InjectedDependencies = {
* Service for managing stock locations.
*/
export default class StockLocationService extends TransactionBaseService {
export default class StockLocationService {
static Events = {
CREATED: "stock-location.created",
UPDATED: "stock-location.updated",
DELETED: "stock-location.deleted",
}
protected readonly manager_: EntityManager
protected readonly eventBusService_: IEventBusService
constructor(
{ eventBusService }: InjectedDependencies,
{ eventBusService, manager }: InjectedDependencies,
options?: unknown,
moduleDeclaration?: ConfigurableModuleDeclaration
moduleDeclaration?: InternalModuleDeclaration
) {
// @ts-ignore
super(...arguments)
if (moduleDeclaration?.resources !== MODULE_RESOURCE_TYPE.SHARED) {
throw new MedusaError(
MedusaError.Types.INVALID_ARGUMENT,
"At the moment this module can only be used with shared resources"
)
}
this.manager_ = manager
this.eventBusService_ = eventBusService
}
@@ -62,11 +49,13 @@ export default class StockLocationService extends TransactionBaseService {
* @param config - Additional configuration for the query.
* @return A list of stock locations.
*/
@InjectEntityManager()
async list(
selector: FilterableStockLocationProps = {},
config: FindConfig<StockLocation> = { relations: [], skip: 0, take: 10 }
config: FindConfig<StockLocation> = { relations: [], skip: 0, take: 10 },
@MedusaContext() context: SharedContext = {}
): Promise<StockLocation[]> {
const manager = this.activeManager_
const manager = context.transactionManager!
const locationRepo = manager.getRepository(StockLocation)
const query = buildQuery(selector, config)
@@ -79,11 +68,13 @@ export default class StockLocationService extends TransactionBaseService {
* @param config - Additional configuration for the query.
* @return A list of stock locations and the count of matching stock locations.
*/
@InjectEntityManager()
async listAndCount(
selector: FilterableStockLocationProps = {},
config: FindConfig<StockLocation> = { relations: [], skip: 0, take: 10 }
config: FindConfig<StockLocation> = { relations: [], skip: 0, take: 10 },
@MedusaContext() context: SharedContext = {}
): Promise<[StockLocation[], number]> {
const manager = this.activeManager_
const manager = context.transactionManager!
const locationRepo = manager.getRepository(StockLocation)
const query = buildQuery(selector, config)
@@ -97,9 +88,11 @@ export default class StockLocationService extends TransactionBaseService {
* @return The stock location.
* @throws If the stock location ID is not definedor the stock location with the given ID was not found.
*/
@InjectEntityManager()
async retrieve(
stockLocationId: string,
config: FindConfig<StockLocation> = {}
config: FindConfig<StockLocation> = {},
@MedusaContext() context: SharedContext = {}
): Promise<StockLocation> {
if (!isDefined(stockLocationId)) {
throw new MedusaError(
@@ -108,7 +101,7 @@ export default class StockLocationService extends TransactionBaseService {
)
}
const manager = this.activeManager_
const manager = context.transactionManager!
const locationRepo = manager.getRepository(StockLocation)
const query = buildQuery({ id: stockLocationId }, config)
@@ -129,41 +122,44 @@ export default class StockLocationService extends TransactionBaseService {
* @param data - The input data for creating a Stock Location.
* @returns The created stock location.
*/
async create(data: CreateStockLocationInput): Promise<StockLocation> {
return await this.atomicPhase_(async (manager) => {
const locationRepo = manager.getRepository(StockLocation)
@InjectEntityManager()
async create(
data: CreateStockLocationInput,
@MedusaContext() context: SharedContext = {}
): Promise<StockLocation> {
const manager = context.transactionManager!
const loc = locationRepo.create({
name: data.name,
const locationRepo = manager.getRepository(StockLocation)
const loc = locationRepo.create({
name: data.name,
})
if (isDefined(data.address) || isDefined(data.address_id)) {
if (typeof data.address === "string" || data.address_id) {
const addrId = (data.address ?? data.address_id) as string
loc.address_id = addrId
} else {
const locAddressRepo = manager.getRepository(StockLocationAddress)
const locAddress = locAddressRepo.create(data.address!)
const addressResult = await locAddressRepo.save(locAddress)
loc.address_id = addressResult.id
}
}
const { metadata } = data
if (metadata) {
loc.metadata = setMetadata(loc, metadata)
}
const result = await locationRepo.save(loc)
await this.eventBusService_
.withTransaction(manager)
.emit(StockLocationService.Events.CREATED, {
id: result.id,
})
if (isDefined(data.address) || isDefined(data.address_id)) {
if (typeof data.address === "string" || data.address_id) {
const addrId = (data.address ?? data.address_id) as string
loc.address_id = addrId
} else {
const locAddressRepo = manager.getRepository(StockLocationAddress)
const locAddress = locAddressRepo.create(data.address!)
const addressResult = await locAddressRepo.save(locAddress)
loc.address_id = addressResult.id
}
}
const { metadata } = data
if (metadata) {
loc.metadata = setMetadata(loc, metadata)
}
const result = await locationRepo.save(loc)
await this.eventBusService_
.withTransaction(manager)
.emit(StockLocationService.Events.CREATED, {
id: result.id,
})
return result
})
return result
}
/**
@@ -172,46 +168,46 @@ export default class StockLocationService extends TransactionBaseService {
* @param updateData - The update data for the stock location.
* @returns The updated stock location.
*/
@InjectEntityManager()
async update(
stockLocationId: string,
updateData: UpdateStockLocationInput
updateData: UpdateStockLocationInput,
@MedusaContext() context: SharedContext = {}
): Promise<StockLocation> {
return await this.atomicPhase_(async (manager) => {
const locationRepo = manager.getRepository(StockLocation)
const manager = context.transactionManager!
const locationRepo = manager.getRepository(StockLocation)
const item = await this.retrieve(stockLocationId)
const item = await this.retrieve(stockLocationId, undefined, context)
const { address, ...data } = updateData
const { address, ...data } = updateData
if (address) {
if (item.address_id) {
await this.updateAddress(item.address_id, address)
} else {
const locAddressRepo = manager.getRepository(StockLocationAddress)
const locAddress = locAddressRepo.create(address)
const addressResult = await locAddressRepo.save(locAddress)
data.address_id = addressResult.id
}
if (address) {
if (item.address_id) {
await this.updateAddress(item.address_id, address, context)
} else {
const locAddressRepo = manager.getRepository(StockLocationAddress)
const locAddress = locAddressRepo.create(address)
const addressResult = await locAddressRepo.save(locAddress)
data.address_id = addressResult.id
}
}
const { metadata, ...fields } = data
const { metadata, ...fields } = data
const toSave = locationRepo.merge(item, fields)
if (metadata) {
toSave.metadata = setMetadata(toSave, metadata)
}
const toSave = locationRepo.merge(item, fields)
if (metadata) {
toSave.metadata = setMetadata(toSave, metadata)
}
await locationRepo.save(toSave)
await locationRepo.save(toSave)
await this.eventBusService_
.withTransaction(manager)
.emit(StockLocationService.Events.UPDATED, {
id: stockLocationId,
})
await this.eventBusService_
.withTransaction(manager)
.emit(StockLocationService.Events.UPDATED, {
id: stockLocationId,
})
return item
})
return item
}
/**
@@ -220,10 +216,11 @@ export default class StockLocationService extends TransactionBaseService {
* @param address - The update data for the address.
* @returns The updated stock location address.
*/
@InjectEntityManager()
protected async updateAddress(
addressId: string,
address: StockLocationAddressInput
address: StockLocationAddressInput,
@MedusaContext() context: SharedContext = {}
): Promise<StockLocationAddress> {
if (!isDefined(addressId)) {
throw new MedusaError(
@@ -232,28 +229,27 @@ export default class StockLocationService extends TransactionBaseService {
)
}
return await this.atomicPhase_(async (manager) => {
const locationAddressRepo = manager.getRepository(StockLocationAddress)
const manager = context.transactionManager!
const locationAddressRepo = manager.getRepository(StockLocationAddress)
const existingAddress = await locationAddressRepo.findOne({
where: { id: addressId },
})
if (!existingAddress) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`StockLocation address with id ${addressId} was not found`
)
}
const { metadata, ...fields } = address
const toSave = locationAddressRepo.merge(existingAddress, fields)
if (metadata) {
toSave.metadata = setMetadata(toSave, metadata)
}
return await locationAddressRepo.save(toSave)
const existingAddress = await locationAddressRepo.findOne({
where: { id: addressId },
})
if (!existingAddress) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`StockLocation address with id ${addressId} was not found`
)
}
const { metadata, ...fields } = address
const toSave = locationAddressRepo.merge(existingAddress, fields)
if (metadata) {
toSave.metadata = setMetadata(toSave, metadata)
}
return await locationAddressRepo.save(toSave)
}
/**
@@ -261,17 +257,20 @@ export default class StockLocationService extends TransactionBaseService {
* @param id - The ID of the stock location to delete.
* @returns An empty promise.
*/
async delete(id: string): Promise<void> {
return await this.atomicPhase_(async (manager) => {
const locationRepo = manager.getRepository(StockLocation)
@InjectEntityManager()
async delete(
id: string,
@MedusaContext() context: SharedContext = {}
): Promise<void> {
const manager = context.transactionManager!
const locationRepo = manager.getRepository(StockLocation)
await locationRepo.softRemove({ id })
await locationRepo.softRemove({ id })
await this.eventBusService_
.withTransaction(manager)
.emit(StockLocationService.Events.DELETED, {
id,
})
})
await this.eventBusService_
.withTransaction(manager)
.emit(StockLocationService.Events.DELETED, {
id,
})
}
}