1- import { BigNumberRawValue } from "@medusajs/types"
21import {
32 BeforeCreate ,
43 Collection ,
54 Entity ,
65 EntityManager ,
6+ Filter ,
77 ManyToMany ,
88 ManyToOne ,
99 MikroORM ,
@@ -15,15 +15,18 @@ import {
1515 wrap ,
1616} from "@medusajs/deps/mikro-orm/core"
1717import { defineConfig } from "@medusajs/deps/mikro-orm/postgresql"
18+ import { BigNumberRawValue } from "@medusajs/types"
1819import BigNumber from "bignumber.js"
1920import { dropDatabase } from "pg-god"
2021import { MikroOrmBigNumberProperty } from "../../big-number-field"
2122import { mikroOrmBaseRepositoryFactory } from "../../mikro-orm-repository"
23+ import { mikroOrmSoftDeletableFilterOptions } from "../../mikro-orm-soft-deletable-filter"
2224import { getDatabaseURL , pgGodCredentials } from "../__fixtures__/database"
2325
2426const dbName = "mikroorm-integration-1"
2527
2628jest . setTimeout ( 300000 )
29+ @Filter ( mikroOrmSoftDeletableFilterOptions )
2730@Entity ( )
2831class Entity1 {
2932 @PrimaryKey ( )
@@ -243,6 +246,45 @@ class Entity6 {
243246 }
244247}
245248
249+ // Entity with a non-nullable foreign key
250+ @Entity ( )
251+ class Entity7 {
252+ @PrimaryKey ( )
253+ id : string
254+
255+ @Property ( )
256+ title : string
257+
258+ @Unique ( )
259+ @Property ( )
260+ handle : string
261+
262+ @Property ( { nullable : true } )
263+ deleted_at : Date | null
264+
265+ @ManyToOne ( ( ) => Entity1 , {
266+ columnType : "text" ,
267+ nullable : false ,
268+ mapToPk : true ,
269+ fieldName : "entity1_id" ,
270+ deleteRule : "set null" ,
271+ } )
272+ entity1_id : string
273+
274+ @ManyToOne ( ( ) => Entity1 , { persist : false , nullable : false } )
275+ entity1 : Entity1 | null
276+
277+ @OnInit ( )
278+ @BeforeCreate ( )
279+ onInit ( ) {
280+ if ( ! this . id ) {
281+ this . id = Math . random ( ) . toString ( 36 ) . substring ( 7 )
282+ }
283+
284+ this . entity1_id ??= this . entity1 ?. id !
285+ }
286+ }
287+
246288// Entity whose primary key is a custom (non-id) column
247289@Entity ( )
248290class CustomPkEntity {
@@ -278,6 +320,7 @@ const Entity3Repository = mikroOrmBaseRepositoryFactory(Entity3)
278320const Entity4Repository = mikroOrmBaseRepositoryFactory ( Entity4 )
279321const Entity5Repository = mikroOrmBaseRepositoryFactory ( Entity5 )
280322const Entity6Repository = mikroOrmBaseRepositoryFactory ( Entity6 )
323+ const Entity7Repository = mikroOrmBaseRepositoryFactory ( Entity7 )
281324const CustomPkEntityRepository = mikroOrmBaseRepositoryFactory ( CustomPkEntity )
282325const CompositePkEntityRepository =
283326 mikroOrmBaseRepositoryFactory ( CompositePkEntity )
@@ -301,6 +344,9 @@ describe("mikroOrmRepository", () => {
301344 const manager5 = ( ) => {
302345 return new Entity5Repository ( { manager : manager . fork ( ) } )
303346 }
347+ const manager7 = ( ) => {
348+ return new Entity7Repository ( { manager : manager . fork ( ) } )
349+ }
304350 // @ts -expect-error
305351 const manager6 = ( ) => {
306352 return new Entity6Repository ( { manager : manager . fork ( ) } )
@@ -327,10 +373,14 @@ describe("mikroOrmRepository", () => {
327373 Entity4 ,
328374 Entity5 ,
329375 Entity6 ,
376+ Entity7 ,
330377 CustomPkEntity ,
331378 CompositePkEntity ,
332379 ] ,
333380 clientUrl : getDatabaseURL ( dbName ) ,
381+ // Match Medusa's production config: soft-delete filters are not
382+ // auto-joined onto referenced entities unless they are populated.
383+ autoJoinRefsForFilters : false ,
334384 } )
335385 )
336386
@@ -390,6 +440,33 @@ describe("mikroOrmRepository", () => {
390440 expect ( updatedEntity1 [ 0 ] . entity3 . getItems ( ) ) . toHaveLength ( 0 )
391441 } )
392442
443+ it ( "should return rows even when a populated relation is soft-deleted" , async ( ) => {
444+ await manager1 ( ) . upsertWithReplace ( [ { id : "1" , title : "en1" } ] )
445+ await manager7 ( ) . upsertWithReplace ( [
446+ { id : "2" , title : "en2" , handle : "handle-2" , entity1 : { id : "1" } } ,
447+ { id : "3" , title : "en3" , handle : "handle-3" , entity1 : { id : "1" } } ,
448+ ] )
449+
450+ const softDeleteManager = orm . em . fork ( )
451+ await new Entity1Repository ( { manager : softDeleteManager } ) . softDelete (
452+ [ "1" ] ,
453+ { transactionManager : softDeleteManager }
454+ )
455+ await softDeleteManager . flush ( )
456+
457+ const afterSoftDelete = await manager7 ( ) . find ( {
458+ where : { } ,
459+ options : {
460+ fields : [ "entity1.id" ] ,
461+ } ,
462+ } )
463+ expect ( afterSoftDelete ) . toHaveLength ( 2 )
464+ expect ( afterSoftDelete [ 0 ] . id ) . toBe ( "2" )
465+ expect ( afterSoftDelete [ 0 ] . entity1 ) . toBeNull ( )
466+ expect ( afterSoftDelete [ 1 ] . id ) . toBe ( "3" )
467+ expect ( afterSoftDelete [ 1 ] . entity1 ) . toBeNull ( )
468+ } )
469+
393470 describe ( "upsert with replace" , ( ) => {
394471 it ( "should successfully create a flat entity" , async ( ) => {
395472 const entity1 = { id : "1" , title : "en1" , amount : 100 }
@@ -1690,7 +1767,7 @@ describe("mikroOrmRepository", () => {
16901767 expect ( e5InsertCalls ) . toBe ( 2 ) // One batch insert for Entity5s, one for Entity6s
16911768
16921769 // Check that the expected batch sizes exist (order may vary)
1693- const e5BatchSizes = qbInsertSpy . mock . calls . map ( call => call [ 0 ] . length )
1770+ const e5BatchSizes = qbInsertSpy . mock . calls . map ( ( call ) => call [ 0 ] . length )
16941771 expect ( e5BatchSizes ) . toContain ( 800 ) // entity5 25 * 8 * 4
16951772 expect ( e5BatchSizes ) . toContain ( 2400 ) // entity6 25 * 8 * 4 * 3
16961773
@@ -1722,7 +1799,7 @@ describe("mikroOrmRepository", () => {
17221799 expect ( e3InsertCalls ) . toBe ( 3 ) // One batch insert for Entity3s, one for Entity4s and one pivot entity3 -> entity5
17231800
17241801 // Check that the expected batch sizes exist (order may vary)
1725- const e3BatchSizes = qbInsertSpy . mock . calls . map ( call => call [ 0 ] . length )
1802+ const e3BatchSizes = qbInsertSpy . mock . calls . map ( ( call ) => call [ 0 ] . length )
17261803 expect ( e3BatchSizes ) . toContain ( 200 ) // entity3: 25 * 8
17271804 expect ( e3BatchSizes ) . toContain ( 800 ) // pivot entity3 -> entity5: 25 * 8 * 4
17281805 expect ( e3BatchSizes ) . toContain ( 1000 ) // entity4: 25 * 8 * 5
@@ -1753,7 +1830,9 @@ describe("mikroOrmRepository", () => {
17531830 expect ( mainInsertCalls ) . toBe ( 3 ) // One batch insert for Entity1s, one for Entity2s, one for Entity3s
17541831
17551832 // Check that the expected batch sizes exist (order may vary)
1756- const mainBatchSizes = qbInsertSpy . mock . calls . map ( call => call [ 0 ] . length )
1833+ const mainBatchSizes = qbInsertSpy . mock . calls . map (
1834+ ( call ) => call [ 0 ] . length
1835+ )
17571836 expect ( mainBatchSizes ) . toContain ( 25 ) // entity1: 25
17581837 expect ( mainBatchSizes ) . toContain ( 200 ) // entity3: 25 * 8
17591838 expect ( mainBatchSizes ) . toContain ( 250 ) // entity2: 25 * 10
@@ -1833,7 +1912,9 @@ describe("mikroOrmRepository", () => {
18331912 // Should use batch inserts for new entities and pivot relationships
18341913 expect ( updateInsertCalls ) . toBe ( 2 ) // pivot Entity1 - Entity3 (with conflict resolution) + new Entity2s
18351914 // Check that the expected batch sizes exist (order may vary)
1836- const updateBatchSizes = qbInsertSpy . mock . calls . map ( call => call [ 0 ] . length )
1915+ const updateBatchSizes = qbInsertSpy . mock . calls . map (
1916+ ( call ) => call [ 0 ] . length
1917+ )
18371918 expect ( updateBatchSizes ) . toContain ( 100 ) // pivot Entity1 - Entity3: 25 parents × 4 entity3s each (uses onConflict().ignore())
18381919 expect ( updateBatchSizes ) . toContain ( 50 ) // New Entity2s: 25 parents × 2 new each
18391920
0 commit comments