You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ma...@apache.org on 2017/11/12 18:14:35 UTC
[26/42] atlas git commit: ATLAS-2251: Remove TypeSystem and related
implementation, to avoid unncessary duplicate of type details in cache
http://git-wip-us.apache.org/repos/asf/atlas/blob/435fe3fb/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/435fe3fb/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/435fe3fb/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)
- }
-}