Skip to content

Commit d712594

Browse files
committed
Began work on many-to-many tests
1 parent 3662060 commit d712594

File tree

2 files changed

+227
-0
lines changed

2 files changed

+227
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.beeproduced.datasource.test.manytomany
2+
3+
import com.beeproduced.bee.persistent.blaze.BeeBlazeRepository
4+
import com.beeproduced.bee.persistent.blaze.annotations.BeeRepository
5+
import jakarta.persistence.*
6+
import java.io.Serializable
7+
8+
/**
9+
*
10+
*
11+
* @author Kacper Urbaniec
12+
* @version 2024-01-15
13+
*/
14+
15+
@Entity
16+
@Table(name = "foos")
17+
data class Foo(
18+
@Id
19+
@GeneratedValue
20+
val id: Long = -1,
21+
@ManyToMany(fetch = FetchType.LAZY, cascade = [CascadeType.DETACH])
22+
@JoinTable(
23+
name = "foo_bar_relations",
24+
joinColumns = [JoinColumn(name = "foo")],
25+
inverseJoinColumns = [JoinColumn(name = "bar")]
26+
)
27+
// Use sets instead of lists to allow fetching multiple collections eagerly at once
28+
// to omit "MultipleBagFetchException - cannot simultaneously fetch multiple bags"
29+
// https://stackoverflow.com/a/4335514/12347616
30+
val bars: Set<Bar>? = null
31+
)
32+
33+
34+
@BeeRepository
35+
interface FooRepository : BeeBlazeRepository<Foo, Long>
36+
37+
@Entity
38+
@Table(name = "bars")
39+
data class Bar(
40+
@Id
41+
@GeneratedValue
42+
val id: Long = -1,
43+
@ManyToMany(mappedBy="bars", fetch = FetchType.LAZY, cascade = [CascadeType.DETACH])
44+
val foos: Set<Foo>? = null
45+
)
46+
47+
@BeeRepository
48+
interface BarRepository : BeeBlazeRepository<Bar, Long>
49+
50+
@Embeddable
51+
data class FooBarId(
52+
val foo: Long = -1,
53+
val bar: Long = -1,
54+
) : Serializable
55+
56+
@Entity
57+
@Table(name = "foo_bar_relations")
58+
data class FooBarRelation(
59+
@EmbeddedId
60+
val id: FooBarId
61+
)
62+
63+
@BeeRepository
64+
interface FooBarRepository : BeeBlazeRepository<FooBarRelation, FooBarId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package com.beeproduced.bee.persistent.test.base
2+
3+
import com.beeproduced.datasource.a.FooBar
4+
import com.beeproduced.datasource.test.dsl.BarDSL
5+
import com.beeproduced.datasource.test.dsl.FooDSL
6+
import com.beeproduced.datasource.test.manytomany.*
7+
import jakarta.persistence.EntityManager
8+
import org.junit.jupiter.api.AfterEach
9+
import org.junit.jupiter.api.BeforeAll
10+
import org.junit.jupiter.api.TestInstance
11+
import org.junit.jupiter.api.extension.ExtendWith
12+
import org.springframework.beans.factory.annotation.Autowired
13+
import org.springframework.beans.factory.annotation.Qualifier
14+
import org.springframework.boot.test.context.SpringBootTest
15+
import org.springframework.test.context.TestPropertySource
16+
import org.springframework.test.context.junit.jupiter.SpringExtension
17+
import org.springframework.transaction.PlatformTransactionManager
18+
import org.springframework.transaction.support.TransactionTemplate
19+
import kotlin.test.Test
20+
import kotlin.test.assertEquals
21+
import kotlin.test.assertNotNull
22+
import kotlin.test.assertTrue
23+
24+
/**
25+
*
26+
*
27+
* @author Kacper Urbaniec
28+
* @version 2024-01-15
29+
*/
30+
@ExtendWith(SpringExtension::class)
31+
@SpringBootTest(classes = [BaseTestConfig::class])
32+
@TestPropertySource("classpath:application.properties")
33+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
34+
class ManyToManyTest(
35+
@Qualifier("testEM")
36+
val em: EntityManager,
37+
@Qualifier("testTM")
38+
transactionManager: PlatformTransactionManager,
39+
@Autowired
40+
val fooRepo: FooRepository,
41+
@Autowired
42+
val barRepo: BarRepository,
43+
@Autowired
44+
val fooBarRepo: FooBarRepository
45+
) {
46+
private val transaction = TransactionTemplate(transactionManager)
47+
48+
@BeforeAll
49+
fun beforeAll() = clear()
50+
51+
@AfterEach
52+
fun afterEach() = clear()
53+
54+
fun clear() = transaction.executeWithoutResult {
55+
fooBarRepo.cbf.delete(em, FooBarRelation::class.java)
56+
fooRepo.cbf.delete(em, Foo::class.java).executeUpdate()
57+
barRepo.cbf.delete(em, Bar::class.java).executeUpdate()
58+
}
59+
60+
@Test
61+
fun `add relation`() {
62+
var barId: Long = -1
63+
var foo1Id: Long = -1
64+
var foo2Id: Long = -1
65+
var foo3Id: Long = -1
66+
67+
transaction.executeWithoutResult {
68+
val bar = barRepo.persist(Bar())
69+
barId = bar.id
70+
val foo1 = fooRepo.persist(Foo())
71+
foo1Id = foo1.id
72+
val foo2 = fooRepo.persist(Foo())
73+
foo2Id = foo2.id
74+
val foo3 = fooRepo.persist(Foo())
75+
foo3Id = foo3.id
76+
}
77+
78+
transaction.executeWithoutResult {
79+
val bars = barRepo.select()
80+
assertEquals(1, bars.count())
81+
val foos = fooRepo.select()
82+
assertEquals(3, foos.count())
83+
}
84+
85+
transaction.executeWithoutResult {
86+
fooBarRepo.persist(FooBarRelation(FooBarId(foo1Id, barId)))
87+
}
88+
89+
val barSelection = BarDSL.select { this.foos { this.bars { this.foos { } } } }
90+
val fooSelection = FooDSL.select { this.bars { this.foos { this.bars { } } } }
91+
transaction.executeWithoutResult {
92+
val bar = barRepo.select(barSelection) {
93+
where(BarDSL.id.eq(barId))
94+
}.firstOrNull()
95+
assertNotNull(bar)
96+
assertBar(bar, setOf(barId), setOf(foo1Id), 3)
97+
val foo1 = fooRepo.select(fooSelection) {
98+
where(FooDSL.id.eq(foo1Id))
99+
}.firstOrNull()
100+
assertNotNull(foo1)
101+
assertFoo(foo1, setOf(foo1Id), setOf(barId), 3)
102+
val foo2 = fooRepo.select(fooSelection) {
103+
where(FooDSL.id.eq(foo2Id))
104+
}.firstOrNull()
105+
assertNotNull(foo2)
106+
assertFoo(foo2, setOf(foo2Id), emptySet(), 3)
107+
}
108+
109+
transaction.executeWithoutResult {
110+
fooBarRepo.persist(FooBarRelation(FooBarId(foo2Id, barId)))
111+
}
112+
113+
transaction.executeWithoutResult {
114+
val bar = barRepo.select(barSelection) {
115+
where(BarDSL.id.eq(barId))
116+
}.firstOrNull()
117+
assertNotNull(bar)
118+
assertBar(bar, setOf(barId), setOf(foo1Id, foo2Id), 3)
119+
val foo1 = fooRepo.select(fooSelection) {
120+
where(FooDSL.id.eq(foo1Id))
121+
}.firstOrNull()
122+
assertNotNull(foo1)
123+
assertFoo(foo1, setOf(foo1Id, foo2Id), setOf(barId), 3)
124+
val foo2 = fooRepo.select(fooSelection) {
125+
where(FooDSL.id.eq(foo2Id))
126+
}.firstOrNull()
127+
assertNotNull(foo2)
128+
assertFoo(foo2, setOf(foo2Id, foo1Id), setOf(barId), 3)
129+
}
130+
}
131+
132+
133+
private fun assertBar(
134+
bar: Bar, barIds: Set<Long>, fooIds: Set<Long>, depth: Int
135+
) {
136+
assertTrue { barIds.contains(bar.id) }
137+
val foos = bar.foos
138+
if (depth == 0) {
139+
assertTrue { foos.isNullOrEmpty() }
140+
return
141+
}
142+
143+
assertNotNull(foos)
144+
for (foo in foos)
145+
assertFoo(foo, fooIds, barIds, depth - 1)
146+
}
147+
148+
private fun assertFoo(
149+
foo: Foo, fooIds: Set<Long>, barIds: Set<Long>, depth: Int
150+
) {
151+
assertTrue { fooIds.contains(foo.id) }
152+
val bars = foo.bars
153+
if (depth == 0) {
154+
assertTrue { bars.isNullOrEmpty() }
155+
return
156+
}
157+
158+
assertNotNull(bars)
159+
for (bar in bars)
160+
assertBar(bar, barIds, fooIds, depth - 1)
161+
}
162+
163+
}

0 commit comments

Comments
 (0)