Skip to content

Commit f052cb6

Browse files
authored
[ID-1179] Add Sam lock dao layer (#1423)
* Add SamLock DAO * Handle duplicate locks * Add delete lock dao methods * Fix tests * Fix lock type in test
1 parent a65f522 commit f052cb6

File tree

5 files changed

+141
-0
lines changed

5 files changed

+141
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.broadinstitute.dsde.workbench.sam.dataAccess
2+
3+
import cats.effect.IO
4+
import java.util.UUID
5+
import org.broadinstitute.dsde.workbench.sam.model.api.SamLock
6+
import org.broadinstitute.dsde.workbench.sam.util.SamRequestContext
7+
8+
trait LockDao {
9+
def create(lock: SamLock, samRequestContext: SamRequestContext): IO[SamLock]
10+
11+
def delete(lockId: UUID, samRequestContext: SamRequestContext): IO[Boolean]
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.broadinstitute.dsde.workbench.sam.dataAccess
2+
3+
import akka.http.scaladsl.model.StatusCodes
4+
import cats.effect.{IO, Temporal}
5+
import com.typesafe.scalalogging.LazyLogging
6+
import java.util.UUID
7+
import org.broadinstitute.dsde.workbench.sam.errorReportSource
8+
import org.broadinstitute.dsde.workbench.model.{ErrorReport, WorkbenchExceptionWithErrorReport}
9+
import org.broadinstitute.dsde.workbench.sam.db.SamParameterBinderFactory._
10+
import org.broadinstitute.dsde.workbench.sam.db._
11+
import org.broadinstitute.dsde.workbench.sam.db.tables._
12+
import org.broadinstitute.dsde.workbench.sam.model.api.SamLock
13+
import org.broadinstitute.dsde.workbench.sam.util.{DatabaseSupport, SamRequestContext}
14+
import org.postgresql.util.PSQLException
15+
import scala.util.{Failure, Try}
16+
17+
class PostgresLockDAO(protected val writeDbRef: DbReference, protected val readDbRef: DbReference)(implicit timer: Temporal[IO])
18+
extends LockDao
19+
with DatabaseSupport
20+
with LazyLogging {
21+
22+
override def create(lock: SamLock, samRequestContext: SamRequestContext): IO[SamLock] =
23+
serializableWriteTransaction("createLock", samRequestContext) { implicit session =>
24+
val lockTableColumn = LockTable.column
25+
val insertLockQuery =
26+
samsql"""insert into ${LockTable.table} (${lockTableColumn.id}, ${lockTableColumn.description}, ${lockTableColumn.lock_type}, ${lockTableColumn.lock_detail})
27+
values (${lock.id}, ${lock.description}, ${lock.lockType}, ${lock.lockDetails.toString()}::jsonb)"""
28+
Try {
29+
insertLockQuery.update().apply()
30+
}.recoverWith {
31+
case duplicateException: PSQLException if duplicateException.getSQLState == PSQLStateExtensions.UNIQUE_VIOLATION =>
32+
Failure(new WorkbenchExceptionWithErrorReport(ErrorReport(StatusCodes.Conflict, s"A lock with id ${lock.id} already exists")))
33+
}.get
34+
lock
35+
}
36+
37+
override def delete(lockId: UUID, samRequestContext: SamRequestContext): IO[Boolean] =
38+
serializableWriteTransaction("deleteLock", samRequestContext) { implicit session =>
39+
val lockTableColumn = LockTable.column
40+
samsql"delete from ${LockTable.table} where ${lockTableColumn.id} = $lockId".update().apply() > 0
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.broadinstitute.dsde.workbench.sam.db.tables
2+
3+
import java.util.UUID
4+
5+
final case class LockRecord(id: UUID, description: String, lock_type: String, lock_detail: Object)
6+
7+
object LockTable extends SQLSyntaxSupportWithDefaultSamDB[LockRecord] {
8+
override def tableName: String = "SAM_LOCK"
9+
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.broadinstitute.dsde.workbench.sam.model.api
2+
import spray.json.JsObject
3+
4+
import java.util.UUID
5+
6+
case class SamLock(
7+
id: UUID,
8+
description: String,
9+
lockType: String,
10+
lockDetails: JsObject
11+
) {
12+
13+
override def equals(other: Any): Boolean = other match {
14+
case lock: SamLock =>
15+
this.id == lock.id &&
16+
this.description == lock.description &&
17+
this.lockType == lock.lockType &&
18+
this.lockDetails == lock.lockDetails
19+
case _ => false
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.broadinstitute.dsde.workbench.sam.dataAccess
2+
3+
import akka.http.scaladsl.model.StatusCodes
4+
import cats.effect.unsafe.implicits.global
5+
import org.broadinstitute.dsde.workbench.model.WorkbenchExceptionWithErrorReport
6+
import org.broadinstitute.dsde.workbench.sam.TestSupport.{databaseEnabled, databaseEnabledClue, samRequestContext}
7+
import org.broadinstitute.dsde.workbench.sam.matchers.TimeMatchers
8+
import org.broadinstitute.dsde.workbench.sam.model.api.SamLock
9+
import org.broadinstitute.dsde.workbench.sam.{RetryableAnyFreeSpec, TestSupport}
10+
import org.scalatest.matchers.should.Matchers
11+
import org.scalatest.{BeforeAndAfterEach, OptionValues}
12+
import spray.json.{JsObject, JsString}
13+
14+
import java.util.UUID
15+
16+
class PostgresLockDAOSpec extends RetryableAnyFreeSpec with Matchers with BeforeAndAfterEach with TimeMatchers with OptionValues {
17+
val dao = new PostgresLockDAO(TestSupport.dbRef, TestSupport.dbRef)
18+
val description = "Test lock"
19+
val lockType = "DUOS"
20+
val lockDetails: JsObject = JsObject("datasetId" -> JsString("DUOS_123"))
21+
val lockNoDescription: SamLock = SamLock(UUID.randomUUID(), null, lockType, lockDetails)
22+
23+
override protected def beforeEach(): Unit =
24+
TestSupport.truncateAll
25+
26+
"PostgresLockDAO" - {
27+
"create" - {
28+
"create a lock" in {
29+
assume(databaseEnabled, databaseEnabledClue)
30+
val lock: SamLock = SamLock(UUID.randomUUID(), description, lockType, lockDetails)
31+
dao.create(lock, samRequestContext = samRequestContext).unsafeRunSync() shouldEqual lock
32+
}
33+
"creating a lock with a duplicate id fails" in {
34+
assume(databaseEnabled, databaseEnabledClue)
35+
val lock: SamLock = SamLock(UUID.randomUUID(), description, lockType, lockDetails)
36+
dao.create(lock, samRequestContext = samRequestContext).unsafeRunSync()
37+
val exception = intercept[WorkbenchExceptionWithErrorReport] {
38+
dao.create(lock, samRequestContext = samRequestContext).unsafeRunSync()
39+
}
40+
exception.errorReport.statusCode shouldEqual Some(StatusCodes.Conflict)
41+
}
42+
}
43+
"delete" - {
44+
"delete a lock" in {
45+
assume(databaseEnabled, databaseEnabledClue)
46+
val lock: SamLock = SamLock(UUID.randomUUID(), description, lockType, lockDetails)
47+
dao.create(lock, samRequestContext = samRequestContext).unsafeRunSync() shouldEqual lock
48+
dao.delete(lock.id, samRequestContext).unsafeRunSync() shouldBe true
49+
}
50+
"delete a non-existent lock" in {
51+
assume(databaseEnabled, databaseEnabledClue)
52+
dao.delete(UUID.randomUUID(), samRequestContext).unsafeRunSync() shouldBe false
53+
}
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)