app/models/PlutoCommission.scala (171 lines of code) (raw):

package models import java.sql.Timestamp import java.time.{ZoneId, ZonedDateTime} import org.joda.time.DateTime import play.api.Logger import play.api.libs.functional.syntax.unlift import play.api.libs.json._ import play.api.libs.functional.syntax._ import slick.lifted.{TableQuery, Tag} import slick.jdbc.PostgresProfile.api._ import scala.concurrent.Future import scala.util.{Failure, Success, Try} import scala.concurrent.ExecutionContext.Implicits.global import ProductionOfficeMapper._ import com.fasterxml.jackson.module.scala.JsonScalaEnumeration case class PlutoCommission (id:Option[Int], collectionId:Option[Int], siteId: Option[String], created: Timestamp, updated:Timestamp, title: String, status: EntryStatus.Value, description: Option[String], workingGroup: Int, originalCommissionerName:Option[String], scheduledCompletion:Timestamp, owner:String, notes:Option[String], @JsonScalaEnumeration(classOf[ProductionOfficeMapper.EnumStatusType]) productionOffice:ProductionOffice.Value, originalTitle:Option[String], googleFolder:Option[String], confidential: Option[Boolean]) extends PlutoModel { private def logger = Logger(getClass) var projectCount: Option[Int] = None /** * writes this model into the database, inserting if id is None and returning a fresh object with id set. If an id * was set, then updates the database record and returns the same object. */ def save(implicit db: slick.jdbc.JdbcProfile#Backend#Database):Future[Try[PlutoCommission]] = id match { case None=> logger.debug("Inserting commission record") val insertQuery = TableQuery[PlutoCommissionRow] returning TableQuery[PlutoCommissionRow].map(_.id) into ((item,id)=>item.copy(id=Some(id))) db.run( (insertQuery+=this).asTry ).map({ case Success(insertResult)=> logger.debug(s"Successful insert: $insertResult") Success(insertResult.asInstanceOf[PlutoCommission]) //maybe only intellij needs the cast here? case Failure(error)=> logger.error(s"could not insert record: ",error) Failure(error) }) case Some(realEntityId)=> logger.debug(s"Updating commission record $realEntityId") db.run( TableQuery[PlutoCommissionRow].filter(_.id===realEntityId).update(this).asTry ).map({ case Success(rowsAffected)=>Success(this) case Failure(error)=>Failure(error) }) } /** * inserts this record into the database if there is nothing with the given uuid present * @param db - implicitly provided database object * @return a Future containing a Try containing a [[PlutoCommission]] object. * If it was newly saved, or exists in the db, the id member will be set. */ def ensureRecorded(implicit db: slick.jdbc.JdbcProfile#Backend#Database):Future[Try[PlutoCommission]] = { db.run( TableQuery[PlutoCommissionRow].filter(_.collectionId===collectionId).filter(_.siteId===siteId).result.asTry ).flatMap({ case Success(rows)=> if(rows.isEmpty) { logger.info(s"Saving commission $title ($siteId-$collectionId) to the database") this.save } else { logger.info(s"Commission $title ($siteId-$collectionId) already existed") val updatedInfo = this.copy(id=Some(rows.head.id.get)) updatedInfo.save Future(Success(updatedInfo)) } case Failure(error)=> logger.error("could not check commission: ",error) Future(Failure(error)) }) } /** * returns the contents as a string->string map, for passing to postrun actions * @return */ def asStringMap:Map[String,String] = Map( "commissionId"->s"$siteId-$collectionId", "commissionCreated"->created.toString, "commissionUpdated"->updated.toString, "commissionTitle"->title, "commissionDescription"->description.getOrElse("") ) def removeFromDatabase(implicit db:slick.jdbc.PostgresProfile#Backend#Database):Future[Try[Unit]] = id match { case Some(realEntityId)=> db.run(DBIO.seq( TableQuery[PlutoCommissionRow].filter(_.id===realEntityId).delete, ).asTry) case None=> Future(Failure(new RuntimeException("A record must have been saved before it can be removed from the database."))) } } class PlutoCommissionRow (tag:Tag) extends Table[PlutoCommission](tag,"PlutoCommission"){ import EntryStatusMapper._ import ProductionOfficeMapper._ def id = column[Int]("id",O.PrimaryKey, O.AutoInc) def collectionId = column[Option[Int]]("i_collection_id") def siteId = column[Option[String]]("s_site_id") def created = column[Timestamp]("t_created") def updated = column[Timestamp]("t_updated") def title = column[String]("s_title") def status = column[EntryStatus.Value]("s_status") def description = column[Option[String]]("s_description") def workingGroup = column[Int]("k_working_group") def originalCommissionerName = column[Option[String]]("s_original_commissioner") def scheduledCompletion = column[Timestamp]("t_scheduled_completion") def owner = column[String]("s_owner") def notes = column[Option[String]]("s_notes") def productionOffice = column[ProductionOffice.Value]("s_production_office") def originalTitle = column[Option[String]]("s_original_title") def googleFolder = column[Option[String]]("s_google_folder") def confidential = column[Option[Boolean]]("b_confidential") def * = (id.?, collectionId, siteId, created, updated, title, status, description, workingGroup, originalCommissionerName, scheduledCompletion, owner, notes, productionOffice, originalTitle, googleFolder, confidential) <> (PlutoCommission.tupled, PlutoCommission.unapply) } trait PlutoCommissionSerializer extends TimestampSerialization { import EntryStatusMapper._ implicit val plutoCommissionWrites: Writes[PlutoCommission] = (commission: PlutoCommission) => { val tuple = plutoCommissionTupleWrites.writes(commission).as[JsObject] commission.projectCount match { case Some(count) => tuple .+ ("projectCount", JsNumber(count)) case None => tuple } } val plutoCommissionTupleWrites:Writes[PlutoCommission] = ( (JsPath \ "id").writeNullable[Int] and (JsPath \ "collectionId").writeNullable[Int] and (JsPath \ "siteId").writeNullable[String] and (JsPath \ "created").write[Timestamp] and (JsPath \ "updated").write[Timestamp] and (JsPath \ "title").write[String] and (JsPath \ "status").write[EntryStatus.Value] and (JsPath \ "description").writeNullable[String] and (JsPath \ "workingGroupId").write[Int] and (JsPath \ "originalCommissionerName").writeNullable[String] and (JsPath \ "scheduledCompletion").write[Timestamp] and (JsPath \ "owner").write[String] and (JsPath \ "notes").writeNullable[String] and (JsPath \ "productionOffice").write[ProductionOffice.Value] and (JsPath \ "originalTitle").writeNullable[String] and (JsPath \ "googleFolder").writeNullable[String] and (JsPath \ "confidential").writeNullable[Boolean] )(unlift(PlutoCommission.unapply)) implicit val plutoCommissionReads:Reads[PlutoCommission] = ( (JsPath \ "id").readNullable[Int] and (JsPath \ "collectionId").readNullable[Int] and (JsPath \ "siteId").readNullable[String] and (JsPath \ "created").read[Timestamp] and (JsPath \ "updated").read[Timestamp] and (JsPath \ "title").read[String] and (JsPath \ "status").read[EntryStatus.Value] and (JsPath \ "description").readNullable[String] and (JsPath \ "workingGroupId").read[Int] and (JsPath \ "originalCommissionerName").readNullable[String] and (JsPath \ "scheduledCompletion").read[Timestamp] and (JsPath \ "owner").read[String] and (JsPath \ "notes").readNullable[String] and (JsPath \ "productionOffice").read[ProductionOffice.Value] and (JsPath \ "originalTitle").readNullable[String] and (JsPath \ "googleFolder").readNullable[String] and (JsPath \ "confidential").readNullable[Boolean] )(PlutoCommission.apply _) } object PlutoCommission extends ((Option[Int],Option[Int],Option[String],Timestamp,Timestamp,String,EntryStatus.Value,Option[String],Int,Option[String],Timestamp,String,Option[String],ProductionOffice.Value, Option[String], Option[String], Option[Boolean])=>PlutoCommission) { def entryForVsid(vsid:String)(implicit db:slick.jdbc.PostgresProfile#Backend#Database):Future[Option[PlutoCommission]] = { val idparts = vsid.split("-") if(idparts.length!=2) return Future(None) db.run( TableQuery[PlutoCommissionRow].filter(_.siteId===idparts.head).filter(_.collectionId===idparts(1).toInt).result ).map(_.headOption) } def forId(id:Int) (implicit db:slick.jdbc.PostgresProfile#Backend#Database):Future[Option[PlutoCommission]] = db.run { TableQuery[PlutoCommissionRow].filter(_.id===id).result }.map(_.headOption) //handle different explicit time format def timestampToDateTime(t: Timestamp): ZonedDateTime = ZonedDateTime.ofInstant(t.toInstant, ZoneId.systemDefault()) def dateTimeToTimestamp(dt: ZonedDateTime): Timestamp = new Timestamp(dt.toInstant.toEpochMilli) /** * performs a conversion from java.sql.Timestamp to Joda DateTime and back again */ implicit val timestampFormat = new Format[Timestamp] { def writes(t: Timestamp): JsValue = Json.toJson(timestampToDateTime(t)) def reads(json: JsValue): JsResult[Timestamp] = Json.fromJson[ZonedDateTime](json).map(dateTimeToTimestamp) } }