https://github.com/j5ik2o/scala-ddd-base
scala-ddd-base provides traits to support for ddd repositories and aggregates.
https://github.com/j5ik2o/scala-ddd-base
ddd scala
Last synced: 4 months ago
JSON representation
scala-ddd-base provides traits to support for ddd repositories and aggregates.
- Host: GitHub
- URL: https://github.com/j5ik2o/scala-ddd-base
- Owner: j5ik2o
- License: mit
- Created: 2017-06-20T13:06:37.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2023-12-15T05:14:29.000Z (about 2 years ago)
- Last Synced: 2025-03-22T10:23:13.723Z (9 months ago)
- Topics: ddd, scala
- Language: Scala
- Homepage:
- Size: 2.54 MB
- Stars: 44
- Watchers: 4
- Forks: 8
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# scala-ddd-base
[](https://circleci.com/gh/j5ik2o/scala-ddd-base/tree/master)
[](https://maven-badges.herokuapp.com/maven-central/com.github.j5ik2o/scala-ddd-base-core_2.12)
[](http://javadoc-badge.appspot.com/com.github.j5ik2o/scala-ddd-base-core_2.12/com/github/j5ik2o/dddbase/index.html?javadocio=true)
[](LICENSE)
`scala-ddd-base` provides traits to support for ddd repositories and aggregates.
## Installation
Add the following to your sbt build (Scala 2.11.x, 2.12.x):
```scala
resolvers += "Sonatype OSS Release Repository" at "https://oss.sonatype.org/content/repositories/releases/"
val scalaDddBaseVersion = "..."
libraryDependencies ++= Seq(
"com.github.j5ik2o" %% "scala-ddd-base-core" % scalaDddBaseVersion,
// Please set as necessary
// "com.github.j5ik2o" %% "scala-ddd-base-slick" % scalaDddBaseVersion,
// "com.github.j5ik2o" %% "scala-ddd-base-skinny" % scalaDddBaseVersion,
// "com.github.j5ik2o" %% "scala-ddd-base-redis" % scalaDddBaseVersion,
// "com.github.j5ik2o" %% "scala-ddd-base-memcached" % scalaDddBaseVersion,
// "com.github.j5ik2o" %% "scala-ddd-base-dynamodb" % scalaDddBaseVersion,
// "com.github.j5ik2o" %% "scala-ddd-base-memory" % scalaDddBaseVersion
)
```
## Core traits
The following provides basic abstract methods.
- AggregateSingleReader
- AggregateSingleWriter
- AggregateMultiReader
- AggregateMultiWriter
- AggregateSingleSoftDeletable
- AggregateSingleHardDeletable
- AggregateMultiSoftDeletable
- AggregateMultiHardDeletable
## Support traits
The following provides an implementation for each ORM/KVS.
- AggregateSingleReadFeature
- AggregateSingleWriteFeature
- AggregateMultiReadFeature
- AggregateMultiWriteFeature
- AggregateSingleSoftDeleteFeature
- AggregateSingleHardDeleteFeature
- AggregateMultiSoftDeleteFeature
- AggregateMultiHardDeleteFeature
The supported ORM/KVS/Cache is below.
- Slick(JDBC)
- SkinnyORM(JDBC)
- Redis([reactive-redis](https://github.com/j5ik2o/reactive-redis))
- Memcached([reactive-memcached](https://github.com/j5ik2o/reactive-memcached))
- DynamoDB([reactive-aws-dynamodb](https://github.com/j5ik2o/reactive-aws-client/tree/master/reactive-aws-dynamodb))
- Memory([Guava Cache](https://github.com/google/guava))
## Example
Please mix in the core and support traits to your implementation.
Slick, SkinnyORM, Memcached, Redis, Memory etc. You can also choose the implementation as you like.
```scala
trait UserAccountRepository[M[_]]
extends AggregateSingleReader[M]
with AggregateMultiReader[M]
with AggregateSingleWriter[M]
with AggregateMultiWriter[M]
with AggregateSingleSoftDeletable[M]
with AggregateMultiSoftDeletable[M] {
override type IdType = UserAccountId
override type AggregateType = UserAccount
}
object UserAccountRepository {
type OnRedis[A] = ReaderT[Task, RedisConnection, A]
type OnMemcached[A] = ReaderT[Task, MemcachedConnection, A]
type OnDynamoDB[A] = Task[A]
type OnMemory[A] = Task[A]
type BySlick[A] = Task[A]
type BySkinny[A] = ReaderT[Task, DBSession, A]
type ByFree[A] = Free[UserRepositoryDSL, A]
def bySlick(profile: JdbcProfile, db: JdbcProfile#Backend#Database): UserAccountRepository[BySlick] =
new UserAccountRepositoryBySlick(profile, db)
def bySkinny: UserAccountRepository[BySkinny] = new UserAccountRepositoryBySkinny
def onRedis(
expireDuration: Duration
)(implicit actorSystem: ActorSystem): UserAccountRepository[OnRedis] =
new UserAccountRepositoryOnRedis(expireDuration)
def onMemcached(
expireDuration: Duration
)(implicit actorSystem: ActorSystem): UserAccountRepository[OnMemcached] =
new UserAccountRepositoryOnMemcached(expireDuration)
def onDynamoDB(dynamoDbAsyncClient: DynamoDbAsyncClient): UserAccountRepository[OnDynamoDB] =
new UserAccountRepositoryOnDynamoDB(DynamoDBTaskClientV2(DynamoDBAsyncClientV2(underlying))
def onMemory(minSize: Option[Int] = None,
maxSize: Option[Int] = None,
expireDuration: Option[Duration] = None,
concurrencyLevel: Option[Int] = None,
maxWeight: Option[Int] = None): UserAccountRepository[OnMemory] =
new UserAccountRepositoryOnMemory(minSize, maxSize, expireDuration, concurrencyLevel, maxWeight)
}
```
- [for Slick3](example/src/main/scala/com/github/j5ik2o/dddbase/example/repository/slick/UserAccountRepositoryBySlick.scala)
- [for SkinnyORM](example/src/main/scala/com/github/j5ik2o/dddbase/example/repository/skinny/UserAccountRepositoryBySkinny.scala)
- [for Memcached](example/src/main/scala/com/github/j5ik2o/dddbase/example/repository/memcached/UserAccountRepositoryOnMemcached.scala)
- [for Redis](example/src/main/scala/com/github/j5ik2o/dddbase/example/repository/redis/UserAccountRepositoryOnRedis.scala)
- [for DynamoDB](example/src/main/scala/com/github/j5ik2o/dddbase/example/repository/dynamodb/UserAccountRepositoryOnDynamoDB.scala)
- [for Memory(Guava Cache)](example/src/main/scala/com/github/j5ik2o/dddbase/example/repository/memory/UserAccountRepositoryOnMemory.scala)
- [for Free](example/src/main/scala/com/github/j5ik2o/dddbase/example/repository/free/UserAccountRepositoryByFree.scala)
### Usage
- for Slick3
```scala
val userAccountRepository: UserAccountRepository[BySlick] = UserAccountRepository.bySlick(dbConfig.profile, dbConfig.db)
val resultTask: Task[UserAccount] = for {
_ <- userAccountRepository.store(userAccount)
result <- userAccountRepository.resolveBy(userAccount.id)
} yield result
val resultFuture: Future[UserAccount] = resultTask.runToFuture
```
- for SkinnyORM
```scala
val userAccountRepository: UserAccountRepository[BySkinny] = UserAccountRepository.bySkinny
val resultTask: Task[UserAccount] = for {
_ <- userAccountRepository.store(userAccount)
result <- userAccountRepository.resolveBy(userAccount.id)
} yield result
val resultFuture: Future[UserAccount] = resultTask.run(AutoSession).runToFuture
```
- for Memcached
```scala
val userAccountRepository: UserAccountRepository[OnMemcached] = UserAccountRepository.onMemcached(expireDuration = 5 minutes)
val resultFuture: Future[UserAccount] = connectionPool
.withConnectionF { con =>
(for {
_ <- userAccountRepository.store(userAccount)
r <- userAccountRepository.resolveById(userAccount.id)
} yield r).run(con)
}
.runToFuture
```
- for Redis
```scala
val userAccountRepository: UserAccountRepository[OnRedis] = UserAccountRepository.onRedis(expireDuration = 5 minutes)
val resultFuture: Future[UserAccount] = connectionPool
.withConnectionF { con =>
(for {
_ <- userAccountRepository.store(userAccount)
r <- userAccountRepository.resolveById(userAccount.id)
} yield r).run(con)
}
.runToFuture
```
- for DynamoDB
```scala
val userAccountRepository: UserAccountRepository[OnDynamoDB] = UserAccountRepository.onDynamoDB(dynamoDbAsyncClient)
val resultFuture: Future[UserAccount] = (for {
_ <- userAccountRepository.store(userAccount)
r <- userAccountRepository.resolveById(userAccount.id)
} yield r).runToFuture
```
- for Memory(Guava Cache)
```scala
val userAccountRepository: UserAccountRepository[OnMemory] = UserAccountRepository.onMemory(expireAfterWrite = Some(5 minutes))
val resultFuture: Future[UserAccount] = (for {
_ <- repository.store(userAccount)
r <- repository.resolveById(userAccount.id)
} yield r).runToFuture
```
- for Free
```scala
val free: UserAccountRepository[ByFree] = UserAccountRepositoryByFree
val program: Free[UserRepositoryDSL, UserAccount] = for {
_ <- free.store(userAccount)
result <- free.resolveById(userAccount.id)
} yield result
val slick = UserAccountRepository.bySlick(dbConfig.profile, dbConfig.db)
val resultTask: Task[UserAccount] = UserAccountRepositoryOnFree.evaluate(slick)(program)
val resultFuture: Future[UserAccount] = evalResult.runToFuture
// if evaluation by skinny
// val skinny = UserAccountRepository.bySkinny
// val resultTask: Task[UserAccount] = UserAccountRepositoryOnFree.evaluate(skinny)(program)
// val resultFuture: Future[UserAccount] = evalResult.run(AutoSession).runToFuture
```