-
Notifications
You must be signed in to change notification settings - Fork 27
/
valuemapping.scala
148 lines (122 loc) · 5.32 KB
/
valuemapping.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright (c) 2016-2020 Association of Universities for Research in Astronomy, Inc. (AURA)
// For license information see LICENSE or https://opensource.org/licenses/BSD-3-Clause
package edu.gemini.grackle
import scala.collection.Factory
import scala.reflect.ClassTag
import cats.Monad
import cats.implicits._
import io.circe.Json
import org.tpolecat.sourcepos.SourcePos
import Cursor.{Context, Env}
import QueryInterpreter.mkErrorResult
abstract class ValueMapping[F[_]](implicit val M: Monad[F]) extends Mapping[F] with ValueMappingLike[F]
trait ValueMappingLike[F[_]] extends Mapping[F] {
def valueCursor[T](tpe: Type, env: Env, t: T): Cursor =
ValueCursor(Context(tpe), t, None, env)
override def mkCursorForField(parent: Cursor, fieldName: String, resultName: Option[String]): Result[Cursor] = {
val context = parent.context
val fieldContext = context.forFieldOrAttribute(fieldName, resultName)
fieldMapping(context, fieldName) match {
case Some(ValueField(_, f, _)) =>
val parentFocus: Any = parent match {
case vc: ValueCursor => vc.focus
case _ => ()
}
val childFocus = f.asInstanceOf[Any => Any](parentFocus)
if(isLeaf(fieldContext.tpe))
LeafCursor(fieldContext, childFocus, Some(parent), parent.env).rightIor
else
ValueCursor(fieldContext, childFocus, Some(parent), parent.env).rightIor
case _ =>
super.mkCursorForField(parent, fieldName, resultName)
}
}
sealed trait ValueFieldMapping[T] extends FieldMapping
object ValueFieldMapping {
implicit def wrap[T](fm: FieldMapping): ValueFieldMapping[T] = Wrap(fm)
case class Wrap[T](fm: FieldMapping)(implicit val pos: SourcePos) extends ValueFieldMapping[T] {
def fieldName = fm.fieldName
def hidden = fm.hidden
def withParent(tpe: Type): FieldMapping = fm.withParent(tpe)
}
}
case class ValueField[T](fieldName: String, f: T => Any, hidden: Boolean = false)(implicit val pos: SourcePos) extends ValueFieldMapping[T] {
def withParent(tpe: Type): ValueField[T] = this
}
object ValueField {
def fromValue[T](fieldName: String, t: T, hidden: Boolean = false)(implicit pos: SourcePos): ValueField[Unit] =
new ValueField[Unit](fieldName, _ => t, hidden)
}
case class ValueObjectMapping[T](
tpe: Type,
fieldMappings: List[FieldMapping],
classTag: ClassTag[T]
)(implicit val pos: SourcePos) extends ObjectMapping
def ValueObjectMapping[T](
tpe: Type,
fieldMappings: List[ValueFieldMapping[T]]
)(implicit classTag: ClassTag[T], pos: SourcePos): ValueObjectMapping[T] =
new ValueObjectMapping(tpe, fieldMappings.map(_.withParent(tpe)), classTag)
case class ValueCursor(
context: Context,
focus: Any,
parent: Option[Cursor],
env: Env
) extends Cursor {
def withEnv(env0: Env): Cursor = copy(env = env.add(env0))
def mkChild(context: Context = context, focus: Any = focus): ValueCursor =
ValueCursor(context, focus, Some(this), Env.empty)
def isLeaf: Boolean = false
def asLeaf: Result[Json] =
mkErrorResult(s"Not a leaf: $tpe")
def preunique: Result[Cursor] = {
val listTpe = tpe.nonNull.list
focus match {
case _: List[_] => mkChild(context.asType(listTpe), focus).rightIor
case _ =>
mkErrorResult(s"Expected List type, found $focus for ${listTpe}")
}
}
def isList: Boolean = (tpe, focus) match {
case (_: ListType, _: List[_]) => true
case _ => false
}
def asList[C](factory: Factory[Cursor, C]): Result[C] = (tpe, focus) match {
case (ListType(tpe), it: List[_]) => it.view.map(f => mkChild(context.asType(tpe), f)).to(factory).rightIor
case _ => mkErrorResult(s"Expected List type, found $tpe")
}
def listSize: Result[Int] = (tpe, focus) match {
case (ListType(_), it: List[_]) => it.size.rightIor
case _ => mkErrorResult(s"Expected List type, found $tpe")
}
def isNullable: Boolean = (tpe, focus) match {
case (_: NullableType, _: Option[_]) => true
case _ => false
}
def asNullable: Result[Option[Cursor]] = (tpe, focus) match {
case (NullableType(tpe), o: Option[_]) => o.map(f => mkChild(context.asType(tpe), f)).rightIor
case (_: NullableType, _) => mkErrorResult(s"Found non-nullable $focus for $tpe")
case _ => mkErrorResult(s"Expected Nullable type, found $focus for $tpe")
}
def isDefined: Result[Boolean] = (tpe, focus) match {
case (_: NullableType, opt: Option[_]) => opt.isDefined.rightIor
case _ => mkErrorResult(s"Expected Nullable type, found $focus for $tpe")
}
def narrowsTo(subtpe: TypeRef): Boolean =
subtpe <:< tpe &&
objectMapping(context.asType(subtpe)).map {
case ValueObjectMapping(_, _, classTag) =>
classTag.runtimeClass.isInstance(focus)
case _ => false
}.getOrElse(false)
def narrow(subtpe: TypeRef): Result[Cursor] =
if (narrowsTo(subtpe))
mkChild(context.asType(subtpe)).rightIor
else
mkErrorResult(s"Focus ${focus} of static type $tpe cannot be narrowed to $subtpe")
def hasField(fieldName: String): Boolean =
fieldMapping(context, fieldName).isDefined
def field(fieldName: String, resultName: Option[String]): Result[Cursor] =
mkCursorForField(this, fieldName, resultName)
}
}