feat(product): Move mikro orm utils to the utils package (#4631)

Move utils to the utils package as much as possible

Co-authored-by: Shahed Nasser <27354907+shahednasser@users.noreply.github.com>
This commit is contained in:
Adrien de PerettiandShahed Nasser authored and GitHub committed 2023-07-31 11:30:43 +00:00
1 parent 648eb106d6
commit 4073b73130
39 files changed
+523 -375

No files matched your search

+2 -3
View File
@@ -6,12 +6,11 @@ import {
MODULE_RESOURCE_TYPE,
MODULE_SCOPE,
} from "@medusajs/modules-sdk"
import { MedusaError, ModulesSdkUtils } from "@medusajs/utils"
import { DALUtils, MedusaError, ModulesSdkUtils } from "@medusajs/utils"
import { EntitySchema } from "@mikro-orm/core"
import * as ProductModels from "@models"
import { createConnection } from "../utils"
import { ConfigModule, ModulesSdkTypes } from "@medusajs/types"
export default async (
@@ -61,7 +60,7 @@ async function loadDefault({ database, container }) {
}
const entities = Object.values(ProductModels) as unknown as EntitySchema[]
const orm = await createConnection(database, entities)
const orm = await DALUtils.mikroOrmCreateConnection(database, entities)
container.register({
manager: asValue(orm.em.fork()),
@@ -1,5 +1,4 @@
import * as DefaultRepositories from "@repositories"
import {
BaseRepository,
ProductCategoryRepository,
@@ -2,6 +2,7 @@ import {
BeforeCreate,
Collection,
Entity,
Filter,
Index,
OneToMany,
OptionalProps,
@@ -10,14 +11,13 @@ import {
Unique,
} from "@mikro-orm/core"
import { generateEntityId, kebabCase } from "@medusajs/utils"
import { DALUtils, generateEntityId, kebabCase } from "@medusajs/utils"
import Product from "./product"
import { SoftDeletable } from "../utils"
type OptionalRelations = "products"
@Entity({ tableName: "product_collection" })
@SoftDeletable()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductCollection {
[OptionalProps]?: OptionalRelations
+3 -3
View File
@@ -2,6 +2,7 @@ import {
BeforeCreate,
Collection,
Entity,
Filter,
Index,
ManyToMany,
OptionalProps,
@@ -9,14 +10,13 @@ import {
Property,
} from "@mikro-orm/core"
import { generateEntityId } from "@medusajs/utils"
import { DALUtils, generateEntityId } from "@medusajs/utils"
import Product from "./product"
import { SoftDeletable } from "../utils"
type OptionalRelations = "products"
@Entity({ tableName: "image" })
@SoftDeletable()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductImage {
[OptionalProps]?: OptionalRelations
@@ -1,6 +1,7 @@
import {
BeforeCreate,
Entity,
Filter,
Index,
ManyToOne,
OptionalProps,
@@ -8,9 +9,7 @@ import {
Property,
} from "@mikro-orm/core"
import { ProductOption, ProductVariant } from "./index"
import { SoftDeletable } from "../utils"
import { generateEntityId } from "@medusajs/utils"
import { DALUtils, generateEntityId } from "@medusajs/utils"
type OptionalFields =
| "created_at"
@@ -22,7 +21,7 @@ type OptionalFields =
type OptionalRelations = "product" | "option" | "variant"
@Entity({ tableName: "product_option_value" })
@SoftDeletable()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductOptionValue {
[OptionalProps]?: OptionalFields | OptionalRelations
@@ -1,9 +1,10 @@
import { generateEntityId } from "@medusajs/utils"
import { DALUtils, generateEntityId } from "@medusajs/utils"
import {
BeforeCreate,
Cascade,
Collection,
Entity,
Filter,
Index,
ManyToOne,
OneToMany,
@@ -13,13 +14,12 @@ import {
} from "@mikro-orm/core"
import { Product } from "./index"
import ProductOptionValue from "./product-option-value"
import { SoftDeletable } from "../utils"
type OptionalRelations = "values" | "product"
type OptionalFields = "product_id"
@Entity({ tableName: "product_option" })
@SoftDeletable()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductOption {
[OptionalProps]?: OptionalRelations | OptionalFields
+3 -3
View File
@@ -2,6 +2,7 @@ import {
BeforeCreate,
Collection,
Entity,
Filter,
Index,
ManyToMany,
OptionalProps,
@@ -9,14 +10,13 @@ import {
Property,
} from "@mikro-orm/core"
import { generateEntityId } from "@medusajs/utils"
import { DALUtils, generateEntityId } from "@medusajs/utils"
import Product from "./product"
import { SoftDeletable } from "../utils"
type OptionalRelations = "products"
@Entity({ tableName: "product_tag" })
@SoftDeletable()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductTag {
[OptionalProps]?: OptionalRelations
+3 -3
View File
@@ -1,16 +1,16 @@
import {
BeforeCreate,
Entity,
Filter,
Index,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import { generateEntityId } from "@medusajs/utils"
import { SoftDeletable } from "../utils"
import { DALUtils, generateEntityId } from "@medusajs/utils"
@Entity({ tableName: "product_type" })
@SoftDeletable()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductType {
@PrimaryKey({ columnType: "text" })
id!: string
@@ -1,9 +1,10 @@
import { generateEntityId } from "@medusajs/utils"
import { DALUtils, generateEntityId } from "@medusajs/utils"
import {
BeforeCreate,
Cascade,
Collection,
Entity,
Filter,
Index,
ManyToOne,
OneToMany,
@@ -14,7 +15,6 @@ import {
} from "@mikro-orm/core"
import { Product } from "@models"
import ProductOptionValue from "./product-option-value"
import { SoftDeletable } from "../utils"
type OptionalFields =
| "created_at"
@@ -25,7 +25,7 @@ type OptionalFields =
| "product_id"
@Entity({ tableName: "product_variant" })
@SoftDeletable()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductVariant {
[OptionalProps]?: OptionalFields
+3 -3
View File
@@ -3,6 +3,7 @@ import {
Collection,
Entity,
Enum,
Filter,
Index,
ManyToMany,
ManyToOne,
@@ -14,7 +15,7 @@ import {
} from "@mikro-orm/core"
import { ProductTypes } from "@medusajs/types"
import { generateEntityId, kebabCase } from "@medusajs/utils"
import { DALUtils, generateEntityId, kebabCase } from "@medusajs/utils"
import ProductCategory from "./product-category"
import ProductCollection from "./product-collection"
import ProductOption from "./product-option"
@@ -22,7 +23,6 @@ import ProductTag from "./product-tag"
import ProductType from "./product-type"
import ProductVariant from "./product-variant"
import ProductImage from "./product-image"
import { SoftDeletable } from "../utils"
type OptionalRelations = "collection" | "type"
type OptionalFields =
@@ -34,7 +34,7 @@ type OptionalFields =
| "updated_at"
@Entity({ tableName: "product" })
@SoftDeletable()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class Product {
[OptionalProps]?: OptionalRelations | OptionalFields
-286
View File
@@ -1,286 +0,0 @@
import { Context, DAL, RepositoryTransformOptions } from "@medusajs/types"
import { SoftDeletableFilterKey } from "@medusajs/utils"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import {
buildQuery,
InjectTransactionManager,
MedusaContext,
} from "@medusajs/utils"
import { serialize } from "@mikro-orm/core"
// TODO: move to utils package
async function transactionWrapper<TManager = unknown>(
this: any,
task: (transactionManager: unknown) => Promise<any>,
{
transaction,
isolationLevel,
enableNestedTransactions = false,
}: {
isolationLevel?: string
transaction?: TManager
enableNestedTransactions?: boolean
} = {}
): Promise<any> {
// Reuse the same transaction if it is already provided and nested transactions are disabled
if (!enableNestedTransactions && transaction) {
return await task(transaction)
}
const options = {}
if (transaction) {
Object.assign(options, { ctx: transaction })
}
if (isolationLevel) {
Object.assign(options, { isolationLevel })
}
return await (this.manager_ as SqlEntityManager).transactional(task, options)
}
// TODO: move to utils package
const mikroOrmUpdateDeletedAtRecursively = async <T extends object = any>(
manager: any,
entities: T[],
value: Date | null
) => {
for (const entity of entities) {
if (!("deleted_at" in entity)) continue
;(entity as any).deleted_at = value
const relations = manager
.getDriver()
.getMetadata()
.get(entity.constructor.name).relations
const relationsToCascade = relations.filter((relation) =>
relation.cascade.includes("soft-remove" as any)
)
for (const relation of relationsToCascade) {
let collectionRelation = entity[relation.name]
if (!collectionRelation.isInitialized()) {
await collectionRelation.init()
}
const relationEntities = await collectionRelation.getItems({
filters: {
[SoftDeletableFilterKey]: {
withDeleted: true,
},
},
})
await mikroOrmUpdateDeletedAtRecursively(manager, relationEntities, value)
}
await manager.persist(entity)
}
}
const serializer = <TOutput extends object>(
data: any,
options?: any
): Promise<TOutput> => {
options ??= {}
const result = serialize(data, options)
return result as unknown as Promise<TOutput>
}
// TODO: move to utils package
class AbstractBase<T = any> {
protected readonly manager_: SqlEntityManager
protected constructor({ manager }) {
this.manager_ = manager
}
getFreshManager<TManager = unknown>(): TManager {
return (this.manager_.fork
? this.manager_.fork()
: this.manager_) as unknown as TManager
}
getActiveManager<TManager = unknown>(
@MedusaContext()
{ transactionManager, manager }: Context = {}
): TManager {
return (transactionManager ?? manager ?? this.manager_) as TManager
}
async transaction<TManager = unknown>(
task: (transactionManager: TManager) => Promise<any>,
{
transaction,
isolationLevel,
enableNestedTransactions = false,
}: {
isolationLevel?: string
enableNestedTransactions?: boolean
transaction?: TManager
} = {}
): Promise<any> {
return await transactionWrapper.apply(this, arguments)
}
async serialize<TOutput extends object | object[]>(
data: any,
options?: any
): Promise<TOutput> {
return await serializer<TOutput>(data, options)
}
}
export abstract class AbstractBaseRepository<T = any>
extends AbstractBase
implements DAL.RepositoryService<T>
{
abstract find(options?: DAL.FindOptions<T>, context?: Context)
abstract findAndCount(
options?: DAL.FindOptions<T>,
context?: Context
): Promise<[T[], number]>
abstract create(data: unknown[], context?: Context): Promise<T[]>
abstract delete(ids: string[], context?: Context): Promise<void>
@InjectTransactionManager()
async softDelete(
ids: string[],
@MedusaContext()
{ transactionManager: manager }: Context = {}
): Promise<T[]> {
const entities = await this.find({ where: { id: { $in: ids } } as any })
const date = new Date()
await mikroOrmUpdateDeletedAtRecursively(
manager as SqlEntityManager,
entities,
date
)
return entities
}
@InjectTransactionManager()
async restore(
ids: string[],
@MedusaContext()
{ transactionManager: manager }: Context<SqlEntityManager> = {}
): Promise<T[]> {
const query = buildQuery(
{ id: { $in: ids } },
{
withDeleted: true,
}
)
const entities = await this.find(query)
await mikroOrmUpdateDeletedAtRecursively(
manager as SqlEntityManager,
entities,
null
)
return entities
}
}
// TODO: move to utils package
export abstract class AbstractTreeRepositoryBase<T = any>
extends AbstractBase<T>
implements DAL.TreeRepositoryService<T>
{
protected constructor({ manager }) {
// @ts-ignore
super(...arguments)
}
abstract find(
options?: DAL.FindOptions<T>,
transformOptions?: RepositoryTransformOptions,
context?: Context
)
abstract findAndCount(
options?: DAL.FindOptions<T>,
transformOptions?: RepositoryTransformOptions,
context?: Context
): Promise<[T[], number]>
abstract create(data: unknown, context?: Context): Promise<T>
abstract delete(id: string, context?: Context): Promise<void>
}
// TODO: move to utils package
/**
* Only used internally in order to be able to wrap in transaction from a
* non identified repository
*/
export class BaseRepository extends AbstractBaseRepository {
constructor({ manager }) {
// @ts-ignore
super(...arguments)
}
create(data: unknown[], context?: Context): Promise<any[]> {
throw new Error("Method not implemented.")
}
delete(ids: string[], context?: Context): Promise<void> {
throw new Error("Method not implemented.")
}
find(options?: DAL.FindOptions, context?: Context): Promise<any[]> {
throw new Error("Method not implemented.")
}
findAndCount(
options?: DAL.FindOptions,
context?: Context
): Promise<[any[], number]> {
throw new Error("Method not implemented.")
}
}
export class BaseTreeRepository extends AbstractTreeRepositoryBase {
constructor({ manager }) {
// @ts-ignore
super(...arguments)
}
find(
options?: DAL.FindOptions,
transformOptions?: RepositoryTransformOptions,
context?: Context
): Promise<any[]> {
throw new Error("Method not implemented.")
}
findAndCount(
options?: DAL.FindOptions,
transformOptions?: RepositoryTransformOptions,
context?: Context
): Promise<[any[], number]> {
throw new Error("Method not implemented.")
}
create(data: unknown, context?: Context): Promise<any> {
throw new Error("Method not implemented.")
}
delete(id: string, context?: Context): Promise<void> {
throw new Error("Method not implemented.")
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
export { BaseRepository } from "./base"
export { MikroOrmBaseRepository as BaseRepository } from "@medusajs/utils"
export { ProductRepository } from "./product"
export { ProductTagRepository } from "./product-tag"
export { ProductVariantRepository } from "./product-variant"
@@ -3,12 +3,17 @@ import {
FindOptions as MikroOptions,
LoadStrategy,
} from "@mikro-orm/core"
import { Product, ProductCategory } from "@models"
import { ProductCategory } from "@models"
import { Context, DAL, ProductCategoryTransformOptions } from "@medusajs/types"
import groupBy from "lodash/groupBy"
import { BaseTreeRepository } from "./base"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { InjectTransactionManager, MedusaContext, isDefined, MedusaError } from "@medusajs/utils"
import {
DALUtils,
InjectTransactionManager,
isDefined,
MedusaContext,
MedusaError,
} from "@medusajs/utils"
import { ProductCategoryServiceTypes } from "../types"
@@ -25,7 +30,7 @@ export type ReorderConditions = {
}
export const tempReorderRank = 99999
export class ProductCategoryRepository extends BaseTreeRepository {
export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeRepository {
protected readonly manager_: SqlEntityManager
constructor({ manager }: { manager: SqlEntityManager }) {
@@ -209,12 +214,9 @@ export class ProductCategoryRepository extends BaseTreeRepository {
): Promise<ProductCategory> {
const categoryData = { ...data }
const manager = this.getActiveManager<SqlEntityManager>(sharedContext)
const siblings = await manager.find(
ProductCategory,
{
parent_category_id: categoryData?.parent_category_id || null
},
)
const siblings = await manager.find(ProductCategory, {
parent_category_id: categoryData?.parent_category_id || null,
})
if (!isDefined(categoryData.rank)) {
categoryData.rank = siblings.length
@@ -343,25 +345,19 @@ export class ProductCategoryRepository extends BaseTreeRepository {
// The current sibling count will replace targetRank if
// targetRank is greater than the count of siblings.
const siblingCount = await manager.count(
ProductCategory,
{
parent_category_id: targetParentId || null,
id: { $ne: targetCategoryId },
}
)
const siblingCount = await manager.count(ProductCategory, {
parent_category_id: targetParentId || null,
id: { $ne: targetCategoryId },
})
// The category record that will be placed at the requested rank
// We've temporarily placed it at a temporary rank that is
// beyond a reasonable value (tempReorderRank)
const targetCategory = await manager.findOne(
ProductCategory,
{
id: targetCategoryId,
parent_category_id: targetParentId || null,
rank: tempReorderRank,
}
)
const targetCategory = await manager.findOne(ProductCategory, {
id: targetCategoryId,
parent_category_id: targetParentId || null,
rank: tempReorderRank,
})
// If the targetRank is not present, or if targetRank is beyond the
// rank of the last category, we set the rank as the last rank
@@ -7,14 +7,13 @@ import {
import { Context, DAL, ProductTypes } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import {
DALUtils,
InjectTransactionManager,
MedusaContext,
MedusaError,
} from "@medusajs/utils"
import { BaseRepository } from "./base"
export class ProductCollectionRepository extends BaseRepository {
export class ProductCollectionRepository extends DALUtils.MikroOrmBaseRepository {
protected readonly manager_: SqlEntityManager
constructor({ manager }: { manager: SqlEntityManager }) {
@@ -5,11 +5,14 @@ import {
} from "@mikro-orm/core"
import { Context, DAL } from "@medusajs/types"
import { Image, Product } from "@models"
import { AbstractBaseRepository } from "./base"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { InjectTransactionManager, MedusaContext } from "@medusajs/utils"
import {
DALUtils,
InjectTransactionManager,
MedusaContext,
} from "@medusajs/utils"
export class ProductImageRepository extends AbstractBaseRepository<Image> {
export class ProductImageRepository extends DALUtils.MikroOrmAbstractBaseRepository<Image> {
protected readonly manager_: SqlEntityManager
constructor({ manager }: { manager: SqlEntityManager }) {
@@ -5,15 +5,15 @@ import {
} from "@mikro-orm/core"
import { Product, ProductOption } from "@models"
import { Context, DAL, ProductTypes } from "@medusajs/types"
import { AbstractBaseRepository } from "./base"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import {
DALUtils,
InjectTransactionManager,
MedusaContext,
MedusaError,
} from "@medusajs/utils"
export class ProductOptionRepository extends AbstractBaseRepository<ProductOption> {
export class ProductOptionRepository extends DALUtils.MikroOrmAbstractBaseRepository<ProductOption> {
protected readonly manager_: SqlEntityManager
constructor({ manager }: { manager: SqlEntityManager }) {
@@ -88,13 +88,15 @@ export class ProductOptionRepository extends AbstractBaseRepository<ProductOptio
data.forEach((d) => d.product_id && productIds.push(d.product_id))
const existingProducts = await manager.find(
Product,
{ id: { $in: productIds } },
)
const existingProducts = await manager.find(Product, {
id: { $in: productIds },
})
const existingProductsMap = new Map(
existingProducts.map<[string, Product]>((product) => [product.id, product])
existingProducts.map<[string, Product]>((product) => [
product.id,
product,
])
)
const productOptions = data.map((optionData) => {
@@ -136,7 +138,10 @@ export class ProductOptionRepository extends AbstractBaseRepository<ProductOptio
)
const existingOptionsMap = new Map(
existingOptions.map<[string, ProductOption]>((option) => [option.id, option])
existingOptions.map<[string, ProductOption]>((option) => [
option.id,
option,
])
)
const productOptions = data.map((optionData) => {
@@ -12,15 +12,15 @@ import {
UpdateProductTagDTO,
UpsertProductTagDTO,
} from "@medusajs/types"
import { BaseRepository } from "./base"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import {
DALUtils,
InjectTransactionManager,
MedusaContext,
MedusaError,
} from "@medusajs/utils"
export class ProductTagRepository extends BaseRepository {
export class ProductTagRepository extends DALUtils.MikroOrmBaseRepository {
protected readonly manager_: SqlEntityManager
constructor({ manager }: { manager: SqlEntityManager }) {
@@ -13,14 +13,13 @@ import {
} from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import {
DALUtils,
InjectTransactionManager,
MedusaContext,
MedusaError,
} from "@medusajs/utils"
import { BaseRepository } from "./base"
export class ProductTypeRepository extends BaseRepository {
export class ProductTypeRepository extends DALUtils.MikroOrmBaseRepository {
protected readonly manager_: SqlEntityManager
constructor({ manager }: { manager: SqlEntityManager }) {
@@ -8,17 +8,15 @@ import { ProductVariant } from "@models"
import { Context, DAL, WithRequiredProperty } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import {
MedusaError,
isDefined,
DALUtils,
InjectTransactionManager,
MedusaContext,
MedusaError,
} from "@medusajs/utils"
import { ProductVariantServiceTypes } from "../types/services"
import { AbstractBaseRepository } from "./base"
import { doNotForceTransaction } from "../utils"
export class ProductVariantRepository extends AbstractBaseRepository<ProductVariant> {
export class ProductVariantRepository extends DALUtils.MikroOrmAbstractBaseRepository<ProductVariant> {
protected readonly manager_: SqlEntityManager
constructor({ manager }: { manager: SqlEntityManager }) {
@@ -96,14 +94,17 @@ export class ProductVariantRepository extends AbstractBaseRepository<ProductVari
}
async update(
data: WithRequiredProperty<ProductVariantServiceTypes.UpdateProductVariantDTO, "id">[],
data: WithRequiredProperty<
ProductVariantServiceTypes.UpdateProductVariantDTO,
"id"
>[],
context: Context = {}
): Promise<ProductVariant[]> {
const manager = (context.transactionManager ??
this.manager_) as SqlEntityManager
const productVariantsToUpdate = await manager.find(ProductVariant, {
id: data.map((updateData) => updateData.id)
id: data.map((updateData) => updateData.id),
})
const productVariantsToUpdateMap = new Map<string, ProductVariant>(
+56 -37
View File
@@ -2,15 +2,14 @@ import {
Product,
ProductCategory,
ProductCollection,
ProductType,
ProductTag,
ProductType,
} from "@models"
import {
FilterQuery as MikroFilterQuery,
FindOptions as MikroOptions,
LoadStrategy,
wrap
} from "@mikro-orm/core"
import {
@@ -20,12 +19,17 @@ import {
WithRequiredProperty,
} from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { MedusaError, isDefined, InjectTransactionManager, MedusaContext } from "@medusajs/utils"
import {
DALUtils,
InjectTransactionManager,
isDefined,
MedusaContext,
MedusaError,
} from "@medusajs/utils"
import { AbstractBaseRepository } from "./base"
import { ProductServiceTypes } from "../types/services"
export class ProductRepository extends AbstractBaseRepository<Product> {
export class ProductRepository extends DALUtils.MikroOrmAbstractBaseRepository<Product> {
protected readonly manager_: SqlEntityManager
constructor({ manager }: { manager: SqlEntityManager }) {
@@ -157,12 +161,10 @@ export class ProductRepository extends AbstractBaseRepository<Product> {
data.forEach((productData) => {
categoryIds = categoryIds.concat(
productData?.categories?.map(c => c.id) || []
productData?.categories?.map((c) => c.id) || []
)
tagIds = tagIds.concat(
productData?.tags?.map(c => c.id) || []
)
tagIds = tagIds.concat(productData?.tags?.map((c) => c.id) || [])
if (productData.collection_id) {
collectionIds.push(productData.collection_id)
@@ -173,27 +175,39 @@ export class ProductRepository extends AbstractBaseRepository<Product> {
}
})
const productsToUpdate = await manager.find(Product, {
id: data.map((updateData) => updateData.id)
}, {
populate: ["tags", "categories"]
})
const productsToUpdate = await manager.find(
Product,
{
id: data.map((updateData) => updateData.id),
},
{
populate: ["tags", "categories"],
}
)
const collectionsToAssign = collectionIds.length ? await manager.find(ProductCollection, {
id: collectionIds
}) : []
const collectionsToAssign = collectionIds.length
? await manager.find(ProductCollection, {
id: collectionIds,
})
: []
const typesToAssign = typeIds.length ? await manager.find(ProductType, {
id: typeIds
}) : []
const typesToAssign = typeIds.length
? await manager.find(ProductType, {
id: typeIds,
})
: []
const categoriesToAssign = categoryIds.length ? await manager.find(ProductCategory, {
id: categoryIds
}) : []
const categoriesToAssign = categoryIds.length
? await manager.find(ProductCategory, {
id: categoryIds,
})
: []
const tagsToAssign = tagIds.length ? await manager.find(ProductTag, {
id: tagIds
}) : []
const tagsToAssign = tagIds.length
? await manager.find(ProductTag, {
id: tagIds,
})
: []
const categoriesToAssignMap = new Map<string, ProductCategory>(
categoriesToAssign.map((category) => [category.id, category])
@@ -227,8 +241,8 @@ export class ProductRepository extends AbstractBaseRepository<Product> {
}
const {
categories: categoriesData,
tags: tagsData,
categories: categoriesData = [],
tags: tagsData = [],
collection_id: collectionId,
type_id: typeId,
} = updateData
@@ -249,10 +263,15 @@ export class ProductRepository extends AbstractBaseRepository<Product> {
}
}
const categoryIdsToAssignSet = new Set(categoriesData.map(cd => cd.id))
const categoriesToDelete = product.categories.getItems().filter(
(existingCategory) => !categoryIdsToAssignSet.has(existingCategory.id)
const categoryIdsToAssignSet = new Set(
categoriesData.map((cd) => cd.id)
)
const categoriesToDelete = product.categories
.getItems()
.filter(
(existingCategory) =>
!categoryIdsToAssignSet.has(existingCategory.id)
)
await product.categories.remove(categoriesToDelete)
}
@@ -272,22 +291,22 @@ export class ProductRepository extends AbstractBaseRepository<Product> {
}
}
const tagIdsToAssignSet = new Set(tagsData.map(cd => cd.id))
const tagsToDelete = product.tags.getItems().filter(
(existingTag) => !tagIdsToAssignSet.has(existingTag.id)
)
const tagIdsToAssignSet = new Set(tagsData.map((cd) => cd.id))
const tagsToDelete = product.tags
.getItems()
.filter((existingTag) => !tagIdsToAssignSet.has(existingTag.id))
await product.tags.remove(tagsToDelete)
}
if (isDefined(collectionId)) {
const collection = collectionsToAssignMap.get(collectionId)
const collection = collectionsToAssignMap.get(collectionId!)
product.collection = collection || null
}
if (isDefined(typeId)) {
const type = typesToAssignMap.get(typeId)
const type = typesToAssignMap.get(typeId!)
if (type) {
product.type = type
@@ -3,8 +3,7 @@ import * as ProductModels from "@models"
import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types"
import { EntitySchema } from "@mikro-orm/core"
import { ModulesSdkUtils } from "@medusajs/utils"
import { createConnection } from "../utils"
import { DALUtils, ModulesSdkUtils } from "@medusajs/utils"
/**
* This script is only valid for mikro orm managers. If a user provide a custom manager
@@ -28,7 +27,7 @@ export async function revertMigration({
const dbData = ModulesSdkUtils.loadDatabaseConfig("product", options)
const entities = Object.values(ProductModels) as unknown as EntitySchema[]
const orm = await createConnection(dbData, entities)
const orm = await DALUtils.mikroOrmCreateConnection(dbData, entities)
try {
const migrator = orm.getMigrator()
+2 -3
View File
@@ -1,8 +1,7 @@
import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types"
import { createConnection } from "../utils"
import * as ProductModels from "@models"
import { EntitySchema } from "@mikro-orm/core"
import { ModulesSdkUtils } from "@medusajs/utils"
import { DALUtils, ModulesSdkUtils } from "@medusajs/utils"
/**
* This script is only valid for mikro orm managers. If a user provide a custom manager
@@ -26,7 +25,7 @@ export async function runMigrations({
const dbData = ModulesSdkUtils.loadDatabaseConfig("product", options)
const entities = Object.values(ProductModels) as unknown as EntitySchema[]
const orm = await createConnection(dbData, entities)
const orm = await DALUtils.mikroOrmCreateConnection(dbData, entities)
try {
const migrator = orm.getMigrator()
+2 -3
View File
@@ -1,4 +1,3 @@
import { createConnection } from "../utils"
import * as ProductModels from "@models"
import { Product, ProductCategory, ProductVariant } from "@models"
import { EntitySchema } from "@mikro-orm/core"
@@ -6,7 +5,7 @@ import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types"
import { EOL } from "os"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { resolve } from "path"
import { ModulesSdkUtils } from "@medusajs/utils"
import { DALUtils, ModulesSdkUtils } from "@medusajs/utils"
export async function run({
options,
@@ -38,7 +37,7 @@ export async function run({
const dbData = ModulesSdkUtils.loadDatabaseConfig("product", options)
const entities = Object.values(ProductModels) as unknown as EntitySchema[]
const orm = await createConnection(dbData, entities)
const orm = await DALUtils.mikroOrmCreateConnection(dbData, entities)
const manager = orm.em.fork()
try {
@@ -1,27 +0,0 @@
import { MikroORM, PostgreSqlDriver } from "@mikro-orm/postgresql"
import { ModuleServiceInitializeOptions } from "@medusajs/types"
export async function createConnection(
database: ModuleServiceInitializeOptions["database"],
entities: any[]
) {
const schema = database.schema || "public"
const orm = await MikroORM.init<PostgreSqlDriver>({
discovery: { disableDynamicFileAccess: true },
entities,
debug: database.debug ?? process.env.NODE_ENV?.startsWith("dev") ?? false,
baseDir: process.cwd(),
clientUrl: database.clientUrl,
schema,
driverOptions: database.driverOptions ?? {
connection: { ssl: true },
},
tsNode: process.env.APP_ENV === "development",
type: "postgresql",
migrations: {
path: __dirname + "/../migrations",
},
})
return orm
}
-3
View File
@@ -1,8 +1,5 @@
import { MODULE_RESOURCE_TYPE } from "@medusajs/types"
export * from "./create-connection"
export * from "./soft-deletable"
export function shouldForceTransaction(target: any): boolean {
return target.moduleDeclaration?.resources === MODULE_RESOURCE_TYPE.ISOLATED
}
@@ -1,23 +0,0 @@
// TODO: Should we create a mikro orm specific package for this and the base repository?
import { Filter } from "@mikro-orm/core"
import { SoftDeletableFilterKey } from "@medusajs/utils"
interface FilterArguments {
withDeleted?: boolean
}
export const SoftDeletable = (): ClassDecorator => {
return Filter({
name: SoftDeletableFilterKey,
cond: ({ withDeleted }: FilterArguments = {}) => {
if (withDeleted) {
return {}
}
return {
deleted_at: null,
}
},
default: true,
})
}