app/dao/impl/LaboratoryDAOImpl.scala
package dao.impl
import javax.inject.Inject
import com.google.inject.Singleton
import dao.{LaboratoryDAO, RoomDAO}
import model.table._
import model._
import org.h2.jdbc.JdbcSQLException
import play.Logger
import play.api.db.slick.DatabaseConfigProvider
import play.api.libs.concurrent.Execution.Implicits._
import services.state.ActionState
import services.state
import slick.driver.JdbcProfile
import scala.concurrent.Future
import scala.util.{Failure, Success}
/**
* Implements DAO operations of Laboratories
*
* @author Camilo Sampedro <camilo.sampedro@udea.edu.co>
* @param dbConfigProvider DB manager injected.
*/
@Singleton
class LaboratoryDAOImpl @Inject()
(dbConfigProvider: DatabaseConfigProvider, roomDAO: RoomDAO) extends LaboratoryDAO {
/**
* Database configuration
*/
val dbConfig = dbConfigProvider.get[JdbcProfile]
import dbConfig._
import driver.api._
/**
* Table with all laboratories, like select * from laboratory
*/
implicit val laboratories = TableQuery[LaboratoryTable]
implicit val rooms = TableQuery[RoomTable]
implicit val computers = TableQuery[ComputerTable]
implicit val computerStates = TableQuery[ComputerStateTable]
implicit val connectedUsers = TableQuery[ConnectedUserTable]
implicit val computersAndRoomsPentaJoin = {
laboratories joinLeft rooms on {
_.id === _.laboratoryId
} joinLeft computers on { (x, y) => x._2.map(_.id) === y.roomId } joinLeft computerStates on { (x, y) => x._2.map(_.ip) === y.computerIp } joinLeft connectedUsers on { (x, y) => x._2.map(_.computerIp) === y.computerStateComputerIp && x._2.map(_.registeredDate) === y.computerStateRegisteredDate }
}
/**
* Adds a new laboratory to database.
*
* @param laboratory Laboratory to add.
* @return Result string message.
*/
override def add(laboratory: Laboratory): Future[ActionState] = {
Logger.debug(s"""Adding to database: $laboratory""")
db.run(laboratories += laboratory).map(res => state.ActionCompleted).recover {
case ex: Exception =>
Logger.error(s"There was an exception adding the laboratory $laboratory to the database", ex)
state.Failed
}
}
/**
* Removes a laboratory
*
* @param id Laboratory's ID.
* @return Operation result.
*/
override def delete(id: Long): Future[ActionState] = {
db.run(search(id).delete).map {
case 1 => state.ActionCompleted
case 0 => state.NotFound
case error =>
play.Logger.error(s"Error code deleting that laboratory: $error")
state.Failed
}
}
private def search(id: Long) = laboratories.filter(_.id === id)
/**
* List all the laboratories on the database.
*
* @return All the laboratories found.
*/
override def listAll: Future[Seq[Laboratory]] = {
db.run(laboratories.result)
}
/**
* Gets the laboratory with all the rooms an computers associated.
*
* @param id Laboratory's ID.
* @return Found laboratory with all its rooms and computers.
*/
override def getWithChildren(id: Long): Future[Seq[(Laboratory, Option[Room], (Option[Computer], Option[ComputerState], Option[ConnectedUser]))]] = {
db.run {
computersAndRoomsPentaJoin
.filter(_._1._1._1._1.id === id)
.map(x => (x._1._1._1._1, x._1._1._1._2, (x._1._1._2, x._1._2, x._2)))
.result
}
}
/**
* Gets a laboratory by its ID.
*
* @param id Laboratory's ID.
* @return Some found laboratory or None if its not found.
*/
override def get(id: Long): Future[Option[Laboratory]] = {
// Select * from laboratory where id = $id
db.run(search(id).result.headOption)
}
override def update(laboratory: Laboratory): Future[ActionState] = {
db.run {
val foundLaboratory = search(laboratory.id)
foundLaboratory.update(laboratory).asTry
}.map{
case Success(res) if res == 1 =>
play.Logger.info(s"updated with result: $res")
state.ActionCompleted
case Success(_) =>
play.Logger.info("Laboratory not found")
state.NotFound
case Failure(e: JdbcSQLException) =>
play.Logger.error("There was an error looking for that laboratory",e)
state.NotFound
case _ => state.Failed
}
}
}