From 3b3582bc0eabec9f2a8b3bb0d13b077c6725b821 Mon Sep 17 00:00:00 2001
From: deviantbadge <deviantbadge21@gmail.com>
Date: Wed, 7 Nov 2018 19:03:51 +0300
Subject: [PATCH 1/2] Lecture practice

---
 lecture07/src/main/resources/sql/data/data.sql | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lecture07/src/main/resources/sql/data/data.sql b/lecture07/src/main/resources/sql/data/data.sql
index 281e97bf..b1554760 100644
--- a/lecture07/src/main/resources/sql/data/data.sql
+++ b/lecture07/src/main/resources/sql/data/data.sql
@@ -13,3 +13,6 @@ select *
 from chat.message
 where time > '2017-03-25';
 
+
+select *
+from chat.user;
\ No newline at end of file

From 49a6406fe3b27ffa22e75c440d9d7cdedb86eec0 Mon Sep 17 00:00:00 2001
From: deviantbadge <deviantbadge21@gmail.com>
Date: Tue, 13 Nov 2018 00:37:54 +0300
Subject: [PATCH 2/2] Add Dao implementation + several tests

---
 lecture07/build.gradle.kts                    |  3 +-
 .../io/rybalkinsd/kotlinbootcamp/Main.kt      |  4 ++
 .../io/rybalkinsd/kotlinbootcamp/dao/Dao.kt   |  5 +-
 .../kotlinbootcamp/dao/MessageDao.kt          | 37 ++++++++++--
 .../rybalkinsd/kotlinbootcamp/dao/UserDao.kt  | 34 +++++++++--
 .../rybalkinsd/kotlinbootcamp/dao/database.kt |  2 +-
 .../kotlinbootcamp/db/DbConnector.kt          |  7 +--
 .../kotlinbootcamp/model/modelExt.kt          | 11 +++-
 .../src/main/resources/sql/data/data.sql      |  9 ++-
 .../kotlinbootcamp/dao/MessageDaoTest.kt      |  8 +--
 .../kotlinbootcamp/dao/UserDaoTest.kt         | 18 +++---
 .../practice/ChatMessageDaoTest.kt            | 50 ++++++++++------
 .../practice/ChatUserDaoTest.kt               | 59 ++++++++++---------
 13 files changed, 169 insertions(+), 78 deletions(-)
 create mode 100644 lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/Main.kt

diff --git a/lecture07/build.gradle.kts b/lecture07/build.gradle.kts
index 8303c09e..f8a0952d 100644
--- a/lecture07/build.gradle.kts
+++ b/lecture07/build.gradle.kts
@@ -36,9 +36,10 @@ dependencies {
     compile(spring("web"))
     compile(spring("actuator"))
 
-    testCompile("junit", "junit", "4.12")
+    testCompile("org.testng", "testng", "6.14.3")
     testCompile(spring("test"))
 
+
     ktlint("com.github.shyiko", "ktlint", "0.28.0")
 }
 
diff --git a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/Main.kt b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/Main.kt
new file mode 100644
index 00000000..9aa13aad
--- /dev/null
+++ b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/Main.kt
@@ -0,0 +1,4 @@
+package io.rybalkinsd.kotlinbootcamp
+
+fun main() {
+}
\ No newline at end of file
diff --git a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/Dao.kt b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/Dao.kt
index f8265734..f34cf141 100644
--- a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/Dao.kt
+++ b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/Dao.kt
@@ -1,5 +1,6 @@
 package io.rybalkinsd.kotlinbootcamp.dao
 
+import org.jetbrains.exposed.sql.Op
 
 interface Dao<T> {
     /**
@@ -10,7 +11,7 @@ interface Dao<T> {
     /**
      * SELECT * ... WHERE cond0 AND ... AND condN
      */
-    fun getAllWhere(vararg conditions: String): List<T>
+    fun getAllWhere(vararg where: Op<Boolean>): List<T>
 
     /**
      * INSERT INTO ...
@@ -21,5 +22,5 @@ interface Dao<T> {
      * SELECT * from ... WHERE id=
      * @return Optional.empty() if nothing found
      */
-    fun findById(id: Int): T? = getAllWhere("id=$id").firstOrNull()
+    fun findById(id: Int): T
 }
diff --git a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/MessageDao.kt b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/MessageDao.kt
index 63b3ac36..5e4106cb 100644
--- a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/MessageDao.kt
+++ b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/MessageDao.kt
@@ -1,17 +1,44 @@
 package io.rybalkinsd.kotlinbootcamp.dao
 
 import io.rybalkinsd.kotlinbootcamp.model.Message
+import io.rybalkinsd.kotlinbootcamp.model.toMessage
+import org.jetbrains.exposed.sql.Op
+import org.jetbrains.exposed.sql.ResultRow
+import org.jetbrains.exposed.sql.and
+import org.jetbrains.exposed.sql.insert
+import org.jetbrains.exposed.sql.select
+import org.jetbrains.exposed.sql.selectAll
+import org.jetbrains.exposed.sql.transactions.transaction
 
 class MessageDao : Dao<Message> {
+    override fun findById(id: Int) = transaction {
+        Messages.select { Messages.id eq id }
+                .firstOrNull()
+                ?.toMessage()
+                ?: throw IllegalStateException("Message with $id not found in database")
+    }
+
     override val all: List<Message>
-        get() = TODO("not implemented")
+        get() = transaction {
+            Messages.selectAll()
+                    .toList()
+                    .map(ResultRow::toMessage)
+        }
 
-    override fun getAllWhere(vararg conditions: String): List<Message> {
-        TODO("not implemented")
+    override fun getAllWhere(vararg where: Op<Boolean>): List<Message> = transaction {
+        Messages.select(where.reduce { resultExpr, condition -> resultExpr and condition })
+                .toList()
+                .map(ResultRow::toMessage)
     }
 
     override fun insert(t: Message) {
-        TODO("not implemented")
+        transaction {
+            Messages.insert {
+                it[id] = t.id
+                it[user] = t.user.id
+                it[time] = t.timestamp
+                it[value] = t.value
+            }
+        }
     }
-
 }
diff --git a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/UserDao.kt b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/UserDao.kt
index 319d1802..6d815c87 100644
--- a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/UserDao.kt
+++ b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/UserDao.kt
@@ -1,16 +1,42 @@
 package io.rybalkinsd.kotlinbootcamp.dao
 
 import io.rybalkinsd.kotlinbootcamp.model.User
+import io.rybalkinsd.kotlinbootcamp.model.toUser
+import org.jetbrains.exposed.sql.Op
+import org.jetbrains.exposed.sql.ResultRow
+import org.jetbrains.exposed.sql.and
+import org.jetbrains.exposed.sql.insert
+import org.jetbrains.exposed.sql.select
+import org.jetbrains.exposed.sql.selectAll
+import org.jetbrains.exposed.sql.transactions.transaction
 
 class UserDao : Dao<User> {
+    override fun findById(id: Int) = transaction {
+        Users.select { Users.id eq id }
+                .firstOrNull()
+                ?.toUser()
+                ?: throw IllegalStateException("User with $id not found in database")
+    }
+
     override val all: List<User>
-        get() = TODO("not implemented")
+        get() = transaction {
+            Users.selectAll()
+                    .toList()
+                    .map(ResultRow::toUser)
+        }
 
-    override fun getAllWhere(vararg conditions: String): List<User> {
-        TODO("not implemented")
+    override fun getAllWhere(vararg where: Op<Boolean>) = transaction {
+        Users.select(where.reduce { resultExpr, condition -> resultExpr and condition })
+                .toList()
+                .map(ResultRow::toUser)
     }
 
     override fun insert(t: User) {
-        TODO("not implemented")
+        transaction {
+            Users.insert {
+                it[id] = t.id
+                it[login] = t.login
+            }
+        }
     }
 }
diff --git a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/database.kt b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/database.kt
index 17778d1d..5ce75f8a 100644
--- a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/database.kt
+++ b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/dao/database.kt
@@ -12,4 +12,4 @@ object Messages : Table("chat.message") {
     val user = integer("user") references Users.id
     val time = datetime("time")
     val value = text("value")
-}
\ No newline at end of file
+}
diff --git a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/db/DbConnector.kt b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/db/DbConnector.kt
index 243d89be..6ccaca83 100644
--- a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/db/DbConnector.kt
+++ b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/db/DbConnector.kt
@@ -3,15 +3,14 @@ package io.rybalkinsd.kotlinbootcamp.db
 import io.rybalkinsd.kotlinbootcamp.util.logger
 import org.jetbrains.exposed.sql.Database
 
-
 object DbConnector {
     private val log = logger()
 
     private val host = "54.224.37.210"
     private val port = 5432
-    private val dbName = "chatdb_atom49"
-    private val user = "atom49"
-    private val password = "atom49"
+    private val dbName = "chatdb_atom6"
+    private val user = "atom6"
+    private val password = "atom6"
 
     init {
         Database.connect(
diff --git a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/model/modelExt.kt b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/model/modelExt.kt
index 3508344c..208ca68f 100644
--- a/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/model/modelExt.kt
+++ b/lecture07/src/main/kotlin/io/rybalkinsd/kotlinbootcamp/model/modelExt.kt
@@ -1,6 +1,15 @@
 package io.rybalkinsd.kotlinbootcamp.model
 
+import io.rybalkinsd.kotlinbootcamp.dao.Messages
+import io.rybalkinsd.kotlinbootcamp.dao.UserDao
 import io.rybalkinsd.kotlinbootcamp.dao.Users
 import org.jetbrains.exposed.sql.ResultRow
 
-internal fun ResultRow.toUser() = User(this[Users.id], this[Users.login])
\ No newline at end of file
+internal fun ResultRow.toUser() = User(this[Users.id], this[Users.login])
+
+internal fun ResultRow.toMessage() = Message(
+        this[Messages.id],
+        UserDao().findById(this[Messages.user]),
+        this[Messages.time],
+        this[Messages.value]
+)
diff --git a/lecture07/src/main/resources/sql/data/data.sql b/lecture07/src/main/resources/sql/data/data.sql
index b1554760..be6659b5 100644
--- a/lecture07/src/main/resources/sql/data/data.sql
+++ b/lecture07/src/main/resources/sql/data/data.sql
@@ -14,5 +14,10 @@ from chat.message
 where time > '2017-03-25';
 
 
-select *
-from chat.user;
\ No newline at end of file
+select login, value
+from chat.user, chat.message
+where "user"=44;
+
+select value, chat.user.login
+from chat.message
+left join chat.user on chat.message.user = chat.user.id;
\ No newline at end of file
diff --git a/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/dao/MessageDaoTest.kt b/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/dao/MessageDaoTest.kt
index 0abfd7c2..e2bbc9e8 100644
--- a/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/dao/MessageDaoTest.kt
+++ b/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/dao/MessageDaoTest.kt
@@ -6,8 +6,9 @@ import org.jetbrains.exposed.sql.addLogger
 import org.jetbrains.exposed.sql.insert
 import org.jetbrains.exposed.sql.transactions.transaction
 import org.joda.time.DateTime
-import org.junit.Test
+import org.testng.annotations.Test
 
+@Test(enabled = false)
 class MessageDaoTest {
 
     @Test
@@ -18,10 +19,9 @@ class MessageDaoTest {
             addLogger(StdOutSqlLogger)
 
             Messages.insert {
-                it[id] = 0
-                it[user] = 42
+                it[user] = 44
                 it[time] = DateTime.now()
-                it[value] = "My first message"
+                it[value] = "My first haha"
             }
         }
     }
diff --git a/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/dao/UserDaoTest.kt b/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/dao/UserDaoTest.kt
index 2fea86e9..bf522706 100644
--- a/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/dao/UserDaoTest.kt
+++ b/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/dao/UserDaoTest.kt
@@ -2,17 +2,19 @@ package io.rybalkinsd.kotlinbootcamp.dao
 
 import io.rybalkinsd.kotlinbootcamp.db.DbConnector
 import io.rybalkinsd.kotlinbootcamp.model.toUser
+import org.jetbrains.exposed.sql.ResultRow
 import org.jetbrains.exposed.sql.StdOutSqlLogger
 import org.jetbrains.exposed.sql.addLogger
 import org.jetbrains.exposed.sql.insert
 import org.jetbrains.exposed.sql.selectAll
 import org.jetbrains.exposed.sql.transactions.transaction
-import org.junit.Before
-import org.junit.Test
+import org.testng.annotations.BeforeClass
+import org.testng.annotations.Test
 
+@Test(enabled = false)
 class UserDaoTest {
 
-    @Before
+    @BeforeClass
     fun setUp() {
         DbConnector
     }
@@ -23,7 +25,7 @@ class UserDaoTest {
             addLogger(StdOutSqlLogger)
 
             val id = Users.insert {
-                it[id] = 44
+                it[id] = 1
                 it[login] = "login44"
             } get Users.id
 
@@ -32,17 +34,13 @@ class UserDaoTest {
     }
 
     @Test
-    fun `select * from User`() {
+    fun `select from User`() {
         transaction {
             addLogger(StdOutSqlLogger)
 
-            val users = Users.selectAll().map {
-                it.toUser()
-            }
+            val users = Users.selectAll().map(ResultRow::toUser)
 
             println(users)
         }
     }
-
-
 }
\ No newline at end of file
diff --git a/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/practice/ChatMessageDaoTest.kt b/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/practice/ChatMessageDaoTest.kt
index 31f0dafd..7f5c91a8 100644
--- a/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/practice/ChatMessageDaoTest.kt
+++ b/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/practice/ChatMessageDaoTest.kt
@@ -1,37 +1,53 @@
 package io.rybalkinsd.kotlinbootcamp.practice
 
 import io.rybalkinsd.kotlinbootcamp.dao.MessageDao
+import io.rybalkinsd.kotlinbootcamp.dao.Messages
 import io.rybalkinsd.kotlinbootcamp.db.DbConnector
 import io.rybalkinsd.kotlinbootcamp.model.Message
-import junit.framework.TestCase.assertTrue
-import org.junit.Before
-import org.junit.Ignore
-import org.junit.Test
+import io.rybalkinsd.kotlinbootcamp.practice.ChatUserDaoTest.Companion.admin
+import org.assertj.core.api.Assertions
+import org.assertj.core.api.Assertions.assertThat
+import org.jetbrains.exposed.sql.Op
+import org.joda.time.DateTime
+import org.testng.annotations.BeforeClass
+import org.testng.annotations.Test
 
-
-@Ignore
 class ChatMessageDaoTest {
 
     val messageDao = MessageDao()
 
-    @Before
+    @BeforeClass
     fun setUp() {
         DbConnector
     }
 
     @Test
-    fun `select * from message`() {
-        assertTrue(messageDao.all.isNotEmpty())
-    }
-
-    @Test
-    fun `insert message`() {
+    fun insertMessage() {
         val before = messagesNumber()
-        messageDao.insert(dummyMessage())
+        messageDao.insert(dummyMessage(before))
         val after = messagesNumber()
-        assertTrue(before + 1 >= after)
+        assertThat(before + 1).isEqualTo(after)
+    }
+
+    @Test(dependsOnMethods = ["insertMessage"])
+    fun selectAll() {
+        assertThat(messageDao.all)
+                .isNotEmpty
+    }
+
+    @Test(dependsOnMethods = ["selectAll"])
+    fun getMessageById() {
+        val id = messageDao.all.firstOrNull()?.id
+                ?: return Assertions.fail("Failed to load id from database")
+        assertThat(messageDao.findById(id).id).isEqualTo(id)
+    }
+
+    @Test(dependsOnMethods = ["insertMessage"])
+    fun getHelloMessage() {
+        assertThat(messageDao.getAllWhere(Op.build { Messages.value like "Hello %" }))
+                .isNotEmpty
     }
 
-    fun messagesNumber(): Long = TODO()
-    fun dummyMessage(): Message = TODO()
+    private fun messagesNumber() = messageDao.all.size
+    private fun dummyMessage(messageAmunt: Int) = Message(messageAmunt, admin, DateTime(0), "Hello guys")
 }
\ No newline at end of file
diff --git a/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/practice/ChatUserDaoTest.kt b/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/practice/ChatUserDaoTest.kt
index 4d740400..3e522a13 100644
--- a/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/practice/ChatUserDaoTest.kt
+++ b/lecture07/src/test/kotlin/io/rybalkinsd/kotlinbootcamp/practice/ChatUserDaoTest.kt
@@ -1,53 +1,58 @@
 package io.rybalkinsd.kotlinbootcamp.practice
 
 import io.rybalkinsd.kotlinbootcamp.dao.UserDao
+import io.rybalkinsd.kotlinbootcamp.dao.Users
 import io.rybalkinsd.kotlinbootcamp.db.DbConnector
 import io.rybalkinsd.kotlinbootcamp.model.User
-import junit.framework.TestCase
-import org.junit.Assert.assertTrue
-import org.junit.Before
-import org.junit.Ignore
-import org.junit.Test
-import kotlin.random.Random
+import org.assertj.core.api.Assertions
+import org.assertj.core.api.Assertions.assertThat
+import org.jetbrains.exposed.sql.Op
+import org.testng.annotations.BeforeClass
+import org.testng.annotations.Test
 
 /**
  * Created by sergey on 3/25/17.
  */
-@Ignore
 class ChatUserDaoTest {
+    companion object {
+        val admin = User(0, "admin")
+    }
+
     val userDao = UserDao()
 
-    @Before
+    @BeforeClass
     fun setUp() {
         DbConnector
     }
 
-    @Test
-    fun getAllTest() {
-        assertTrue(userDao.all.isNotEmpty())
-    }
-
     @Test
     fun insertTest() {
         val before = userNumber()
-        userDao.insert(dummyUser())
+        userDao.insert(dummyUser(before))
         val after = userNumber()
-        TestCase.assertTrue(before + 1 >= after)
+        assertThat(before + 1).isEqualTo(after)
     }
 
-    @Test
-    fun `find lol`() {
-        userDao.insert(User(Random.nextInt(), "Lolita"))
-        val lols = userDao.getAllWhere("login like 'Lol%'")
-
-        assertTrue(
-            lols.asSequence()
-                .map { it.login }
-                .any { it.startsWith("Lol") }
-        )
+    @Test(dependsOnMethods = ["insertTest"])
+    fun getAllTest() {
+        assertThat(userDao.all)
+                .isNotEmpty
     }
 
-    fun userNumber(): Long = TODO()
-    fun dummyUser(): User = TODO()
+    @Test(dependsOnMethods = ["getAllTest"])
+    fun getByIdTest() {
+        val id = userDao.all.firstOrNull()?.id
+                ?: return Assertions.fail("Failed to load id from database")
+        assertThat(userDao.findById(id).id).isEqualTo(id)
+    }
+
+    @Test(dependsOnMethods = ["insertTest"])
+    fun getAngel() {
+        val users = userDao.getAllWhere(Op.build { Users.login like "angel *" })
+        assertThat(users)
+                .allMatch { user -> user.login.startsWith("angel ") }
+    }
 
+    fun userNumber() = userDao.all.size
+    fun dummyUser(userAmount: Int) = User(userAmount, "angel $userAmount")
 }
\ No newline at end of file