Skip to content

Commit fb31205

Browse files
committed
Publish UserRegistered domain event
1 parent adb8ab4 commit fb31205

File tree

16 files changed

+111
-42
lines changed

16 files changed

+111
-42
lines changed

src/main/tv/codely/scala_http_api/entry_point/ScalaHttpApi.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ object ScalaHttpApi {
3131
implicit val executionContext: ExecutionContext = sharedDependencies.executionContext
3232

3333
val container = new EntryPointDependencyContainer(
34-
new UserModuleDependencyContainer(sharedDependencies.doobieDbConnection),
34+
new UserModuleDependencyContainer(sharedDependencies.doobieDbConnection, sharedDependencies.messagePublisher),
3535
new VideoModuleDependencyContainer(sharedDependencies.doobieDbConnection, sharedDependencies.messagePublisher)
3636
)
3737

src/main/tv/codely/scala_http_api/module/shared/infrastructure/marshaller/MessageJsonFormatMarshaller.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,22 @@ package tv.codely.scala_http_api.module.shared.infrastructure.marshaller
33
import spray.json._
44
import spray.json.{DefaultJsonProtocol, DeserializationException, JsString, JsValue, RootJsonFormat, SerializationException}
55
import tv.codely.scala_http_api.module.shared.domain.Message
6+
import tv.codely.scala_http_api.module.user.domain.UserRegistered
67
import tv.codely.scala_http_api.module.video.domain.VideoCreated
78
import tv.codely.scala_http_api.module.video.infrastructure.marshaller.VideoCreatedJsonFormatMarshaller._
9+
import tv.codely.scala_http_api.module.user.infrastructure.marshaller.UserRegisteredJsonFormatMarshaller._
810

911
object MessageJsonFormatMarshaller extends DefaultJsonProtocol {
1012
implicit object MessageMarshaller extends RootJsonFormat[Message] {
1113
override def write(m: Message): JsValue = m match {
12-
case vc: VideoCreated => vc.toJson
13-
case unknown => throw new SerializationException(s"Unknown message type to write <${unknown.getClass}>")
14+
case vc: VideoCreated => vc.toJson
15+
case ur: UserRegistered => ur.toJson
16+
case unknown => throw new SerializationException(s"Unknown message type to write <${unknown.getClass}>")
1417
}
1518

1619
override def read(jv: JsValue): Message = jv.asJsObject.getFields("type") match {
17-
case Seq(JsString("codelytv_scala_api.video_created")) => jv.convertTo[VideoCreated]
20+
case Seq(JsString("codelytv_scala_api.video_created")) => jv.convertTo[VideoCreated]
21+
case Seq(JsString("codelytv_scala_api.user_registered")) => jv.convertTo[UserRegistered]
1822
case Seq(JsString(unknown)) =>
1923
throw DeserializationException(s"Unknown message type to read <$unknown>")
2024
}
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package tv.codely.scala_http_api.module.user.application.register
22

3-
import tv.codely.scala_http_api.module.user.domain.{User, UserId, UserName, UserRepository}
3+
import tv.codely.scala_http_api.module.shared.domain.MessagePublisher
4+
import tv.codely.scala_http_api.module.user.domain._
45

5-
final class UserRegisterer(repository: UserRepository) {
6+
final class UserRegisterer(repository: UserRepository, publisher: MessagePublisher) {
67
def register(id: UserId, name: UserName): Unit = {
78
val user = User(id, name)
89

910
repository.save(user)
11+
12+
publisher.publish(UserRegistered(user))
1013
}
1114
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package tv.codely.scala_http_api.module.user.domain
2+
3+
import tv.codely.scala_http_api.module.shared.domain.Message
4+
5+
object UserRegistered {
6+
def apply(id: String, name: String): UserRegistered = apply(UserId(id), UserName(name))
7+
8+
def apply(user: User): UserRegistered = apply(user.id, user.name)
9+
}
10+
11+
final case class UserRegistered(id: UserId, name: UserName) extends Message {
12+
override val subType: String = "user_registered"
13+
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package tv.codely.scala_http_api.module.user.infrastructure.dependency_injection
22

3+
import tv.codely.scala_http_api.module.shared.domain.MessagePublisher
34
import tv.codely.scala_http_api.module.shared.infrastructure.persistence.doobie.DoobieDbConnection
45
import tv.codely.scala_http_api.module.user.application.register.UserRegisterer
56
import tv.codely.scala_http_api.module.user.application.search.UsersSearcher
@@ -9,10 +10,11 @@ import tv.codely.scala_http_api.module.user.infrastructure.repository.DoobieMySq
910
import scala.concurrent.ExecutionContext
1011

1112
final class UserModuleDependencyContainer(
12-
doobieDbConnection: DoobieDbConnection
13+
doobieDbConnection: DoobieDbConnection,
14+
messagePublisher: MessagePublisher
1315
)(implicit executionContext: ExecutionContext) {
1416
val repository: UserRepository = new DoobieMySqlUserRepository(doobieDbConnection)
1517

1618
val usersSearcher: UsersSearcher = new UsersSearcher(repository)
17-
val userRegisterer: UserRegisterer = new UserRegisterer(repository)
19+
val userRegisterer: UserRegisterer = new UserRegisterer(repository, messagePublisher)
1820
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package tv.codely.scala_http_api.module.user.infrastructure.marshaller
2+
3+
import java.util.UUID
4+
5+
import spray.json.{DefaultJsonProtocol, DeserializationException, JsString, JsValue, JsonFormat}
6+
import tv.codely.scala_http_api.module.shared.infrastructure.marshaller.UuidJsonFormatMarshaller._
7+
import tv.codely.scala_http_api.module.user.domain.{UserId, UserName}
8+
import spray.json._
9+
10+
object UserAttributesJsonFormatMarshaller extends DefaultJsonProtocol {
11+
implicit object UserIdMarshaller extends JsonFormat[UserId] {
12+
override def write(value: UserId): JsValue = value.value.toJson
13+
14+
override def read(value: JsValue): UserId = UserId(value.convertTo[UUID])
15+
}
16+
17+
implicit object UserNameMarshaller extends JsonFormat[UserName] {
18+
override def write(value: UserName): JsValue = JsString(value.value)
19+
20+
override def read(value: JsValue): UserName = value match {
21+
case JsString(name) => UserName(name)
22+
case _ => throw DeserializationException("Expected 1 string for UserName")
23+
}
24+
}
25+
}
Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,9 @@
11
package tv.codely.scala_http_api.module.user.infrastructure.marshaller
22

3-
import java.util.UUID
4-
5-
import spray.json.{DeserializationException, JsString, JsValue, JsonFormat, RootJsonFormat}
3+
import spray.json.{DefaultJsonProtocol, RootJsonFormat}
64
import tv.codely.scala_http_api.module.user.domain.{User, UserId, UserName}
7-
import tv.codely.scala_http_api.module.shared.infrastructure.marshaller.UuidJsonFormatMarshaller._
8-
import spray.json._
5+
import UserAttributesJsonFormatMarshaller._
96

107
object UserJsonFormatMarshaller extends DefaultJsonProtocol {
11-
implicit object UserIdMarshaller extends JsonFormat[UserId] {
12-
override def write(value: UserId): JsValue = value.value.toJson
13-
14-
override def read(value: JsValue): UserId = UserId(value.convertTo[UUID])
15-
}
16-
17-
implicit object UserNameMarshaller extends JsonFormat[UserName] {
18-
override def write(value: UserName): JsValue = JsString(value.value)
19-
20-
override def read(value: JsValue): UserName = value match {
21-
case JsString(name) => UserName(name)
22-
case _ => throw DeserializationException("Expected 1 string for UserName")
23-
}
24-
}
25-
268
implicit val userFormat: RootJsonFormat[User] = jsonFormat2(User.apply(_: UserId, _: UserName))
279
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package tv.codely.scala_http_api.module.user.infrastructure.marshaller
2+
3+
import spray.json.{DefaultJsonProtocol, DeserializationException, JsObject, JsString, JsValue, RootJsonFormat}
4+
import tv.codely.scala_http_api.module.user.domain.UserRegistered
5+
import UserAttributesJsonFormatMarshaller._
6+
import spray.json._
7+
8+
object UserRegisteredJsonFormatMarshaller extends DefaultJsonProtocol {
9+
implicit object UserRegisteredJsonFormat extends RootJsonFormat[UserRegistered] {
10+
override def write(ur: UserRegistered): JsValue = JsObject(
11+
"type" -> JsString(ur.`type`),
12+
"id" -> ur.id.toJson,
13+
"name" -> ur.name.toJson
14+
)
15+
16+
override def read(value: JsValue): UserRegistered =
17+
value.asJsObject.getFields("id", "name") match {
18+
case Seq(JsString(id), JsString(name)) => UserRegistered(id, name)
19+
case unknown => throw DeserializationException(s"Error reading VideoCreated JSON <$unknown>")
20+
}
21+
}
22+
}

src/main/tv/codely/scala_http_api/module/video/application/create/VideoCreator.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ final class VideoCreator(repository: VideoRepository, publisher: MessagePublishe
77
def create(id: VideoId, title: VideoTitle, duration: VideoDuration, category: VideoCategory): Unit = {
88
val video = Video(id, title, duration, category)
99

10-
publisher.publish(VideoCreated(video))
11-
1210
repository.save(video)
11+
12+
publisher.publish(VideoCreated(video))
1313
}
1414
}
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
package tv.codely.scala_http_api.module.shared.infrastructure.marshaller
1+
package tv.codely.scala_http_api.module.video.infrastructure.marshaller
22

33
import java.util.UUID
44

5-
import spray.json.{DeserializationException, JsNumber, JsString, JsValue, JsonFormat}
6-
import tv.codely.scala_http_api.module.video.domain._
5+
import spray.json.{DeserializationException, JsNumber, JsString, JsValue, JsonFormat, _}
76
import tv.codely.scala_http_api.module.shared.infrastructure.marshaller.UuidJsonFormatMarshaller._
8-
import spray.json._
7+
import tv.codely.scala_http_api.module.video.domain._
98

109
object VideoAttributesJsonFormatMarshaller {
1110
implicit object VideoIdMarshaller extends JsonFormat[VideoId] {

src/main/tv/codely/scala_http_api/module/video/infrastructure/marshaller/VideoCreatedJsonFormatMarshaller.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package tv.codely.scala_http_api.module.video.infrastructure.marshaller
22

33
import spray.json.{DefaultJsonProtocol, DeserializationException, JsString, JsValue, RootJsonFormat}
44
import tv.codely.scala_http_api.module.video.domain._
5-
import tv.codely.scala_http_api.module.shared.infrastructure.marshaller.VideoAttributesJsonFormatMarshaller._
5+
import VideoAttributesJsonFormatMarshaller._
66
import spray.json._
77

88
object VideoCreatedJsonFormatMarshaller extends DefaultJsonProtocol {

src/main/tv/codely/scala_http_api/module/video/infrastructure/marshaller/VideoJsonFormatMarshaller.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package tv.codely.scala_http_api.module.video.infrastructure.marshaller
22

33
import spray.json.{DefaultJsonProtocol, RootJsonFormat}
4-
import tv.codely.scala_http_api.module.shared.infrastructure.marshaller.VideoAttributesJsonFormatMarshaller._
4+
import VideoAttributesJsonFormatMarshaller._
55
import tv.codely.scala_http_api.module.video.domain._
66

77
object VideoJsonFormatMarshaller extends DefaultJsonProtocol {

src/test/tv/codely/scala_http_api/entry_point/AcceptanceSpec.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ protected[entry_point] abstract class AcceptanceSpec
2525

2626
private val sharedDependencies = new SharedModuleDependencyContainer(actorSystemName, dbConfig, publisherConfig)
2727

28-
protected val userDependencies = new UserModuleDependencyContainer(sharedDependencies.doobieDbConnection)
28+
protected val userDependencies = new UserModuleDependencyContainer(
29+
sharedDependencies.doobieDbConnection,
30+
sharedDependencies.messagePublisher
31+
)
2932
protected val videoDependencies = new VideoModuleDependencyContainer(
3033
sharedDependencies.doobieDbConnection,
3134
sharedDependencies.messagePublisher

src/test/tv/codely/scala_http_api/module/user/UserIntegrationTestCase.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import tv.codely.scala_http_api.module.user.domain.UserRepository
55
import tv.codely.scala_http_api.module.user.infrastructure.dependency_injection.UserModuleDependencyContainer
66

77
protected[user] trait UserIntegrationTestCase extends IntegrationTestCase {
8-
private val container = new UserModuleDependencyContainer(doobieDbConnection)
8+
private val container = new UserModuleDependencyContainer(doobieDbConnection, messagePublisher)
99

1010
protected val repository: UserRepository = container.repository
1111
}
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
package tv.codely.scala_http_api.module.user.application.register
22

3+
import tv.codely.scala_http_api.module.shared.infrastructure.MessagePublisherMock
34
import tv.codely.scala_http_api.module.user.UserUnitTestCase
4-
import tv.codely.scala_http_api.module.user.domain.UserStub
5+
import tv.codely.scala_http_api.module.user.domain.{UserRegisteredStub, UserStub}
56

6-
final class UserRegistererShould extends UserUnitTestCase {
7-
private val registerer = new UserRegisterer(repository)
7+
final class UserRegistererShould extends UserUnitTestCase with MessagePublisherMock {
8+
private val registerer = new UserRegisterer(repository, messagePublisher)
89

9-
"save a user" in {
10+
"register a user" in {
1011
val user = UserStub.random
12+
val userRegistered = UserRegisteredStub(user)
1113

1214
repositoryShouldSave(user)
1315

16+
publisherShouldPublish(userRegistered)
17+
1418
registerer.register(user.id, user.name).shouldBe(())
1519
}
1620
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package tv.codely.scala_http_api.module.user.domain
2+
3+
object UserRegisteredStub {
4+
def apply(
5+
id: UserId = UserIdStub.random,
6+
name: UserName = UserNameStub.random
7+
): UserRegistered = UserRegistered(id, name)
8+
9+
def apply(user: User): UserRegistered = apply(user.id, user.name)
10+
11+
def random: UserRegistered = apply()
12+
}

0 commit comments

Comments
 (0)