Starting work on the database implementation.

This commit is contained in:
Pat Garrity 2024-07-24 21:50:58 -05:00
parent 284c1e06b8
commit 456e625e82
Signed by: pfm
GPG key ID: 5CA5D21BAB7F3A76
7 changed files with 117 additions and 2 deletions

View file

@ -75,6 +75,7 @@ lazy val model = project
lazy val db = project
.in(file("modules/db"))
.dependsOn(model)
.settings(sharedSettings)
.settings(testSettings)
.settings(name := s"${gsProjectName.value}-db")
@ -86,6 +87,7 @@ lazy val db = project
lazy val api = project
.in(file("modules/api"))
.dependsOn(model, db)
.settings(sharedSettings)
.settings(testSettings)
.settings(name := s"${gsProjectName.value}-api")

View file

@ -0,0 +1,20 @@
package gs.smolban.db
import gs.smolban.model.SmolbanError
import gs.smolban.model.Ticket
/** Parent type of all database errors in Smolban.
*/
sealed trait DbError extends SmolbanError
object DbError:
/** Returned if an attempt is made to insert a [[Ticket]], where the Ticket ID
* already exists for the specified [[gs.smolban.model.Group]].
*
* @param ref
* The Ticket Reference that was in conflict.
*/
case class TicketAlreadyExists(ref: Ticket.Reference) extends DbError
end DbError

View file

@ -0,0 +1,48 @@
package gs.smolban.db
import cats.data.EitherT
import gs.smolban.model.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]

View file

@ -0,0 +1,27 @@
package gs.smolban.db.doobie
import cats.data.EitherT
import cats.effect.Async
import gs.smolban.db.DbError
import gs.smolban.db.TicketDb
import gs.smolban.model.Ticket
final class DoobieTicketDb[F[_]: Async] extends TicketDb[F]:
/** @inheritdoc
*/
override def createTicket(ticket: Ticket): EitherT[F, DbError, Ticket] = ???
/** @inheritdoc
*/
override def readTicket(ref: Ticket.Reference): F[Option[Ticket]] = ???
/** @inheritdoc
*/
override def updateTicket(
ref: Ticket.Reference,
newValue: Ticket
): F[Option[Ticket]] = ???
/** @inheritdoc
*/
override def deleteTicket(ref: Ticket.Reference): F[Boolean] = ???

View file

@ -0,0 +1,5 @@
package gs.smolban.model
/** The parent trait for all errors in Smolban.
*/
trait SmolbanError

View file

@ -38,10 +38,23 @@ case class Ticket(
status: Ticket.Status,
statusHistory: List[(Ticket.Status, Instant)],
assignee: Option[User.Id]
)
):
lazy val reference: Ticket.Reference = Ticket.Reference(id, group)
object Ticket:
/** Composite reference that uniquely addresses any [[Ticket]].
*
* @param id
* The ticket's unique identifier within the [[Group]].
* @param group
* The unique identifier of the [[Group]].
*/
case class Reference(
id: Ticket.Id,
group: Group.Id
)
/** Unique identifier - relative to some [[Group]] - for a [[Ticket]]. This is
* an opaque type for a Long. In general, [[Ticket]] identifiers are
* sequences within a group.

View file

@ -1 +1 @@
sbt.version=1.10.0
sbt.version=1.10.1