Skip to content

Commit

Permalink
work on directives
Browse files Browse the repository at this point in the history
  • Loading branch information
ValdemarGr committed Apr 20, 2024
1 parent 0feb9ad commit d19c64f
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 43 deletions.
4 changes: 3 additions & 1 deletion modules/core/src/main/scala/gql/Validation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,9 @@ object Validation {
arg.entries.toChain
.mapFilter(x => x.defaultValue.tupleLeft(x))
.traverse_[G, Unit] { case (a: ArgValue[a], pv) =>
(new ArgParsing[Unit](Map.empty))
lazy val ap: ArgParsing[F, Unit] = new ArgParsing[F, Unit](Map.empty, da)
lazy val da: DirectiveAlg[F, Unit] = new DirectiveAlg[F, Unit](discovery.positions, ap)
ap
.decodeIn[a](a.input.value, pv.map(List(_)), ambigiousEnum = false)
.run match {
case Left(errs) =>
Expand Down
18 changes: 13 additions & 5 deletions modules/core/src/main/scala/gql/preparation/ArgParsing.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ import gql.parser.AnyValue
import gql.parser.NonVar
import gql.parser.{Value => V}

class ArgParsing[C](variables: VariableMap[C]) {
class ArgParsing[F[_], C](
variables: VariableMap[C],
da: => DirectiveAlg[F, C]
) {
type G[A] = Alg[C, A]
val G = Alg.Ops[C]

Expand Down Expand Up @@ -159,11 +162,16 @@ class ArgParsing[C](variables: VariableMap[C]) {
)
}
}
case (Scalar(name, _, decoder,_, _), x: NonVar[List[C]]) =>
G.ambientField(name) {
G.raiseEither(decoder(x.map(_ => ())), x.c)
case (s: Scalar[A], x: NonVar[List[C]]) =>
G.ambientField(s.name) {
da.scalar(s, x.c).flatMap{ s =>
G.raiseEither(s.decoder(x.map(_ => ())), x.c)
}
}
case (in: Input[A], V.ObjectValue(xs, cs)) =>
da.input(in, cs).flatMap{ in =>
decodeArg(in.fields, xs.toMap, ambigiousEnum, cs)
}
case (Input(_, fields,_, _), V.ObjectValue(xs, cs)) => decodeArg(fields, xs.toMap, ambigiousEnum, cs)
case (a: InArr[a, c], V.ListValue(vs, cs)) =>
vs.zipWithIndex
.parTraverse { case (v, i) =>
Expand Down
43 changes: 39 additions & 4 deletions modules/core/src/main/scala/gql/preparation/DirectiveAlg.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import gql.ast._

class DirectiveAlg[F[_], C](
positions: Map[String, List[Position[F, ?]]],
ap: ArgParsing[C]
ap: => ArgParsing[F, C]
) {
type G[A] = Alg[C, A]
val G = Alg.Ops[C]
Expand Down Expand Up @@ -94,18 +94,53 @@ class DirectiveAlg[F[_], C](
go(sd.position: P[?]).widen[ParsedDirective[?, P]]
}

def enumTpe[A](e: Enum[A], ctx: List[C]): G[Enum[A]] =
foldSchemaDirectives(e, e.directives, ctx) { case (e, d) => d.p.handler(d.a, e) }

def scalar[A](s: Scalar[A], ctx: List[C]): G[Scalar[A]] =
foldSchemaDirectives(s, s.directives, ctx) { case (s, d) => d.p.handler(d.a, s) }

def input[A](i: Input[A], ctx: List[C]): G[Input[A]] =
foldSchemaDirectives(i, i.directives, ctx) { case (i, d) => d.p.handler(d.a, i) }

def interface[A](i: Interface[F, A], ctx: List[C]): G[Interface[F, A]] =
foldSchemaDirectives(i, i.directives, ctx) { case (i, d) => d.p.handler(d.a, i) }

def union[A](u: Union[F, A], ctx: List[C]): G[Union[F, A]] =
foldSchemaDirectives(u, u.directives, ctx) { case (u, d) => d.p.handler(d.a, u) }

def tpe[A](t: ast.Type[F, A], ctx: List[C]): G[ast.Type[F, A]] =
foldSchemaDirectives(t, t.directives, ctx) { case (t, d) => d.p.handler(d.a, t) }

def selectable[A](s: Selectable[F, A], ctx: List[C]): G[ast.Selectable[F,A]] =
s match {
case t: ast.Type[F, A] => tpe(t, ctx)
case i: Interface[F, A] => interface(i, ctx)
case u: Union[F, A] => union(u, ctx)
}

def field[I, O](fi: MergedFieldInfo[F, C], field: Field[F, I, O]): G[List[(Field[F, I, _], MergedFieldInfo[F, C])]] =
(
field.directives.parTraverse(parseSchemaDirective(_, List(fi.caret))),
parseProvidedSubtype[Position.Field[F, *]](fi.directives, List(fi.caret))
).flatMap{ xs =>
val ys = /*field.directives.map(sd => ) ++*/ xs
ys.foldLeftM[G, List[(Field[F, I, ?], MergedFieldInfo[F, C])]](List((field, fi))) { case (xs, prov) =>
).parMapN(_ ++ _).flatMap{ xs =>
xs.foldLeftM[G, List[(Field[F, I, ?], MergedFieldInfo[F, C])]](List((field, fi))) { case (xs, prov) =>
xs.parFlatTraverse { case (f: Field[F, I, ?], fi) =>
G.raiseEither(prov.p.handler(prov.a, f, fi), List(fi.caret))
}
}
}

def foldSchemaDirectives[A, B, P[x] <: SchemaPosition[F, x]](
a: A,
directives: List[SchemaDirective[F, P]],
ctx: List[C]
)(
run: (A, ParsedDirective[?, P]) => Either[String, A],
) = directives
.parTraverse(parseSchemaDirective(_, ctx))
.flatMap(_.foldLeftM(a){ case (a, d) => G.raiseEither(run(a, d), ctx) })

def foldDirectives[P[x] <: Position[F, x]]: DirectiveAlg.PartiallyAppliedFold[F, C, P] =
new DirectiveAlg.PartiallyAppliedFold[F, C, P] {
override def apply[H[_]: Traverse, A](directives: Option[QueryAst.Directives[C, AnyValue]], context: List[C])(base: A)(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import gql.Position
class FieldCollection[F[_], C](
implementations: SchemaShape.Implementations[F],
fragments: Map[String, QA.FragmentDefinition[C]],
ap: ArgParsing[C],
ap: ArgParsing[F, C],
da: DirectiveAlg[F, C]
) {
type G[A] = Alg[C, A]
Expand Down
55 changes: 27 additions & 28 deletions modules/core/src/main/scala/gql/preparation/QueryPreparation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import gql.std.LazyT
import org.typelevel.scalaccompat.annotation._

class QueryPreparation[F[_], C](
ap: ArgParsing[C],
ap: ArgParsing[F, C],
da: DirectiveAlg[F, C],
variables: VariableMap[C],
implementations: SchemaShape.Implementations[F]
Expand All @@ -50,7 +50,7 @@ class QueryPreparation[F[_], C](
u.types.toList.map { case x: gql.ast.Variant[F, A, b] =>
Specialization.Union(u, x)
}
case it @ Interface(_, _, _,_, _) =>
case it @ Interface(_, _, _, _, _) =>
val m: Map[String, SchemaShape.InterfaceImpl[F, A]] =
implementations
.get(it.name)
Expand Down Expand Up @@ -121,7 +121,8 @@ class QueryPreparation[F[_], C](
t: Out[F, A],
fieldMeta: PartialFieldMeta[C],
uec: UniqueEdgeCursor
): Analyze[Prepared[F, A]] =
): Analyze[Prepared[F, A]] = {
val cs = List(fi.caret)
(t, fi.selections.toNel) match {
case (out: gql.ast.OutArr[F, a, c, b], _) =>
val innerStep: Step[F, a, b] = out.resolver.underlying
Expand All @@ -138,38 +139,33 @@ class QueryPreparation[F[_], C](
PreparedOption(nid, PreparedCont(s, c))
}
case (s: Selectable[F, a], Some(ss)) =>
liftK(prepareSelectable[A](s, ss).widen[Prepared[F, A]])
liftK(prepareSelectable[A](s, ss, cs).widen[Prepared[F, A]])
case (e: Enum[a], None) =>
val cs = List(fi.caret)
liftK {
e.directives
.parTraverse(da.parseSchemaDirective(_, cs))
.flatMap(_.foldLeftM(e){ case (e, d) => G.raiseEither(d.p.handler(d.a, e), cs) })
.flatMap{ e =>
da.enumTpe(e, cs).flatMap { e =>
nextNodeId.map(PreparedLeaf[F, a](_, e.name, x => Json.fromString(e.revm(x))))
}
}
case (s: Scalar[a], None) =>
import io.circe.syntax._
liftK(nextNodeId).map(PreparedLeaf(_, s.name, x => s.encoder(x).asJson))
liftK {
da.scalar(s, cs).flatMap { s =>
nextNodeId.map(PreparedLeaf[F, a](_, s.name, x => s.encoder(x).asJson))
}
}
case (o, Some(_)) =>
liftK(G.raise(s"Type `${ModifierStack.fromOut(o).show(_.name)}` cannot have selections.", List(fi.caret)))
case (o, None) =>
liftK(G.raise(s"Object like type `${ModifierStack.fromOut(o).show(_.name)}` must have a selection.", List(fi.caret)))
}
}

def prepareField[I, O](
fi: MergedFieldInfo[F, C],
field: Field[F, I, O],
currentTypename: String
): G[List[PreparedDataField[F, I, ?]]] = {
da
.parseProvidedSubtype[Position.Field[F, *]](fi.directives, List(fi.caret))
.flatMap(_.foldLeftM[G, List[(Field[F, I, ?], MergedFieldInfo[F, C])]](List((field, fi))) { case (xs, prov) =>
xs.parFlatTraverse { case (f: Field[F, I, ?], fi) =>
G.raiseEither(prov.p.handler(prov.a, f, fi), List(fi.caret))
}
})
da.field(fi, field)
.flatMap(_.parTraverse { case (field: Field[F, I, o2], fi) =>
val rootUniqueName = UniqueEdgeCursor(s"${currentTypename}_${fi.name}")

Expand Down Expand Up @@ -334,21 +330,24 @@ class QueryPreparation[F[_], C](

def prepareSelectable[A](
s: Selectable[F, A],
sis: NonEmptyList[SelectionInfo[F, C]]
sis: NonEmptyList[SelectionInfo[F, C]],
ctx: List[C]
): G[Selection[F, A]] =
mergeImplementations[A](s, sis)
.flatMap { impls =>
impls.parTraverse[G, PreparedSpecification[F, A, ?]] { case impl: MergedSpecialization[F, A, b, C] =>
val fa = impl.selections.toList.parFlatTraverse { sel =>
sel.field match {
case field: Field[F, b2, t] => prepareField[b, t](sel.info, field, impl.spec.typename)
da.selectable(s, ctx).flatMap { s =>
mergeImplementations[A](s, sis)
.flatMap { impls =>
impls.parTraverse[G, PreparedSpecification[F, A, ?]] { case impl: MergedSpecialization[F, A, b, C] =>
val fa = impl.selections.toList.parFlatTraverse { sel =>
sel.field match {
case field: Field[F, b2, t] => prepareField[b, t](sel.info, field, impl.spec.typename)
}
}
}

nextNodeId.flatMap(nid => fa.map(xs => PreparedSpecification[F, A, b](nid, impl.spec, xs)))
nextNodeId.flatMap(nid => fa.map(xs => PreparedSpecification[F, A, b](nid, impl.spec, xs)))
}
}
}
.flatMap(xs => nextNodeId.map(nid => Selection(nid, xs.toList, s)))
.flatMap(xs => nextNodeId.map(nid => Selection(nid, xs.toList, s)))
}
}

final case class MergedFieldInfo[G[_], C](
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ class RootPreparation[F[_], C] {
variableMap: Map[String, Json],
schema: SchemaShape[F, ?, ?, ?]
): Alg[C, VariableMap[C]] = {
val ap = new ArgParsing[C](Map.empty)
lazy val ap: ArgParsing[F, C] = new ArgParsing[F, C](Map.empty, da)
lazy val da: DirectiveAlg[F, C] = new DirectiveAlg[F, C](schema.discover.positions, ap)

/*
* Convert the variable signature into a gql arg and parse both the default value and the provided value
* Then save the provided getOrElse default into a map along with the type
Expand Down Expand Up @@ -135,8 +137,8 @@ class RootPreparation[F[_], C] {

def runWith[A](o: gql.ast.Type[F, A]): G[Selection[F, A]] =
variables(od, variableMap, schema).flatMap { vm =>
val ap = new ArgParsing[C](vm)
val da = new DirectiveAlg[F, C](schema.discover.positions, ap)
lazy val ap: ArgParsing[F, C] = new ArgParsing[F, C](vm, da)
lazy val da: DirectiveAlg[F, C] = new DirectiveAlg[F, C](schema.discover.positions, ap)

val fragMap = frags.map(x => x.name -> x).toMap
val fc = new FieldCollection[F, C](
Expand All @@ -159,7 +161,7 @@ class RootPreparation[F[_], C] {
val prog: G[Selection[F, A]] = fc.collectSelectionInfo(o, ss).flatMap {
case x :: xs =>
val r = NonEmptyList(x, xs)
fm.checkSelectionsMerge(r) >> qp.prepareSelectable(o, r)
fm.checkSelectionsMerge(r) >> qp.prepareSelectable(o, r, Nil)
case _ => G.nextId.map(NodeId(_)).map(Selection(_, Nil, o))
}
(prog, G.usedVariables).tupled.flatMap { case (res, used) =>
Expand Down

0 comments on commit d19c64f

Please sign in to comment.