feat(medusa): Improve base-service
This commit is contained in:
1 parent
313cb0658b
commit
bfb81b8b32
2 files changed
+45
-50
No files matched your search
@@ -1,4 +1,4 @@
|
|||||||
import BaseService from "../base-service"
|
import { BaseService } from "../base-service"
|
||||||
import { In, Not } from "typeorm"
|
import { In, Not } from "typeorm"
|
||||||
import { MockManager } from "medusa-test-utils"
|
import { MockManager } from "medusa-test-utils"
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@ describe("BaseService", () => {
|
|||||||
it("should cloned the child class withTransaction", () => {
|
it("should cloned the child class withTransaction", () => {
|
||||||
class Child extends BaseService<Child> {
|
class Child extends BaseService<Child> {
|
||||||
constructor(protected readonly container) {
|
constructor(protected readonly container) {
|
||||||
super(container, {});
|
super(container);
|
||||||
this.container = container
|
this.container = container
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,4 +58,4 @@ describe("BaseService", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import { EntityManager, FindOperator, In, Raw } from "typeorm"
|
import { EntityManager, FindOperator, In, Raw } from "typeorm"
|
||||||
import { IsolationLevel } from "typeorm/driver/types/IsolationLevel"
|
import { IsolationLevel } from "typeorm/driver/types/IsolationLevel"
|
||||||
import { FindConfig } from "../types/common"
|
import { FindConfig, Writable } from "../types/common"
|
||||||
|
|
||||||
type Selector<TEntity> = { [key in keyof TEntity]?: unknown }
|
type Selector<TEntity> = { [key in keyof TEntity]?: unknown }
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ type Selector<TEntity> = { [key in keyof TEntity]?: unknown }
|
|||||||
* Common functionality for Services
|
* Common functionality for Services
|
||||||
* @interface
|
* @interface
|
||||||
*/
|
*/
|
||||||
class BaseService<
|
export class BaseService<
|
||||||
TChild extends BaseService<TChild, TContainer>,
|
TChild extends BaseService<TChild, TContainer>,
|
||||||
TContainer = unknown
|
TContainer = unknown
|
||||||
> {
|
> {
|
||||||
@@ -19,22 +19,17 @@ class BaseService<
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
container: TContainer,
|
container: TContainer,
|
||||||
protected readonly configModule: Record<string, unknown>
|
protected readonly configModule?: Record<string, unknown>
|
||||||
) {
|
) {
|
||||||
this.container_ = container
|
this.container_ = container
|
||||||
}
|
}
|
||||||
|
|
||||||
withTransaction(): this
|
|
||||||
withTransaction(transactionManager: EntityManager): TChild
|
|
||||||
withTransaction(transactionManager?: EntityManager): this | TChild {
|
withTransaction(transactionManager?: EntityManager): this | TChild {
|
||||||
if (!transactionManager) {
|
if (!transactionManager) {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
const cloned = new (<typeof BaseService>this.constructor)<
|
const cloned = new (<any>this.constructor)(
|
||||||
TChild,
|
|
||||||
TContainer
|
|
||||||
>(
|
|
||||||
{
|
{
|
||||||
...this.container_,
|
...this.container_,
|
||||||
manager: transactionManager,
|
manager: transactionManager,
|
||||||
@@ -57,12 +52,12 @@ class BaseService<
|
|||||||
selector: Selector<TEntity>,
|
selector: Selector<TEntity>,
|
||||||
config: FindConfig<TEntity> = {}
|
config: FindConfig<TEntity> = {}
|
||||||
): FindConfig<TEntity> & {
|
): FindConfig<TEntity> & {
|
||||||
where: { [key in keyof TEntity]?: unknown }
|
where: Partial<Writable<TEntity>>
|
||||||
withDeleted?: boolean
|
withDeleted?: boolean
|
||||||
} {
|
} {
|
||||||
const build = (
|
const build = (
|
||||||
obj: Record<string, unknown>
|
obj: Record<string, unknown>
|
||||||
): { [key in keyof TEntity]?: unknown } => {
|
): Partial<Writable<TEntity>> => {
|
||||||
return Object.entries(obj).reduce((acc, [key, value]: any) => {
|
return Object.entries(obj).reduce((acc, [key, value]: any) => {
|
||||||
// Undefined values indicate that they have no significance to the query.
|
// Undefined values indicate that they have no significance to the query.
|
||||||
// If the query is looking for rows where a column is not set it should use null instead of undefined
|
// If the query is looking for rows where a column is not set it should use null instead of undefined
|
||||||
@@ -83,27 +78,25 @@ class BaseService<
|
|||||||
acc[key] = In([...(value as unknown[])])
|
acc[key] = In([...(value as unknown[])])
|
||||||
break
|
break
|
||||||
case value !== null && typeof value === "object":
|
case value !== null && typeof value === "object":
|
||||||
Object.entries(value as Record<string, unknown>).map(
|
Object.entries(value).map(([modifier, val]) => {
|
||||||
([modifier, val]) => {
|
switch (modifier) {
|
||||||
switch (modifier) {
|
case "lt":
|
||||||
case "lt":
|
subquery.push({ operator: "<", value: val })
|
||||||
subquery.push({ operator: "<", value: val })
|
break
|
||||||
break
|
case "gt":
|
||||||
case "gt":
|
subquery.push({ operator: ">", value: val })
|
||||||
subquery.push({ operator: ">", value: val })
|
break
|
||||||
break
|
case "lte":
|
||||||
case "lte":
|
subquery.push({ operator: "<=", value: val })
|
||||||
subquery.push({ operator: "<=", value: val })
|
break
|
||||||
break
|
case "gte":
|
||||||
case "gte":
|
subquery.push({ operator: ">=", value: val })
|
||||||
subquery.push({ operator: ">=", value: val })
|
break
|
||||||
break
|
default:
|
||||||
default:
|
acc[key] = value
|
||||||
acc[key] = value
|
break
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
|
|
||||||
if (subquery.length) {
|
if (subquery.length) {
|
||||||
acc[key] = Raw(
|
acc[key] = Raw(
|
||||||
@@ -121,11 +114,11 @@ class BaseService<
|
|||||||
}
|
}
|
||||||
|
|
||||||
return acc
|
return acc
|
||||||
}, {} as { [key in keyof TEntity]?: unknown })
|
}, {} as Partial<Writable<TEntity>>)
|
||||||
}
|
}
|
||||||
|
|
||||||
const query: FindConfig<TEntity> & {
|
const query: FindConfig<TEntity> & {
|
||||||
where: { [key in keyof TEntity]?: unknown }
|
where: Partial<Writable<TEntity>>
|
||||||
withDeleted?: boolean
|
withDeleted?: boolean
|
||||||
} = {
|
} = {
|
||||||
where: build(selector),
|
where: build(selector),
|
||||||
@@ -217,17 +210,19 @@ class BaseService<
|
|||||||
* @param maybeErrorHandlerOrDontFail Potential error handler
|
* @param maybeErrorHandlerOrDontFail Potential error handler
|
||||||
* @return the result of the transactional work
|
* @return the result of the transactional work
|
||||||
*/
|
*/
|
||||||
async atomicPhase_(
|
async atomicPhase_<TResult, TError>(
|
||||||
work: (transactionManager: EntityManager) => Promise<unknown>,
|
work: (transactionManager: EntityManager) => Promise<TResult | never>,
|
||||||
isolationOrErrorHandler?:
|
isolationOrErrorHandler?:
|
||||||
| IsolationLevel
|
| IsolationLevel
|
||||||
| ((error: unknown) => Promise<unknown>),
|
| ((error: TError) => Promise<never | TResult | void>),
|
||||||
maybeErrorHandlerOrDontFail?: (error: unknown) => Promise<unknown>
|
maybeErrorHandlerOrDontFail?: (
|
||||||
): Promise<unknown | never> {
|
error: TError
|
||||||
|
) => Promise<never | TResult | void>
|
||||||
|
): Promise<never | TResult> {
|
||||||
let errorHandler = maybeErrorHandlerOrDontFail
|
let errorHandler = maybeErrorHandlerOrDontFail
|
||||||
let isolation:
|
let isolation:
|
||||||
| IsolationLevel
|
| IsolationLevel
|
||||||
| ((error: unknown) => Promise<unknown>)
|
| ((error: TError) => Promise<never | TResult | void>)
|
||||||
| undefined
|
| undefined
|
||||||
| null = isolationOrErrorHandler
|
| null = isolationOrErrorHandler
|
||||||
let dontFail = false
|
let dontFail = false
|
||||||
@@ -238,7 +233,7 @@ class BaseService<
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.transactionManager_) {
|
if (this.transactionManager_) {
|
||||||
const doWork = async (m: EntityManager): Promise<unknown | never> => {
|
const doWork = async (m: EntityManager): Promise<never | TResult> => {
|
||||||
this.manager_ = m
|
this.manager_ = m
|
||||||
this.transactionManager_ = m
|
this.transactionManager_ = m
|
||||||
try {
|
try {
|
||||||
@@ -256,10 +251,10 @@ class BaseService<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return doWork(this.transactionManager_)
|
return await doWork(this.transactionManager_)
|
||||||
} else {
|
} else {
|
||||||
const temp = this.manager_
|
const temp = this.manager_
|
||||||
const doWork = async (m: EntityManager): Promise<unknown | never> => {
|
const doWork = async (m: EntityManager): Promise<never | TResult> => {
|
||||||
this.manager_ = m
|
this.manager_ = m
|
||||||
this.transactionManager_ = m
|
this.transactionManager_ = m
|
||||||
try {
|
try {
|
||||||
@@ -284,8 +279,9 @@ class BaseService<
|
|||||||
return result
|
return result
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (this.shouldRetryTransaction(error)) {
|
if (this.shouldRetryTransaction(error)) {
|
||||||
return this.manager_.transaction(isolation as IsolationLevel, (m) =>
|
return this.manager_.transaction(
|
||||||
doWork(m)
|
isolation as IsolationLevel,
|
||||||
|
(m): Promise<never | TResult> => doWork(m)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
if (errorHandler) {
|
if (errorHandler) {
|
||||||
@@ -302,7 +298,7 @@ class BaseService<
|
|||||||
if (errorHandler) {
|
if (errorHandler) {
|
||||||
const result = await errorHandler(error)
|
const result = await errorHandler(error)
|
||||||
if (dontFail) {
|
if (dontFail) {
|
||||||
return result
|
return result as TResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,5 +334,4 @@ class BaseService<
|
|||||||
...newData,
|
...newData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default BaseService
|
|
||||||
Reference in new issue
Block a user