http://git-wip-us.apache.org/repos/asf/atlas/blob/0877e47c/repository/src/main/scala/org/apache/atlas/query/Expressions.scala ---------------------------------------------------------------------- diff --git a/repository/src/main/scala/org/apache/atlas/query/Expressions.scala b/repository/src/main/scala/org/apache/atlas/query/Expressions.scala deleted file mode 100644 index bf9efd2..0000000 --- a/repository/src/main/scala/org/apache/atlas/query/Expressions.scala +++ /dev/null @@ -1,923 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.atlas.query - -import com.google.common.collect.ImmutableCollection -import org.apache.atlas.AtlasException -import org.apache.atlas.typesystem.types.DataTypes.{ArrayType, PrimitiveType, TypeCategory} -import org.apache.atlas.typesystem.types._ -import scala.collection.JavaConverters._ - -object Expressions { - - import TypeUtils._ - - class ExpressionException(val e: Expression, message: String, cause: Throwable, enableSuppression: Boolean, - writableStackTrace: Boolean) - extends AtlasException(message, cause, enableSuppression, writableStackTrace) { - - def this(e: Expression, message: String) { - this(e, message, null, false, true) - } - - def this(e: Expression, message: String, cause: Throwable) { - this(e, message, cause, false, true) - } - - def this(e: Expression, cause: Throwable) { - this(e, null, cause, false, true) - } - - override def getMessage: String = { - val eString = e.toString - s"${super.getMessage}, expression:${if (eString contains "\n") "\n" else " "}$e" - } - - } - - class UnresolvedException(expr: Expression, function: String) extends - ExpressionException(expr, s"Unresolved $function") - - def attachExpression[A](e: Expression, msg: String = "")(f: => A): A = { - try f catch { - case eex: ExpressionException => throw eex - case ex: Exception => throw new ExpressionException(e, msg, ex) - } - } - - trait Expression { - self: Product => - def isAggregator = false - def children: Seq[Expression] - - /** - * Returns `true` if the schema for this expression and all its children have been resolved. - * The default logic is that an Expression is resolve if all its children are resolved. - */ - lazy val resolved: Boolean = childrenResolved - - /** - * Returns the output [[IDataType[_]] of this expression. Expressions that are unresolved will - * throw if this method is invoked. - */ - def dataType: IDataType[_] - - /** - * Returns true if all the children have been resolved. - */ - def childrenResolved = !children.exists(!_.resolved) - - - /** - * the aliases that are present in this Expression Tree - */ - def namedExpressions: Map[String, Expression] = Map() - - def fastEquals(other: Expression): Boolean = { - this.eq(other) || this == other - } - - def makeCopy(newArgs: Array[AnyRef]): this.type = attachExpression(this, "makeCopy") { - try { - val defaultCtor = getClass.getConstructors.find(_.getParameterTypes.size != 0).head - defaultCtor.newInstance(newArgs: _*).asInstanceOf[this.type] - } catch { - case e: java.lang.IllegalArgumentException => - throw new ExpressionException( - this, s"Failed to copy node. Reason: ${e.getMessage}.") - } - } - - def transformChildrenDown(rule: PartialFunction[Expression, Expression]): this.type = { - var changed = false - val newArgs = productIterator.map { - case arg: Expression if children contains arg => - val newChild = arg.asInstanceOf[Expression].transformDown(rule) - if (!(newChild fastEquals arg)) { - changed = true - newChild - } else { - arg - } - case Some(arg: Expression) if children contains arg => - val newChild = arg.asInstanceOf[Expression].transformDown(rule) - if (!(newChild fastEquals arg)) { - changed = true - Some(newChild) - } else { - Some(arg) - } - case m: Map[_, _] => m - case args: Traversable[_] => args.map { - case arg: Expression if children contains arg => - val newChild = arg.asInstanceOf[Expression].transformDown(rule) - if (!(newChild fastEquals arg)) { - changed = true - newChild - } else { - arg - } - case other => other - } - case nonChild: AnyRef => nonChild - case null => null - }.toArray - if (changed) makeCopy(newArgs) else this - } - - def transformDown(rule: PartialFunction[Expression, Expression]): Expression = { - val afterRule = rule.applyOrElse(this, identity[Expression]) - // Check if unchanged and then possibly return old copy to avoid gc churn. - if (this fastEquals afterRule) { - transformChildrenDown(rule) - } else { - afterRule.transformChildrenDown(rule) - } - } - - def traverseChildren(traverseFunc: (Expression, PartialFunction[Expression, Unit]) => Unit) - (rule: PartialFunction[Expression, Unit]): Unit = { - productIterator.foreach { - case arg: Expression if children contains arg => - traverseFunc(arg.asInstanceOf[Expression], rule) - case Some(arg: Expression) if children contains arg => - traverseFunc(arg.asInstanceOf[Expression], rule) - case m: Map[_, _] => m - case args: Traversable[_] => args.map { - case arg: Expression if children contains arg => - traverseFunc(arg.asInstanceOf[Expression], rule) - case other => other - } - case nonChild: AnyRef => nonChild - case null => null - } - } - - def traverseChildrenDown = traverseChildren(_traverseDown) _ - - private def _traverseDown(e: Expression, rule: PartialFunction[Expression, Unit]): Unit = { - if (rule.isDefinedAt(e)) { - rule.apply(e) - } - e.traverseChildrenDown(rule) - } - - def traverseDown(rule: PartialFunction[Expression, Unit]): Unit = { - _traverseDown(this, rule) - } - - def traverseChildrenUp = traverseChildren(_traverseUp) _ - - private def _traverseUp(e: Expression, rule: PartialFunction[Expression, Unit]): Unit = { - e.traverseChildrenUp(rule) - if (rule.isDefinedAt(e)) { - rule.apply(e) - } - } - - def traverseUp(rule: PartialFunction[Expression, Unit]): Unit = { - _traverseUp(this, rule) - } - - def transformUp(rule: PartialFunction[Expression, Expression]): Expression = { - val afterRuleOnChildren = transformChildrenUp(rule); - if (this fastEquals afterRuleOnChildren) { - rule.applyOrElse(this, identity[Expression]) - } else { - rule.applyOrElse(afterRuleOnChildren, identity[Expression]) - } - } - - def transformChildrenUp(rule: PartialFunction[Expression, Expression]): this.type = { - var changed = false - val newArgs = productIterator.map { - case arg: Expression if children contains arg => - val newChild = arg.asInstanceOf[Expression].transformUp(rule) - if (!(newChild fastEquals arg)) { - changed = true - newChild - } else { - arg - } - case Some(arg: Expression) if children contains arg => - val newChild = arg.asInstanceOf[Expression].transformUp(rule) - if (!(newChild fastEquals arg)) { - changed = true - Some(newChild) - } else { - Some(arg) - } - case m: Map[_, _] => m - case args: Traversable[_] => args.map { - case arg: Expression if children contains arg => - val newChild = arg.asInstanceOf[Expression].transformUp(rule) - if (!(newChild fastEquals arg)) { - changed = true - newChild - } else { - arg - } - case other => other - } - case nonChild: AnyRef => nonChild - case null => null - }.toArray - if (changed) makeCopy(newArgs) else this - } - - /* - * treeString methods - */ - def nodeName = getClass.getSimpleName - - def argString: String = productIterator.flatMap { - case e: Expression if children contains e => Nil - case e: Expression if e.toString contains "\n" => s"(${e.simpleString})" :: Nil - case seq: Seq[_] => seq.mkString("[", ",", "]") :: Nil - case set: Set[_] => set.mkString("{", ",", "}") :: Nil - case f: IDataType[_] => f.getName :: Nil - case other => other :: Nil - }.mkString(", ") - - /** String representation of this node without any children */ - def simpleString = s"$nodeName $argString" - - protected def generateTreeString(depth: Int, builder: StringBuilder): StringBuilder = { - builder.append(" " * depth) - builder.append(simpleString) - builder.append("\n") - children.foreach(_.generateTreeString(depth + 1, builder)) - builder - } - - def treeString = generateTreeString(0, new StringBuilder).toString - - /* - * Fluent API methods - */ - def field(fieldName: String) = new UnresolvedFieldExpression(this, fieldName) - - def join(fieldName: String) = field(fieldName) - - def `.`(fieldName: String) = field(fieldName) - - def as(alias: String) = new AliasExpression(this, alias) - - def arith(op: String)(rightExpr: Expression) = new ArithmeticExpression(op, this, rightExpr) - - def + = arith("+") _ - - def - = arith("-") _ - - def * = arith("*") _ - - def / = arith("/") _ - - def % = arith("%") _ - - def isTrait(name: String) = new isTraitUnaryExpression(name, this) - - def hasField(name: String) = new hasFieldUnaryExpression(name, this) - - def compareOp(op: String)(rightExpr: Expression) = new ComparisonExpression(op, this, rightExpr) - - def `=` = compareOp("=") _ - - def `!=` = compareOp("!=") _ - - def `>` = compareOp(">") _ - - def `>=` = compareOp(">=") _ - - def `<` = compareOp("<") _ - - def `<=` = compareOp("=") _ - - def logicalOp(op: String)(rightExpr: Expression) = new LogicalExpression(op, List(this, rightExpr)) - - def and = logicalOp("and") _ - - def or = logicalOp("or") _ - - def where(condExpr: Expression) = new FilterExpression(this, condExpr) - - def select(selectList: Expression*) = new SelectExpression(this, selectList.toList) - - def loop(loopingExpr: Expression) = new LoopExpression(this, loopingExpr, None) - - def loop(loopingExpr: Expression, times: Literal[Integer]) = - new LoopExpression(this, loopingExpr, Some(times)) - - def traitInstance() = new TraitInstanceExpression(this) - def instance() = new InstanceExpression(this) - - def path() = new PathExpression(this) - - def limit(lmt: Literal[Integer], offset : Literal[Integer]) = new LimitExpression(this, lmt, offset) - - def order(odr: Expression, asc: Boolean) = new OrderExpression(this, odr, asc) - - def max(maxClause: Expression) = new MaxExpression(maxClause) - - def min(minClause: Expression) = new MinExpression(minClause) - - def groupBy(groupBy: SelectExpression, selectExpr: SelectExpression) = new GroupByExpression(this, groupBy, selectExpr) - } - - trait BinaryNode { - self: Expression => - def left: Expression - - def right: Expression - - def children = Seq(left, right) - - override def namedExpressions = left.namedExpressions ++ right.namedExpressions - } - - trait LeafNode { - def children = Nil - } - - trait UnaryNode { - self: Expression => - def child: Expression - - override def namedExpressions = child.namedExpressions - - def children = child :: Nil - } - - abstract class BinaryExpression extends Expression with BinaryNode { - self: Product => - def symbol: String - - override def toString = s"($left $symbol $right)" - } - - case class ClassExpression(clsName: String) extends Expression with LeafNode { - val dataType = typSystem.getDataType(classOf[ClassType], clsName) - - override def toString = clsName - } - - def _class(name: String): Expression = new ClassExpression(name) - - case class TraitExpression(traitName: String) extends Expression with LeafNode { - val dataType = typSystem.getDataType(classOf[TraitType], traitName) - - override def toString = traitName - } - - def _trait(name: String) = new TraitExpression(name) - - object IdExpressionType extends Enumeration { - val Unresolved, NonType = Value; - - class IdExpressionTypeValue(exprValue : Value) { - - def isTypeAllowed = exprValue match { - case Unresolved => true - case _ => false - } - } - import scala.language.implicitConversions - implicit def value2ExprValue(exprValue: Value) = new IdExpressionTypeValue(exprValue) - } - - case class IdExpression(name: String, exprType: IdExpressionType.Value) extends Expression with LeafNode { - override def toString = name - - override lazy val resolved = false - - override def dataType = throw new UnresolvedException(this, "id") - } - - /** - * Creates an IdExpression whose allowed value type will be determined - * later. - */ - def id(name: String) = new IdExpression(name, IdExpressionType.Unresolved) - - /** - * Creates an IdExpression whose value must resolve to a field name - */ - def fieldId(name: String) = new IdExpression(name, IdExpressionType.NonType) - - case class UnresolvedFieldExpression(child: Expression, fieldName: String) extends Expression - with UnaryNode { - override def toString = s"${child}.$fieldName" - override def isAggregator = child.isAggregator - override lazy val resolved = false - - override def dataType = throw new UnresolvedException(this, "field") - } - - case class FieldExpression(fieldName: String, fieldInfo: FieldInfo, child: Option[Expression]) - extends Expression { - - def elemType(t: IDataType[_]): IDataType[_] = { - if (t.getTypeCategory == TypeCategory.ARRAY) { - val aT = t.asInstanceOf[ArrayType] - if (aT.getElemType.getTypeCategory == TypeCategory.CLASS || - aT.getElemType.getTypeCategory == TypeCategory.STRUCT) { - return aT.getElemType - } - } - t - } - - val children = if (child.isDefined) List(child.get) else Nil - import scala.language.existentials - lazy val dataType = { - val t = { - if (fieldInfo.traitName != null ) { - typSystem.getDataType(classOf[TraitType], fieldInfo.traitName) - } else if (!fieldInfo.isReverse) { - fieldInfo.attrInfo.dataType() - } else { - fieldInfo.reverseDataType - } - } - elemType(t) - } - override lazy val resolved: Boolean = true - - override def namedExpressions = if (child.isDefined) child.get.namedExpressions else Map() - - override def toString = { - if (child.isDefined) { - val sep = if (dataType.isInstanceOf[ClassType]) " " else "." - s"${child.get}${sep}$fieldName" - } else { - fieldName - } - } - } - - case class AliasExpression(child: Expression, alias: String) extends Expression with UnaryNode { - override def namedExpressions = child.namedExpressions + (alias -> child) - - override def toString = s"$child as $alias" - override def isAggregator = child.isAggregator - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved child") - } - child.dataType - } - } - - case class BackReference(alias: String, reference: Expression, child: Option[Expression]) extends Expression { - val children = if (child.isDefined) List(child.get) else Nil - val dataType = reference.dataType - - override def namedExpressions = if (child.isDefined) child.get.namedExpressions else Map() - - override def toString = if (child.isDefined) s"${child.get} $alias" else alias - } - - case class Literal[T](dataType: PrimitiveType[T], rawValue: Any) extends Expression with LeafNode { - val value = if (rawValue == null) dataType.nullValue() else dataType.convert(rawValue, Multiplicity.REQUIRED) - - override def toString = value match { - case s: String => s""""$s"""" - case x => x.toString - } - } - - import scala.collection.JavaConversions._ - case class ListLiteral[_](dataType: ArrayType, rawValue: List[Expressions.Literal[_]]) extends Expression with LeafNode { - - val lc : java.util.List[Expressions.Literal[_]] = rawValue - val value = if (rawValue != null) dataType.convert(lc, Multiplicity.REQUIRED) - - override def toString = value match { - case l: Seq[_] - => l.mkString("[",",","]") - case c: ImmutableCollection[_] => - c.asList.mkString("[",",","]") - case x => - x.toString - } - } - - def literal[T](typ: PrimitiveType[T], rawValue: Any) = new Literal[T](typ, rawValue) - - def boolean(rawValue: Any) = literal(DataTypes.BOOLEAN_TYPE, rawValue) - - def byte(rawValue: Any) = literal(DataTypes.BYTE_TYPE, rawValue) - - def short(rawValue: Any) = literal(DataTypes.SHORT_TYPE, rawValue) - - def int(rawValue: Any) = literal(DataTypes.INT_TYPE, rawValue) - - def long(rawValue: Any) = literal(DataTypes.LONG_TYPE, rawValue) - - def float(rawValue: Any) = literal(DataTypes.FLOAT_TYPE, rawValue) - - def double(rawValue: Any) = literal(DataTypes.DOUBLE_TYPE, rawValue) - - def bigint(rawValue: Any) = literal(DataTypes.BIGINTEGER_TYPE, rawValue) - - def bigdecimal(rawValue: Any) = literal(DataTypes.BIGDECIMAL_TYPE, rawValue) - - def string(rawValue: Any) = literal(DataTypes.STRING_TYPE, rawValue) - - def date(rawValue: Any) = literal(DataTypes.DATE_TYPE, rawValue) - - def list[_ <: PrimitiveType[_]](listElements: List[Expressions.Literal[_]]) = { - listLiteral(TypeSystem.getInstance().defineArrayType(listElements.head.dataType), listElements) - } - - def listLiteral[_ <: PrimitiveType[_]](typ: ArrayType, rawValue: List[Expressions.Literal[_]]) = new ListLiteral(typ, rawValue) - - def count() = new CountExpression() - - def maxExpr(maxClause: Expression) = new MaxExpression(maxClause) - - def minExpr(minClause: Expression) = new MinExpression(minClause) - - def sumExpr(sumClause: Expression) = new SumExpression(sumClause) - - case class ArithmeticExpression(symbol: String, - left: Expression, - right: Expression) - extends BinaryExpression { - - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - TypeUtils.combinedType(left.dataType, right.dataType) - } - } - - case class isTraitLeafExpression(traitName: String, classExpression: Option[Expression] = None) - extends Expression with LeafNode { - // validate TraitName - try { - typSystem.getDataType(classOf[TraitType], traitName) - } catch { - case me: AtlasException => throw new ExpressionException(this, "not a TraitType", me) - } - - override lazy val resolved = classExpression.isDefined - lazy val dataType = { - - if (!resolved) { - throw new UnresolvedException(this, - s"cannot resolve isTrait application") - } - - if (!classExpression.get.dataType.isInstanceOf[ClassType]) { - throw new ExpressionException(this, - s"Cannot apply isTrait on ${classExpression.get.dataType.getName}, it is not a ClassType") - } - DataTypes.BOOLEAN_TYPE - } - - override def toString = s"${classExpression.getOrElse("")} is $traitName" - } - - def isTrait(name: String) = new isTraitLeafExpression(name) - - case class isTraitUnaryExpression(traitName: String, child: Expression) - extends Expression with UnaryNode { - // validate TraitName - typSystem.getDataType(classOf[TraitType], traitName) - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved child") - } - if (!child.dataType.isInstanceOf[ClassType]) { - throw new ExpressionException(this, - s"Cannot apply isTrait on ${child.dataType.getName}, it is not a ClassType") - } - DataTypes.BOOLEAN_TYPE - } - - override def toString = s"$child is $traitName" - } - - case class hasFieldLeafExpression(fieldName: String, classExpression: Option[Expression] = None) - extends Expression with LeafNode { - - override lazy val resolved = classExpression.isDefined - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"Cannot apply hasField on ${classExpression.get.dataType.getName}, it is not a ClassType") - } - if (classExpression.isDefined && !TypeUtils.fieldMapping(classExpression.get.dataType).isDefined) { - throw new ExpressionException(this, s"Cannot apply hasField on ${classExpression.get.dataType.getName}") - } - DataTypes.BOOLEAN_TYPE - } - - override def toString = s"${classExpression.getOrElse("")} has $fieldName" - } - - def hasField(name: String) = new hasFieldLeafExpression(name) - - case class hasFieldUnaryExpression(fieldName: String, child: Expression) - extends Expression with UnaryNode { - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved child") - } - if (!TypeUtils.fieldMapping(child.dataType).isDefined) { - throw new AtlasException(s"Cannot apply hasField on ${child.dataType.getName}") - } - DataTypes.BOOLEAN_TYPE - } - - override def toString = s"$child has $fieldName" - } - - case class ComparisonExpression(symbol: String, - left: Expression, - right: Expression) - extends BinaryExpression { - - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - - if(left.dataType.getName.startsWith(DataTypes.ARRAY_TYPE_PREFIX)) { - left.dataType; - } else if(left.dataType == DataTypes.DATE_TYPE) { - DataTypes.DATE_TYPE - } - else if(left.dataType == DataTypes.BOOLEAN_TYPE) { - DataTypes.BOOLEAN_TYPE; - } - else if (left.dataType != DataTypes.STRING_TYPE || right.dataType != DataTypes.STRING_TYPE) { - TypeUtils.combinedType(left.dataType, right.dataType) - } - DataTypes.BOOLEAN_TYPE - } - } - - case class LogicalExpression(symbol: String, children: List[Expression]) - extends Expression { - assert(children.size > 0) - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - children.foreach { childExpr => - if (childExpr.dataType != DataTypes.BOOLEAN_TYPE) { - throw new AtlasException( - s"Cannot apply logical operator '$symbol' on input of type '${childExpr.dataType}") - } - } - DataTypes.BOOLEAN_TYPE - } - - override def toString = children.mkString("", s" $symbol ", "") - } - - case class FilterExpression(val child: Expression, val condExpr: Expression) extends Expression { - val children = List(child, condExpr) - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - if (condExpr.dataType != DataTypes.BOOLEAN_TYPE) { - throw new ExpressionException(this, s"Filter condition '$condExpr' is not a boolean expression") - } - child.dataType - } - - override def namedExpressions = child.namedExpressions ++ condExpr.namedExpressions - - override def toString = s"$child where $condExpr" - } - - case class SelectExpression(child: Expression, selectList: List[Expression], forGroupBy: Boolean = false) extends Expression { - val children = List(child) ::: selectList - - def hasAggregation = { - var result = false; - selectList.foreach { expr => - { - result = result || expr.isAggregator - } - } - result - } - - lazy val selectListWithAlias = selectList.zipWithIndex map { - case (s: AliasExpression, _) => s - case (x, i) => new AliasExpression(x, s"${x}") - } - - - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - TypeUtils.createStructType(selectListWithAlias) - } - - override def namedExpressions = child.namedExpressions ++ (selectList.flatMap(_.namedExpressions)) - - override def toString = { - //When this is part of a group by, the child is only present so that the select - //list gets translated correctly. It is not really part of the query. The child - //ends up both in the GroupByExpression as well as here. We only want to show it - //in the GroupByExpression. Hide it here. - var prefix = if(forGroupBy) { "" } else { s"""${child} select """ } - s"""${prefix}${selectListWithAlias.mkString("", ", ", "")}""" - } - - def toJavaList = selectListWithAlias.asJava - } - - case class LoopExpression(val input: Expression, val loopingExpression: Expression, - val times: Option[Literal[Integer]]) extends Expression { - val children = List(input, loopingExpression) - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - if (input.dataType.getTypeCategory != TypeCategory.CLASS) { - throw new ExpressionException(this, s"Loop Expression applied to type : '${input.dataType.getName}';" + - " loop can only be applied to Class Expressions") - } - if (input.dataType != loopingExpression.dataType) { - throw new ExpressionException(this, - s"Invalid Loop Expression; input and loopExpression dataTypes don't match: " + - s"(${input.dataType.getName},${loopingExpression.dataType.getName}})") - } - input.dataType - } - - override def namedExpressions = input.namedExpressions - - override def toString = { - if (times.isDefined) s"$input loop ($loopingExpression) times ${times.get.value}" - else s"$input loop ($loopingExpression)" - } - } - - case class TraitInstanceExpression(child: Expression) - extends Expression with UnaryNode { - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved child") - } - if (!child.dataType.isInstanceOf[TraitType]) { - throw new ExpressionException(this, - s"Cannot apply instance on ${child.dataType.getName}, it is not a TraitType") - } - typSystem.getIdType.getStructType - } - - override def toString = s"$child traitInstance" - } - - case class InstanceExpression(child: Expression) - extends Expression with UnaryNode { - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved child") - } - typSystem.getIdType.getStructType - } - - override def toString = s"$child instance" - } - - case class PathExpression(child: Expression) - extends Expression with UnaryNode { - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved child") - } - TypeUtils.ResultWithPathStruct.createType(this, child.dataType) - } - - override def toString = s"$child withPath" - } - - case class LimitExpression(child: Expression, limit: Literal[Integer], offset: Literal[Integer]) extends Expression with UnaryNode { - - override def toString = s"$child limit $limit offset $offset " - - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - child.dataType - } - } - - case class OrderExpression(child: Expression, odr: Expression, asc: Boolean) extends Expression with UnaryNode { - - override def toString = s"$child orderby $odr asc $asc" - - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - child.dataType - } - } - - case class CountExpression() extends Expression { - override def isAggregator = true - override def toString = s"count()" - val children = Nil - lazy val dataType = { - DataTypes.LONG_TYPE - } - - } - case class MaxExpression(maxClause: Expression) extends Expression { - - override def toString = s"max($maxClause)" - override def isAggregator = true - val children = List(maxClause) - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - maxClause.dataType - } - } - - case class MinExpression(minClause: Expression) extends Expression { - - override def toString = s"min($minClause)" - override def isAggregator = true - val children = List(minClause) - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - minClause.dataType - } - } - - case class SumExpression(sumClause: Expression) extends Expression { - - override def toString = s"sum($sumClause)" - override def isAggregator = true - val children = List(sumClause) - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - sumClause.dataType - } - } - - case class GroupByExpression(child: Expression, groupBy: SelectExpression, selExpr: SelectExpression) extends Expression{ - - override def toString = s"from ${child} groupby(${groupBy}) select ${selExpr}" - val children = List(child, groupBy, selExpr) - lazy val dataType = { - if (!resolved) { - throw new UnresolvedException(this, - s"datatype. Can not resolve due to unresolved children") - } - selExpr.dataType - } - } -}
http://git-wip-us.apache.org/repos/asf/atlas/blob/0877e47c/repository/src/main/scala/org/apache/atlas/query/GraphPersistenceStrategies.scala ---------------------------------------------------------------------- diff --git a/repository/src/main/scala/org/apache/atlas/query/GraphPersistenceStrategies.scala b/repository/src/main/scala/org/apache/atlas/query/GraphPersistenceStrategies.scala deleted file mode 100755 index c2b3436..0000000 --- a/repository/src/main/scala/org/apache/atlas/query/GraphPersistenceStrategies.scala +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.atlas.query - -import java.util -import java.util.Date - -import scala.collection.JavaConversions._ -import scala.collection.JavaConversions.seqAsJavaList -import scala.language.existentials - -import org.apache.atlas.groovy.GroovyExpression -import org.apache.atlas.query.TypeUtils.FieldInfo -import org.apache.atlas.repository.RepositoryException -import org.apache.atlas.repository.graph.GraphHelper -import org.apache.atlas.repository.graphdb._ -import org.apache.atlas.typesystem.ITypedInstance -import org.apache.atlas.typesystem.ITypedReferenceableInstance -import org.apache.atlas.typesystem.persistence.Id -import org.apache.atlas.typesystem.types._ -import org.apache.atlas.typesystem.types.DataTypes._ - -/** - * Represents the Bridge between the QueryProcessor and the Graph Persistence scheme used. - * Some of the behaviors captured are: - * - how is type and id information stored in the Vertex that represents an [[ITypedReferenceableInstance]] - * - how are edges representing trait and attribute relationships labeled. - * - how are attribute names mapped to Property Keys in Vertices. - * - * This is a work in progress. - * - */ -trait GraphPersistenceStrategies { - - @throws(classOf[RepositoryException]) - def getGraph() : AtlasGraph[_,_] - - def getSupportedGremlinVersion() : GremlinVersion = getGraph().getSupportedGremlinVersion; - def generatePersisentToLogicalConversionExpression(expr: GroovyExpression, t: IDataType[_]) : GroovyExpression = getGraph().generatePersisentToLogicalConversionExpression(expr, t); - def isPropertyValueConversionNeeded(attrType: IDataType[_]) : Boolean = getGraph().isPropertyValueConversionNeeded(attrType); - - def addInitialQueryCondition(parent: GroovyExpression) : GroovyExpression = if (getGraph().requiresInitialIndexedPredicate()) { getGraph().getInitialIndexedPredicate(parent) } else { parent }; - - /** - * Name of attribute used to store typeName in vertex - */ - def typeAttributeName: String - - /** - * Name of attribute used to store super type names in vertex. - */ - def superTypeAttributeName: String - - /** - * Name of attribute used to store guid in vertex - */ - def idAttributeName : String - - /** - * Name of attribute used to store state in vertex - */ - def stateAttributeName : String - /** - * Name of attribute used to store version in vertex - */ - def versionAttributeName : String - - /** - * Given a dataType and a reference attribute, how is edge labeled - */ - def edgeLabel(iDataType: IDataType[_], aInfo: AttributeInfo): String - - def traitLabel(cls: IDataType[_], traitName: String): String - - def instanceToTraitEdgeDirection : AtlasEdgeDirection = AtlasEdgeDirection.OUT; - - def traitToInstanceEdgeDirection : AtlasEdgeDirection = instanceToTraitEdgeDirection match { - case AtlasEdgeDirection.OUT => AtlasEdgeDirection.IN; - case AtlasEdgeDirection.IN => AtlasEdgeDirection.OUT; - case x => AtlasEdgeDirection.IN; - } - - /** - * The propertyKey used to store the attribute in a Graph Vertex. - * @param dataType - * @param aInfo - * @return - */ - def fieldNameInVertex(dataType: IDataType[_], aInfo: AttributeInfo): String - - /** - * from a vertex for an [[ITypedReferenceableInstance]] get the traits that it has. - * @param v - * @return - */ - def traitNames(v: AtlasVertex[_,_]): java.util.List[String] - - def edgeLabel(fInfo: FieldInfo): String = fInfo match { - case FieldInfo(dataType, aInfo, null, null) => edgeLabel(dataType, aInfo) - case FieldInfo(dataType, aInfo, reverseDataType, null) => edgeLabel(reverseDataType, aInfo) - case FieldInfo(dataType, null, null, traitName) => traitLabel(dataType, traitName) - } - - /** - * extract the Id from a Vertex. - * @param dataTypeNm the dataType of the instance that the given vertex represents - * @param v - * @return - */ - def getIdFromVertex(dataTypeNm: String, v: AtlasVertex[_,_]): Id - - def constructInstance[U](dataType: IDataType[U], v: java.lang.Object): U - - def constructClassInstanceId[U](dataType: ClassType, v: java.lang.Object): ITypedReferenceableInstance - - def addGraphVertexPrefix(preStatements : Traversable[GroovyExpression]) = !collectTypeInstancesIntoVar - - /** - * Controls behavior of how instances of a Type are discovered. - * - query is generated in a way that indexes are exercised using a local set variable across multiple lookups - * - query is generated using an 'or' expression. - * - * '''This is a very bad idea: controlling query execution behavior via query generation.''' But our current - * knowledge of seems to indicate we have no choice. See - * [[https://groups.google.com/forum/#!topic/gremlin-users/n1oV86yr4yU discussion in Gremlin group]]. - * Also this seems a fragile solution, dependend on the memory requirements of the Set variable. - * For now enabling via the '''collectTypeInstancesIntoVar''' behavior setting. Reverting back would require - * setting this to false. - * - * Long term have to get to the bottom of Gremlin: - * - there doesn't seem to be way to see the physical query plan. Maybe we should directly interface with Titan. - * - At least from querying perspective a columnar db maybe a better route. Daniel Abadi did some good work - * on showing how to use a columnar store as a Graph Db. - * - * - * @return - */ - def collectTypeInstancesIntoVar = true - - def filterBySubTypes = true - - private def propertyValueSet(vertexRef : String, attrName: String) : String = { - s"""org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils.set(${vertexRef}.values('${attrName})""" - } - - -} - - -case class GraphPersistenceStrategy1(g: AtlasGraph[_,_]) extends GraphPersistenceStrategies { - - val typeAttributeName = "typeName" - val superTypeAttributeName = "superTypeNames" - val idAttributeName = "guid" - val stateAttributeName = "state" - val versionAttributeName = "version" - - override def getGraph() : AtlasGraph[_,_] = { - return g; - } - - def edgeLabel(dataType: IDataType[_], aInfo: AttributeInfo) = s"__${dataType.getName}.${aInfo.name}" - - def edgeLabel(propertyName: String) = s"__${propertyName}" - - def traitLabel(cls: IDataType[_], traitName: String) = s"${cls.getName}.$traitName" - - def fieldNameInVertex(dataType: IDataType[_], aInfo: AttributeInfo) = GraphHelper.getQualifiedFieldName(dataType, aInfo.name) - - def getIdFromVertex(dataTypeNm: String, v: AtlasVertex[_,_]): Id = - new Id(v.getId.toString, 0, dataTypeNm) - - def getIdFromVertex(v: AtlasVertex[_,_]): Id = - getIdFromVertex(v.getProperty(typeAttributeName, classOf[java.lang.String]), v) - - def traitNames(v: AtlasVertex[_,_]): java.util.List[String] = { - val s = v.getProperty("traitNames", classOf[String]) - if (s != null) { - Seq[String](s.split(","): _*) - } else { - Seq() - } - } - def constructClassInstanceId[U](classType: ClassType, v: AnyRef): ITypedReferenceableInstance = { - val vertex = v.asInstanceOf[AtlasVertex[_,_]]; - val id = getIdFromVertex(vertex) - val cInstance = classType.createInstance(id) - classType.convert(cInstance, Multiplicity.OPTIONAL) - } - def constructInstance[U](dataType: IDataType[U], v: AnyRef): U = { - dataType.getTypeCategory match { - case DataTypes.TypeCategory.PRIMITIVE => dataType.convert(v, Multiplicity.OPTIONAL) - case DataTypes.TypeCategory.ARRAY => - dataType.convert(v, Multiplicity.OPTIONAL) - case DataTypes.TypeCategory.STRUCT - if dataType.getName == TypeSystem.getInstance().getIdType.getName => { - val sType = dataType.asInstanceOf[StructType] - val sInstance = sType.createInstance() - val tV = v.asInstanceOf[AtlasVertex[_,_]] - sInstance.set(TypeSystem.getInstance().getIdType.typeNameAttrName, - tV.getProperty(typeAttributeName, classOf[java.lang.String])) - sInstance.set(TypeSystem.getInstance().getIdType.idAttrName, - tV.getProperty(idAttributeName, classOf[java.lang.String])) - dataType.convert(sInstance, Multiplicity.OPTIONAL) - } - case DataTypes.TypeCategory.STRUCT => { - val sType = dataType.asInstanceOf[StructType] - val sInstance = sType.createInstance() - loadStructInstance(sType, sInstance, v.asInstanceOf[AtlasVertex[_,_]]) - dataType.convert(sInstance, Multiplicity.OPTIONAL) - } - case DataTypes.TypeCategory.TRAIT => { - val tType = dataType.asInstanceOf[TraitType] - val tInstance = tType.createInstance() - /* - * this is not right, we should load the Instance associated with this trait. - * for now just loading the trait struct. - */ - loadStructInstance(tType, tInstance, v.asInstanceOf[AtlasVertex[_,_]]) - dataType.convert(tInstance, Multiplicity.OPTIONAL) - } - case DataTypes.TypeCategory.CLASS => { - val cType = dataType.asInstanceOf[ClassType] - val cInstance = constructClassInstance(dataType.asInstanceOf[ClassType], v.asInstanceOf[AtlasVertex[_,_]]) - dataType.convert(cInstance, Multiplicity.OPTIONAL) - } - case DataTypes.TypeCategory.ENUM => dataType.convert(v, Multiplicity.OPTIONAL) - case x => throw new UnsupportedOperationException(s"load for ${dataType} not supported") - } - } - - def loadStructInstance(dataType: IConstructableType[_, _ <: ITypedInstance], - typInstance: ITypedInstance, v: AtlasVertex[_,_]): Unit = { - import scala.collection.JavaConversions._ - dataType.fieldMapping().fields.foreach { t => - val fName = t._1 - val aInfo = t._2 - loadAttribute(dataType, aInfo, typInstance, v) - } - } - - def constructClassInstance(dataType: ClassType, v: AtlasVertex[_,_]): ITypedReferenceableInstance = { - val id = getIdFromVertex(dataType.name, v) - val tNms = traitNames(v) - val cInstance = dataType.createInstance(id, tNms: _*) - // load traits - tNms.foreach { tNm => - val tLabel = traitLabel(dataType, tNm) - val edges = v.getEdges(AtlasEdgeDirection.OUT, tLabel) - val tVertex = edges.iterator().next().getInVertex().asInstanceOf[AtlasVertex[_,_]] - val tType = TypeSystem.getInstance().getDataType[TraitType](classOf[TraitType], tNm) - val tInstance = cInstance.getTrait(tNm).asInstanceOf[ITypedInstance] - loadStructInstance(tType, tInstance, tVertex) - } - loadStructInstance(dataType, cInstance, v) - cInstance - } - - def loadAttribute(dataType: IDataType[_], aInfo: AttributeInfo, i: ITypedInstance, v: AtlasVertex[_,_]): Unit = { - aInfo.dataType.getTypeCategory match { - case DataTypes.TypeCategory.PRIMITIVE => loadPrimitiveAttribute(dataType, aInfo, i, v) - case DataTypes.TypeCategory.ENUM => loadEnumAttribute(dataType, aInfo, i, v) - case DataTypes.TypeCategory.ARRAY => - loadArrayAttribute(dataType, aInfo, i, v) - case DataTypes.TypeCategory.MAP => - throw new UnsupportedOperationException(s"load for ${aInfo.dataType()} not supported") - case DataTypes.TypeCategory.STRUCT => loadStructAttribute(dataType, aInfo, i, v) - case DataTypes.TypeCategory.TRAIT => - throw new UnsupportedOperationException(s"load for ${aInfo.dataType()} not supported") - case DataTypes.TypeCategory.CLASS => loadStructAttribute(dataType, aInfo, i, v) - case DataTypes.TypeCategory.RELATIONSHIP => - throw new UnsupportedOperationException(s"load for ${aInfo.dataType()} not supported") - } - } - - private def loadEnumAttribute(dataType: IDataType[_], aInfo: AttributeInfo, i: ITypedInstance, v: AtlasVertex[_,_]) - : Unit = { - val fName = fieldNameInVertex(dataType, aInfo) - i.setInt(aInfo.name, v.getProperty(fName, classOf[java.lang.Integer])) - } - - private def loadPrimitiveAttribute(dataType: IDataType[_], aInfo: AttributeInfo, - i: ITypedInstance, v: AtlasVertex[_,_]): Unit = { - val fName = fieldNameInVertex(dataType, aInfo) - aInfo.dataType() match { - case x: BooleanType => i.setBoolean(aInfo.name, v.getProperty(fName, classOf[java.lang.Boolean])) - case x: ByteType => i.setByte(aInfo.name, v.getProperty(fName, classOf[java.lang.Byte])) - case x: ShortType => i.setShort(aInfo.name, v.getProperty(fName, classOf[java.lang.Short])) - case x: IntType => i.setInt(aInfo.name, v.getProperty(fName, classOf[java.lang.Integer])) - case x: LongType => i.setLong(aInfo.name, v.getProperty(fName, classOf[java.lang.Long])) - case x: FloatType => i.setFloat(aInfo.name, v.getProperty(fName, classOf[java.lang.Float])) - case x: DoubleType => i.setDouble(aInfo.name, v.getProperty(fName, classOf[java.lang.Double])) - case x: StringType => i.setString(aInfo.name, v.getProperty(fName, classOf[java.lang.String])) - case x: DateType => { - val dateVal = v.getProperty(fName, classOf[java.lang.Long]) - i.setDate(aInfo.name, new Date(dateVal)) - } - case _ => throw new UnsupportedOperationException(s"load for ${aInfo.dataType()} not supported") - } - } - - - private def loadArrayAttribute[T](dataType: IDataType[_], aInfo: AttributeInfo, - i: ITypedInstance, v: AtlasVertex[_,_]): Unit = { - import scala.collection.JavaConversions._ - val list: java.util.List[_] = v.getListProperty(aInfo.name) - val arrayType: DataTypes.ArrayType = aInfo.dataType.asInstanceOf[ArrayType] - - var values = new util.ArrayList[Any] - list.foreach( listElement => - values += mapVertexToCollectionEntry(v, aInfo, arrayType.getElemType, i, listElement) - ) - i.set(aInfo.name, values) - } - - private def loadStructAttribute(dataType: IDataType[_], aInfo: AttributeInfo, - i: ITypedInstance, v: AtlasVertex[_,_], edgeLbl: Option[String] = None): Unit = { - val eLabel = edgeLbl match { - case Some(x) => x - case None => edgeLabel(FieldInfo(dataType, aInfo, null)) - } - val edges = v.getEdges(AtlasEdgeDirection.OUT, eLabel) - val sVertex = edges.iterator().next().getInVertex().asInstanceOf[AtlasVertex[_,_]] - if (aInfo.dataType().getTypeCategory == DataTypes.TypeCategory.STRUCT) { - val sType = aInfo.dataType().asInstanceOf[StructType] - val sInstance = sType.createInstance() - loadStructInstance(sType, sInstance, sVertex) - i.set(aInfo.name, sInstance) - } else { - val cInstance = constructClassInstance(aInfo.dataType().asInstanceOf[ClassType], sVertex) - i.set(aInfo.name, cInstance) - } - } - - private def mapVertexToCollectionEntry(instanceVertex: AtlasVertex[_,_], attributeInfo: AttributeInfo, elementType: IDataType[_], i: ITypedInstance, value: Any): Any = { - elementType.getTypeCategory match { - case DataTypes.TypeCategory.PRIMITIVE => value - case DataTypes.TypeCategory.ENUM => value - case DataTypes.TypeCategory.STRUCT => - throw new UnsupportedOperationException(s"load for ${attributeInfo.dataType()} not supported") - case DataTypes.TypeCategory.TRAIT => - throw new UnsupportedOperationException(s"load for ${attributeInfo.dataType()} not supported") - case DataTypes.TypeCategory.CLASS => //loadStructAttribute(elementType, attributeInfo, i, v) - throw new UnsupportedOperationException(s"load for ${attributeInfo.dataType()} not supported") - case _ => - throw new UnsupportedOperationException(s"load for ${attributeInfo.dataType()} not supported") - } - } - -} - http://git-wip-us.apache.org/repos/asf/atlas/blob/0877e47c/repository/src/main/scala/org/apache/atlas/query/GremlinEvaluator.scala ---------------------------------------------------------------------- diff --git a/repository/src/main/scala/org/apache/atlas/query/GremlinEvaluator.scala b/repository/src/main/scala/org/apache/atlas/query/GremlinEvaluator.scala deleted file mode 100755 index 5f8ef8a..0000000 --- a/repository/src/main/scala/org/apache/atlas/query/GremlinEvaluator.scala +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.atlas.query - - -import org.apache.atlas.query.Expressions._ -import org.apache.atlas.query.TypeUtils.ResultWithPathStruct -import org.apache.atlas.repository.graphdb.AtlasGraph -import org.apache.atlas.typesystem.json._ -import org.apache.atlas.typesystem.types.DataTypes.TypeCategory -import org.apache.atlas.typesystem.types._ -import org.json4s._ -import org.json4s.native.Serialization._ - -import scala.language.existentials - -case class GremlinQueryResult(query: String, - resultDataType: IDataType[_], - rows: java.util.List[_]) { - def toJson = JsonHelper.toJson(this) -} - -class GremlinEvaluator(qry: GremlinQuery, persistenceStrategy: GraphPersistenceStrategies, g: AtlasGraph[_,_]) { - - /** - * - * @param gResultObj is the object returned from gremlin. This must be a List - * @param qryResultObj is the object constructed for the output w/o the Path. - * @return a ResultWithPathStruct - */ - def addPathStruct(gResultObj: AnyRef, qryResultObj: Any): Any = { - if (!qry.isPathExpression) { - qryResultObj - } else { - import scala.collection.JavaConversions._ - import scala.collection.JavaConverters._ - - val iPaths = gResultObj.asInstanceOf[java.util.List[AnyRef]].init - - val oPaths = iPaths.map { value => - persistenceStrategy.constructInstance(TypeSystem.getInstance().getIdType.getStructType, value) - }.toList.asJava - val sType = qry.expr.dataType.asInstanceOf[StructType] - val sInstance = sType.createInstance() - sInstance.set(ResultWithPathStruct.pathAttrName, oPaths) - sInstance.set(ResultWithPathStruct.resultAttrName, qryResultObj) - sInstance - } - } - - def instanceObject(v: AnyRef): AnyRef = { - if (qry.isPathExpression) { - import scala.collection.JavaConversions._ - v.asInstanceOf[java.util.List[AnyRef]].last - } else { - v - } - } - - def evaluate(): GremlinQueryResult = { - import scala.collection.JavaConversions._ - val debug:Boolean = false - val rType = qry.expr.dataType - val oType = if (qry.isPathExpression) { - qry.expr.children(0).dataType - } - else { - rType - } - val rawRes = g.executeGremlinScript(qry.queryStr, qry.isPathExpression); - if(debug) { - println(" rawRes " +rawRes) - } - if (!qry.hasSelectList && ! qry.isGroupBy) { - val rows = rawRes.asInstanceOf[java.util.List[AnyRef]].map { v => - val instObj = instanceObject(v) - val o = persistenceStrategy.constructInstance(oType, instObj) - addPathStruct(v, o) - } - GremlinQueryResult(qry.expr.toString, rType, rows.toList) - } else { - val sType = oType.asInstanceOf[StructType] - val rows = rawRes.asInstanceOf[java.util.List[AnyRef]].map { r => - val rV = instanceObject(r) - val sInstance = sType.createInstance() - val selObj = SelectExpressionHelper.extractSelectExpression(qry.expr) - if (selObj.isDefined) { - val selExpr = selObj.get.asInstanceOf[Expressions.SelectExpression] - selExpr.selectListWithAlias.foreach { aE => - val cName = aE.alias - val (src, idx) = qry.resultMaping(cName) - val v = getColumnValue(rV, src, idx) - //if select clause is selecting the entire object then return only the instance id (guid, version, state and typeName) - if (aE.dataType.getTypeCategory == TypeCategory.CLASS) { - sInstance.set(cName, persistenceStrategy.constructClassInstanceId(aE.dataType.asInstanceOf[ClassType], v)) - } else { - sInstance.set(cName, persistenceStrategy.constructInstance(aE.dataType, v)) - } - } - } - else if(qry.isGroupBy) { - //the order in the result will always match the order in the select list - val selExpr = qry.expr.asInstanceOf[GroupByExpression].selExpr - var idx = 0; - val row : java.util.List[Object] = rV.asInstanceOf[java.util.List[Object]] - selExpr.selectListWithAlias.foreach { aE => - val cName = aE.alias - val cValue = row.get(idx); - - sInstance.set(cName, persistenceStrategy.constructInstance(aE.dataType, cValue)) - idx += 1; - } - } - addPathStruct(r, sInstance) - } - GremlinQueryResult(qry.expr.toString, rType, rows.toList) - } - - } - - private def getColumnValue(rowValue: AnyRef, colName: String, idx: Integer) : AnyRef = { - - var rawColumnValue: AnyRef = null; - if(rowValue.isInstanceOf[java.util.Map[_,_]]) { - val columnsMap = rowValue.asInstanceOf[java.util.Map[String,AnyRef]]; - rawColumnValue = columnsMap.get(colName); - } - else { - //when there is only one column, result does not come back as a map - rawColumnValue = rowValue; - } - - var value : AnyRef = null; - if(rawColumnValue.isInstanceOf[java.util.List[_]] && idx >= 0) { - val arr = rawColumnValue.asInstanceOf[java.util.List[AnyRef]]; - value = arr.get(idx); - } - else { - value = rawColumnValue; - } - - return value; - } -} - -object JsonHelper { - - class GremlinQueryResultSerializer() - extends Serializer[GremlinQueryResult] { - def deserialize(implicit format: Formats) = { - throw new UnsupportedOperationException("Deserialization of GremlinQueryResult not supported") - } - - def serialize(implicit f: Formats) = { - case GremlinQueryResult(query, rT, rows) => - JObject(JField("query", JString(query)), - JField("dataType", TypesSerialization.toJsonValue(rT)(f)), - JField("rows", Extraction.decompose(rows)(f)) - ) - } - } - - implicit val formats = org.json4s.native.Serialization.formats(NoTypeHints) + new TypedStructSerializer + - new TypedReferenceableInstanceSerializer + new BigDecimalSerializer + new BigIntegerSerializer + - new GremlinQueryResultSerializer - - def toJson(r: GremlinQueryResult): String = { - writePretty(r) - } -}