Compare commits
6 commits
efa65652d2
...
bed837db76
Author | SHA1 | Date | |
---|---|---|---|
|
bed837db76 | ||
![]() |
c1099c97f9 | ||
![]() |
310b3961ad | ||
![]() |
a478d5dccf | ||
![]() |
32ce6be392 | ||
![]() |
0d872fc382 |
23
.github/workflows/scala.yml
vendored
Normal file
23
.github/workflows/scala.yml
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
name: Scala CI
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- 'homework/*'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- 'homework/*'
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Run tests
|
||||||
|
run: sbt test
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Formatting
|
||||||
|
run: sbt scalafmtCheck test:scalafmtCheck
|
8
.scalafmt.conf
Normal file
8
.scalafmt.conf
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
maxColumn = 120
|
||||||
|
runner.dialect = scala3
|
||||||
|
includeCurlyBraceInSelectChains = false
|
||||||
|
align.preset = more
|
||||||
|
version = "3.7.7"
|
||||||
|
rewrite.trailingCommas.style = keep
|
||||||
|
newlines.penalizeSingleSelectMultiArgList = false
|
||||||
|
newlines.alwaysBeforeMultilineDef = false
|
16
build.sbt
Normal file
16
build.sbt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
ThisBuild / version := "0.1.0"
|
||||||
|
|
||||||
|
ThisBuild / scalaVersion := "3.2.1"
|
||||||
|
|
||||||
|
libraryDependencies ++= Seq(
|
||||||
|
"com.typesafe.akka" %% "akka-stream" % "2.8.2",
|
||||||
|
"co.fs2" %% "fs2-core" % "3.7.0",
|
||||||
|
"org.typelevel" %% "cats-effect" % "3.5.2",
|
||||||
|
"org.typelevel" %% "cats-mtl" % "1.3.1",
|
||||||
|
"org.scalatest" %% "scalatest" % "3.2.15" % "test"
|
||||||
|
)
|
||||||
|
|
||||||
|
scalacOptions := List("-Ykind-projector")
|
||||||
|
|
||||||
|
lazy val lang = (project in file("."))
|
||||||
|
.settings(name := "bachelor-homeworks")
|
1
project/build.properties
Normal file
1
project/build.properties
Normal file
|
@ -0,0 +1 @@
|
||||||
|
sbt.version=1.6.2
|
1
project/plugins.sbt
Normal file
1
project/plugins.sbt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")
|
42
src/main/scala/hw/logger/Logger.scala
Normal file
42
src/main/scala/hw/logger/Logger.scala
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
//> using dep org.typelevel::cats-core:2.10.0
|
||||||
|
package hw.logger
|
||||||
|
|
||||||
|
import cats.{Monad, Monoid}
|
||||||
|
|
||||||
|
import scala.util.Try
|
||||||
|
import cats.data.WriterT
|
||||||
|
import cats.syntax.applicative.*
|
||||||
|
import cats.implicits.catsSyntaxApplicativeId
|
||||||
|
|
||||||
|
case class Debug(debug: String)
|
||||||
|
case class Info(info: String)
|
||||||
|
case class Error(error: String)
|
||||||
|
|
||||||
|
type WriterTF[F[_], L] = [A] =>> WriterT[F, L, A]
|
||||||
|
case class LogEmbed[F[_], A](value: WriterT[WriterTF[WriterTF[F, Vector[Debug]], Vector[Info]], Vector[Error], A])
|
||||||
|
|
||||||
|
final case class Logger[F[_]: Monad]():
|
||||||
|
|
||||||
|
def debug(debugMsg: String): LogEmbed[F, Unit] = {
|
||||||
|
val in = WriterT[F, Vector[Debug], (Vector[Info], (Vector[Error], Unit))](
|
||||||
|
Monad[F].pure((Vector(Debug(debugMsg)), (Vector.empty[Info], (Vector.empty[Error], ()))))
|
||||||
|
)
|
||||||
|
val iin = WriterT[WriterTF[F, Vector[Debug]], Vector[Info], (Vector[Error], Unit)](in)
|
||||||
|
LogEmbed(WriterT[WriterTF[WriterTF[F, Vector[Debug]], Vector[Info]], Vector[Error], Unit](iin))
|
||||||
|
}
|
||||||
|
|
||||||
|
def info(infoMsg: String): LogEmbed[F, Unit] = {
|
||||||
|
val in = WriterT[F, Vector[Debug], (Vector[Info], (Vector[Error], Unit))](
|
||||||
|
Monad[F].pure((Vector.empty[Debug], (Vector(Info(infoMsg)), (Vector.empty[Error], ()))))
|
||||||
|
)
|
||||||
|
val iin = WriterT[WriterTF[F, Vector[Debug]], Vector[Info], (Vector[Error], Unit)](in)
|
||||||
|
LogEmbed(WriterT[WriterTF[WriterTF[F, Vector[Debug]], Vector[Info]], Vector[Error], Unit](iin))
|
||||||
|
}
|
||||||
|
|
||||||
|
def error(errorMsg: String): LogEmbed[F, Unit] = {
|
||||||
|
val in = WriterT[F, Vector[Debug], (Vector[Info], (Vector[Error], Unit))](
|
||||||
|
Monad[F].pure((Vector.empty[Debug], (Vector.empty[Info], (Vector(Error(errorMsg)), ()))))
|
||||||
|
)
|
||||||
|
val iin = WriterT[WriterTF[F, Vector[Debug]], Vector[Info], (Vector[Error], Unit)](in)
|
||||||
|
LogEmbed(WriterT[WriterTF[WriterTF[F, Vector[Debug]], Vector[Info]], Vector[Error], Unit](iin))
|
||||||
|
}
|
19
src/main/scala/hw/traits/Ask.scala
Normal file
19
src/main/scala/hw/traits/Ask.scala
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package hw.traits
|
||||||
|
|
||||||
|
import cats.Monad
|
||||||
|
import cats.data.{Reader, ReaderT}
|
||||||
|
import cats.syntax.applicative.*
|
||||||
|
|
||||||
|
trait Ask[F[_], R]:
|
||||||
|
def ask: F[R]
|
||||||
|
|
||||||
|
object Ask:
|
||||||
|
def apply[F[_], R](using ask: Ask[F, R]): Ask[F, R] = ask
|
||||||
|
|
||||||
|
given [R]: Ask[Reader[R, *], R] =
|
||||||
|
new Ask[Reader[R, *], R]:
|
||||||
|
def ask: Reader[R, R] = Reader(identity)
|
||||||
|
|
||||||
|
given [F[_]: Monad, R]: Ask[ReaderT[F, R, *], R] =
|
||||||
|
new Ask[ReaderT[F, R, *], R]:
|
||||||
|
def ask: ReaderT[F, R, R] = ReaderT(r => r.pure[F])
|
21
src/main/scala/hw/traits/Tell.scala
Normal file
21
src/main/scala/hw/traits/Tell.scala
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package hw.traits
|
||||||
|
|
||||||
|
import cats.{Monad, Monoid}
|
||||||
|
import cats.data.{Writer, WriterT}
|
||||||
|
import cats.syntax.applicative.*
|
||||||
|
import cats.syntax.writer._
|
||||||
|
import cats.syntax.flatMap._
|
||||||
|
|
||||||
|
trait Tell[F[_], W]:
|
||||||
|
def tell(log: W): F[Unit]
|
||||||
|
|
||||||
|
object Tell:
|
||||||
|
def apply[F[_], W](using tell: Tell[F, W]): Tell[F, W] = tell
|
||||||
|
|
||||||
|
given [W: Monoid]: Tell[Writer[W, *], W] with
|
||||||
|
def tell(log: W): Writer[W, Unit] =
|
||||||
|
Writer(log, ())
|
||||||
|
|
||||||
|
given [F[_]: Monad, W: Monoid]: Tell[WriterT[F, W, *], W] with
|
||||||
|
def tell(log: W): WriterT[F, W, Unit] =
|
||||||
|
WriterT.tell[F, W](log)
|
20
src/main/scala/hw/user/User.scala
Normal file
20
src/main/scala/hw/user/User.scala
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package hw.user
|
||||||
|
|
||||||
|
type UserId = UserId.T
|
||||||
|
object UserId:
|
||||||
|
opaque type T <: Int = Int
|
||||||
|
def apply(i: Int): UserId = i
|
||||||
|
|
||||||
|
type UserName = UserName.T
|
||||||
|
object UserName:
|
||||||
|
opaque type T <: String = String
|
||||||
|
def apply(s: String): UserName = s
|
||||||
|
|
||||||
|
type Age = Age.T
|
||||||
|
object Age:
|
||||||
|
opaque type T <: Byte = Byte
|
||||||
|
val Adult: Age = 18.toByte
|
||||||
|
def apply(v: Byte): Age = v
|
||||||
|
|
||||||
|
final case class User(id: UserId, name: UserName, age: Age, friends: Set[UserId]):
|
||||||
|
def isAdult: Boolean = age >= Age.Adult
|
5
src/main/scala/hw/user/UserErrors.scala
Normal file
5
src/main/scala/hw/user/UserErrors.scala
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package hw.user
|
||||||
|
|
||||||
|
object UserErrors:
|
||||||
|
case class UserAlreadyExists(name: UserName) extends Throwable
|
||||||
|
case class UserDoesNotExists(id: UserId) extends Throwable
|
57
src/main/scala/hw/user/UserRepositoryDao.scala
Normal file
57
src/main/scala/hw/user/UserRepositoryDao.scala
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package hw.user
|
||||||
|
|
||||||
|
import cats.MonadThrow
|
||||||
|
import cats.mtl.Ask
|
||||||
|
import cats.syntax.applicativeError.*
|
||||||
|
import cats.syntax.applicative.*
|
||||||
|
import cats.syntax.flatMap.*
|
||||||
|
import cats.syntax.functor.*
|
||||||
|
import hw.user.UserErrors.*
|
||||||
|
|
||||||
|
case class Config(chunkSize: Int)
|
||||||
|
|
||||||
|
trait UserRepositoryDao:
|
||||||
|
def findAll(config: Config): List[User]
|
||||||
|
def create(name: UserName, age: Age, friends: Set[UserId] = Set.empty)(
|
||||||
|
config: Config
|
||||||
|
): Either[UserAlreadyExists, User]
|
||||||
|
def delete(userId: UserId)(config: Config): Either[UserDoesNotExists, Unit]
|
||||||
|
def update(user: User)(config: Config): Either[UserDoesNotExists, Unit]
|
||||||
|
|
||||||
|
trait UserRepository[F[_]]:
|
||||||
|
def findAll: F[List[User]]
|
||||||
|
def create(name: UserName, age: Age, friends: Set[UserId] = Set.empty): F[User]
|
||||||
|
def delete(userId: UserId): F[Unit]
|
||||||
|
def update(user: User): F[Unit]
|
||||||
|
|
||||||
|
object UserRepositoryDao:
|
||||||
|
def apply[F[_]: MonadThrow](dao: UserRepositoryDao)(using Ask[F, Config]): UserRepository[F] = new UserRepository[F]:
|
||||||
|
|
||||||
|
override def findAll: F[List[User]] =
|
||||||
|
Ask[F, Config].ask.flatMap { config =>
|
||||||
|
dao.findAll(config).pure[F]
|
||||||
|
}
|
||||||
|
|
||||||
|
override def create(name: UserName, age: Age, friends: Set[UserId] = Set.empty): F[User] =
|
||||||
|
Ask[F, Config].ask.flatMap { config =>
|
||||||
|
dao.create(name, age, friends)(config) match {
|
||||||
|
case Right(user) => user.pure[F]
|
||||||
|
case Left(error) => MonadThrow[F].raiseError[User](error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override def delete(userId: UserId): F[Unit] =
|
||||||
|
Ask[F, Config].ask.flatMap { config =>
|
||||||
|
dao.delete(userId)(config) match {
|
||||||
|
case Right(_) => ().pure[F]
|
||||||
|
case Left(error) => MonadThrow[F].raiseError[Unit](error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override def update(user: User): F[Unit] =
|
||||||
|
Ask[F, Config].ask.flatMap { config =>
|
||||||
|
dao.update(user)(config) match {
|
||||||
|
case Right(_) => ().pure[F]
|
||||||
|
case Left(error) => MonadThrow[F].raiseError[Unit](error)
|
||||||
|
}
|
||||||
|
}
|
37
src/test/scala/hw/logger/Logger.test.scala
Normal file
37
src/test/scala/hw/logger/Logger.test.scala
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package hw.logger
|
||||||
|
|
||||||
|
import cats.data.WriterT
|
||||||
|
import org.scalatest.flatspec.AnyFlatSpec
|
||||||
|
import org.scalatest.matchers.should.Matchers
|
||||||
|
|
||||||
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
|
class Tests extends AnyFlatSpec with Matchers:
|
||||||
|
def logEmbed(debug: Vector[String], info: Vector[String], error: Vector[String]): LogEmbed[Try, Unit] =
|
||||||
|
LogEmbed(
|
||||||
|
WriterT(WriterT(WriterT(Success((debug.map(Debug.apply), (info.map(Info.apply), (error.map(Error.apply), ())))))))
|
||||||
|
)
|
||||||
|
|
||||||
|
it should "info log" in {
|
||||||
|
val logger = Logger[Try]()
|
||||||
|
logger.info("info") shouldBe logEmbed(Vector.empty, Vector("info"), Vector.empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "debug log" in {
|
||||||
|
val logger = Logger[Try]()
|
||||||
|
logger.debug("debug") shouldBe logEmbed(Vector("debug"), Vector.empty, Vector.empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "error log" in {
|
||||||
|
val logger = Logger[Try]()
|
||||||
|
logger.error("error") shouldBe logEmbed(Vector.empty, Vector.empty, Vector("error"))
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "log everything" in {
|
||||||
|
val logger = Logger[Try]()
|
||||||
|
(for {
|
||||||
|
_ <- logger.info("info").value
|
||||||
|
_ <- logger.debug("debug").value
|
||||||
|
_ <- logger.error("error").value
|
||||||
|
} yield ()) shouldBe logEmbed(Vector("debug"), Vector("info"), Vector("error")).value
|
||||||
|
}
|
14
src/test/scala/hw/traits/Ask.test.scala
Normal file
14
src/test/scala/hw/traits/Ask.test.scala
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package hw.traits
|
||||||
|
|
||||||
|
import cats.data.{Reader, ReaderT}
|
||||||
|
import org.scalatest.flatspec.AnyFlatSpec
|
||||||
|
import org.scalatest.matchers.should.Matchers
|
||||||
|
|
||||||
|
class AskTests extends AnyFlatSpec with Matchers:
|
||||||
|
it should "create Ask[Reader] instance" in {
|
||||||
|
Ask[Reader[Int, *], Int].ask.run(42) shouldBe 42
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "create Ask[ReaderT] instance" in {
|
||||||
|
Ask[ReaderT[Option, Int, *], Int].ask.run(42) shouldBe Some(42)
|
||||||
|
}
|
14
src/test/scala/hw/traits/Tell.test.scala
Normal file
14
src/test/scala/hw/traits/Tell.test.scala
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package hw.traits
|
||||||
|
|
||||||
|
import cats.data.{Writer, WriterT}
|
||||||
|
import org.scalatest.flatspec.AnyFlatSpec
|
||||||
|
import org.scalatest.matchers.should.Matchers
|
||||||
|
|
||||||
|
class TellTests extends AnyFlatSpec with Matchers:
|
||||||
|
it should "create Tell[Writer] instance" in {
|
||||||
|
Tell[Writer[Int, *], Int].tell(42).run shouldBe (42, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "create Tell[WriterT] instance" in {
|
||||||
|
Tell[WriterT[Option, Int, *], Int].tell(42).run shouldBe Some((42, ()))
|
||||||
|
}
|
151
src/test/scala/hw/user/UserRepositoryDao.test.scala
Normal file
151
src/test/scala/hw/user/UserRepositoryDao.test.scala
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
package hw.user
|
||||||
|
|
||||||
|
import cats.mtl.Ask
|
||||||
|
import cats.{Applicative, MonadError, MonadThrow}
|
||||||
|
import hw.user.UserErrors.{UserAlreadyExists, UserDoesNotExists}
|
||||||
|
import org.scalatest.flatspec.AnyFlatSpec
|
||||||
|
import org.scalatest.matchers.should.Matchers
|
||||||
|
|
||||||
|
import scala.util.Random
|
||||||
|
|
||||||
|
object TestsData:
|
||||||
|
var lastConfig: Either[Unit, Config] = Left(())
|
||||||
|
val sampleUsers: List[User] = List(
|
||||||
|
User(UserId(0), UserName("Subject #0"), Age(42), Set.empty),
|
||||||
|
User(UserId(1), UserName("Subject #1"), Age(41), Set.empty),
|
||||||
|
User(UserId(2), UserName("Subject #2"), Age(40), Set.empty),
|
||||||
|
User(UserId(3), UserName("Subject #3"), Age(39), Set.empty),
|
||||||
|
User(UserId(4), UserName("Subject #4"), Age(38), Set.empty)
|
||||||
|
)
|
||||||
|
|
||||||
|
def dao(users: List[User]) = new UserRepositoryDao:
|
||||||
|
var usersList = users.toSet
|
||||||
|
|
||||||
|
override def findAll(config: Config): List[User] =
|
||||||
|
lastConfig = Right(config)
|
||||||
|
usersList.toList
|
||||||
|
|
||||||
|
override def create(name: UserName, age: Age, friends: Set[UserId])(
|
||||||
|
config: Config
|
||||||
|
): Either[UserAlreadyExists, User] =
|
||||||
|
lastConfig = Right(config)
|
||||||
|
if (usersList.exists(_.name == name)) Left(UserAlreadyExists(name))
|
||||||
|
else
|
||||||
|
val user = User(UserId(usersList.size), name, age, friends)
|
||||||
|
usersList += user
|
||||||
|
Right(user)
|
||||||
|
|
||||||
|
override def delete(userId: UserId)(config: Config): Either[UserDoesNotExists, Unit] =
|
||||||
|
lastConfig = Right(config)
|
||||||
|
if (usersList.exists(_.id == userId))
|
||||||
|
usersList -= usersList.find(_.id == userId).get
|
||||||
|
Right(())
|
||||||
|
else Left(UserDoesNotExists(userId))
|
||||||
|
|
||||||
|
override def update(user: User)(config: Config): Either[UserDoesNotExists, Unit] =
|
||||||
|
lastConfig = Right(config)
|
||||||
|
if (usersList.exists(_.id == user.id))
|
||||||
|
usersList -= usersList.find(_.id == user.id).get
|
||||||
|
usersList += user
|
||||||
|
Right(())
|
||||||
|
else Left(UserDoesNotExists(user.id))
|
||||||
|
|
||||||
|
type M = [A] =>> Config => Either[Throwable, A]
|
||||||
|
|
||||||
|
object M:
|
||||||
|
given MonadThrow[M] = new MonadError[M, Throwable]:
|
||||||
|
override def pure[A](x: A): M[A] = _ => Right(x)
|
||||||
|
override def flatMap[A, B](fa: M[A])(f: A => M[B]): M[B] = c => fa(c).flatMap(a => f(a)(c))
|
||||||
|
override def tailRecM[A, B](a: A)(f: A => M[Either[A, B]]): M[B] =
|
||||||
|
c =>
|
||||||
|
f(a)(c) match
|
||||||
|
case Left(e) => Left(e)
|
||||||
|
case Right(Left(a)) => tailRecM(a)(f)(c)
|
||||||
|
case Right(Right(b)) => Right(b)
|
||||||
|
override def raiseError[A](e: Throwable): M[A] = _ => Left(e)
|
||||||
|
override def handleErrorWith[A](fa: M[A])(f: Throwable => M[A]): M[A] = c =>
|
||||||
|
fa(c) match
|
||||||
|
case Left(e) => f(e)(c)
|
||||||
|
case Right(a) => Right(a)
|
||||||
|
|
||||||
|
given Ask[M, Config] = new Ask[M, Config]:
|
||||||
|
override def applicative: Applicative[M] = MonadThrow[M]
|
||||||
|
|
||||||
|
override def ask[E2 >: Config]: M[E2] = c => Right(c)
|
||||||
|
|
||||||
|
class Tests extends AnyFlatSpec with Matchers:
|
||||||
|
import TestsData.*
|
||||||
|
import M.given
|
||||||
|
|
||||||
|
it should "correct findAll config propagation" in {
|
||||||
|
val repository = UserRepositoryDao[M](dao(List.empty))
|
||||||
|
val config = Config(42)
|
||||||
|
repository.findAll(config)
|
||||||
|
lastConfig shouldBe Right(Config(42))
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "correct create config propagation" in {
|
||||||
|
val repository = UserRepositoryDao[M](dao(List.empty))
|
||||||
|
val config = Config(43)
|
||||||
|
repository.create(UserName("Subject #0"), Age(0), Set.empty)(config)
|
||||||
|
lastConfig shouldBe Right(Config(43))
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "correct delete config propagation" in {
|
||||||
|
val repository = UserRepositoryDao[M](dao(List.empty))
|
||||||
|
val config = Config(44)
|
||||||
|
repository.delete(UserId(0))(config)
|
||||||
|
lastConfig shouldBe Right(Config(44))
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "correct update config propagation" in {
|
||||||
|
val repository = UserRepositoryDao[M](dao(List.empty))
|
||||||
|
val config = Config(45)
|
||||||
|
repository.update(User(UserId(0), UserName("Subject #0"), Age(0), Set.empty))(config)
|
||||||
|
lastConfig shouldBe Right(Config(45))
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "correct return all users" in {
|
||||||
|
val repository = UserRepositoryDao[M](dao(sampleUsers))
|
||||||
|
val config = Config(46)
|
||||||
|
repository.findAll(config) shouldBe Right(sampleUsers.toSet.toList)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "correct create new user" in {
|
||||||
|
val repository = UserRepositoryDao[M](dao(sampleUsers))
|
||||||
|
val config = Config(46)
|
||||||
|
repository.create(UserName("New subject"), Age(0), Set.empty)(config) shouldBe Right(
|
||||||
|
User(UserId(5), UserName("New subject"), Age(0), Set.empty)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "not create user more than once" in {
|
||||||
|
val repository = UserRepositoryDao[M](dao(sampleUsers))
|
||||||
|
val config = Config(46)
|
||||||
|
repository.create(UserName("Subject #2"), Age(0), Set.empty)(config) shouldBe a[Left[Throwable, User]]
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "delete existing user" in {
|
||||||
|
val repository = UserRepositoryDao[M](dao(sampleUsers))
|
||||||
|
val config = Config(46)
|
||||||
|
repository.delete(UserId(2))(config) shouldBe Right(())
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "not delete nonexistent user" in {
|
||||||
|
val repository = UserRepositoryDao[M](dao(sampleUsers))
|
||||||
|
val config = Config(46)
|
||||||
|
repository.delete(UserId(42))(config) shouldBe a[Left[Throwable, Unit]]
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "update existing user" in {
|
||||||
|
val repository = UserRepositoryDao[M](dao(sampleUsers))
|
||||||
|
val config = Config(46)
|
||||||
|
repository.update(User(UserId(2), UserName("Subject #2"), Age(42), Set.empty))(config) shouldBe Right(())
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "not update nonexistent user" in {
|
||||||
|
val repository = UserRepositoryDao[M](dao(sampleUsers))
|
||||||
|
val config = Config(46)
|
||||||
|
repository
|
||||||
|
.update(User(UserId(22), UserName("Subject #22"), Age(42), Set.empty))(config) shouldBe a[Left[Throwable, Unit]]
|
||||||
|
}
|
Loading…
Reference in a new issue