Skip to content

Commit

Permalink
Removing extract and sequence helpers now that cotraverse and indexed…
Browse files Browse the repository at this point in the history
…Cosequence exists
  • Loading branch information
blast-hardcheese committed Sep 25, 2019
1 parent fa3568d commit c3dee31
Show file tree
Hide file tree
Showing 12 changed files with 48 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ object Common {
)
basePath = swagger
.downField("servers", _.getServers)
.extract(_.downField("url", _.getUrl))
.cotraverse(_.downField("url", _.getUrl))
.headOption
.flatMap(_.get)
.flatMap(url => Option(new URI(url).getPath))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import cats.free.Free
import cats.implicits._
import com.twilio.guardrail.SwaggerUtil.Resolved
import com.twilio.guardrail.core.{ Mappish, Tracker }
import com.twilio.guardrail.core.implicits._
import com.twilio.guardrail.extract.VendorExtension.VendorExtensible._
import com.twilio.guardrail.generators.RawParameterType
import com.twilio.guardrail.generators.syntax._
Expand Down Expand Up @@ -340,7 +341,7 @@ object ProtocolGenerator {
maybeClassDefinition <- fromModel(nestedClassName, schema, parents, concreteTypes, definitions)
} yield Option(maybeClassDefinition)
)
.orRefine({ case a: ArraySchema => a })(_.downField("items", _.getItems()).sequence.flatTraverse(processProperty(name, _)))
.orRefine({ case a: ArraySchema => a })(_.downField("items", _.getItems()).indexedCosequence.flatTraverse(processProperty(name, _)))
.getOrElse(Free.pure[F, Option[Either[String, ClassDefinition[L]]]](Option.empty))
}
val needCamelSnakeConversion = props.forall { case (k, _) => couldBeSnakeCase(k) }
Expand Down Expand Up @@ -515,7 +516,7 @@ object ProtocolGenerator {
import S._
import Sw._

val definitions = swagger.downField("components", _.getComponents()).flatDownField("schemas", _.getSchemas()).sequence
val definitions = swagger.downField("components", _.getComponents()).flatDownField("schemas", _.getSchemas()).indexedCosequence
for {
(hierarchies, definitionsWithoutPoly) <- groupHierarchies(definitions)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,10 @@ trait IndexedDistributiveImplicits {
implicit class IndexedDistributiveSyntax[G[_]: Functor: IndexedFunctor: Foldable, F[_]: IndexedDistributive, A](value: F[G[A]]) {
def indexedDistribute: G[F[A]] = IndexedDistributive[F].indexedDistribute(value)
def cotraverse[B](f: F[A] => B): G[B] = IndexedDistributive.cotraverse(value)(f)
def cosequence: G[F[A]] = cotraverse(identity)
def indexedCosequence: G[F[A]] = cotraverse(identity)
def flatCotraverse[B](f: F[A] => G[B])(implicit ev: FlatMap[G]): G[B] = ev.flatten(IndexedDistributive.cotraverse(value)(f))
def flatExtract[B](f: F[A] => G[B])(implicit G: MonoidK[G]): G[B] = value.cotraverse(f).foldLeft(G.empty[B])(G.combineK)
def exists(f: F[A] => Boolean): Boolean = value.indexedDistribute.foldLeft(false) { case (acc, n) => acc || f(n) }

@deprecated("Please use cotraverse", "0.0.0")
def extract[B](f: F[A] => B): G[B] = value.cotraverse(f)

@deprecated("Please use cosequence or distribute", "0.0.0")
def sequence: G[F[A]] = extract(identity)
}

// These don't belong here, but they intersect a lot with the usage of IndexedDistributive
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ object IndexedFunctor {
def label(i: Int) = Some(s"[${i}]")
}

implicit def indexedMappish[F[_]](implicit F: IndexedFunctor[F]): IndexedFunctor[Mappish[F, String, ?]] = new IndexedFunctor[Mappish[F, String, ?]] {
type I = String
def map[A, B](fa: Mappish[F, String, A])(f: (I, A) => B): Mappish[F, String, B] = new Mappish(F.map(fa.value)({ case (_, (k, v)) => (k, f(k, v)) }))
def label(i: I) = Some(s"[${i}]")
}

implicit object indexedNonEmptyList extends IndexedFunctor[NonEmptyList] {
type I = Int
def map[A, B](fa: NonEmptyList[A])(f: (I, A) => B): NonEmptyList[B] = fa.zipWithIndex.map({ case (v, k) => f(k, v) })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ class Mappish[F[_], K, V](val value: F[(K, V)])
object Mappish {
def apply[F[_], A, B](value: F[(A, B)]): Mappish[F, A, B] = new Mappish(value)

// could not find implicit value for evidence parameter of type com.twilio.guardrail.core.IndexedFunctor[[V]com.twilio.guardrail.core.Mappish[cats.data.NonEmptyList,io.swagger.v3.oas.models.PathItem.HttpMethod,V]]
}

trait MappishImplicits {

def buildMappishIndexedFunctor[F[_], Z](buildLabel: Z => String)(implicit F: IndexedFunctor[F]): IndexedFunctor[Mappish[F, Z, ?]] =
new IndexedFunctor[Mappish[F, Z, ?]] {
type I = Z
def map[A, B](fa: Mappish[F, I, A])(f: (I, A) => B): Mappish[F, I, B] = Mappish(F.map(fa.value)({ case (_, (z, a)) => (z, f(z, a)) }))
def label(i: I): Option[String] = Some(buildLabel(i))
}

implicit def stringMIF[F[_]: IndexedFunctor] = buildMappishIndexedFunctor[F, String](x => s"[$x]")
implicit def httpMethodMIF[F[_]: IndexedFunctor] = buildMappishIndexedFunctor[F, io.swagger.v3.oas.models.PathItem.HttpMethod](x => s"[${x.name}]")

implicit def mappishFunctor[F[_], Z](implicit F: Functor[F]): Functor[Mappish[F, Z, ?]] = new Functor[Mappish[F, Z, ?]] {
def map[A, B](fa: Mappish[F, Z, A])(f: A => B): Mappish[F, Z, B] = Mappish(F.map(fa.value)({ case (z, a) => (z, f(a)) }))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ trait HighPriorityTrackerSyntax extends LowPriorityTrackerSyntax {
}

implicit class OptionSyntax[A](tracker: Tracker[Option[A]]) {
def orHistory: Either[Vector[String], Tracker[A]] = tracker.sequence.toRight(tracker.history)
def raiseErrorIfEmpty(err: String): Target[Tracker[A]] = Target.fromOption(tracker.sequence, s"${err} (${tracker.showHistory})")
def orHistory: Either[Vector[String], Tracker[A]] = tracker.indexedCosequence.toRight(tracker.history)
def raiseErrorIfEmpty(err: String): Target[Tracker[A]] = Target.fromOption(tracker.indexedCosequence, s"${err} (${tracker.showHistory})")
class FlatDownFieldPartiallyApplied[C](val dummy: Boolean = true) {
def apply[B](label: String, f: A => B)(implicit ev: Tracker.Convincer[Option[B], C]): Tracker[C] =
new Tracker(ev(tracker.get.flatMap(x => Option(f(x)))), tracker.history :+ s".${label}")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.twilio.guardrail

package core {
object implicits extends IndexedDistributiveImplicits
object implicits extends IndexedDistributiveImplicits with MappishImplicits
}

package object core extends core.IndexedDistributiveImplicits
package object core extends core.IndexedDistributiveImplicits with core.MappishImplicits
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import cats.data.NonEmptyList
import cats.implicits._
import cats.~>
import com.twilio.guardrail.core.Tracker
import com.twilio.guardrail.core.implicits._
import com.twilio.guardrail.extract.{ DataRedaction, Default, EmptyValueIsNull }
import com.twilio.guardrail.generators.syntax.RichString
import com.twilio.guardrail.languages.ScalaLanguage
Expand Down Expand Up @@ -98,11 +99,11 @@ object CirceProtocolGenerator {
case ExtractProperties(swagger) =>
swagger
.refine[Target[List[(String, Tracker[Schema[_]])]]]({ case o: ObjectSchema => o })(
m => Target.pure(m.downField("properties", _.getProperties).sequence.value)
m => Target.pure(m.downField("properties", _.getProperties).indexedCosequence.value)
)
.orRefine({ case c: ComposedSchema => c })({ comp =>
val extractedProps =
comp.downField("allOf", _.getAllOf()).indexedDistribute.flatMap(_.downField("properties", _.getProperties).sequence.value)
comp.downField("allOf", _.getAllOf()).indexedDistribute.flatMap(_.downField("properties", _.getProperties).indexedCosequence.value)
Target.pure(extractedProps)
})
.orRefine({ case x: Schema[_] if Option(x.get$ref()).isDefined => x })(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import cats.~>
import com.github.javaparser.ast.`type`.{ ClassOrInterfaceType, PrimitiveType, Type, UnknownType }
import com.twilio.guardrail.Discriminator
import com.twilio.guardrail.core.Tracker
import com.twilio.guardrail.core.implicits._
import com.twilio.guardrail.extract.{ DataRedaction, Default, EmptyValueIsNull }
import com.twilio.guardrail.generators.syntax.Java._
import com.twilio.guardrail.generators.syntax.RichString
Expand Down Expand Up @@ -729,7 +730,7 @@ object JacksonGenerator {
def apply[T](term: ModelProtocolTerm[JavaLanguage, T]): Target[T] = term match {
case ExtractProperties(swagger) =>
swagger
.refine({ case m: ObjectSchema => m })(m => Target.pure(m.downField("properties", _.getProperties()).sequence.value))
.refine({ case m: ObjectSchema => m })(m => Target.pure(m.downField("properties", _.getProperties()).indexedCosequence.value))
.orRefine({ case c: ComposedSchema => c })(
comp =>
Target.pure(
Expand All @@ -738,7 +739,7 @@ object JacksonGenerator {
.indexedDistribute
.lastOption
.toList
.flatMap(_.downField("properties", _.getProperties).sequence.value.toList)
.flatMap(_.downField("properties", _.getProperties).indexedCosequence.value.toList)
)
)
.orRefine({ case x: Schema[_] if Option(x.get$ref()).isDefined => x })(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package generators
import cats.implicits._
import cats.~>
import com.twilio.guardrail.core.Tracker
import com.twilio.guardrail.core.implicits._
import com.twilio.guardrail.extract.{ PackageName, SecurityOptional }
import com.twilio.guardrail.generators.syntax._
import com.twilio.guardrail.languages.LA
Expand Down Expand Up @@ -34,14 +35,14 @@ object SwaggerGenerator {
case ExtractOperations(paths, commonRequestBodies, globalSecurityRequirements) =>
Target.log.function("extractOperations")(for {
_ <- Target.log.debug(s"Args: ${paths.get.value.map({ case (a, b) => (a, b.showNotNull) })} (${paths.showHistory})")
routes <- paths.sequence.value.flatTraverse({
routes <- paths.indexedCosequence.value.flatTraverse({
case (pathStr, path) =>
for {
operationMap <- path
.downField("operations", _.readOperationsMap)
.toNel
.raiseErrorIfEmpty(s"No operations defined")
operationRoutes <- operationMap.sequence.toList.traverse({
operationRoutes <- operationMap.indexedCosequence.value.toList.traverse({
case (httpMethod, operation) =>
val securityRequirements =
operation
Expand Down Expand Up @@ -122,7 +123,7 @@ object SwaggerGenerator {
operation
.downField("tags", _.getTags)
.toNel
.sequence
.indexedCosequence
.map { tags =>
println(
s"Warning: Using `tags` to define package membership is deprecated in favor of the `x-jvm-package` vendor extension (${tags.history})"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import cats.data.State
import cats.implicits._
import cats.Order
import com.twilio.guardrail.core.{ Mappish, Tracker }
import com.twilio.guardrail.core.implicits._
import com.twilio.guardrail.generators.{ ScalaParameter, ScalaParameters }
import com.twilio.guardrail.generators.syntax._
import com.twilio.guardrail.languages.LA
Expand Down Expand Up @@ -90,7 +91,7 @@ case class RouteMeta(path: Tracker[String], method: HttpMethod, operation: Track
case Nil => Option.empty
}
for {
schema <- unifyEntries(requestBody.downField("content", _.getContent()).sequence.value.map(_.map(_.get)))
schema <- unifyEntries(requestBody.downField("content", _.getContent()).indexedCosequence.value.map(_.map(_.get)))
tpe <- Option(schema.getType())
} yield {
val p = new Parameter
Expand All @@ -115,9 +116,9 @@ case class RouteMeta(path: Tracker[String], method: HttpMethod, operation: Track
// (these are both represented in the same RequestBody class)
private def extractRefParamFromRequestBody(requestBody: Tracker[RequestBody]): Option[Tracker[Parameter]] = {
val content = for {
(_, mt) <- requestBody.downField("content", _.getContent()).sequence.value.headOption
schema <- mt.downField("schema", _.getSchema()).sequence
ref <- schema.downField("$ref", _.get$ref()).sequence
(_, mt) <- requestBody.downField("content", _.getContent()).indexedCosequence.value.headOption
schema <- mt.downField("schema", _.getSchema()).indexedCosequence
ref <- schema.downField("$ref", _.get$ref()).indexedCosequence
} yield {
val p = new Parameter

Expand All @@ -137,7 +138,7 @@ case class RouteMeta(path: Tracker[String], method: HttpMethod, operation: Track
Tracker.hackyAdapt(p, requestBody.history)
}

val ref = requestBody.downField("$ref", _.get$ref()).sequence.map { x =>
val ref = requestBody.downField("$ref", _.get$ref()).cotraverse { x =>
val p = new Parameter

p.setIn("body")
Expand All @@ -160,17 +161,17 @@ case class RouteMeta(path: Tracker[String], method: HttpMethod, operation: Track
type Count = Int
type ParameterCountState = (Count, Map[HashCode, Count])
val contentTypes: List[RouteMeta.ContentType] =
requestBody.downField("content", _.getContent()).sequence.value.map(_._1).flatMap(RouteMeta.ContentType.unapply)
requestBody.downField("content", _.getContent()).indexedCosequence.value.map(_._1).flatMap(RouteMeta.ContentType.unapply)
val ((maxCount, instances), ps) = requestBody
.downField("content", _.getContent())
.sequence
.indexedCosequence
.value
.flatMap({
case (_, mt) =>
for {
mtSchema <- mt.downField("schema", _.getSchema()).sequence.toList
mtSchema <- mt.downField("schema", _.getSchema()).indexedCosequence.toList
requiredFields = mtSchema.downField("required", _.getRequired).get.toSet
(name, schema) <- mtSchema.downField("properties", _.getProperties()).sequence.value
(name, schema) <- mtSchema.downField("properties", _.getProperties()).indexedCosequence.value
} yield {
val p = new Parameter

Expand All @@ -192,7 +193,7 @@ case class RouteMeta(path: Tracker[String], method: HttpMethod, operation: Track
p.setRequired(isRequired)
p.setExtensions(schema.unwrapTracker.getExtensions)

if (schema.downField("type", _.getType()).sequence.exists(_.get == "file") && contentTypes.contains(RouteMeta.UrlencodedFormData)) {
if (schema.downField("type", _.getType()).indexedCosequence.exists(_.get == "file") && contentTypes.contains(RouteMeta.UrlencodedFormData)) {
p.setRequired(false)
}

Expand Down
6 changes: 3 additions & 3 deletions modules/codegen/src/test/scala/core/TrackerTests.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package core

import com.twilio.guardrail.core.{ Tracker, TrackerTestExtensions }
// import com.twilio.guardrail.core.implicits.IndexedDistributiveSyntax
import com.twilio.guardrail.core.implicits._
import com.twilio.guardrail.generators.Http4s
import com.twilio.guardrail.{ CodegenTarget, Context, UserError }
import cats.instances.all._
Expand Down Expand Up @@ -81,7 +81,7 @@ Tracker should:
forAll { parent: Parent =>
Tracker(parent)
.downField("child1", _.child1)
.extract(_.downField("grandchild", _.grandchild).sequence)
.cotraverse(_.downField("grandchild", _.grandchild).indexedCosequence)
.zipWithIndex
.foreach({ case (x, i) => x.foreach(x => assert(pattern(i) === x.showHistory)) })
}
Expand All @@ -92,7 +92,7 @@ Tracker should:
forAll { parent: Parent =>
Tracker(parent)
.downField("child2", _.child2)
.sequence
.indexedCosequence
.value
.foreach({ case (k, v) => assert(pattern(k) === v.showHistory) })
}
Expand Down

0 comments on commit c3dee31

Please sign in to comment.