WIP: More db prepping to run tests with sqlite
This commit is contained in:
parent
f25c9658eb
commit
8d0567195a
11 changed files with 79 additions and 338 deletions
13
build.sbt
13
build.sbt
|
|
@ -28,6 +28,13 @@ val Deps = new {
|
||||||
|
|
||||||
val Doobie = new {
|
val Doobie = new {
|
||||||
val Core: ModuleID = "org.tpolecat" %% "doobie-core" % "1.0.0-RC11"
|
val Core: ModuleID = "org.tpolecat" %% "doobie-core" % "1.0.0-RC11"
|
||||||
|
val Hikari: ModuleID = "org.tpolecat" %% "doobie-hikari" % "1.0.0-RC11"
|
||||||
|
val Postgres: ModuleID = "org.tpolecat" %% "doobie-postgres" % "1.0.0-RC11"
|
||||||
|
}
|
||||||
|
|
||||||
|
val JdbcDriver = new {
|
||||||
|
val Sqlite: ModuleID = "org.xerial" % "sqlite-jdbc" % "3.51.1.0"
|
||||||
|
val PostgreSQL: ModuleID = "org.postgresql" % "postgresql" % "42.7.9"
|
||||||
}
|
}
|
||||||
|
|
||||||
val Http4s = new {
|
val Http4s = new {
|
||||||
|
|
@ -96,7 +103,11 @@ lazy val db = project
|
||||||
.settings(name := s"${gsProjectName.value}-db")
|
.settings(name := s"${gsProjectName.value}-db")
|
||||||
.settings(
|
.settings(
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
Deps.Doobie.Core
|
Deps.Doobie.Core,
|
||||||
|
Deps.Doobie.Hikari,
|
||||||
|
Deps.Doobie.Postgres,
|
||||||
|
Deps.JdbcDriver.Sqlite,
|
||||||
|
Deps.JdbcDriver.PostgreSQL
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package gs.smolban.db
|
|
||||||
|
|
||||||
object DbConstants:
|
|
||||||
|
|
||||||
val UniqueConstraintFailed: List[Int] =
|
|
||||||
List(Sqlite.UniqueConstraintFailed)
|
|
||||||
|
|
||||||
object Sqlite:
|
|
||||||
|
|
||||||
val UniqueConstraintFailed: Int = 2067
|
|
||||||
|
|
||||||
end Sqlite
|
|
||||||
|
|
||||||
end DbConstants
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
package gs.smolban.db
|
package gs.smolban.db
|
||||||
|
|
||||||
|
import _root_.doobie.enumerated.SqlState
|
||||||
import gs.smolban.auth.CredentialId
|
import gs.smolban.auth.CredentialId
|
||||||
import gs.smolban.model.SmolbanError
|
import gs.smolban.model.SmolbanError
|
||||||
import gs.smolban.model.account.AccountId
|
import gs.smolban.model.account.AccountId
|
||||||
import gs.smolban.model.account.AccountName
|
import gs.smolban.model.account.AccountName
|
||||||
import gs.smolban.model.account.AccountType
|
import gs.smolban.model.account.AccountType
|
||||||
|
import gs.smolban.model.metadata.TagValue
|
||||||
|
|
||||||
/** Parent type of all database errors in Smolban.
|
/** Parent type of all database errors in Smolban.
|
||||||
*/
|
*/
|
||||||
|
|
@ -12,6 +14,10 @@ sealed trait DbError extends SmolbanError
|
||||||
|
|
||||||
object DbError:
|
object DbError:
|
||||||
|
|
||||||
|
case class GenericDatabaseError(sqlState: SqlState) extends DbError
|
||||||
|
|
||||||
|
case class TagAlreadyExists(value: TagValue) extends DbError
|
||||||
|
|
||||||
/** Produced when creating any new account fails because an account with the
|
/** Produced when creating any new account fails because an account with the
|
||||||
* same name already exists.
|
* same name already exists.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
package gs.smolban.db
|
|
||||||
|
|
||||||
import cats.data.EitherT
|
|
||||||
import gs.smolban.model.Group
|
|
||||||
|
|
||||||
/** Database interface for [[Group]].
|
|
||||||
*/
|
|
||||||
trait GroupDb[F[_]]:
|
|
||||||
/** Create a new [[Group]] in the database.
|
|
||||||
*
|
|
||||||
* @param group
|
|
||||||
* The [[Group]] to store.
|
|
||||||
* @return
|
|
||||||
* The [[Group]] that was stored, or an error.
|
|
||||||
*/
|
|
||||||
def createGroup(group: Group): EitherT[F, DbError, Group]
|
|
||||||
|
|
||||||
/** Read the specified [[Group]] from the database.
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
* The unique identifier of the [[Group]] to retrieve.
|
|
||||||
* @return
|
|
||||||
* The [[Group]], or `None` if the specified ID does not exist.
|
|
||||||
*/
|
|
||||||
def readGroup(id: Group.Id): F[Option[Group]]
|
|
||||||
|
|
||||||
/** Delete the specified [[Group]]. Note that this operation deletes all
|
|
||||||
* [[Ticket]] associated with the group and should be used with care.
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
* The unique identifier of the [[Group]] to delete.
|
|
||||||
* @return
|
|
||||||
* `true` if the group was deleted, `false` otherwise.
|
|
||||||
*/
|
|
||||||
def deleteGroup(id: Group.Id): F[Boolean]
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package gs.smolban.db
|
package gs.smolban.db
|
||||||
|
|
||||||
import cats.data.EitherT
|
import cats.data.EitherT
|
||||||
import gs.smolban.model.CreatedAt
|
import gs.smolban.model.metadata.CreatedAt
|
||||||
import gs.smolban.model.Tag
|
import gs.smolban.model.metadata.Tag
|
||||||
|
import gs.smolban.model.metadata.TagValue
|
||||||
|
|
||||||
trait TagDb[F[_]]:
|
trait TagDb[F[_]]:
|
||||||
|
|
||||||
|
|
@ -16,24 +17,24 @@ trait TagDb[F[_]]:
|
||||||
* The new [[Tag]], or an error if the value already exists.
|
* The new [[Tag]], or an error if the value already exists.
|
||||||
*/
|
*/
|
||||||
def createTag(
|
def createTag(
|
||||||
tag: Tag.Value,
|
tag: TagValue,
|
||||||
createdAt: CreatedAt
|
createdAt: CreatedAt
|
||||||
): EitherT[F, DbError, Tag]
|
): EitherT[F, DbError, Tag]
|
||||||
|
|
||||||
/** Get the value of some [[Tag]] by ID.
|
/** Get the value of some [[Tag]] by value.
|
||||||
*
|
*
|
||||||
* @param id
|
* @param tag
|
||||||
* The internal identifier of the [[Tag]].
|
* The value of the [[Tag]].
|
||||||
* @return
|
* @return
|
||||||
* The found [[Tag]], or `None` if the ID does not exist.
|
* The found [[Tag]], or `None` if the value does not exist.
|
||||||
*/
|
*/
|
||||||
def readTag(id: Tag.Id): F[Option[Tag]]
|
def readTag(tag: TagValue): F[Option[Tag]]
|
||||||
|
|
||||||
/** Delete a [[Tag]] by ID.
|
/** Delete a [[Tag]] by value.
|
||||||
*
|
*
|
||||||
* @param id
|
* @param tag
|
||||||
* The unique ID of the [[Tag]] to delete.
|
* The unique value of the [[Tag]] to delete.
|
||||||
* @return
|
* @return
|
||||||
* `true` if the [[Tag]] was deleted, `false` otherwise.
|
* `true` if the [[Tag]] was deleted, `false` otherwise.
|
||||||
*/
|
*/
|
||||||
def deleteTag(id: Tag.Id): F[Boolean]
|
def deleteTag(tag: TagValue): F[Boolean]
|
||||||
|
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
package gs.smolban.db
|
|
||||||
|
|
||||||
import cats.data.EitherT
|
|
||||||
import gs.smolban.model.Ticket
|
|
||||||
|
|
||||||
/** Database interface for [[Ticket]].
|
|
||||||
*/
|
|
||||||
trait TicketDb[F[_]]:
|
|
||||||
/** Create a new [[Ticket]] in the database.
|
|
||||||
*
|
|
||||||
* @param ticket
|
|
||||||
* The [[Ticket]] to store.
|
|
||||||
* @return
|
|
||||||
* The [[Ticket]] that was created, or an error.
|
|
||||||
*/
|
|
||||||
def createTicket(ticket: Ticket): EitherT[F, DbError, Ticket]
|
|
||||||
|
|
||||||
/** Read the specified [[Ticket]] from the database.
|
|
||||||
*
|
|
||||||
* @param ref
|
|
||||||
* The reference to the [[Ticket]] to retrieve.
|
|
||||||
* @return
|
|
||||||
* The value of the [[Ticket]], or `None` if no such [[Ticket]] exists.
|
|
||||||
*/
|
|
||||||
def readTicket(ref: Ticket.Reference): F[Option[Ticket]]
|
|
||||||
|
|
||||||
/** Given a reference to a [[Ticket]] and some new value for that [[Ticket]],
|
|
||||||
* update the [[Ticket]] in the database.
|
|
||||||
*
|
|
||||||
* @param ref
|
|
||||||
* The refrence to the [[Ticket]] to update.
|
|
||||||
* @param newValue
|
|
||||||
* The new values with which to overwrite the [[Ticket]].
|
|
||||||
* @return
|
|
||||||
* The modified [[Ticket]] if the operation succeeded, or `None` if the
|
|
||||||
* given reference does not exist.
|
|
||||||
*/
|
|
||||||
def updateTicket(
|
|
||||||
ref: Ticket.Reference,
|
|
||||||
newValue: Ticket
|
|
||||||
): F[Option[Ticket]]
|
|
||||||
|
|
||||||
/** Delete the specified [[Ticket]].
|
|
||||||
*
|
|
||||||
* @param ref
|
|
||||||
* The reference to the [[Ticket]] to delete.
|
|
||||||
* @return
|
|
||||||
* `true` if the operation deleted a [[Ticket]], `false` otherwise.
|
|
||||||
*/
|
|
||||||
def deleteTicket(ref: Ticket.Reference): F[Boolean]
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package gs.smolban.db.doobie
|
||||||
|
|
||||||
|
import doobie.enumerated.SqlState
|
||||||
|
|
||||||
|
sealed trait CuratedSqlStates:
|
||||||
|
def uniqueViolation: SqlState
|
||||||
|
|
||||||
|
object CuratedSqlStates:
|
||||||
|
|
||||||
|
final class PostgreSQL extends CuratedSqlStates:
|
||||||
|
|
||||||
|
override val uniqueViolation: SqlState =
|
||||||
|
doobie.postgres.sqlstate.class23.UNIQUE_VIOLATION
|
||||||
|
|
||||||
|
final class Sqlite extends CuratedSqlStates:
|
||||||
|
|
||||||
|
override val uniqueViolation: SqlState =
|
||||||
|
SqlState("2067")
|
||||||
|
|
||||||
|
end CuratedSqlStates
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
package gs.smolban.db.doobie
|
|
||||||
|
|
||||||
import cats.MonadError
|
|
||||||
import cats.data.EitherT
|
|
||||||
import cats.syntax.all.*
|
|
||||||
import doobie.*
|
|
||||||
import doobie.implicits.*
|
|
||||||
import gs.smolban.db.DbError
|
|
||||||
import gs.smolban.db.GroupDb
|
|
||||||
import gs.smolban.db.doobie.DoobieTypes.*
|
|
||||||
import gs.smolban.model.CreatedAt
|
|
||||||
import gs.smolban.model.Group
|
|
||||||
|
|
||||||
final class DoobieGroupDb() extends GroupDb[ConnectionIO]:
|
|
||||||
|
|
||||||
import DoobieGroupDb.Sql
|
|
||||||
import gs.smolban.db.DbConstants
|
|
||||||
|
|
||||||
/** @inheritdoc
|
|
||||||
*/
|
|
||||||
override def createGroup(
|
|
||||||
group: Group
|
|
||||||
): EitherT[ConnectionIO, DbError, Group] =
|
|
||||||
EitherT(
|
|
||||||
Sql.createGroup(group).run.attemptSql.flatMap {
|
|
||||||
case Left(ex) =>
|
|
||||||
if DbConstants.UniqueConstraintFailed.contains(ex.getErrorCode()) then
|
|
||||||
Left(
|
|
||||||
DbError.GroupAlreadyExists(group.id, group.slug)
|
|
||||||
).pure[ConnectionIO]
|
|
||||||
else MonadError[ConnectionIO, Throwable].raiseError(ex)
|
|
||||||
case Right(_) =>
|
|
||||||
Right(group).pure[ConnectionIO]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
/** @inheritdoc
|
|
||||||
*/
|
|
||||||
override def readGroup(id: Group.Id): ConnectionIO[Option[Group]] =
|
|
||||||
Sql.readGroup(id).option
|
|
||||||
|
|
||||||
/** @inheritdoc
|
|
||||||
*/
|
|
||||||
override def deleteGroup(id: Group.Id): ConnectionIO[Boolean] =
|
|
||||||
for
|
|
||||||
_ <- Sql.deleteAllTicketsForGroup(id).run
|
|
||||||
rows <- Sql.deleteGroup(id).run
|
|
||||||
yield rows > 0
|
|
||||||
|
|
||||||
object DoobieGroupDb:
|
|
||||||
|
|
||||||
private object Sql:
|
|
||||||
|
|
||||||
def createGroup(group: Group): Update0 = sql"""
|
|
||||||
INSERT INTO groups (group_id, slug, created_at)
|
|
||||||
VALUES (${group.id}, ${group.slug}, ${group.createdAt})
|
|
||||||
""".update
|
|
||||||
|
|
||||||
def readGroup(groupId: Group.Id): Query0[Group] = sql"""
|
|
||||||
SELECT slug, created_at
|
|
||||||
FROM groups
|
|
||||||
WHERE group_id = $groupId
|
|
||||||
""".query[Group]
|
|
||||||
|
|
||||||
def deleteAllTicketsForGroup(groupId: Group.Id): Update0 = sql"""
|
|
||||||
DELETE FROM tickets
|
|
||||||
WHERE group_id = $groupId
|
|
||||||
""".update
|
|
||||||
|
|
||||||
def deleteGroup(groupId: Group.Id): Update0 = sql"""
|
|
||||||
DELETE FROM groups
|
|
||||||
WHERE group_id = $groupId
|
|
||||||
""".update
|
|
||||||
|
|
||||||
end Sql
|
|
||||||
|
|
||||||
object ErrorCodes:
|
|
||||||
|
|
||||||
val UniqueConstraintFailed: List[Int] =
|
|
||||||
List(Sqlite.UniqueConstraintFailed)
|
|
||||||
|
|
||||||
object Sqlite:
|
|
||||||
|
|
||||||
val UniqueConstraintFailed: Int = 2067
|
|
||||||
|
|
||||||
end Sqlite
|
|
||||||
|
|
||||||
end ErrorCodes
|
|
||||||
|
|
||||||
end DoobieGroupDb
|
|
||||||
|
|
@ -1,51 +1,47 @@
|
||||||
package gs.smolban.db.doobie
|
package gs.smolban.db.doobie
|
||||||
|
|
||||||
import cats.MonadError
|
|
||||||
import cats.data.EitherT
|
import cats.data.EitherT
|
||||||
import cats.syntax.all.*
|
|
||||||
import doobie.*
|
import doobie.*
|
||||||
import doobie.implicits.*
|
import doobie.implicits.*
|
||||||
import gs.smolban.db.DbError
|
import gs.smolban.db.DbError
|
||||||
import gs.smolban.db.TagDb
|
import gs.smolban.db.TagDb
|
||||||
import gs.smolban.db.doobie.DoobieTypes.*
|
import gs.smolban.db.doobie.DoobieTypes.*
|
||||||
import gs.smolban.model.CreatedAt
|
import gs.smolban.model.metadata.CreatedAt
|
||||||
import gs.smolban.model.Tag
|
import gs.smolban.model.metadata.Tag
|
||||||
|
import gs.smolban.model.metadata.TagValue
|
||||||
|
|
||||||
final class DoobieTagDb() extends TagDb[ConnectionIO]:
|
final class DoobieTagDb(
|
||||||
|
sqlStates: CuratedSqlStates
|
||||||
|
) extends TagDb[ConnectionIO]:
|
||||||
|
|
||||||
import DoobieTagDb.Sql
|
import DoobieTagDb.Sql
|
||||||
import gs.smolban.db.DbConstants
|
|
||||||
|
|
||||||
/** @inheritdoc
|
/** @inheritdoc
|
||||||
*/
|
*/
|
||||||
override def createTag(
|
override def createTag(
|
||||||
value: Tag.Value,
|
value: TagValue,
|
||||||
createdAt: CreatedAt
|
createdAt: CreatedAt
|
||||||
): EitherT[ConnectionIO, DbError, Tag] =
|
): EitherT[ConnectionIO, DbError, Tag] =
|
||||||
EitherT(
|
EitherT(
|
||||||
Sql.createTag(value, createdAt).option.attemptSql.flatMap {
|
Sql.createTag(value, createdAt).run.attemptSqlState.map {
|
||||||
case Left(ex) =>
|
case Left(sqlState) =>
|
||||||
if DbConstants.UniqueConstraintFailed.contains(ex.getErrorCode()) then
|
if sqlState.value == sqlStates.uniqueViolation.value then
|
||||||
Left(
|
Left(DbError.TagAlreadyExists(value))
|
||||||
DbError.TagAlreadyExists(value)
|
else Left(DbError.GenericDatabaseError(sqlState))
|
||||||
).pure[ConnectionIO]
|
case Right(_) =>
|
||||||
else MonadError[ConnectionIO, Throwable].raiseError(ex)
|
Right(Tag(value, createdAt))
|
||||||
case Right(None) =>
|
|
||||||
Left(DbError.SilentInsertFailure("doobie-tag-db")).pure[ConnectionIO]
|
|
||||||
case Right(Some(newId)) =>
|
|
||||||
Right(Tag(newId, value, createdAt)).pure[ConnectionIO]
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
/** @inheritdoc
|
/** @inheritdoc
|
||||||
*/
|
*/
|
||||||
override def readTag(id: Tag.Id): ConnectionIO[Option[Tag]] =
|
override def readTag(tag: TagValue): ConnectionIO[Option[Tag]] =
|
||||||
Sql.readTag(id).option
|
Sql.readTag(tag).option
|
||||||
|
|
||||||
/** @inheritdoc
|
/** @inheritdoc
|
||||||
*/
|
*/
|
||||||
override def deleteTag(id: Tag.Id): ConnectionIO[Boolean] =
|
override def deleteTag(tag: TagValue): ConnectionIO[Boolean] =
|
||||||
for rows <- Sql.deleteTag(id).run
|
for rows <- Sql.deleteTag(tag).run
|
||||||
yield rows > 0
|
yield rows > 0
|
||||||
|
|
||||||
object DoobieTagDb:
|
object DoobieTagDb:
|
||||||
|
|
@ -53,23 +49,22 @@ object DoobieTagDb:
|
||||||
private object Sql:
|
private object Sql:
|
||||||
|
|
||||||
def createTag(
|
def createTag(
|
||||||
tv: Tag.Value,
|
tag: TagValue,
|
||||||
createdAt: CreatedAt
|
createdAt: CreatedAt
|
||||||
): Query0[Tag.Id] = sql"""
|
): Update0 = sql"""
|
||||||
INSERT INTO tags (tag_value, created_at)
|
INSERT INTO tags (tag_value, created_at)
|
||||||
VALUES ($tv, $createdAt)
|
VALUES ($tag, $createdAt)
|
||||||
RETURNING id
|
""".update
|
||||||
""".query[Tag.Id]
|
|
||||||
|
|
||||||
def readTag(tagId: Tag.Id): Query0[Tag] = sql"""
|
def readTag(tag: TagValue): Query0[Tag] = sql"""
|
||||||
SELECT id, value, created_at
|
SELECT tag_value, created_at
|
||||||
FROM tags
|
FROM tags
|
||||||
WHERE id = $tagId
|
WHERE tag_value = $tag
|
||||||
""".query[Tag]
|
""".query[Tag]
|
||||||
|
|
||||||
def deleteTag(tagId: Tag.Id): Update0 = sql"""
|
def deleteTag(tag: TagValue): Update0 = sql"""
|
||||||
DELETE FROM tags
|
DELETE FROM tags
|
||||||
WHERE id = $tagId
|
WHERE tag_value = $tag
|
||||||
""".update
|
""".update
|
||||||
|
|
||||||
end Sql
|
end Sql
|
||||||
|
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
package gs.smolban.db.doobie
|
|
||||||
|
|
||||||
import cats.data.EitherT
|
|
||||||
import cats.syntax.all.*
|
|
||||||
import doobie.*
|
|
||||||
import doobie.implicits.*
|
|
||||||
import gs.smolban.db.DbError
|
|
||||||
import gs.smolban.db.TicketDb
|
|
||||||
import gs.smolban.db.doobie.DoobieTypes.*
|
|
||||||
import gs.smolban.model.CreatedAt
|
|
||||||
import gs.smolban.model.Group
|
|
||||||
import gs.smolban.model.Tag
|
|
||||||
import gs.smolban.model.Ticket
|
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
final class DoobieTicketDb() extends TicketDb[ConnectionIO]:
|
|
||||||
import DoobieTicketDb.Sql
|
|
||||||
|
|
||||||
/** @inheritdoc
|
|
||||||
*/
|
|
||||||
override def createTicket(ticket: Ticket)
|
|
||||||
: EitherT[ConnectionIO, DbError, Ticket] = ???
|
|
||||||
|
|
||||||
/** @inheritdoc
|
|
||||||
*/
|
|
||||||
override def readTicket(ref: Ticket.Reference): ConnectionIO[Option[Ticket]] =
|
|
||||||
Sql.readTicket(ref.number, ref.group).option.flatMap {
|
|
||||||
case None => None.pure[ConnectionIO]
|
|
||||||
case Some(ticketContents) =>
|
|
||||||
for
|
|
||||||
tags <- Sql.readTagsForTicket(ticketContents.id).stream.compile.toList
|
|
||||||
history <- Sql
|
|
||||||
.readHistoryForTicket(ticketContents.id)
|
|
||||||
.stream
|
|
||||||
.compile
|
|
||||||
.toList
|
|
||||||
yield Some(
|
|
||||||
Ticket(
|
|
||||||
number = ref.number,
|
|
||||||
group = ref.group,
|
|
||||||
createdAt = ticketContents.createdAt,
|
|
||||||
title = ticketContents.title,
|
|
||||||
description = ticketContents.description,
|
|
||||||
tags = tags,
|
|
||||||
status = ticketContents.status,
|
|
||||||
statusHistory = history
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @inheritdoc
|
|
||||||
*/
|
|
||||||
override def updateTicket(
|
|
||||||
ref: Ticket.Reference,
|
|
||||||
newValue: Ticket
|
|
||||||
): ConnectionIO[Option[Ticket]] = ???
|
|
||||||
|
|
||||||
/** @inheritdoc
|
|
||||||
*/
|
|
||||||
override def deleteTicket(ref: Ticket.Reference): ConnectionIO[Boolean] = ???
|
|
||||||
|
|
||||||
object DoobieTicketDb:
|
|
||||||
|
|
||||||
private object Sql:
|
|
||||||
|
|
||||||
case class TicketContents(
|
|
||||||
id: Long,
|
|
||||||
createdAt: CreatedAt,
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
status: Ticket.Status
|
|
||||||
)
|
|
||||||
|
|
||||||
def readTicket(
|
|
||||||
ticketNumber: Ticket.Number,
|
|
||||||
groupId: Group.Id
|
|
||||||
): Query0[TicketContents] = sql"""
|
|
||||||
SELECT id, created_at, created_by, title, description, status, assignee
|
|
||||||
FROM tickets
|
|
||||||
WHERE ticket_number = $ticketNumber AND group_id = $groupId
|
|
||||||
""".query[TicketContents]
|
|
||||||
|
|
||||||
def readTagsForTicket(
|
|
||||||
ticketId: Long
|
|
||||||
): Query0[Tag] = sql"""
|
|
||||||
SELECT id, tag_value, created_at
|
|
||||||
FROM tags
|
|
||||||
WHERE ticket_id = $ticketId
|
|
||||||
""".query[Tag]
|
|
||||||
|
|
||||||
def readHistoryForTicket(
|
|
||||||
ticketId: Long
|
|
||||||
): Query0[(Ticket.Status, Instant)] = sql"""
|
|
||||||
SELECT status, set_at
|
|
||||||
FROM ticket_history
|
|
||||||
WHERE ticket_id = $ticketId
|
|
||||||
""".query[(Ticket.Status, Instant)]
|
|
||||||
|
|
||||||
end Sql
|
|
||||||
|
|
||||||
end DoobieTicketDb
|
|
||||||
|
|
@ -3,10 +3,8 @@ package gs.smolban.db.doobie
|
||||||
import DoobieTypes.ErrorMessages
|
import DoobieTypes.ErrorMessages
|
||||||
import doobie.*
|
import doobie.*
|
||||||
import gs.smolban.model.metadata.CreatedAt
|
import gs.smolban.model.metadata.CreatedAt
|
||||||
import gs.smolban.model.metadata.Tag
|
|
||||||
import gs.smolban.model.metadata.TagValue
|
import gs.smolban.model.metadata.TagValue
|
||||||
import gs.smolban.model.ticket.CommentId
|
import gs.smolban.model.ticket.CommentId
|
||||||
import gs.smolban.model.ticket.Ticket
|
|
||||||
import gs.smolban.model.ticket.TicketStatus
|
import gs.smolban.model.ticket.TicketStatus
|
||||||
import gs.uuid.v0.UUID
|
import gs.uuid.v0.UUID
|
||||||
import gs.uuid.v0.UUIDFormat
|
import gs.uuid.v0.UUIDFormat
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue