Skip to content

Commit

Permalink
feat(pollux): implement the DAL for CRUD on the verifiable policy ent…
Browse files Browse the repository at this point in the history
…ity. ATL-2478 (#368)

* feat(pollux): implement the DAL for CRUD on the verifiable policy entity ATL-2487
  • Loading branch information
yshyn-iohk committed Feb 13, 2023
1 parent a2d9c98 commit b290a18
Show file tree
Hide file tree
Showing 10 changed files with 786 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.iohk.atala.pollux.core.model

import zio.{Clock, Random, ZIO}

import java.time.{OffsetDateTime, ZoneId, ZoneOffset}
import java.util.UUID

case class VerificationPolicy(
id: UUID,
name: String,
description: String,
createdAt: OffsetDateTime,
updatedAt: OffsetDateTime,
constrains: Seq[VerificationPolicyConstraint]
) {
def nonce: Int = hashCode()
}

object VerificationPolicy {
def make(name: String, description: String, constraints: Seq[VerificationPolicyConstraint]) =
for {
id <- Random.nextUUID
ts <- Clock.currentDateTime.map(_.atZoneSameInstant(ZoneOffset.UTC).toOffsetDateTime)
} yield VerificationPolicy(id, name, description, createdAt = ts, updatedAt = ts, constrains = constraints)
}
sealed trait VerificationPolicyConstraint

case class CredentialSchemaAndTrustedIssuersConstraint(
schemaId: String,
trustedIssuers: Seq[String]
) extends VerificationPolicyConstraint
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.iohk.atala.pollux.core.model.error

import java.util.UUID

sealed trait VerificationPolicyError
object VerificationPolicyError {
final case class RepositoryError(cause: Throwable) extends VerificationPolicyError
final case class NotFoundError(id: UUID) extends VerificationPolicyError
final case class UnexpectedError(cause: Throwable) extends VerificationPolicyError
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.iohk.atala.pollux.core.repository

import io.iohk.atala.pollux.core.model.{VerificationPolicy, VerificationPolicyConstraint}

import java.util.UUID

trait VerificationPolicyRepository[F[_]] {

def create(verificationPolicy: VerificationPolicy): F[VerificationPolicy]

def get(id: UUID): F[Option[VerificationPolicy]]

def exists(id: UUID): F[Boolean]

def getHash(id: UUID): F[Option[Int]]

def update(
id: UUID,
nonce: Int,
verificationPolicy: VerificationPolicy
): F[Option[VerificationPolicy]]

def delete(id: UUID, hash: Int): F[Option[VerificationPolicy]]

def totalCount(): F[Long]

def filteredCount(nameOpt: Option[String]): F[Long]

def lookup(
nameOpt: Option[String],
offsetOpt: Option[Int],
limitOpt: Option[Int]
): F[List[VerificationPolicy]]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package io.iohk.atala.pollux.core.service

import io.iohk.atala.pollux.core.model.error.VerificationPolicyError
import io.iohk.atala.pollux.core.model.error.VerificationPolicyError.*
import io.iohk.atala.pollux.core.model.{VerificationPolicy, VerificationPolicyConstraint}
import zio.IO

import java.util.UUID

trait VerificationPolicyService {

def create(
name: String,
description: String,
constraints: Seq[VerificationPolicyConstraint] = Seq.empty
): IO[VerificationPolicyError, VerificationPolicy]

def get(id: UUID): IO[VerificationPolicyError, Option[VerificationPolicy]]

def getHash(id: UUID): IO[VerificationPolicyError, Option[Int]]

def update(
id: UUID,
hash: Int,
verificationPolicy: VerificationPolicy
): IO[VerificationPolicyError, Option[VerificationPolicy]]

def delete(id: UUID, hash: Int): IO[VerificationPolicyError, Option[VerificationPolicy]]

def totalCount(): IO[VerificationPolicyError, Long]

def filteredCount(name: Option[String]): IO[VerificationPolicyError, Long]

def lookup(
name: Option[String],
offset: Option[Int],
limit: Option[Int]
): IO[VerificationPolicyError, List[VerificationPolicy]]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package io.iohk.atala.pollux.core.service

import io.iohk.atala.pollux.core.model.{VerificationPolicy, VerificationPolicyConstraint}
import io.iohk.atala.pollux.core.model.error.VerificationPolicyError
import io.iohk.atala.pollux.core.repository.VerificationPolicyRepository
import zio.{Clock, IO, Random, Task, URLayer, ZLayer}

import java.util.UUID

object VerificationPolicyServiceImpl {
val layer: URLayer[VerificationPolicyRepository[Task], VerificationPolicyService] =
ZLayer.fromFunction(VerificationPolicyServiceImpl(_))
}

class VerificationPolicyServiceImpl(
repository: VerificationPolicyRepository[Task]
) extends VerificationPolicyService {

private val throwableToVerificationPolicyError: Throwable => VerificationPolicyError =
VerificationPolicyError.RepositoryError.apply

override def create(
name: String,
description: String,
constraints: Seq[VerificationPolicyConstraint]
): IO[VerificationPolicyError, VerificationPolicy] = {
for {
verificationPolicy <- VerificationPolicy.make(name, description, constraints)
createdVerificationPolicy <- repository.create(verificationPolicy)
} yield createdVerificationPolicy
}.mapError(throwableToVerificationPolicyError)

override def get(id: UUID): IO[VerificationPolicyError, Option[VerificationPolicy]] =
repository
.get(id)
.mapError(throwableToVerificationPolicyError)

override def getHash(id: UUID): IO[VerificationPolicyError, Option[Int]] =
repository
.getHash(id)
.mapError(throwableToVerificationPolicyError)

override def update(
id: UUID,
hash: Int,
verificationPolicy: VerificationPolicy
): IO[VerificationPolicyError, Option[VerificationPolicy]] =
repository
.update(id, hash, verificationPolicy)
.mapError(throwableToVerificationPolicyError)

override def delete(id: UUID, hash: Int): IO[VerificationPolicyError, Option[VerificationPolicy]] =
repository
.delete(id, hash)
.mapError(throwableToVerificationPolicyError)

override def totalCount(): IO[VerificationPolicyError, Long] =
repository.totalCount().mapError(throwableToVerificationPolicyError)

override def filteredCount(
name: Option[String]
): IO[VerificationPolicyError, Long] =
repository.filteredCount(name).mapError(throwableToVerificationPolicyError)

override def lookup(
name: Option[String],
offset: Option[Int],
limit: Option[Int]
): IO[VerificationPolicyError, List[VerificationPolicy]] =
repository
.lookup(name, offset, limit)
.mapError(throwableToVerificationPolicyError)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
CREATE TABLE public.verification_policy
(
id UUID PRIMARY KEY default gen_random_uuid(),
name VARCHAR(255) NOT NULL,
nonce INTEGER NOT NULL,
description TEXT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL default now(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL default now()
);

CREATE INDEX verification_policy_name_index ON public.verification_policy (name);
CREATE INDEX verification_policy_created_at_index ON public.verification_policy (created_at);
CREATE INDEX verification_policy_updated_at_index ON public.verification_policy (updated_at);

CREATE TABLE public.verification_policy_constraint
(
fk_id UUID NOT NULL,
index INT NOT NULL,
type VARCHAR(128) NOT NULL,
schema_id VARCHAR(255),
trusted_issuers VARCHAR(255) ARRAY,

UNIQUE (fk_id, index),

CONSTRAINT fk_verification_policy
FOREIGN KEY (fk_id)
REFERENCES public.verification_policy (id)
ON DELETE CASCADE
);

CREATE INDEX verification_policy_constraint_fk_id_index ON public.verification_policy_constraint (fk_id);
CREATE INDEX verification_policy_constraint_type_index ON public.verification_policy_constraint (type);


Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package io.iohk.atala.pollux.sql.model.db

import io.getquill.InsertMeta

import java.util.UUID
import io.getquill.*
import io.getquill.doobie.DoobieContext

import java.time.OffsetDateTime
import io.getquill.*
import io.getquill.idiom.*
import io.iohk.atala.pollux.sql.model.VerifiableCredentialSchema.sql.run

case class VerificationPolicy(
id: UUID,
nonce: Int,
name: String,
description: String,
createdAt: OffsetDateTime,
updatedAt: OffsetDateTime
)

case class VerificationPolicyConstraint(
fk_id: UUID,
index: Int,
`type`: String,
schemaId: String,
trustedIssuers: Seq[String]
)

object VerificationPolicySql extends DoobieContext.Postgres(SnakeCase) {
import io.iohk.atala.pollux.sql.repository.VerificationPolicyExtensions._

def insert(verificationPolicy: VerificationPolicy) = {
inline given InsertMeta[VerificationPolicy] = insertMeta(exclude = _.id, _.createdAt, _.updatedAt)
run(quote(query[VerificationPolicy].insertValue(lift(verificationPolicy)).returning(vp => vp)))
}

def insertConstraints(constraints: Seq[VerificationPolicyConstraint]) = {
run(
quote(liftQuery(constraints).foreach(c => query[VerificationPolicyConstraint].insertValue(c).returning(c => c)))
)
}

def dropConstraintsByVerificationPolicyId(fk_id: UUID) = {
run(quote(query[VerificationPolicyConstraint].filter(_.fk_id == lift(fk_id)).delete))
}

def getById(id: UUID) =
run(
quote(
query[VerificationPolicy]
.filter(_.id == lift(id))
)
).map(_.headOption)

def getHashById(id: UUID) =
run(
quote(
query[VerificationPolicy]
.filter(_.id == lift(id))
.map(_.nonce)
)
).map(_.headOption)

def exists(id: UUID) =
run(quote(query[VerificationPolicy].filter(_.id == lift(id)).isEmpty))

def exists(id: UUID, hash: Int) =
run(
quote(
query[VerificationPolicy]
.filter(_.id == lift(id))
.filter(_.nonce == lift(hash))
.isEmpty
)
)

def getVerificationPolicyConstrains(fk_ids: Seq[UUID]) =
run(
quote(
query[VerificationPolicyConstraint].filter(vpc => liftQuery(fk_ids).contains(vpc.fk_id))
)
)

def update(verificationPolicy: VerificationPolicy, nonce: Int) =
inline given UpdateMeta[VerificationPolicy] = updateMeta(exclude = _.id)
run(
quote(
query[VerificationPolicy]
.filter(_.id == lift(verificationPolicy.id))
.filter(_.nonce == lift(nonce))
.update(
_.nonce -> lift(verificationPolicy.nonce),
_.description -> lift(verificationPolicy.description),
_.name -> lift(verificationPolicy.name),
_.updatedAt -> lift(verificationPolicy.updatedAt)
)
.returning(vp => vp)
)
)

def delete(id: UUID) =
run(
quote(query[VerificationPolicy])
.filter(_.id == lift(id))
.delete
.returning(vp => vp)
)

def delete(id: UUID, hash: Int) =
run(
quote(query[VerificationPolicy])
.filter(_.id == lift(id))
.filter(_.nonce == lift(hash))
.delete
.returning(vp => vp)
)

def deleteAll() = run(quote(query[VerificationPolicy].delete))

def deleteConstraints(fk_id: UUID) =
run(quote(query[VerificationPolicyConstraint]).filter(_.fk_id == lift(fk_id)).delete)

def count() = run(quote(query[VerificationPolicy].size))

def countOfConstraints() = run(quote(query[VerificationPolicyConstraint]).size)

def countFiltered(nameOpt: Option[String]) =
run(
quote(query[VerificationPolicy]).dynamic
.filterOpt(nameOpt)((vp, name) => quote(vp.name.like(name)))
.size
)

def filteredVerificationPolicies(nameOpt: Option[String], offsetOpt: Option[Int], limitOpt: Option[Int]) = run {

quote(query[VerificationPolicy]).dynamic
.filterOpt(nameOpt)((vcs, name) => quote(vcs.name.like(name)))
.sortBy(_.id)
.dropOpt(offsetOpt)
.take(limitOpt.getOrElse(1000))
}
}

0 comments on commit b290a18

Please sign in to comment.