From 8825e9a3eca94e464f9e1b54ef26d4fca02a1762 Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Wed, 18 Feb 2015 17:28:08 +0100 Subject: [PATCH 1/2] create dsl, need better test (working at least) --- .../org/virtuslab/unicorn/dsl/Entity.scala | 29 ++++++++++ .../virtuslab/unicorn/dsl/EntityTest.scala | 54 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 unicorn-core/src/main/scala/org/virtuslab/unicorn/dsl/Entity.scala create mode 100644 unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityTest.scala diff --git a/unicorn-core/src/main/scala/org/virtuslab/unicorn/dsl/Entity.scala b/unicorn-core/src/main/scala/org/virtuslab/unicorn/dsl/Entity.scala new file mode 100644 index 0000000..bf30d77 --- /dev/null +++ b/unicorn-core/src/main/scala/org/virtuslab/unicorn/dsl/Entity.scala @@ -0,0 +1,29 @@ +package org.virtuslab.unicorn.dsl + +import org.virtuslab.unicorn.{HasJdbcDriver, Unicorn} + +import scala.slick.lifted.TableQuery + +abstract class Entity[Underlaying](val unicorn: HasJdbcDriver with Unicorn[Underlaying]) { + + import unicorn._ + + case class Id(id: Underlaying) extends BaseId + + object Id extends CoreCompanion[Id] + + type Row <: BaseRow + + final type BaseRow = WithId[Id] + + type Table <: BaseTable + + final type BaseTable = IdTable[Id, Row] + + + def query: TableQuery[Table] + + class BaseRepository(implicit mapping: driver.simple.BaseColumnType[Id]) + extends BaseIdRepository[Id, Row, Table](query)(mapping) +} + diff --git a/unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityTest.scala b/unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityTest.scala new file mode 100644 index 0000000..b31ccd9 --- /dev/null +++ b/unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityTest.scala @@ -0,0 +1,54 @@ +package org.virtuslab.unicorn.dsl + +import org.virtuslab.unicorn.{BaseTest, TestUnicorn, HasJdbcDriver, Unicorn} + +import scala.slick.lifted + +/** + * Author: Krzysztof Romanowski + */ +class EntityTest extends BaseTest[Long] { + + val unicorn: Unicorn[Long] with HasJdbcDriver = TestUnicorn + + import unicorn.driver.simple._ + + object User extends Entity(unicorn) { + + case class Row(id: Option[Id], name: String) extends BaseRow + + class Table(tag: Tag) extends BaseTable(tag, "USERS") { + def name = column[String]("name") + + def * = (id.?, name) <>(Row.tupled, Row.unapply) + } + + override def query: TableQuery[Table] = TableQuery[Table] + } + + //somewhere in other file... + object UserRepository extends User.BaseRepository + + object File extends Entity(unicorn) { + + case class Row(id: Option[Id], name: String, user: User.Id) extends BaseRow + + class Table(tag: Tag) extends BaseTable(tag, "USERS") { + def name = column[String]("name") + + def userId = column[User.Id]("userId") + + def * = (id.?, name, userId) <>(Row.tupled, Row.unapply) + } + + override def query: TableQuery[Table] = TableQuery[Table] + } + + //somewhere in other file... + object FileRepository extends User.BaseRepository + + "dsl" should "work" in rollback { implicit session => + UserRepository.findAll() should be('empty) + } + +} From 55c3c6ff90f2f5e485bdc50cf369d5e0a2c0116a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jerzy=20M=C3=BCller?= Date: Thu, 19 Feb 2015 10:42:01 +0100 Subject: [PATCH 2/2] Tests added, types fixed --- .../dsl/{Entity.scala => EntityDsl.scala} | 27 ++- .../org/virtuslab/unicorn/BaseTest.scala | 7 +- .../virtuslab/unicorn/dsl/EntityDslTest.scala | 226 ++++++++++++++++++ .../virtuslab/unicorn/dsl/EntityTest.scala | 54 ----- 4 files changed, 253 insertions(+), 61 deletions(-) rename unicorn-core/src/main/scala/org/virtuslab/unicorn/dsl/{Entity.scala => EntityDsl.scala} (50%) create mode 100644 unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityDslTest.scala delete mode 100644 unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityTest.scala diff --git a/unicorn-core/src/main/scala/org/virtuslab/unicorn/dsl/Entity.scala b/unicorn-core/src/main/scala/org/virtuslab/unicorn/dsl/EntityDsl.scala similarity index 50% rename from unicorn-core/src/main/scala/org/virtuslab/unicorn/dsl/Entity.scala rename to unicorn-core/src/main/scala/org/virtuslab/unicorn/dsl/EntityDsl.scala index bf30d77..d466c48 100644 --- a/unicorn-core/src/main/scala/org/virtuslab/unicorn/dsl/Entity.scala +++ b/unicorn-core/src/main/scala/org/virtuslab/unicorn/dsl/EntityDsl.scala @@ -1,29 +1,44 @@ package org.virtuslab.unicorn.dsl -import org.virtuslab.unicorn.{HasJdbcDriver, Unicorn} +import org.virtuslab.unicorn.{ HasJdbcDriver, Unicorn } import scala.slick.lifted.TableQuery -abstract class Entity[Underlaying](val unicorn: HasJdbcDriver with Unicorn[Underlaying]) { +/** + * TODO + * + * @param unicorn + * @tparam Underlying type of id + */ +abstract class EntityDsl[Underlying](val unicorn: Unicorn[Underlying] with HasJdbcDriver) { import unicorn._ - case class Id(id: Underlaying) extends BaseId + /** TODO */ + case class Id(id: Underlying) extends BaseId + /** TODO */ object Id extends CoreCompanion[Id] + /** TODO */ type Row <: BaseRow + /** TODO */ final type BaseRow = WithId[Id] + /** TODO */ type Table <: BaseTable + /** TODO */ final type BaseTable = IdTable[Id, Row] - + /** TODO */ def query: TableQuery[Table] - class BaseRepository(implicit mapping: driver.simple.BaseColumnType[Id]) + /** + * TODO + * @param mapping + */ + class BaseRepository(implicit mapping: driver.simple.BaseColumnType[Id]) extends BaseIdRepository[Id, Row, Table](query)(mapping) } - diff --git a/unicorn-core/src/test/scala/org/virtuslab/unicorn/BaseTest.scala b/unicorn-core/src/test/scala/org/virtuslab/unicorn/BaseTest.scala index 4f44e5e..2ffcfff 100644 --- a/unicorn-core/src/test/scala/org/virtuslab/unicorn/BaseTest.scala +++ b/unicorn-core/src/test/scala/org/virtuslab/unicorn/BaseTest.scala @@ -29,7 +29,12 @@ trait LongTestUnicorn { lazy val unicorn = TestUnicorn } -trait BaseTest[Underlying] extends FlatSpecLike with Matchers with BeforeAndAfterEach with RollbackHelper[Underlying] { +trait BaseTest[Underlying] + extends FlatSpecLike + with OptionValues + with Matchers + with BeforeAndAfterEach + with RollbackHelper[Underlying] { val dbURL = "jdbc:h2:mem:unicorn" diff --git a/unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityDslTest.scala b/unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityDslTest.scala new file mode 100644 index 0000000..152fdb4 --- /dev/null +++ b/unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityDslTest.scala @@ -0,0 +1,226 @@ +package org.virtuslab.unicorn.dsl + +import org.virtuslab.unicorn.{ BaseTest, HasJdbcDriver, TestUnicorn, Unicorn } + +class EntityDslTest extends BaseTest[Long] { + + val unicorn: Unicorn[Long] with HasJdbcDriver = TestUnicorn + abstract class TestEntityDsl extends EntityDsl(unicorn) + + import unicorn.driver.simple._ + + object User extends TestEntityDsl { + + case class Row(id: Option[Id], + email: String, + firstName: String, + lastName: String) extends BaseRow + + class Table(tag: Tag) extends BaseTable(tag, "USERS") { + def email = column[String]("EMAIL", O.NotNull) + + def firstName = column[String]("FIRST_NAME", O.NotNull) + + def lastName = column[String]("LAST_NAME", O.NotNull) + + override def * = (id.?, email, firstName, lastName) <> (Row.tupled, Row.unapply) + } + + override val query = TableQuery[Table] + } + + object UsersRepository extends User.BaseRepository + + // TODO - find a way to not duplicate whole UsersRepositoryTest + + "Users Service" should "save and query users" in rollback { + implicit session => + // setup + UsersRepository.create() + + val user = User.Row(None, "test@email.com", "Krzysztof", "Nowak") + val userId = UsersRepository save user + val userOpt = UsersRepository findById userId + + userOpt shouldBe defined + + userOpt.value should have( + 'email(user.email), + 'firstName(user.firstName), + 'lastName(user.lastName) + ) + userOpt.value.id shouldBe defined + } + + it should "save and query multiple users" in rollback { + implicit session => + // setup + UsersRepository.create() + + val users = (Stream from 1 take 10) map (n => User.Row(None, "test@email.com", "Krzysztof" + n, "Nowak")) + UsersRepository saveAll users + val newUsers = UsersRepository.findAll() + newUsers.size shouldEqual 10 + newUsers.headOption map (_.firstName) shouldEqual Some("Krzysztof1") + newUsers.lastOption map (_.firstName) shouldEqual Some("Krzysztof10") + } + + it should "query existing user" in rollback { + implicit session => + // setup + UsersRepository.create() + + val user = User.Row(None, "test@email.com", "Krzysztof", "Nowak") + val userId = UsersRepository save user + val user2 = UsersRepository findExistingById userId + + user2 should have( + 'email(user.email), + 'firstName(user.firstName), + 'lastName(user.lastName) + ) + user2.id shouldBe defined + } + + it should "update existing user" in rollback { + implicit session => + // setup + UsersRepository.create() + + var user = User.Row(None, "test@email.com", "Krzysztof", "Nowak") + val userId = UsersRepository save user + user = UsersRepository findExistingById userId + + UsersRepository save user.copy(firstName = "Jerzy", lastName = "Muller") + + user = UsersRepository findExistingById userId + + user should have( + 'email("test@email.com"), + 'firstName("Jerzy"), + 'lastName("Muller"), + 'id(Some(userId)) + ) + } + + it should "query all ids" in rollback { + implicit session => + // setup + UsersRepository.create() + + val users = Seq( + User.Row(None, "test1@email.com", "Krzysztof", "Nowak"), + User.Row(None, "test2@email.com", "Janek", "Nowak"), + User.Row(None, "test3@email.com", "Marcin", "Nowak") + ) + + val ids = UsersRepository saveAll users + + UsersRepository.allIds() shouldEqual ids + } + + it should "sort users by id" in rollback { + implicit session => + // setup + UsersRepository.create() + + val users = Seq( + User.Row(None, "test1@email.com", "Krzysztof", "Nowak"), + User.Row(None, "test2@email.com", "Janek", "Nowak"), + User.Row(None, "test3@email.com", "Marcin", "Nowak") + ) + + val ids = UsersRepository saveAll users + val usersWithIds = (users zip ids).map { case (user, id) => user.copy(id = Some(id)) } + + UsersRepository.findAll().sortBy(_.id) shouldEqual usersWithIds + } + + it should "query multiple users by ids" in rollback { + implicit session => + // setup + UsersRepository.create() + + val users = Seq( + User.Row(None, "test1@email.com", "Krzysztof", "Nowak"), + User.Row(None, "test2@email.com", "Janek", "Nowak"), + User.Row(None, "test3@email.com", "Marcin", "Nowak") + ) + + val ids = UsersRepository saveAll users + val usersWithIds = (users zip ids).map { case (user, id) => user.copy(id = Some(id)) } + UsersRepository.findAll().size shouldEqual 3 + + val selectedUsers = Seq(usersWithIds.head, usersWithIds.last) + + UsersRepository.findByIds(selectedUsers.flatMap(_.id)) shouldEqual selectedUsers + } + + it should "copy user by id" in rollback { + implicit session => + // setup + UsersRepository.create() + + val user = User.Row(None, "test1@email.com", "Krzysztof", "Nowak") + + val id = UsersRepository save user + + val idOfCopy = UsersRepository.copyAndSave(id) + val copiedUser = idOfCopy.flatMap(UsersRepository.findById).value + + copiedUser.id shouldNot be(user.id) + + copiedUser should have( + 'email(user.email), + 'firstName(user.firstName), + 'lastName(user.lastName) + ) + } + + it should "delete user by id" in rollback { + implicit session => + // setup + UsersRepository.create() + + val users = Seq( + User.Row(None, "test1@email.com", "Krzysztof", "Nowak"), + User.Row(None, "test2@email.com", "Janek", "Nowak"), + User.Row(None, "test3@email.com", "Marcin", "Nowak") + ) + + val ids = UsersRepository saveAll users + val usersWithIds = (users zip ids).map { case (user, id) => user.copy(id = Some(id)) } + UsersRepository.findAll() should have size users.size + + UsersRepository.deleteById(ids(1)) + val remainingUsers = Seq(usersWithIds.head, usersWithIds.last) + + UsersRepository.findAll() shouldEqual remainingUsers + } + + it should "delete all users" in rollback { + implicit session => + // setup + UsersRepository.create() + + val users = Seq( + User.Row(None, "test1@email.com", "Krzysztof", "Nowak"), + User.Row(None, "test2@email.com", "Janek", "Nowak"), + User.Row(None, "test3@email.com", "Marcin", "Nowak") + ) + + val ids = UsersRepository saveAll users + UsersRepository.findAll() should have size users.size + + UsersRepository.deleteAll() + + UsersRepository.findAll() shouldBe empty + } + + it should "create and drop table" in rollback { + implicit session => + // setup + UsersRepository.create() + UsersRepository.drop() + } +} diff --git a/unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityTest.scala b/unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityTest.scala deleted file mode 100644 index b31ccd9..0000000 --- a/unicorn-core/src/test/scala/org/virtuslab/unicorn/dsl/EntityTest.scala +++ /dev/null @@ -1,54 +0,0 @@ -package org.virtuslab.unicorn.dsl - -import org.virtuslab.unicorn.{BaseTest, TestUnicorn, HasJdbcDriver, Unicorn} - -import scala.slick.lifted - -/** - * Author: Krzysztof Romanowski - */ -class EntityTest extends BaseTest[Long] { - - val unicorn: Unicorn[Long] with HasJdbcDriver = TestUnicorn - - import unicorn.driver.simple._ - - object User extends Entity(unicorn) { - - case class Row(id: Option[Id], name: String) extends BaseRow - - class Table(tag: Tag) extends BaseTable(tag, "USERS") { - def name = column[String]("name") - - def * = (id.?, name) <>(Row.tupled, Row.unapply) - } - - override def query: TableQuery[Table] = TableQuery[Table] - } - - //somewhere in other file... - object UserRepository extends User.BaseRepository - - object File extends Entity(unicorn) { - - case class Row(id: Option[Id], name: String, user: User.Id) extends BaseRow - - class Table(tag: Tag) extends BaseTable(tag, "USERS") { - def name = column[String]("name") - - def userId = column[User.Id]("userId") - - def * = (id.?, name, userId) <>(Row.tupled, Row.unapply) - } - - override def query: TableQuery[Table] = TableQuery[Table] - } - - //somewhere in other file... - object FileRepository extends User.BaseRepository - - "dsl" should "work" in rollback { implicit session => - UserRepository.findAll() should be('empty) - } - -}