11package dev.helight.krescent.exposed
22
3+ import dev.helight.krescent.event.EventMessage
34import dev.helight.krescent.source.EventPublisher
45import dev.helight.krescent.source.StreamingEventSource
56import dev.helight.krescent.test.StreamingEventSourceContract
67import kotlinx.coroutines.CoroutineScope
78import kotlinx.coroutines.delay
9+ import kotlinx.coroutines.flow.toList
810import kotlinx.coroutines.runBlocking
11+ import kotlinx.serialization.json.buildJsonObject
12+ import kotlinx.serialization.json.put
913import org.jetbrains.exposed.sql.Database
1014import org.testcontainers.containers.GenericContainer
1115import org.testcontainers.junit.jupiter.Container
1216import org.testcontainers.junit.jupiter.Testcontainers
1317import java.time.Duration
1418import java.util.*
19+ import kotlin.test.Test
20+ import kotlin.test.assertEquals
1521
1622@Testcontainers
1723class PostgresStreamingSource : StreamingEventSourceContract {
@@ -35,20 +41,65 @@ class PostgresStreamingSource : StreamingEventSourceContract {
3541 )
3642 }
3743
44+ fun execWithTable (block : suspend CoroutineScope .(Database , KrescentTable ) -> Unit ) = runBlocking {
45+ val db = connect()
46+ val tableName = " krescent_${UUID .randomUUID()} "
47+ val table = KrescentTable (tableName)
48+ table.create(db)
49+ try {
50+ this .block(db, table)
51+ delay(300 )
52+ } finally {
53+ runCatching { table.drop(db) }
54+ }
55+ }
56+
3857 override fun execWithStreamingSource (block : suspend CoroutineScope .(StreamingEventSource , EventPublisher ) -> Unit ) =
39- runBlocking {
40- val db = connect()
41- val tableName = " krescent_${UUID .randomUUID()} "
42- val table = KrescentTable (tableName)
43- table.create(db)
58+ execWithTable { db, table ->
4459 val source = StreamingExposedEventSource (table, db, pollingDelay = 100L )
4560 val publisher = ExposedEventPublisher (table, db, " default" )
46- try {
47- this .block(source, publisher)
48- } finally {
49- runCatching { table.drop(db) }
50- }
51- delay(300 )
61+ this .block(source, publisher)
5262 }
5363
64+
65+ @Test
66+ fun `Like matching event stream` () = execWithTable { db, table ->
67+ ExposedEventPublisher (table, db, " user-ALICE-conversation-1" )
68+ .publish(EventMessage (type = " created" , payload = buildJsonObject { put(" number" , 1 ) }))
69+
70+ ExposedEventPublisher (table, db, " user-BOB-conversation-1" )
71+ .publish(EventMessage (type = " created" , payload = buildJsonObject { put(" number" , 2 ) }))
72+
73+ ExposedEventPublisher (table, db, " user-ALICE-conversation-2" )
74+ .publish(EventMessage (type = " created" , payload = buildJsonObject { put(" number" , 3 ) }))
75+
76+ val aliceEvents = StreamingExposedEventSource (table, db, " user-ALICE-conversation-%" , StreamIdMatcher .LIKE )
77+ .fetchEventsAfter().toList()
78+ val bobEvents = StreamingExposedEventSource (table, db, " user-BOB-conversation-%" , StreamIdMatcher .LIKE )
79+ .fetchEventsAfter().toList()
80+
81+ assertEquals(2 , aliceEvents.size)
82+ assertEquals(1 , bobEvents.size)
83+ }
84+
85+ @Test
86+ fun `Regex matching event stream` () = execWithTable { db, table ->
87+ ExposedEventPublisher (table, db, " user-ALICE-conversation-1" )
88+ .publish(EventMessage (type = " created" , payload = buildJsonObject { put(" number" , 1 ) }))
89+
90+ ExposedEventPublisher (table, db, " user-BOB-conversation-1" )
91+ .publish(EventMessage (type = " created" , payload = buildJsonObject { put(" number" , 2 ) }))
92+
93+ ExposedEventPublisher (table, db, " user-ALICE-conversation-2" )
94+ .publish(EventMessage (type = " created" , payload = buildJsonObject { put(" number" , 3 ) }))
95+
96+ val aliceEvents = StreamingExposedEventSource (table, db, " ^user-ALICE-conversation-.*" , StreamIdMatcher .REGEX )
97+ .fetchEventsAfter().toList()
98+ val bobEvents = StreamingExposedEventSource (table, db, " ^user-BOB-conversation-.*" , StreamIdMatcher .REGEX )
99+ .fetchEventsAfter().toList()
100+
101+ assertEquals(2 , aliceEvents.size)
102+ assertEquals(1 , bobEvents.size)
103+ }
104+
54105}
0 commit comments