Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move around some stuff in core._ #2313

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion phoenix-scala/core/app/core/db/ExceptionWrapper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ object ExceptionWrapper {
import scala.util.{Failure, Success}

dbio.asTry.dbresult.flatMap {
case Success(value) ⇒ DbResultT.good(value)
case Success(value) ⇒ value.pure[DbResultT]
case Failure(e) ⇒ DbResultT.failure(DatabaseFailure(e.getMessage))
}
}
Expand Down
2 changes: 1 addition & 1 deletion phoenix-scala/core/app/core/db/FoxTableQuery.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ abstract class FoxTableQuery[M <: FoxModel[M], T <: FoxTable[M]](construct: Tag
}

def refresh(model: M)(implicit ec: EC): DBIO[M] =
findOneById(model.id).safeGet
findOneById(model.id).unsafeGet

type QuerySeq = Query[T, M, Seq]

Expand Down
9 changes: 5 additions & 4 deletions phoenix-scala/core/app/core/db/SearchTerms.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package core.db

import cats.implicits._
import core.failures.{Failure, NotFoundFailure400, NotFoundFailure404}
import core.utils.Strings._
import slick.jdbc.PostgresProfile.api._
Expand All @@ -24,7 +25,7 @@ trait SearchById[M <: FoxModel[M], T <: FoxTable[M]] {
private def mustFindById(id: M#Id, notFoundFailure: M#Id ⇒ Failure = notFound404K)(implicit ec: EC,
db: DB): DbResultT[M] =
this.findOneById(id).dbresult.flatMap {
case Some(model) ⇒ DbResultT.good(model)
case Some(model) ⇒ model.pure[DbResultT]
case None ⇒ DbResultT.failure(notFoundFailure(id))
}
}
Expand All @@ -37,7 +38,7 @@ trait SearchByRefNum[M <: FoxModel[M], T <: FoxTable[M]] extends SearchById[M, T
implicit ec: EC,
db: DB): DbResultT[M] =
findOneByRefNum(refNum).dbresult.flatMap {
case Some(model) ⇒ DbResultT.good(model)
case Some(model) ⇒ model.pure[DbResultT]
case None ⇒ DbResultT.failure(notFoundFailure(refNum))
}
}
Expand All @@ -49,7 +50,7 @@ trait SearchByCode[M <: FoxModel[M], T <: FoxTable[M]] extends SearchById[M, T]
def mustFindByCode(code: String, notFoundFailure: String ⇒ Failure = notFound404K)(implicit ec: EC,
db: DB): DbResultT[M] =
findOneByCode(code).dbresult.flatMap {
case Some(model) ⇒ DbResultT.good(model)
case Some(model) ⇒ model.pure[DbResultT]
case None ⇒ DbResultT.failure(notFoundFailure(code))
}
}
Expand All @@ -62,7 +63,7 @@ trait SearchByIdAndName[M <: FoxModel[M], T <: FoxTable[M]] extends SearchById[M
implicit ec: EC,
db: DB): DbResultT[M] =
findOneByIdAndName(id, name).dbresult.flatMap {
case Some(model) ⇒ DbResultT.good(model)
case Some(model) ⇒ model.pure[DbResultT]
case None ⇒ DbResultT.failure(notFoundFailure(name))
}
}
39 changes: 21 additions & 18 deletions phoenix-scala/core/app/core/db/Star.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ object * extends LazyLogging {
def <~[A](v: SqlAction[A, NoStream, Effect.All])(implicit ec: EC): DbResultT[A] =
<~(v.map(Either.right))

def <~[A](v: DBIO[A])(implicit ec: EC): DbResultT[A] =
DbResultT.fromF(v)
def <~[A](fa: DBIO[A])(implicit ec: EC): DbResultT[A] =
DbResultT.fromF(fa)

def <~[A](v: Either[Failures, A])(implicit ec: EC): DbResultT[A] =
DbResultT.fromEither(v)
def <~[A](fa: Either[Failures, A])(implicit ec: EC): DbResultT[A] =
DbResultT.fromEither(fa)

def <~[A](v: Future[Either[Failures, A]])(implicit M1: Monad[DBIO], M2: Monad[Future]): DbResultT[A] =
DbResultT.fromResult(Result.fromFEither(v))
def <~[A](gfa: Future[Either[Failures, A]])(implicit M1: Monad[DBIO], M2: Monad[Future]): DbResultT[A] =
DbResultT.fromResult(Result.fromFEither(gfa))

def <~[A](v: Future[A])(implicit ec: EC): DbResultT[A] =
<~(v.map(Either.right(_)).recover {
def <~[A](fa: Future[A])(implicit ec: EC): DbResultT[A] =
<~(fa.map(Either.right).recover {
case ex ⇒
logger.error("A Future failed during conversion to DbResultT.", ex)
Either.left(GeneralFailure(ex.getMessage).single)
Expand All @@ -36,22 +36,25 @@ object * extends LazyLogging {
def <~[A](fa: Result[A])(implicit ec: EC): DbResultT[A] =
DbResultT.fromResult(fa)

def <~[A](v: A)(implicit ec: EC): DbResultT[A] =
DbResultT.pure(v)
// TODO: Is this more readable than inlining? @michalrus
def <~[A](a: A)(implicit ec: EC): DbResultT[A] =
a.pure[DbResultT]

def <~[A](v: Validated[Failures, A])(implicit ec: EC): DbResultT[A] =
DbResultT.fromEither(v.toEither)

def <~[M[_]: TraverseFilter, A](v: M[DbResultT[A]])(implicit ec: EC): DbResultT[M[A]] =
DbResultT.seqCollectFailures(v)
def <~[M[_]: TraverseFilter, A](fas: M[DbResultT[A]])(implicit ec: EC): DbResultT[M[A]] =
DbResultT.seqCollectFailures(fas)

// FIXME: Remove this function after switching all Seqs to List/Vector. Cats don’t have instances for Seq and Seq is unsound. PM me or @kjanosz for details. @michalrus
def <~[A](v: Seq[DbResultT[A]])(implicit ec: EC): DbResultT[List[A]] =
DbResultT.seqCollectFailures(v.toList)
def <~[A](fas: Seq[DbResultT[A]])(implicit ec: EC): DbResultT[List[A]] =
DbResultT.seqCollectFailures(fas.toList)

def <~[A](v: DbResultT[A]): DbResultT[A] =
v
// TODO: Is this more readable than inlining? @michalrus
def <~[A](fa: DbResultT[A]): DbResultT[A] =
fa

def <~[A](v: Option[DbResultT[A]])(implicit ec: EC): DbResultT[Option[A]] = // TODO: sequence? @michalrus - yes, please! @aafa
v.fold(DbResultT.none[A])(_.map(Some(_)))
// TODO: Is this more readable than inlining? @michalrus
def <~[A](ofa: Option[DbResultT[A]])(implicit ec: EC): DbResultT[Option[A]] =
ofa.sequence
}
70 changes: 29 additions & 41 deletions phoenix-scala/core/app/core/db/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,6 @@ package object db {
def fold[B](ra: Failures ⇒ B, rb: A ⇒ B)(implicit F: Monad[F]): FoxyT[F, B] = // TODO: this is not fold… Find a better name or remove it? @michalrus
fa.map(rb).handleError(ra)

def meh(implicit M: Monad[F]): FoxyT[F, Unit] =
fa.void // TODO: remove me? But it’s cute… @michalrus

def failuresToWarnings(valueIfWasFailed: A)(pf: PartialFunction[Failure, Boolean])(
implicit F: Monad[F]): FoxyT[F, A] =
fa.handleErrorWith { fs ⇒
Expand All @@ -105,21 +102,6 @@ package object db {
}

trait FoxyTFunctions[F[_]] {
def apply[A](a: A)(implicit F: Monad[F]): FoxyT[F, A] = // TODO: remove me? @michalrus
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code.

pure(a)

def pure[A](a: A)(implicit F: Monad[F]): FoxyT[F, A] =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, we have pure from cats.

Monad[FoxyT[F, ?]].pure(a)

def good[A](a: A)(implicit F: Monad[F]): FoxyT[F, A] = // TODO: remove me @michalrus
pure(a)

def unit(implicit F: Monad[F]): FoxyT[F, Unit] =
pure(()) // TODO: remove me? @michalrus

def none[A](implicit F: Monad[F]): FoxyT[F, Option[A]] =
pure(None) // TODO: remove me? @michalrus

def uiWarning(f: Failure)(implicit F: Monad[F]): FoxyT[F, Unit] =
StateT.modify(MetaResponse.Warning(f) :: _)

Expand Down Expand Up @@ -155,13 +137,15 @@ package object db {
case _ ⇒ EitherT.right(F.pure((s, ())))
})

// TODO: maybe move the quasi-`sequence`-s from Functions to Ops? @michalrus

/** Just like ``sequence`` but—in case of a failure—unlawful, as it will join failures from all Foxies. */
def seqCollectFailures[L[_], A](lfa: L[FoxyT[F, A]])(implicit L: TraverseFilter[L],
F: Monad[F]): FoxyT[F, L[A]] =
L.map(lfa)(_.fold(Either.left(_), Either.right(_))).sequence.flatMap { xa ⇒
val failures = L.collect(xa) { case Left(f) ⇒ f.toList }.toList.flatten
val values = L.collect(xa) { case Right(a) ⇒ a }
NonEmptyList.fromList(failures).fold(FoxyT[F].pure(values))(FoxyT[F].failures(_))
NonEmptyList.fromList(failures).fold(values.pure[FoxyT[F, ?]])(FoxyT[F].failures(_))
}

/** A bit like ``sequence`` but will ignore failed Foxies. */
Expand Down Expand Up @@ -276,35 +260,40 @@ package object db {
def appendForUpdate[A, B <: slick.dbio.NoStream](sql: SqlAction[A, B, Effect.Read]): DBIO[A] =
sql.overrideStatements(sql.statements.map(_ + " for update"))

def lift[A](value: A): DBIO[A] = DBIO.successful(value)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, we have pure from cats.


def liftFuture[A](future: Future[A]): DBIO[A] = DBIO.from(future)

// TODO: Is this more readable than inlining? @michalrus
def ifElse[A](condition: Boolean, ifBranch: ⇒ DbResultT[A], elseBranch: ⇒ DbResultT[A]) =
if (condition) ifBranch else elseBranch

def doOrMeh(condition: Boolean, action: ⇒ DbResultT[_])(implicit ec: EC): DbResultT[Unit] =
if (condition) action.meh else DbResultT.unit
def when[F[_]: Applicative](p: Boolean, s: ⇒ F[Unit]): F[Unit] =
if (p) s else ().pure[F]

def doOrGood[A](condition: Boolean, action: ⇒ DbResultT[A], good: ⇒ A)(implicit ec: EC): DbResultT[A] =
if (condition) action else DbResultT.good(good)
// TODO: Is this more readable than inlining? @michalrus
def doOrGood[F[_]: Applicative, A](p: Boolean, action: ⇒ F[A], good: ⇒ A)(implicit ec: EC): F[A] =
if (p) action else good.pure[F]

def doOrFail[A](condition: Boolean, action: ⇒ DbResultT[A], failure: ⇒ Failure)(
implicit ec: EC): DbResultT[A] =
if (condition) action else DbResultT.failure(failure)
// TODO: Is this more readable than inlining? @michalrus
def doOrFail[F[_]: Monad, A](p: Boolean, action: ⇒ FoxyT[F, A], failure: ⇒ Failure)(
implicit ec: EC): FoxyT[F, A] =
if (p) action else FoxyT[F].failure(failure)

// TODO: Is this more readable than inlining? @michalrus
// FIXME: should be defined over FoxyT, but inference fails then… @michalrus
def failIf(condition: Boolean, failure: ⇒ Failure)(implicit ec: EC): DbResultT[Unit] =
if (condition) DbResultT.failure(failure) else DbResultT.unit
if (condition) DbResultT.failure(failure) else ().pure[DbResultT]

// TODO: Is this more readable than inlining? @michalrus
// FIXME: should be defined over FoxyT, but inference fails then… @michalrus
def failIfNot(condition: Boolean, failure: ⇒ Failure)(implicit ec: EC): DbResultT[Unit] =
failIf(!condition, failure)

def failIfFailures(failures: Seq[Failure])(implicit ec: EC): DbResultT[Unit] =
// TODO: Is this more readable than inlining? @michalrus
// TODO: There’s only one usage in the whole codebase. @michalrus
def failIfFailures[F[_]: Monad](failures: Seq[Failure]): FoxyT[F, Unit] =
failures match {
case head :: tail ⇒
DbResultT.failures(NonEmptyList.of(head, tail: _*))
FoxyT[F].failures(NonEmptyList.of(head, tail: _*))
case _ ⇒
DbResultT.unit
().pure[FoxyT[F, ?]]
}

implicit class EnrichedSQLActionBuilder(val action: SQLActionBuilder) extends AnyVal {
Expand Down Expand Up @@ -338,33 +327,32 @@ package object db {

def findOrCreate(r: DbResultT[R])(implicit ec: EC): DbResultT[R] =
dbio.dbresult.flatMap {
case Some(model) ⇒ DbResultT.good(model)
case Some(model) ⇒ model.pure[DbResultT]
case None ⇒ r
}

// Last item in tuple determines if cart was created or not
def findOrCreateExtended(r: DbResultT[R])(implicit ec: EC): DbResultT[(R, FoundOrCreated)] =
dbio.dbresult.flatMap {
case Some(model) ⇒ DbResultT.good((model, Found))
case Some(model) ⇒ (model, Found: FoundOrCreated).pure[DbResultT]
case _ ⇒ r.map(result ⇒ (result, Created))
}

def mustFindOr(notFoundFailure: Failure)(implicit ec: EC): DbResultT[R] =
dbio.dbresult.flatMap {
case Some(model) ⇒ DbResultT.good(model)
case Some(model) ⇒ model.pure[DbResultT]
case None ⇒ DbResultT.failure(notFoundFailure)
}

def mustNotFindOr(shouldNotBeHere: Failure)(implicit ec: EC): DbResultT[Unit] =
dbio.dbresult.flatMap {
case None ⇒ DbResultT.unit
case None ⇒ ().pure[DbResultT]
case Some(_) ⇒ DbResultT.failure(shouldNotBeHere)
}

// we only use this when we *know* we can call head safely on a query. (e.g., you've created a record which
// we only use this when we *know* we can call head unsafely on a query. (e.g., you've created a record which
// has a FK constraint to another table and you then fetch that associated record -- we already *know* it must
// exist.
// FIXME: if you know it, prove it. Or s/safe/unsafe/ in the name *AND* comment. @michalrus
def safeGet(implicit ec: EC): DBIO[R] = dbio.map(_.get)
def unsafeGet(implicit ec: EC): DBIO[R] = dbio.map(_.get)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package objectframework

import java.time.Instant

import cats.implicits._
import cats.data.NonEmptyList
import com.networknt.schema.JsonSchemaFactory
import com.typesafe.scalalogging.LazyLogging
Expand Down Expand Up @@ -34,7 +35,7 @@ object IlluminateAlgorithm extends LazyLogging {
implicit ec: ExecutionContext): DbResultT[JValue] = {
val illuminated = projectFlatAttributes(form.attributes, shadow.attributes)
getInternalAttributes(schema).fold {
DbResultT.good(illuminated)
illuminated.pure[DbResultT]
} { jsonSchema ⇒
val jsonSchemaFactory = new JsonSchemaFactory
val validator = jsonSchemaFactory.getSchema(asJsonNode(jsonSchema))
Expand All @@ -45,7 +46,7 @@ object IlluminateAlgorithm extends LazyLogging {
ObjectValidationFailure(form.kind, shadow.id, err.getMessage)
} match {
case head :: tail ⇒ DbResultT.failures[JValue](NonEmptyList(head, tail))
case Nil ⇒ DbResultT.good(illuminated)
case Nil ⇒ illuminated.pure[DbResultT]
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ object ObjectUtils {
.copy[T](form = updateResult.form, shadow = updateResult.shadow)
updateHead(newObject, commit.id)
case _ ⇒
DbResultT.good(fullObject)
fullObject.pure[DbResultT]
})
} yield committedObject

Expand Down Expand Up @@ -220,7 +220,7 @@ object ObjectUtils {
for {
commit ← * <~ ObjectCommits.create(ObjectCommit(formId = form.id, shadowId = shadow.id))
} yield commit.some
else DbResultT.pure(None)
else none[ObjectCommit].pure[DbResultT]

private def updateIfDifferent(
old: FormAndShadow,
Expand All @@ -244,14 +244,14 @@ object ObjectUtils {
}
_ ← * <~ validateShadow(form, shadow)
} yield UpdateResult(form, shadow, updated = true)
else DbResultT.pure(UpdateResult(old.form, old.shadow, updated = false))
else UpdateResult(old.form, old.shadow, updated = false).pure[DbResultT]

private def validateShadow(form: ObjectForm, shadow: ObjectShadow)(implicit ec: EC,
fmt: Formats): DbResultT[Unit] =
failIfErrors(IlluminateAlgorithm.validateAttributes(form.attributes, shadow.attributes))

def failIfErrors(errors: Seq[Failure])(implicit ec: EC): DbResultT[Unit] = errors match {
case head :: tail ⇒ DbResultT.failures(NonEmptyList(head, tail))
case Nil ⇒ DbResultT.pure(Unit)
case Nil ⇒ ().pure[DbResultT]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package objectframework.models

import java.time.Instant

import cats.implicits._
import core.db.ExPostgresDriver.api._
import core.db._
import objectframework.services.ObjectManager
Expand Down Expand Up @@ -83,13 +84,13 @@ object ObjectHeadLinks {
case right if !linkedRightIds.contains(right.id) ⇒
create(build(left, right))
}
} yield {}
} yield ()

def createIfNotExist(left: L, right: R)(implicit ec: EC, db: DB): DbResultT[Unit] =
for {
linkExists ← * <~ filterLeft(left).filter(_.rightId === right.id).exists.result
_ ← * <~ doOrMeh(!linkExists, create(build(left, right)))
} yield {}
_ ← * <~ when(!linkExists, create(build(left, right)).void)
} yield ()

def build(left: L, right: R): M
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package objectframework.models

import cats.implicits._
import core.db.ExPostgresDriver.api._
import core.db._
import objectframework.ObjectFailures.{LinkAtPositionCannotBeFound, LinkCannotBeFound}
Expand Down Expand Up @@ -44,7 +45,7 @@ abstract class OrderedObjectHeadLinkQueries[M <: OrderedObjectHeadLink[M],
replacedLink ← * <~ allLefts
.filter(_.position === newPosition)
.mustFindOneOr(LinkAtPositionCannotBeFound(baseTableRow.getClass, left.id, newPosition))
newLinks ← * <~ (if (link.position == newPosition) DbResultT.good((link, replacedLink))
newLinks ← * <~ (if (link.position == newPosition) (link, replacedLink).pure[DbResultT]
else swapLinkPositions(link, replacedLink))
(updatedLink, _) = newLinks
} yield updatedLink
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package objectframework.payloads

import cats.implicits._
import cats.data.NonEmptyList
import com.networknt.schema.JsonSchemaFactory
import core.db._
Expand Down Expand Up @@ -35,7 +36,7 @@ object ObjectSchemaValidation {
PayloadValidationFailure(error.getMessage)
} match {
case head :: tail ⇒ DbResultT.failures[M](NonEmptyList(head, tail))
case Nil ⇒ DbResultT.good(payload)
case Nil ⇒ payload.pure[DbResultT]
}

}
Expand Down
Loading