You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by fe...@apache.org on 2016/01/24 19:04:59 UTC
[5/6] incubator-zeppelin git commit: [ZEPPELIN-559] Cassandra
interpreter v2
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/11a45e2e/cassandra/src/main/scala/org/apache/zeppelin/cassandra/DisplaySystem.scala
----------------------------------------------------------------------
diff --git a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/DisplaySystem.scala b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/DisplaySystem.scala
index 2881b4b..135d4cd 100644
--- a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/DisplaySystem.scala
+++ b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/DisplaySystem.scala
@@ -18,7 +18,6 @@ package org.apache.zeppelin.cassandra
import java.util.UUID
-import com.datastax.driver.core.ColumnMetadata.IndexMetadata
import com.datastax.driver.core.utils.UUIDs
import org.apache.zeppelin.cassandra.MetaDataHierarchy._
import org.fusesource.scalate.TemplateEngine
@@ -39,16 +38,30 @@ object DisplaySystem {
val CLUSTER_DETAILS_TEMPLATE = "scalate/clusterDetails.ssp"
val KEYSPACE_DETAILS_TEMPLATE = "scalate/keyspaceDetails.ssp"
+
val TABLE_DETAILS_TEMPLATE = "scalate/tableDetails.ssp"
+ val ALL_TABLES_TEMPLATE = "scalate/allTables.ssp"
+
val UDT_DETAILS_TEMPLATE = "scalate/udtDetails.ssp"
+ val ALL_UDTS_TEMPLATE = "scalate/allUDTs.ssp"
+
+ val FUNCTION_DETAILS_TEMPLATE = "scalate/functionDetails.ssp"
+ val ALL_FUNCTIONS_TEMPLATE = "scalate/allFunctions.ssp"
+
+ val AGGREGATE_DETAILS_TEMPLATE = "scalate/aggregateDetails.ssp"
+ val ALL_AGGREGATES_TEMPLATE = "scalate/allAggregates.ssp"
+
+ val MATERIALIZED_VIEW_DETAILS_TEMPLATE = "scalate/materializedViewDetails.ssp"
+ val ALL_MATERIALIZED_VIEWS_TEMPLATE = "scalate/allMaterializedViews.ssp"
val MENU_TEMPLATE = "scalate/menu.ssp"
val CLUSTER_DROPDOWN_TEMPLATE = "scalate/dropDownMenuForCluster.ssp"
- val KEYSPACE_DROPDOWN_TEMPLATE = "scalate/dropDownMenuForKeyspace.ssp"
+ val KEYSPACE_DROPDOWN_TEMPLATE = "scalate/dropDownMenuForKeyspace.ssp"
val CLUSTER_CONTENT_TEMPLATE = "scalate/clusterContent.ssp"
val KEYSPACE_CONTENT_TEMPLATE = "scalate/keyspaceContent.ssp"
- val ALL_TABLES_TEMPLATE = "scalate/allTables.ssp"
+
+
object TableDisplay {
@@ -58,10 +71,12 @@ object DisplaySystem {
protected[DisplaySystem] def formatWithoutMenu(meta: TableMetadata, withCaption: Boolean): String = {
val tableName: String = meta.getName
- val columnsDetails = MetaDataConverter.tableMetaToColumnDetails(meta)
+ val columnsDetails = MetaDataConverter.Table.tableMetaToColumnDetails(meta)
+ val indicesDetails = MetaDataConverter.Table.tableMetaToIndexDetails(meta)
+ val indicesAsCQL = indicesDetails.map(_.asCQL).mkString("\n")
engine.layout(TABLE_DETAILS_TEMPLATE,
- Map[String, Any]("tableDetails" -> TableDetails(tableName, columnsDetails, meta.exportAsString), "withCaption" -> withCaption))
+ Map[String, Any]("tableDetails" -> TableDetails(tableName, columnsDetails, indicesDetails, TableMetadataWrapper(meta).exportTableOnlyAsString(), indicesAsCQL), "withCaption" -> withCaption))
}
}
@@ -72,13 +87,49 @@ object DisplaySystem {
protected[DisplaySystem] def formatWithoutMenu(userType: UserType, withCaption: Boolean): String = {
val udtName: String = userType.getTypeName
- val columnsDetails = MetaDataConverter.userTypeToColumnDetails(userType)
+ val columnsDetails = MetaDataConverter.UDT.userTypeToColumnDetails(userType)
engine.layout(UDT_DETAILS_TEMPLATE,
- Map[String, Any]("udtDetails" -> UDTDetails(udtName, columnsDetails, userType.exportAsString), "withCaption" -> withCaption))
+ Map[String, Any]("udtDetails" -> UDTDetails(udtName,columnsDetails,userType.exportAsString()), "withCaption" -> withCaption))
+ }
+ }
+
+ object FunctionDisplay {
+ def format(statement: String, functions: List[FunctionMetadata], withCaption: Boolean): String = {
+ MenuDisplay.formatMenu(statement) ++ formatWithoutMenu(functions, withCaption)
+ }
+
+ protected[DisplaySystem] def formatWithoutMenu(functions: List[FunctionMetadata], withCaption: Boolean): String = {
+ val functionDetails: List[FunctionDetails] = functions.map(MetaDataConverter.functionMetaToFunctionDetails(_))
+ engine.layout(FUNCTION_DETAILS_TEMPLATE,
+ Map[String, Any]("sameNameFunctionDetails" -> SameNameFunctionDetails(functionDetails), "withCaption" -> withCaption))
}
}
-
+
+ object AggregateDisplay {
+ def format(statement: String, aggregates: List[AggregateMetadata], withCaption: Boolean, codecRegistry: CodecRegistry): String = {
+ MenuDisplay.formatMenu(statement) ++ formatWithoutMenu(aggregates, withCaption, codecRegistry)
+ }
+
+ protected[DisplaySystem] def formatWithoutMenu(aggregates: List[AggregateMetadata], withCaption: Boolean, codecRegistry: CodecRegistry): String = {
+ val aggDetails: List[AggregateDetails] = aggregates.map(agg => MetaDataConverter.aggregateMetaToAggregateDetails(codecRegistry, agg))
+ engine.layout(AGGREGATE_DETAILS_TEMPLATE,
+ Map[String, Any]("sameNameAggregateDetails" -> SameNameAggregateDetails(aggDetails), "withCaption" -> withCaption))
+ }
+ }
+
+ object MaterializedViewDisplay {
+ def format(statement: String, mv: MaterializedViewMetadata, withCaption: Boolean): String = {
+ MenuDisplay.formatMenu(statement) ++ formatWithoutMenu(mv, withCaption)
+ }
+
+ protected[DisplaySystem] def formatWithoutMenu(mv: MaterializedViewMetadata, withCaption: Boolean): String = {
+ val mvDetails = MetaDataConverter.mvMetaToMaterializedViewDetails(mv)
+ engine.layout(MATERIALIZED_VIEW_DETAILS_TEMPLATE,
+ Map[String, Any]("mvDetails" -> mvDetails, "withCaption" -> withCaption))
+ }
+ }
+
object KeyspaceDisplay {
private def formatCQLQuery(cql: String): String = {
@@ -97,19 +148,32 @@ object DisplaySystem {
Map[String, Any]("ksDetails" -> ksDetails, "withCaption" -> withCaption))
}
- def formatKeyspaceContent(statement: String, meta: KeyspaceMetadata): String = {
+ def formatKeyspaceContent(statement: String, meta: KeyspaceMetadata, codecRegistry: CodecRegistry): String = {
val ksName: String = meta.getName
- val ksDetails = formatKeyspaceOnly(meta, false)
+ val ksDetails = formatKeyspaceOnly(meta, true)
val tableDetails: List[(UUID, String, String)] = meta.getTables.asScala.toList
- .sortBy(meta => meta.getName)
- .map(meta => (UUIDs.timeBased(), meta.getName, TableDisplay.formatWithoutMenu(meta, false)))
+ .sortBy(_.getName)
+ .map(table => (UUIDs.timeBased(), table.getName, TableDisplay.formatWithoutMenu(table, false)))
+
+ val viewDetails: List[(UUID, String, String)] = meta.getMaterializedViews.asScala.toList
+ .sortBy(_.getName)
+ .map(view => (UUIDs.timeBased(), view.getName, MaterializedViewDisplay.formatWithoutMenu(view, false)))
val udtDetails: List[(UUID, String, String)] = meta.getUserTypes.asScala.toList
- .sortBy(udt => udt.getTypeName)
+ .sortBy(_.getTypeName)
.map(udt => (UUIDs.timeBased(), udt.getTypeName, UDTDisplay.formatWithoutMenu(udt, false)))
- val ksContent: KeyspaceContent = KeyspaceContent(ksName, ksDetails, tableDetails, udtDetails)
+ val functionDetails: List[(UUID, String, String)] = meta.getFunctions.asScala.toList
+ .sortBy(_.getSimpleName)
+ .map(function => (UUIDs.timeBased(), function.getSimpleName, FunctionDisplay.formatWithoutMenu(List(function), false)))
+
+ val aggregateDetails: List[(UUID, String, String)] = meta.getAggregates.asScala.toList
+ .sortBy(_.getSimpleName)
+ .map(agg => (UUIDs.timeBased(), agg.getSimpleName, AggregateDisplay.formatWithoutMenu(List(agg), false, codecRegistry)))
+
+ val ksContent: KeyspaceContent = KeyspaceContent(ksName, ksDetails, tableDetails, viewDetails,
+ udtDetails, functionDetails, aggregateDetails)
MenuDisplay.formatMenuForKeyspace(statement, ksContent) +
engine.layout(KEYSPACE_CONTENT_TEMPLATE,
@@ -144,26 +208,152 @@ object DisplaySystem {
def formatAllTables(statement: String, meta: Metadata): String = {
val ksMetas: List[KeyspaceMetadata] = meta.getKeyspaces.asScala.toList
+ .filter(_.getTables.size > 0)
.sortBy(ks => ks.getName)
+ if(ksMetas.isEmpty) {
+ NoResultDisplay.formatNoResult
+ } else {
+ val allTables: Map[(UUID, String), List[String]] = ListMap.empty ++
+ ksMetas
+ .map(ks => {
+ ((UUIDs.timeBased(), ks.getName),
+ ks.getTables.asScala.toList.map(table => table.getName).sortBy(name => name))
+ })
+ .sortBy{case ((id,name), _) => name}
+
+
+ val keyspaceDetails: List[(UUID, String, String)] = allTables
+ .keySet.toList.sortBy{case(id,ksName) => ksName}
+ .map{case(id,ksName) => (id,ksName, "")}
+
+ val clusterContent: ClusterContent = ClusterContent(meta.getClusterName, "", keyspaceDetails)
+
+ MenuDisplay.formatMenuForCluster(statement, clusterContent) +
+ engine.layout(ALL_TABLES_TEMPLATE,
+ Map[String, Any]("allTables" -> allTables))
+ }
+ }
- val allTables: Map[(UUID, String), List[String]] = ListMap.empty ++
- ksMetas
- .map(ks => {
- ((UUIDs.timeBased(), ks.getName),
- ks.getTables.asScala.toList.map(table => table.getName).sortBy(name => name))
- })
- .sortBy{case ((id,name), _) => name}
+ def formatAllUDTs(statement: String, meta: Metadata): String = {
+ val ksMetas: List[KeyspaceMetadata] = meta.getKeyspaces.asScala.toList
+ .filter(_.getUserTypes.size > 0)
+ .sortBy(ks => ks.getName)
+ if(ksMetas.isEmpty) {
+ NoResultDisplay.formatNoResult
+ } else {
+ val allUDTs: Map[(UUID, String), List[String]] = ListMap.empty ++
+ ksMetas
+ .map(ks => {
+ ((UUIDs.timeBased(), ks.getName),
+ ks.getUserTypes.asScala.toList.map(udt => udt.getTypeName).sortBy(name => name))
+ })
+ .sortBy { case ((id, name), _) => name }
- val keyspaceDetails: List[(UUID, String, String)] = allTables
- .keySet.toList.sortBy{case(id,ksName) => ksName}
- .map{case(id,ksName) => (id,ksName, "")}
- val clusterContent: ClusterContent = ClusterContent(meta.getClusterName, "", keyspaceDetails)
+ val keyspaceDetails: List[(UUID, String, String)] = allUDTs
+ .keySet.toList.sortBy { case (id, ksName) => ksName }
+ .map { case (id, ksName) => (id, ksName, "") }
- MenuDisplay.formatMenuForCluster(statement, clusterContent) +
- engine.layout(ALL_TABLES_TEMPLATE,
- Map[String, Any]("allTables" -> allTables))
+ val clusterContent: ClusterContent = ClusterContent(meta.getClusterName, "", keyspaceDetails)
+
+ MenuDisplay.formatMenuForCluster(statement, clusterContent) +
+ engine.layout(ALL_UDTS_TEMPLATE,
+ Map[String, Any]("allUDTs" -> allUDTs))
+ }
+ }
+
+ def formatAllFunctions(statement: String, meta: Metadata): String = {
+ val ksMetas: List[KeyspaceMetadata] = meta.getKeyspaces.asScala.toList
+ .filter(_.getFunctions.size > 0)
+ .sortBy(ks => ks.getName)
+
+ if(ksMetas.isEmpty) {
+ NoResultDisplay.formatNoResult
+ } else {
+ val allFunctions: Map[(UUID, String), List[FunctionSummary]] = ListMap.empty ++
+ ksMetas
+ .map(ks => {
+ ((UUIDs.timeBased(), ks.getName),
+ ks.getFunctions.asScala.toList
+ .map(MetaDataConverter.functionMetaToFunctionSummary(_))
+ .sortBy(_.name))
+ })
+ .sortBy { case ((id, name), _) => name }
+
+ val keyspaceDetails: List[(UUID, String, String)] = allFunctions
+ .keySet.toList.sortBy { case (id, ksName) => ksName }
+ .map { case (id, ksName) => (id, ksName, "") }
+
+
+ val clusterContent: ClusterContent = ClusterContent(meta.getClusterName, "", keyspaceDetails)
+
+ MenuDisplay.formatMenuForCluster(statement, clusterContent) +
+ engine.layout(ALL_FUNCTIONS_TEMPLATE,
+ Map[String, Any]("allFunctions" -> allFunctions))
+ }
+ }
+
+ def formatAllAggregates(statement: String, meta: Metadata): String = {
+ val ksMetas: List[KeyspaceMetadata] = meta.getKeyspaces.asScala.toList
+ .filter(_.getAggregates.size > 0)
+ .sortBy(ks => ks.getName)
+
+ if(ksMetas.isEmpty) {
+ NoResultDisplay.formatNoResult
+ } else {
+ val allAggregates: Map[(UUID, String), List[AggregateSummary]] = ListMap.empty ++
+ ksMetas
+ .map(ks => {
+ ((UUIDs.timeBased(), ks.getName),
+ ks.getAggregates.asScala.toList
+ .map(MetaDataConverter.aggregateMetaToAggregateSummary(_))
+ .sortBy(_.name))
+ })
+ .sortBy { case ((id, name), _) => name }
+
+ val keyspaceDetails: List[(UUID, String, String)] = allAggregates
+ .keySet.toList.sortBy { case (id, ksName) => ksName }
+ .map { case (id, ksName) => (id, ksName, "") }
+
+
+ val clusterContent: ClusterContent = ClusterContent(meta.getClusterName, "", keyspaceDetails)
+
+ MenuDisplay.formatMenuForCluster(statement, clusterContent) +
+ engine.layout(ALL_AGGREGATES_TEMPLATE,
+ Map[String, Any]("allAggregates" -> allAggregates))
+ }
+ }
+
+ def formatAllMaterializedViews(statement: String, meta: Metadata): String = {
+ val ksMetas: List[KeyspaceMetadata] = meta.getKeyspaces.asScala.toList
+ .filter(_.getMaterializedViews.size > 0)
+ .sortBy(ks => ks.getName)
+
+ if(ksMetas.isEmpty) {
+ NoResultDisplay.formatNoResult
+ } else {
+ val allMVs: Map[(UUID, String), List[MaterializedViewSummary]] = ListMap.empty ++
+ ksMetas
+ .map(ks => {
+ ((UUIDs.timeBased(), ks.getName),
+ ks.getMaterializedViews.asScala.toList
+ .map(MetaDataConverter.mvMetaToMaterializedViewSummary(_))
+ .sortBy(_.name))
+ })
+ .sortBy { case ((id, name), _) => name }
+
+ val keyspaceDetails: List[(UUID, String, String)] = allMVs
+ .keySet.toList.sortBy { case (id, ksName) => ksName }
+ .map { case (id, ksName) => (id, ksName, "") }
+
+
+ val clusterContent: ClusterContent = ClusterContent(meta.getClusterName, "", keyspaceDetails)
+
+ MenuDisplay.formatMenuForCluster(statement, clusterContent) +
+ engine.layout(ALL_MATERIALIZED_VIEWS_TEMPLATE,
+ Map[String, Any]("allMVs" -> allMVs))
+ }
}
}
@@ -233,63 +423,150 @@ class ColumnMetaWrapper(val columnMeta: ColumnMetadata) {
*/
object MetaDataConverter {
- def tableMetaToColumnDetails(meta: TableMetadata): List[ColumnDetails] = {
- val partitionKeys: List[ColumnMetaWrapper] = meta.getPartitionKey.asScala.toList.map(new ColumnMetaWrapper(_))
- val clusteringColumns: List[ColumnMetaWrapper] = meta.getClusteringColumns.asScala.toList.map(new ColumnMetaWrapper(_))
- val columns: List[ColumnMetaWrapper] = meta.getColumns.asScala.toList.map(new ColumnMetaWrapper(_))
- .diff(partitionKeys).diff(clusteringColumns)
- val clusteringOrders = meta.getClusteringOrder.asScala.toList
-
- convertPartitionKeys(partitionKeys):::
- extractStaticColumns(columns):::
- convertClusteringColumns(clusteringColumns, clusteringOrders):::
- extractNormalColumns(columns)
- }
-
- def userTypeToColumnDetails(userType: UserType): List[ColumnDetails] = {
- userType.getFieldNames.asScala.toList
- .map(name => new ColumnDetails(name, NormalColumn, userType.getFieldType(name), None))
+ type DriverClusteringOrder = com.datastax.driver.core.ClusteringOrder
+
+ def functionMetaToFunctionDetails(function: FunctionMetadata): FunctionDetails = {
+ new FunctionDetails(function.getKeyspace.getName,
+ function.getSimpleName,
+ function.getArguments.asScala
+ .toMap
+ .map{case(paramName, dataType) => paramName + " " + dataType.asFunctionParameterString()}
+ .toList,
+ function.isCalledOnNullInput,
+ function.getReturnType.asFunctionParameterString(),
+ function.getLanguage,
+ function.getBody,
+ function.exportAsString())
}
- private def extractNormalColumns(columns: List[ColumnMetaWrapper]): List[ColumnDetails] = {
- columns
- .filter(_.columnMeta.isStatic == false)
- .map(c => new ColumnDetails(c.columnMeta.getName, NormalColumn, c.columnMeta.getType, extractIndexDetail(c)))
+ def functionMetaToFunctionSummary(function: FunctionMetadata): FunctionSummary = {
+ new FunctionSummary(function.getKeyspace.getName,
+ function.getSimpleName,
+ function.getArguments.asScala.toMap
+ .mapValues(dataType => dataType.asFunctionParameterString())
+ .values.toList,
+ function.getReturnType.asFunctionParameterString()
+ )
}
- private def extractIndexDetail(column: ColumnMetaWrapper): Option[IndexDetails] = {
- val indexOption = Option(column.columnMeta.getIndex)
+ def aggregateMetaToAggregateDetails(codecRegistry: CodecRegistry, aggregate: AggregateMetadata): AggregateDetails = {
+ val sFunc: FunctionSummary = functionMetaToFunctionSummary(aggregate.getStateFunc)
+ val finalFunc: Option[String] = Option(aggregate.getFinalFunc).map(func => {
+ val finalFunction = functionMetaToFunctionSummary(func)
+ finalFunction.name + finalFunction.arguments.mkString("(", ", ", ")")
+ })
+ val sType = aggregate.getStateType
+ val initCond: Option[String] = Option(aggregate.getInitCond).map(codecRegistry.codecFor(sType).format(_))
+ val returnType: String = Option(aggregate.getFinalFunc) match {
+ case Some(finalFunc) => functionMetaToFunctionSummary(finalFunc).returnType
+ case None => sFunc.returnType
+ }
+
+ new AggregateDetails(aggregate.getKeyspace.getName,
+ aggregate.getSimpleName,
+ aggregate.getArgumentTypes.asScala.toList.map(_.asFunctionParameterString()),
+ sFunc.name + sFunc.arguments.mkString("(",", ", ")"),
+ sType.asFunctionParameterString(),
+ finalFunc,
+ initCond,
+ returnType,
+ aggregate.exportAsString())
+ }
- def buildIndexInfo(indexMeta: IndexMetadata): String = {
- if(indexMeta.isKeys) "KEYS"
- if(indexMeta.isEntries) "ENTRIES"
- if(indexMeta.isFull) "FULL"
- if(indexMeta.isCustomIndex) s"Class = ${indexMeta.getIndexClassName}"
- else ""
+ def aggregateMetaToAggregateSummary(aggregate: AggregateMetadata): AggregateSummary = {
+ val returnType: String = Option(aggregate.getFinalFunc) match {
+ case Some(finalFunc) => functionMetaToFunctionSummary(finalFunc).returnType
+ case None => aggregate.getStateType.asFunctionParameterString()
}
- indexOption.map(index => IndexDetails(index.getName, buildIndexInfo(index)))
+ new AggregateSummary(aggregate.getKeyspace.getName,
+ aggregate.getSimpleName,
+ aggregate.getArgumentTypes.asScala.toList.map(_.asFunctionParameterString()),
+ returnType
+ )
+ }
+
+ def mvMetaToMaterializedViewDetails(mv: MaterializedViewMetadata): MaterializedViewDetails = {
+ new MaterializedViewDetails(mv.getName, MV.mvMetaToColumnDetails(mv), mv.exportAsString(), mv.getBaseTable.getName)
+ }
+
+ def mvMetaToMaterializedViewSummary(mv: MaterializedViewMetadata): MaterializedViewSummary = {
+ new MaterializedViewSummary(mv.getName, mv.getBaseTable.getName)
}
- private def extractStaticColumns(columns: List[ColumnMetaWrapper]): List[ColumnDetails] = {
- columns
- .filter(_.columnMeta.isStatic == true)
- .map(c => new ColumnDetails(c.columnMeta.getName, StaticColumn, c.columnMeta.getType, extractIndexDetail(c)))
+ trait TableOrView {
+ protected def extractNormalColumns(columns: List[ColumnMetaWrapper]): List[ColumnDetails] = {
+ columns
+ .filter(_.columnMeta.isStatic == false)
+ .map(c => new ColumnDetails(c.columnMeta.getName, NormalColumn, c.columnMeta.getType))
+ }
+
+ protected def extractStaticColumns(columns: List[ColumnMetaWrapper]): List[ColumnDetails] = {
+ columns
+ .filter(_.columnMeta.isStatic == true)
+ .map(c => new ColumnDetails(c.columnMeta.getName, StaticColumn, c.columnMeta.getType))
+ }
+
+ protected def convertClusteringColumns(columns: List[ColumnMetaWrapper], orders: List[DriverClusteringOrder]): List[ColumnDetails] = {
+ columns
+ .zip(orders)
+ .map{case(c,order) => new ColumnDetails(c.columnMeta.getName,
+ new ClusteringColumn(OrderConverter.convert(order)),c.columnMeta.getType)}
+
+ }
+
+ protected def convertPartitionKeys(columns: List[ColumnMetaWrapper]): List[ColumnDetails] = {
+ columns
+ .map(c => new ColumnDetails(c.columnMeta.getName, PartitionKey, c.columnMeta.getType))
+ }
}
- private def convertClusteringColumns(columns: List[ColumnMetaWrapper], orders: List[TableMetadata.Order]): List[ColumnDetails] = {
- columns
- .zip(orders)
- .map{case(c,order) => new ColumnDetails(c.columnMeta.getName,
- new ClusteringColumn(OrderConverter.convert(order)),
- c.columnMeta.getType, extractIndexDetail(c))}
+ object Table extends TableOrView {
+ def tableMetaToColumnDetails(meta: TableMetadata): List[ColumnDetails] = {
+ val partitionKeys: List[ColumnMetaWrapper] = meta.getPartitionKey.asScala.toList.map(new ColumnMetaWrapper(_))
+ val clusteringColumns: List[ColumnMetaWrapper] = meta.getClusteringColumns.asScala.toList.map(new ColumnMetaWrapper(_))
+ val columns: List[ColumnMetaWrapper] = meta.getColumns.asScala.toList.map(new ColumnMetaWrapper(_))
+ .diff(partitionKeys).diff(clusteringColumns)
+ val clusteringOrders = meta.getClusteringOrder.asScala.toList
+
+ convertPartitionKeys(partitionKeys):::
+ extractStaticColumns(columns):::
+ convertClusteringColumns(clusteringColumns, clusteringOrders):::
+ extractNormalColumns(columns)
+ }
+
+ def tableMetaToIndexDetails(meta: TableMetadata): List[IndexDetails] = {
+ meta.getIndexes.asScala.toList
+ .map(index => IndexDetails(index.getName, index.getTarget, index.asCQLQuery()))
+ .sortBy(index => index.name)
+ }
+
}
- private def convertPartitionKeys(columns: List[ColumnMetaWrapper]): List[ColumnDetails] = {
- columns
- .map(c => new ColumnDetails(c.columnMeta.getName, PartitionKey, c.columnMeta.getType, extractIndexDetail(c)))
+ object MV extends TableOrView {
+ def mvMetaToColumnDetails(meta: MaterializedViewMetadata): List[ColumnDetails] = {
+ val partitionKeys: List[ColumnMetaWrapper] = meta.getPartitionKey.asScala.toList.map(new ColumnMetaWrapper(_))
+ val clusteringColumns: List[ColumnMetaWrapper] = meta.getClusteringColumns.asScala.toList.map(new ColumnMetaWrapper(_))
+ val columns: List[ColumnMetaWrapper] = meta.getColumns.asScala.toList.map(new ColumnMetaWrapper(_))
+ .diff(partitionKeys).diff(clusteringColumns)
+ val clusteringOrders = meta.getClusteringOrder.asScala.toList
+
+ convertPartitionKeys(partitionKeys):::
+ convertClusteringColumns(clusteringColumns, clusteringOrders):::
+ extractNormalColumns(columns)
+ }
}
+
+ object UDT {
+ def userTypeToColumnDetails(userType: UserType): List[ColumnDetails] = {
+ userType.getFieldNames.asScala.toList
+ .map(name => new ColumnDetails(name, NormalColumn, userType.getFieldType(name)))
+ }
+ }
+
+
+
}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/11a45e2e/cassandra/src/main/scala/org/apache/zeppelin/cassandra/EnhancedSession.scala
----------------------------------------------------------------------
diff --git a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/EnhancedSession.scala b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/EnhancedSession.scala
index c636de9..a0c475a 100644
--- a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/EnhancedSession.scala
+++ b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/EnhancedSession.scala
@@ -20,6 +20,7 @@ import com.datastax.driver.core._
import org.apache.zeppelin.cassandra.TextBlockHierarchy._
import org.apache.zeppelin.interpreter.InterpreterException
+import scala.collection.JavaConverters._
/**
* Enhance the Java driver session
@@ -32,6 +33,9 @@ class EnhancedSession(val session: Session) {
val keyspaceDisplay = DisplaySystem.KeyspaceDisplay
val tableDisplay = DisplaySystem.TableDisplay
val udtDisplay = DisplaySystem.UDTDisplay
+ val functionDisplay = DisplaySystem.FunctionDisplay
+ val aggregateDisplay = DisplaySystem.AggregateDisplay
+ val materializedViewDisplay = DisplaySystem.MaterializedViewDisplay
val helpDisplay = DisplaySystem.HelpDisplay
private val noResultDisplay = DisplaySystem.NoResultDisplay
@@ -61,8 +65,12 @@ class EnhancedSession(val session: Session) {
private def execute(describeKeyspace: DescribeKeyspaceCmd): String = {
val keyspace: String = describeKeyspace.keyspace
- val metadata: KeyspaceMetadata = session.getCluster.getMetadata.getKeyspace(keyspace)
- HTML_MAGIC + keyspaceDisplay.formatKeyspaceContent(describeKeyspace.statement, metadata)
+ val metadata: Option[KeyspaceMetadata] = Option(session.getCluster.getMetadata.getKeyspace(keyspace))
+ metadata match {
+ case Some(ksMeta) => HTML_MAGIC + keyspaceDisplay.formatKeyspaceContent(describeKeyspace.statement, ksMeta,
+ session.getCluster.getConfiguration.getCodecRegistry)
+ case None => throw new InterpreterException(s"Cannot find keyspace $keyspace")
+ }
}
private def execute(describeTable: DescribeTableCmd): String = {
@@ -76,7 +84,7 @@ class EnhancedSession(val session: Session) {
}
}
- private def execute(describeUDT: DescribeUDTCmd): String = {
+ private def execute(describeUDT: DescribeTypeCmd): String = {
val metaData = session.getCluster.getMetadata
val keyspace: String = describeUDT.keyspace.orElse(Option(session.getLoggedKeyspace)).getOrElse("system")
val udtName: String = describeUDT.udtName
@@ -87,6 +95,87 @@ class EnhancedSession(val session: Session) {
}
}
+ private def execute(describeUDTs: DescribeTypesCmd): String = {
+ val metadata: Metadata = session.getCluster.getMetadata
+ HTML_MAGIC + clusterDisplay.formatAllUDTs(describeUDTs.statement, metadata)
+ }
+
+ private def execute(describeFunction: DescribeFunctionCmd): String = {
+ val metaData = session.getCluster.getMetadata
+ val keyspaceName: String = describeFunction.keyspace.orElse(Option(session.getLoggedKeyspace)).getOrElse("system")
+ val functionName: String = describeFunction.function;
+
+ Option(metaData.getKeyspace(keyspaceName)) match {
+ case Some(keyspace) => {
+ val functionMetas: List[FunctionMetadata] = keyspace.getFunctions.asScala.toList
+ .filter(func => func.getSimpleName.toLowerCase == functionName.toLowerCase)
+
+ if(functionMetas.isEmpty) {
+ throw new InterpreterException(s"Cannot find function ${keyspaceName}.$functionName")
+ } else {
+ HTML_MAGIC + functionDisplay.format(describeFunction.statement, functionMetas, true)
+ }
+ }
+ case None => throw new InterpreterException(s"Cannot find function ${keyspaceName}.$functionName")
+ }
+ }
+
+ private def execute(describeFunctions: DescribeFunctionsCmd): String = {
+ val metadata: Metadata = session.getCluster.getMetadata
+ HTML_MAGIC + clusterDisplay.formatAllFunctions(describeFunctions.statement, metadata)
+ }
+
+ private def execute(describeAggregate: DescribeAggregateCmd): String = {
+ val metaData = session.getCluster.getMetadata
+ val keyspaceName: String = describeAggregate.keyspace.orElse(Option(session.getLoggedKeyspace)).getOrElse("system")
+ val aggregateName: String = describeAggregate.aggregate;
+
+ Option(metaData.getKeyspace(keyspaceName)) match {
+ case Some(keyspace) => {
+ val aggMetas: List[AggregateMetadata] = keyspace.getAggregates.asScala.toList
+ .filter(agg => agg.getSimpleName.toLowerCase == aggregateName.toLowerCase)
+
+ if(aggMetas.isEmpty) {
+ throw new InterpreterException(s"Cannot find aggregate ${keyspaceName}.$aggregateName")
+ } else {
+ HTML_MAGIC + aggregateDisplay.format(describeAggregate.statement, aggMetas, true,
+ session
+ .getCluster
+ .getConfiguration
+ .getCodecRegistry)
+ }
+ }
+ case None => throw new InterpreterException(s"Cannot find aggregate ${keyspaceName}.$aggregateName")
+ }
+ }
+
+ private def execute(describeAggregates: DescribeAggregatesCmd): String = {
+ val metadata: Metadata = session.getCluster.getMetadata
+ HTML_MAGIC + clusterDisplay.formatAllAggregates(describeAggregates.statement, metadata)
+ }
+
+ private def execute(describeMV: DescribeMaterializedViewCmd): String = {
+ val metaData = session.getCluster.getMetadata
+ val keyspaceName: String = describeMV.keyspace.orElse(Option(session.getLoggedKeyspace)).getOrElse("system")
+ val viewName: String = describeMV.view
+
+ Option(metaData.getKeyspace(keyspaceName)) match {
+ case Some(keyspace) => {
+ val viewMeta: Option[MaterializedViewMetadata] = Option(keyspace.getMaterializedView(viewName))
+ viewMeta match {
+ case Some(vMeta) => HTML_MAGIC + materializedViewDisplay.format(describeMV.statement, vMeta, true)
+ case None => throw new InterpreterException(s"Cannot find materialized view ${keyspaceName}.$viewName")
+ }
+ }
+ case None => throw new InterpreterException(s"Cannot find materialized view ${keyspaceName}.$viewName")
+ }
+ }
+
+ private def execute(describeMVs: DescribeMaterializedViewsCmd): String = {
+ val metadata: Metadata = session.getCluster.getMetadata
+ HTML_MAGIC + clusterDisplay.formatAllMaterializedViews(describeMVs.statement, metadata)
+ }
+
private def execute(helpCmd: HelpCmd): String = {
HTML_MAGIC + helpDisplay.formatHelp()
}
@@ -95,11 +184,18 @@ class EnhancedSession(val session: Session) {
def execute(st: Any): Any = {
st match {
case x:DescribeClusterCmd => execute(x)
- case x:DescribeKeyspacesCmd => execute(x)
- case x:DescribeTablesCmd => execute(x)
case x:DescribeKeyspaceCmd => execute(x)
+ case x:DescribeKeyspacesCmd => execute(x)
case x:DescribeTableCmd => execute(x)
- case x:DescribeUDTCmd => execute(x)
+ case x:DescribeTablesCmd => execute(x)
+ case x:DescribeTypeCmd => execute(x)
+ case x:DescribeTypesCmd => execute(x)
+ case x:DescribeFunctionCmd => execute(x)
+ case x:DescribeFunctionsCmd => execute(x)
+ case x:DescribeAggregateCmd => execute(x)
+ case x:DescribeAggregatesCmd => execute(x)
+ case x:DescribeMaterializedViewCmd => execute(x)
+ case x:DescribeMaterializedViewsCmd => execute(x)
case x:HelpCmd => execute(x)
case x:Statement => session.execute(x)
case _ => throw new InterpreterException(s"Cannot execute statement '$st' of type ${st.getClass}")
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/11a45e2e/cassandra/src/main/scala/org/apache/zeppelin/cassandra/InterpreterLogic.scala
----------------------------------------------------------------------
diff --git a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/InterpreterLogic.scala b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/InterpreterLogic.scala
index 809bce7..707c16a8 100644
--- a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/InterpreterLogic.scala
+++ b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/InterpreterLogic.scala
@@ -100,7 +100,7 @@ class InterpreterLogic(val session: Session) {
logger.info(s"Executing CQL statements : \n\n$stringStatements\n")
try {
- val protocolVersion = session.getCluster.getConfiguration.getProtocolOptions.getProtocolVersionEnum
+ val protocolVersion = session.getCluster.getConfiguration.getProtocolOptions.getProtocolVersion
val queries:List[AnyBlock] = parseInput(stringStatements)
@@ -137,12 +137,12 @@ class InterpreterLogic(val session: Session) {
case x:BatchStm => {
val builtStatements: List[Statement] = x.statements.map {
case st:SimpleStm => generateSimpleStatement(st, queryOptions, context)
- case st:BoundStm => generateBoundStatement(st, queryOptions, context)
+ case st:BoundStm => generateBoundStatement(session, st, queryOptions, context)
case _ => throw new InterpreterException(s"Unknown statement type")
}
generateBatchStatement(x.batchType, queryOptions, builtStatements)
}
- case x:BoundStm => generateBoundStatement(x, queryOptions, context)
+ case x:BoundStm => generateBoundStatement(session, x, queryOptions, context)
case x:DescribeCommandStatement => x
case x:HelpCmd => x
case x => throw new InterpreterException(s"Unknown statement type : ${x}")
@@ -208,7 +208,7 @@ class InterpreterLogic(val session: Session) {
row => {
val data = columnsDefinitions.map {
case (name, dataType) => {
- if (row.isNull(name)) null else dataType.deserialize(row.getBytesUnsafe(name), protocolVersion)
+ if (row.isNull(name)) null else row.getObject(name)
}
}
output.append(data.mkString("\t")).append("\n")
@@ -283,12 +283,12 @@ class InterpreterLogic(val session: Session) {
statement
}
- def generateBoundStatement(st: BoundStm, options: CassandraQueryOptions,context: InterpreterContext): BoundStatement = {
+ def generateBoundStatement(session: Session, st: BoundStm, options: CassandraQueryOptions,context: InterpreterContext): BoundStatement = {
logger.debug(s"Generating bound statement with name : '${st.name}' and bound values : ${st.values}")
preparedStatements.get(st.name) match {
case Some(ps) => {
val boundValues = maybeExtractVariables(st.values, context)
- createBoundStatement(st.name, ps, boundValues)
+ createBoundStatement(session.getCluster.getConfiguration.getCodecRegistry, st.name, ps, boundValues)
}
case None => throw new InterpreterException(s"The statement '${st.name}' can not be bound to values. " +
s"Are you sure you did prepare it with @prepare[${st.name}] ?")
@@ -342,7 +342,7 @@ class InterpreterLogic(val session: Session) {
options.fetchSize.foreach(statement.setFetchSize(_))
}
- private def createBoundStatement(name: String, ps: PreparedStatement, rawBoundValues: String): BoundStatement = {
+ private def createBoundStatement(codecRegistry: CodecRegistry, name: String, ps: PreparedStatement, rawBoundValues: String): BoundStatement = {
val dataTypes = ps.getVariables.toList
.map(cfDef => cfDef.getType)
@@ -357,6 +357,7 @@ class InterpreterLogic(val session: Session) {
if(value.trim == "null") {
null
} else {
+ val codec: TypeCodec[AnyRef] = codecRegistry.codecFor[AnyRef](dataType)
dataType.getName match {
case (ASCII | TEXT | VARCHAR) => value.trim.replaceAll("(?<!')'","")
case (INT | VARINT) => value.trim.toInt
@@ -369,11 +370,11 @@ class InterpreterLogic(val session: Session) {
case INET => InetAddress.getByName(value.trim)
case TIMESTAMP => parseDate(value.trim)
case (UUID | TIMEUUID) => java.util.UUID.fromString(value.trim)
- case LIST => dataType.parse(boundValuesParser.parse(boundValuesParser.list, value).get)
- case SET => dataType.parse(boundValuesParser.parse(boundValuesParser.set, value).get)
- case MAP => dataType.parse(boundValuesParser.parse(boundValuesParser.map, value).get)
- case UDT => dataType.parse(boundValuesParser.parse(boundValuesParser.udt, value).get)
- case TUPLE => dataType.parse(boundValuesParser.parse(boundValuesParser.tuple, value).get)
+ case LIST => codec.parse(boundValuesParser.parse(boundValuesParser.list, value).get)
+ case SET => codec.parse(boundValuesParser.parse(boundValuesParser.set, value).get)
+ case MAP => codec.parse(boundValuesParser.parse(boundValuesParser.map, value).get)
+ case UDT => codec.parse(boundValuesParser.parse(boundValuesParser.udt, value).get)
+ case TUPLE => codec.parse(boundValuesParser.parse(boundValuesParser.tuple, value).get)
case _ => throw new InterpreterException(s"Cannot parse data of type : ${dataType.toString}")
}
}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/11a45e2e/cassandra/src/main/scala/org/apache/zeppelin/cassandra/MetaDataHierarchy.scala
----------------------------------------------------------------------
diff --git a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/MetaDataHierarchy.scala b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/MetaDataHierarchy.scala
index 66a0776..4b88776 100644
--- a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/MetaDataHierarchy.scala
+++ b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/MetaDataHierarchy.scala
@@ -28,10 +28,10 @@ import scala.util.parsing.json.JSONObject
*/
object MetaDataHierarchy {
object OrderConverter {
- def convert(clusteringOrder: TableMetadata.Order): ClusteringOrder = {
+ def convert(clusteringOrder: com.datastax.driver.core.ClusteringOrder): ClusteringOrder = {
clusteringOrder match {
- case TableMetadata.Order.ASC => ASC
- case TableMetadata.Order.DESC => DESC
+ case com.datastax.driver.core.ClusteringOrder.ASC => ASC
+ case com.datastax.driver.core.ClusteringOrder.DESC => DESC
}
}
}
@@ -46,9 +46,8 @@ object MetaDataHierarchy {
case class ClusteringColumn(order: ClusteringOrder) extends ColumnType
object StaticColumn extends ColumnType
object NormalColumn extends ColumnType
- case class IndexDetails(name: String, info: String)
- case class ColumnDetails(name: String, columnType: ColumnType, dataType: DataType, index: Option[IndexDetails])
-
+ case class IndexDetails(name: String, target: String, asCQL: String)
+ case class ColumnDetails(name: String, columnType: ColumnType, dataType: DataType)
case class ClusterDetails(name: String, partitioner: String)
case class ClusterContent(clusterName: String, clusterDetails: String, keyspaces: List[(UUID, String, String)])
@@ -58,10 +57,26 @@ object MetaDataHierarchy {
JSONObject(replication).toString().replaceAll(""""""","'")
}
}
- case class KeyspaceContent(keyspaceName: String, keyspaceDetails: String, tables: List[(UUID,String, String)], udts: List[(UUID, String, String)])
- case class TableDetails(tableName: String, columns: List[ColumnDetails], asCQL: String, uniqueId: UUID = UUIDs.timeBased())
+ case class KeyspaceContent(keyspaceName: String, keyspaceDetails: String,
+ tables: List[(UUID,String, String)],
+ views: List[(UUID,String, String)],
+ udts: List[(UUID, String, String)],
+ functions: List[(UUID, String, String)],
+ aggregates: List[(UUID, String, String)])
+ case class TableDetails(tableName: String, columns: List[ColumnDetails], indices: List[IndexDetails], asCQL: String, indicesAsCQL: String, uniqueId: UUID = UUIDs.timeBased())
case class UDTDetails(typeName: String, columns: List[ColumnDetails], asCQL: String, uniqueId: UUID = UUIDs.timeBased())
+ case class SameNameFunctionDetails(functions: List[FunctionDetails])
+ case class FunctionDetails(keyspace:String, name: String, arguments: List[String], calledOnNullInput: Boolean, returnType: String,
+ language:String, body: String, asCQL: String, uniqueId: UUID = UUIDs.timeBased())
+ case class FunctionSummary(keyspace:String, name: String, arguments: List[String], returnType: String)
+ case class AggregateDetails(keyspace:String, name: String, arguments: List[String], sFunc: String, sType: String,
+ finalFunc: Option[String], initCond: Option[String], returnType: String,
+ asCQL: String, uniqueId: UUID = UUIDs.timeBased())
+ case class AggregateSummary(keyspace:String, name: String, arguments: List[String], returnType: String)
+ case class SameNameAggregateDetails(aggregates: List[AggregateDetails])
+ case class MaterializedViewDetails(name: String, columns: List[ColumnDetails], asCQL: String, baseTable: String, uniqueId: UUID = UUIDs.timeBased())
+ case class MaterializedViewSummary(name: String, baseTable: String)
}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/11a45e2e/cassandra/src/main/scala/org/apache/zeppelin/cassandra/ParagraphParser.scala
----------------------------------------------------------------------
diff --git a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/ParagraphParser.scala b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/ParagraphParser.scala
index 0cd98ad..e2cb64d 100644
--- a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/ParagraphParser.scala
+++ b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/ParagraphParser.scala
@@ -19,10 +19,20 @@ package org.apache.zeppelin.cassandra
import com.datastax.driver.core._
import org.apache.zeppelin.cassandra.CassandraInterpreter._
import org.apache.zeppelin.interpreter.InterpreterException
+import scala.util.matching.Regex
import scala.util.parsing.combinator._
import org.apache.zeppelin.cassandra.TextBlockHierarchy._
+/**
+ * Parser using Scala combinator parsing
+ *
+ * (?i) means case-insensitive mode
+ * (?s) means DOT ALL mode
+ * (?is) means case-insensitive and DOT ALL mode
+ *
+ */
object ParagraphParser {
+
val CONSISTENCY_LEVEL_PATTERN = ConsistencyLevel.values().toList
.map(_.name()).filter(!_.contains("SERIAL")).mkString("""^\s*@consistency\s*=\s*(""", "|" , """)\s*$""").r
@@ -42,22 +52,43 @@ object ParagraphParser {
val BIND_PATTERN = """^\s*@bind\[([^]]+)\](?:=([^;]+))?""".r
val BATCH_PATTERN = """^(?i)\s*BEGIN\s+(UNLOGGED|COUNTER)?\s*BATCH""".r
+ /**
+ * Very complicated RegExp
+ * (?: OR REPLACE)? -> optional presence of OR REPLACE
+ * .+? -> match ANY character in RELUCTANT mode
+ * (?:\s*|\n|\r|\f) -> white space OR line returns (\n, \r, \f)
+ * (?:\s*|\n|\r|\f)AS(?:\s*|\n|\r|\f) -> AS preceded and followed by white space or line return
+ * (?:'|\$\$) -> simple quote (') OR double dollar ($$) as source code separator
+ * (?:'|\$\$).+?(?:'|\$\$)\s*; ->
+ * source code separator (?:'|\$\$)
+ * followed by ANY character in RELUCTANT mode (.+?)
+ * followed by source code separator (?:'|\$\$)
+ * followed by optional white-space(s) (\s*)
+ * followed by semi-colon (;)
+ */
+ val UDF_PATTERN = """(?is)\s*(CREATE(?:\s+OR REPLACE)?\s+FUNCTION(?:\s+IF\s+NOT\s+EXISTS)?.+?(?:\s+|\n|\r|\f)AS(?:\s+|\n|\r|\f)(?:'|\$\$).+?(?:'|\$\$)\s*;)""".r
+
val GENERIC_STATEMENT_PREFIX =
"""(?is)\s*(?:INSERT|UPDATE|DELETE|SELECT|CREATE|UPDATE|
|DROP|GRANT|REVOKE|TRUNCATE|LIST|USE)\s+""".r
val VALID_IDENTIFIER = "[a-z][a-z0-9_]*"
- val DESCRIBE_CLUSTER_PATTERN = """^(?i)\s*(?:DESCRIBE|DESC)\s+CLUSTER;\s*$""".r
- val DESCRIBE_KEYSPACES_PATTERN = """^(?i)\s*(?:DESCRIBE|DESC)\s+KEYSPACES;\s*$""".r
- val DESCRIBE_TABLES_PATTERN = """^(?i)\s*(?:DESCRIBE|DESC)\s+TABLES;\s*$""".r
+ val DESCRIBE_CLUSTER_PATTERN = """^(?i)\s*(?:DESCRIBE|DESC)\s+CLUSTER\s*;\s*$""".r
+
+
val DESCRIBE_KEYSPACE_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+KEYSPACE\s*("""+VALID_IDENTIFIER+""");\s*$""").r
+ val DESCRIBE_KEYSPACES_PATTERN = """^(?i)\s*(?:DESCRIBE|DESC)\s+KEYSPACES\s*;\s*$""".r
+
+
val DESCRIBE_TABLE_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+TABLE\s*("""+VALID_IDENTIFIER+""");\s*$""").r
val DESCRIBE_TABLE_WITH_KEYSPACE_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+TABLE\s*(""" +
VALID_IDENTIFIER +
""")\.(""" +
VALID_IDENTIFIER +
""");\s*$""").r
+ val DESCRIBE_TABLES_PATTERN = """^(?i)\s*(?:DESCRIBE|DESC)\s+TABLES\s*;\s*$""".r
+
val DESCRIBE_TYPE_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+TYPE\s*("""+VALID_IDENTIFIER+""");\s*$""").r
val DESCRIBE_TYPE_WITH_KEYSPACE_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+TYPE\s*(""" +
@@ -65,6 +96,35 @@ object ParagraphParser {
""")\.(""" +
VALID_IDENTIFIER +
""");\s*$""").r
+ val DESCRIBE_TYPES_PATTERN = """^(?i)\s*(?:DESCRIBE|DESC)\s+TYPES\s*;\s*$""".r
+
+
+ val DESCRIBE_FUNCTION_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+FUNCTION\s*("""+VALID_IDENTIFIER+""");\s*$""").r
+ val DESCRIBE_FUNCTION_WITH_KEYSPACE_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+FUNCTION\s*(""" +
+ VALID_IDENTIFIER +
+ """)\.(""" +
+ VALID_IDENTIFIER +
+ """);\s*$""").r
+ val DESCRIBE_FUNCTIONS_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+FUNCTIONS\s*;\s*$""").r
+
+
+ val DESCRIBE_AGGREGATE_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+AGGREGATE\s*("""+VALID_IDENTIFIER+""");\s*$""").r
+ val DESCRIBE_AGGREGATE_WITH_KEYSPACE_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+AGGREGATE\s*(""" +
+ VALID_IDENTIFIER +
+ """)\.(""" +
+ VALID_IDENTIFIER +
+ """);\s*$""").r
+ val DESCRIBE_AGGREGATES_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+AGGREGATES\s*;\s*$""").r
+
+
+ val DESCRIBE_MATERIALIZED_VIEW_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+MATERIALIZED\s+VIEW\s*("""+VALID_IDENTIFIER+""");\s*$""").r
+ val DESCRIBE_MATERIALIZED_VIEW_WITH_KEYSPACE_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+MATERIALIZED\s+VIEW\s*(""" +
+ VALID_IDENTIFIER +
+ """)\.(""" +
+ VALID_IDENTIFIER +
+ """);\s*$""").r
+ val DESCRIBE_MATERIALIZED_VIEWS_PATTERN = ("""^(?i)\s*(?:DESCRIBE|DESC)\s+MATERIALIZED\s+VIEWS\s*;\s*$""").r
+
val HELP_PATTERN = """^(?i)\s*HELP;\s*$""".r
}
@@ -74,7 +134,10 @@ class ParagraphParser extends RegexParsers{
import ParagraphParser._
- def singleLineComment: Parser[Comment] = """\s*#.*""".r ^^ {case text => Comment(text.trim.replaceAll("#",""))}
+ def singleLineCommentHash: Parser[Comment] = """\s*#.*""".r ^^ {case text => Comment(text.trim.replaceAll("#",""))}
+ def singleLineCommentDoubleSlashes: Parser[Comment] = """\s*//.*""".r ^^ {case text => Comment(text.trim.replaceAll("//",""))}
+ def singleLineComment: Parser[Comment] = singleLineCommentHash | singleLineCommentDoubleSlashes
+
def multiLineComment: Parser[Comment] = """(?s)/\*(.*)\*/""".r ^^ {case text => Comment(text.trim.replaceAll("""/\*""","").replaceAll("""\*/""",""))}
//Query parameters
@@ -85,7 +148,10 @@ class ParagraphParser extends RegexParsers{
def fetchSize: Parser[FetchSize] = """\s*@fetchSize.+""".r ^^ {case x => extractFetchSize(x.trim)}
//Statements
+ def createFunctionStatement: Parser[SimpleStm] = UDF_PATTERN ^^{case x => extractUdfStatement(x.trim)}
def genericStatement: Parser[SimpleStm] = s"""$GENERIC_STATEMENT_PREFIX[^;]+;""".r ^^ {case x => extractSimpleStatement(x.trim)}
+// def allStatement: Parser[SimpleStm] = udfStatement | genericStatement
+
def prepare: Parser[PrepareStm] = """\s*@prepare.+""".r ^^ {case x => extractPreparedStatement(x.trim)}
def removePrepare: Parser[RemovePrepareStm] = """\s*@remove_prepare.+""".r ^^ {case x => extractRemovePreparedStatement(x.trim)}
def bind: Parser[BoundStm] = """\s*@bind.+""".r ^^ {case x => extractBoundStatement(x.trim)}
@@ -95,9 +161,17 @@ class ParagraphParser extends RegexParsers{
private def describeCluster: Parser[DescribeClusterCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+CLUSTER.*""".r ^^ {extractDescribeClusterCmd(_)}
private def describeKeyspaces: Parser[DescribeKeyspacesCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+KEYSPACES.*""".r ^^ {extractDescribeKeyspacesCmd(_)}
private def describeTables: Parser[DescribeTablesCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+TABLES.*""".r ^^ {extractDescribeTablesCmd(_)}
+ private def describeTypes: Parser[DescribeTypesCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+TYPES.*""".r ^^ {extractDescribeTypesCmd(_)}
+ private def describeFunctions: Parser[DescribeFunctionsCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+FUNCTIONS.*""".r ^^ {extractDescribeFunctionsCmd(_)}
+ private def describeAggregates: Parser[DescribeAggregatesCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+AGGREGATES.*""".r ^^ {extractDescribeAggregatesCmd(_)}
+ private def describeMaterializedViews: Parser[DescribeMaterializedViewsCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+MATERIALIZED\s+VIEWS.*""".r ^^ {extractDescribeMaterializedViewsCmd(_)}
private def describeKeyspace: Parser[DescribeKeyspaceCmd] = """\s*(?i)(?:DESCRIBE|DESC)\s+KEYSPACE\s+.+""".r ^^ {extractDescribeKeyspaceCmd(_)}
private def describeTable: Parser[DescribeTableCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+TABLE\s+.+""".r ^^ {extractDescribeTableCmd(_)}
- private def describeType: Parser[DescribeUDTCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+TYPE\s+.*""".r ^^ {extractDescribeTypeCmd(_)}
+ private def describeType: Parser[DescribeTypeCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+TYPE\s+.*""".r ^^ {extractDescribeTypeCmd(_)}
+ private def describeFunction: Parser[DescribeFunctionCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+FUNCTION\s+.*""".r ^^ {extractDescribeFunctionCmd(_)}
+ private def describeAggregate: Parser[DescribeAggregateCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+AGGREGATE\s+.*""".r ^^ {extractDescribeAggregateCmd(_)}
+ private def describeMaterializedView: Parser[DescribeMaterializedViewCmd] = """(?i)\s*(?:DESCRIBE|DESC)\s+MATERIALIZED\s+VIEW\s+.*""".r ^^ {extractDescribeMaterializedViewCmd(_)}
+
//Help
private def helpCommand: Parser[HelpCmd] = """(?i)\s*HELP.*""".r ^^{extractHelpCmd(_)}
@@ -114,8 +188,14 @@ class ParagraphParser extends RegexParsers{
case begin ~ cqls ~ end => BatchStm(extractBatchType(begin),cqls)}
def queries:Parser[List[AnyBlock]] = rep(singleLineComment | multiLineComment | consistency | serialConsistency |
- timestamp | retryPolicy | fetchSize | removePrepare | prepare | bind | batch | describeCluster | describeKeyspaces |
- describeTables | describeKeyspace | describeTable | describeType | helpCommand | genericStatement)
+ timestamp | retryPolicy | fetchSize | removePrepare | prepare | bind | batch | describeCluster |
+ describeKeyspace | describeKeyspaces |
+ describeTable | describeTables |
+ describeType | describeTypes |
+ describeFunction | describeFunctions |
+ describeAggregate | describeAggregates |
+ describeMaterializedView | describeMaterializedViews |
+ helpCommand | createFunctionStatement | genericStatement)
def extractConsistency(text: String): Consistency = {
text match {
@@ -171,6 +251,13 @@ class ParagraphParser extends RegexParsers{
}
}
+ def extractUdfStatement(text: String): SimpleStm = {
+ text match {
+ case UDF_PATTERN(statement) => SimpleStm(statement)
+ case _ => throw new InterpreterException(s"Invalid statement '$text' for UDF creation. Did you forget to add ; (semi-colon) at the end of each CQL statement ?")
+ }
+ }
+
def extractPreparedStatement(text: String): PrepareStm = {
text match {
case PREPARE_STATEMENT_PATTERN(name,queryString) => PrepareStm(name.trim,queryString.trim)
@@ -214,6 +301,14 @@ class ParagraphParser extends RegexParsers{
}
}
+ def extractDescribeKeyspaceCmd(text: String): DescribeKeyspaceCmd = {
+ text match {
+ case DESCRIBE_KEYSPACE_PATTERN(keyspace) => new DescribeKeyspaceCmd(keyspace)
+ case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE KEYSPACE. " +
+ s"""It should comply to the pattern: ${DESCRIBE_KEYSPACE_PATTERN.toString}""")
+ }
+ }
+
def extractDescribeKeyspacesCmd(text: String): DescribeKeyspacesCmd = {
text match {
case DESCRIBE_KEYSPACES_PATTERN() => new DescribeKeyspacesCmd
@@ -222,6 +317,15 @@ class ParagraphParser extends RegexParsers{
}
}
+ def extractDescribeTableCmd(text: String): DescribeTableCmd = {
+ text match {
+ case DESCRIBE_TABLE_WITH_KEYSPACE_PATTERN(keyspace,table) => new DescribeTableCmd(Option(keyspace),table)
+ case DESCRIBE_TABLE_PATTERN(table) => new DescribeTableCmd(Option.empty,table)
+ case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE TABLE. " +
+ s"""It should comply to the patterns: ${DESCRIBE_TABLE_WITH_KEYSPACE_PATTERN.toString} or ${DESCRIBE_TABLE_PATTERN.toString}""".stripMargin)
+ }
+ }
+
def extractDescribeTablesCmd(text: String): DescribeTablesCmd = {
text match {
case DESCRIBE_TABLES_PATTERN() => new DescribeTablesCmd
@@ -230,29 +334,71 @@ class ParagraphParser extends RegexParsers{
}
}
- def extractDescribeKeyspaceCmd(text: String): DescribeKeyspaceCmd = {
+ def extractDescribeTypeCmd(text: String): DescribeTypeCmd = {
text match {
- case DESCRIBE_KEYSPACE_PATTERN(keyspace) => new DescribeKeyspaceCmd(keyspace)
- case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE KEYSPACE. " +
- s"""It should comply to the pattern: ${DESCRIBE_KEYSPACE_PATTERN.toString}""")
+ case DESCRIBE_TYPE_WITH_KEYSPACE_PATTERN(keyspace,table) => new DescribeTypeCmd(Option(keyspace),table)
+ case DESCRIBE_TYPE_PATTERN(table) => new DescribeTypeCmd(Option.empty,table)
+ case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE TYPE. " +
+ s"""It should comply to the patterns: ${DESCRIBE_TYPE_WITH_KEYSPACE_PATTERN.toString} or ${DESCRIBE_TYPE_PATTERN.toString}""".stripMargin)
}
}
- def extractDescribeTableCmd(text: String): DescribeTableCmd = {
+ def extractDescribeTypesCmd(text: String): DescribeTypesCmd = {
text match {
- case DESCRIBE_TABLE_WITH_KEYSPACE_PATTERN(keyspace,table) => new DescribeTableCmd(Option(keyspace),table)
- case DESCRIBE_TABLE_PATTERN(table) => new DescribeTableCmd(Option.empty,table)
- case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE TABLE. " +
- s"""It should comply to the patterns: ${DESCRIBE_TABLE_WITH_KEYSPACE_PATTERN.toString} or ${DESCRIBE_TABLE_PATTERN.toString}""".stripMargin)
+ case DESCRIBE_TYPES_PATTERN() => new DescribeTypesCmd
+ case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE TYPES. " +
+ s"""It should comply to the pattern: ${DESCRIBE_TYPES_PATTERN.toString}""")
}
}
- def extractDescribeTypeCmd(text: String): DescribeUDTCmd = {
+ def extractDescribeFunctionCmd(text: String): DescribeFunctionCmd = {
text match {
- case DESCRIBE_TYPE_WITH_KEYSPACE_PATTERN(keyspace,table) => new DescribeUDTCmd(Option(keyspace),table)
- case DESCRIBE_TYPE_PATTERN(table) => new DescribeUDTCmd(Option.empty,table)
- case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE TYPE. " +
- s"""It should comply to the patterns: ${DESCRIBE_TYPE_WITH_KEYSPACE_PATTERN.toString} or ${DESCRIBE_TYPE_PATTERN.toString}""".stripMargin)
+ case DESCRIBE_FUNCTION_WITH_KEYSPACE_PATTERN(keyspace,function) => new DescribeFunctionCmd(Option(keyspace),function)
+ case DESCRIBE_FUNCTION_PATTERN(function) => new DescribeFunctionCmd(Option.empty,function)
+ case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE FUNCTION. " +
+ s"""It should comply to the patterns: ${DESCRIBE_FUNCTION_WITH_KEYSPACE_PATTERN.toString} or ${DESCRIBE_FUNCTION_PATTERN.toString}""".stripMargin)
+ }
+ }
+
+ def extractDescribeFunctionsCmd(text: String): DescribeFunctionsCmd = {
+ text match {
+ case DESCRIBE_FUNCTIONS_PATTERN() => new DescribeFunctionsCmd
+ case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE FUNCTIONS. " +
+ s"""It should comply to the pattern: ${DESCRIBE_FUNCTIONS_PATTERN.toString}""".stripMargin)
+ }
+ }
+
+ def extractDescribeAggregateCmd(text: String): DescribeAggregateCmd = {
+ text match {
+ case DESCRIBE_AGGREGATE_WITH_KEYSPACE_PATTERN(keyspace,aggregate) => new DescribeAggregateCmd(Option(keyspace),aggregate)
+ case DESCRIBE_AGGREGATE_PATTERN(aggregate) => new DescribeAggregateCmd(Option.empty,aggregate)
+ case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE AGGREGATE. " +
+ s"""It should comply to the patterns: ${DESCRIBE_AGGREGATE_WITH_KEYSPACE_PATTERN.toString} or ${DESCRIBE_AGGREGATE_PATTERN.toString}""".stripMargin)
+ }
+ }
+
+ def extractDescribeAggregatesCmd(text: String): DescribeAggregatesCmd = {
+ text match {
+ case DESCRIBE_AGGREGATES_PATTERN() => new DescribeAggregatesCmd
+ case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE AGGREGATES. " +
+ s"""It should comply to the pattern: ${DESCRIBE_AGGREGATES_PATTERN.toString}""".stripMargin)
+ }
+ }
+
+ def extractDescribeMaterializedViewCmd(text: String): DescribeMaterializedViewCmd = {
+ text match {
+ case DESCRIBE_MATERIALIZED_VIEW_WITH_KEYSPACE_PATTERN(keyspace,view) => new DescribeMaterializedViewCmd(Option(keyspace),view)
+ case DESCRIBE_MATERIALIZED_VIEW_PATTERN(view) => new DescribeMaterializedViewCmd(Option.empty,view)
+ case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE MATERIALIZED VIEW. " +
+ s"""It should comply to the patterns: ${DESCRIBE_MATERIALIZED_VIEW_WITH_KEYSPACE_PATTERN.toString} or ${DESCRIBE_MATERIALIZED_VIEW_PATTERN.toString}""".stripMargin)
+ }
+ }
+
+ def extractDescribeMaterializedViewsCmd(text: String): DescribeMaterializedViewsCmd = {
+ text match {
+ case DESCRIBE_MATERIALIZED_VIEWS_PATTERN() => new DescribeMaterializedViewsCmd
+ case _ => throw new InterpreterException(s"Invalid syntax for DESCRIBE MATERIALIZED VIEWS. " +
+ s"""It should comply to the pattern: ${DESCRIBE_MATERIALIZED_VIEWS_PATTERN.toString}""".stripMargin)
}
}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/11a45e2e/cassandra/src/main/scala/org/apache/zeppelin/cassandra/TextBlockHierarchy.scala
----------------------------------------------------------------------
diff --git a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/TextBlockHierarchy.scala b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/TextBlockHierarchy.scala
index 70b2ce2..61a2d8d 100644
--- a/cassandra/src/main/scala/org/apache/zeppelin/cassandra/TextBlockHierarchy.scala
+++ b/cassandra/src/main/scala/org/apache/zeppelin/cassandra/TextBlockHierarchy.scala
@@ -77,10 +77,16 @@ object TextBlockHierarchy {
object BatchStatementType extends StatementType
object DescribeClusterStatementType extends StatementType
object DescribeAllKeyspacesStatementType extends StatementType
- object DescribeKeyspaceStatementType extends StatementType
object DescribeAllTablesStatementType extends StatementType
+ object DescribeAllTypesStatementType extends StatementType
+ object DescribeAllFunctionsStatementType extends StatementType
+ object DescribeAllAggregatesStatementType extends StatementType
+ object DescribeKeyspaceStatementType extends StatementType
object DescribeTableStatementType extends StatementType
object DescribeTypeStatementType extends StatementType
+ object DescribeFunctionStatementType extends StatementType
+ object DescribeAggregateStatementType extends StatementType
+ object DescribeMaterializedView extends StatementType
object HelpStatementType extends StatementType
abstract class QueryStatement(val statementType: StatementType) extends AnyBlock(StatementBlock) {
@@ -104,15 +110,27 @@ object TextBlockHierarchy {
val statement: String
}
- class DescribeClusterCmd(override val statement: String = "DESCRIBE CLUSTER;")
+ case class DescribeClusterCmd(override val statement: String = "DESCRIBE CLUSTER;")
extends QueryStatement(DescribeClusterStatementType) with DescribeCommandStatement
- class DescribeKeyspacesCmd(override val statement: String = "DESCRIBE KEYSPACES;")
+ case class DescribeKeyspacesCmd(override val statement: String = "DESCRIBE KEYSPACES;")
extends QueryStatement(DescribeAllKeyspacesStatementType) with DescribeCommandStatement
- class DescribeTablesCmd(override val statement: String = "DESCRIBE TABLES;")
+ case class DescribeTablesCmd(override val statement: String = "DESCRIBE TABLES;")
extends QueryStatement(DescribeAllTablesStatementType) with DescribeCommandStatement
+ case class DescribeTypesCmd(override val statement: String = "DESCRIBE TYPES;")
+ extends QueryStatement(DescribeAllTypesStatementType) with DescribeCommandStatement
+
+ case class DescribeFunctionsCmd(override val statement: String = "DESCRIBE FUNCTIONS;") extends QueryStatement(DescribeAllFunctionsStatementType)
+ with DescribeCommandStatement
+
+ case class DescribeAggregatesCmd(override val statement: String = "DESCRIBE AGGREGATES;") extends QueryStatement(DescribeAllAggregatesStatementType)
+ with DescribeCommandStatement
+
+ case class DescribeMaterializedViewsCmd(override val statement: String = "DESCRIBE MATERIALIZED VIEWS;") extends QueryStatement(DescribeAllAggregatesStatementType)
+ with DescribeCommandStatement
+
case class DescribeKeyspaceCmd(keyspace: String) extends QueryStatement(DescribeKeyspaceStatementType)
with DescribeCommandStatement {
override val statement: String = s"DESCRIBE KEYSPACE $keyspace;"
@@ -126,7 +144,7 @@ object TextBlockHierarchy {
}
}
- case class DescribeUDTCmd(keyspace:Option[String],udtName: String) extends QueryStatement(DescribeTypeStatementType)
+ case class DescribeTypeCmd(keyspace:Option[String], udtName: String) extends QueryStatement(DescribeTypeStatementType)
with DescribeCommandStatement {
override val statement: String = keyspace match {
case Some(ks) => s"DESCRIBE TYPE $ks.$udtName;"
@@ -134,6 +152,30 @@ object TextBlockHierarchy {
}
}
- class HelpCmd extends QueryStatement(HelpStatementType)
+ case class DescribeFunctionCmd(keyspace:Option[String], function: String) extends QueryStatement(DescribeFunctionStatementType)
+ with DescribeCommandStatement {
+ override val statement: String = keyspace match {
+ case Some(ks) => s"DESCRIBE FUNCTION $ks.$function;"
+ case None => s"DESCRIBE FUNCTION $function;"
+ }
+ }
+
+ case class DescribeAggregateCmd(keyspace:Option[String], aggregate: String) extends QueryStatement(DescribeAggregateStatementType)
+ with DescribeCommandStatement {
+ override val statement: String = keyspace match {
+ case Some(ks) => s"DESCRIBE AGGREGATE $ks.$aggregate;"
+ case None => s"DESCRIBE AGGREGATE $aggregate;"
+ }
+ }
+
+ case class DescribeMaterializedViewCmd(keyspace:Option[String], view: String) extends QueryStatement(DescribeMaterializedView)
+ with DescribeCommandStatement {
+ override val statement: String = keyspace match {
+ case Some(ks) => s"DESCRIBE MATERIALIZED VIEW $ks.$view;"
+ case None => s"DESCRIBE MATERIALIZED VIEW $view;"
+ }
+ }
+
+ case class HelpCmd(val statement:String = "HELP;") extends QueryStatement(HelpStatementType)
}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/11a45e2e/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java
----------------------------------------------------------------------
diff --git a/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java b/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java
index afca9de..560c57e 100644
--- a/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java
+++ b/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java
@@ -30,22 +30,20 @@ import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.when;
import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.ProtocolVersion;
import com.datastax.driver.core.Session;
-import info.archinnov.achilles.junit.AchillesResource;
-import info.archinnov.achilles.junit.AchillesResourceBuilder;
+
+import info.archinnov.achilles.embedded.CassandraEmbeddedServerBuilder;
+
+import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.Test;
+import org.junit.*;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
-import scala.io.Source;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
@@ -58,16 +56,14 @@ public class CassandraInterpreterTest {
private static final String ARTISTS_TABLE = "zeppelin.artists";
- @ClassRule
- public static AchillesResource resource = AchillesResourceBuilder
+ public static Session session = CassandraEmbeddedServerBuilder
.noEntityPackages()
.withKeyspaceName("zeppelin")
.withScript("prepare_schema.cql")
.withScript("prepare_data.cql")
- .build();
-
- private static Session session = resource.getNativeSession();
-
+ .withProtocolVersion(ProtocolVersion.V3)
+ .buildNativeSessionOnly();
+// public static Session session = null;
private static CassandraInterpreter interpreter;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -76,7 +72,8 @@ public class CassandraInterpreterTest {
@BeforeClass
public static void setUp() {
Properties properties = new Properties();
- final Cluster cluster = resource.getNativeSession().getCluster();
+ final Cluster cluster = session.getCluster();
+// final Cluster cluster = null;
properties.setProperty(CASSANDRA_CLUSTER_NAME, cluster.getClusterName());
properties.setProperty(CASSANDRA_COMPRESSION_PROTOCOL, "NONE");
properties.setProperty(CASSANDRA_CREDENTIALS_USERNAME, "none");
@@ -131,7 +128,7 @@ public class CassandraInterpreterTest {
@Test
public void should_create_cluster_and_session_upon_call_to_open() throws Exception {
assertThat(interpreter.cluster).isNotNull();
- assertThat(interpreter.cluster.getClusterName()).isEqualTo(resource.getNativeSession().getCluster().getClusterName());
+ assertThat(interpreter.cluster.getClusterName()).isEqualTo(session.getCluster().getClusterName());
assertThat(interpreter.session).isNotNull();
assertThat(interpreter.helper).isNotNull();
}
@@ -241,7 +238,7 @@ public class CassandraInterpreterTest {
//Then
assertThat(actual.code()).isEqualTo(Code.ERROR);
assertThat(actual.message())
- .contains("Not enough replica available for query at consistency THREE (3 required but only 1 alive)");
+ .contains("Not enough replicas available for query at consistency THREE (3 required but only 1 alive)");
}
@Test
@@ -329,14 +326,14 @@ public class CassandraInterpreterTest {
assertThat(actual.message()).isEqualTo(
"login\taddresses\tage\tdeceased\tfirstname\tlast_update\tlastname\tlocation\n" +
"jdoe\t" +
- "{street_number:3, street_name:'Beverly Hills Bld', zip_code:90209," +
- " country:'USA', extra_info:['Right on the hills', 'Next to the post box'], " +
- "phone_numbers:{'office':2015790847, 'home':2016778524}}\tnull\t" +
+ "{street_number:3,street_name:'Beverly Hills Bld',zip_code:90209," +
+ "country:'USA',extra_info:['Right on the hills','Next to the post box']," +
+ "phone_numbers:{'office':2015790847,'home':2016778524}}\tnull\t" +
"null\t" +
"John\t" +
"null\t" +
"DOE\t" +
- "('USA', 90209, 'Beverly Hills')\n");
+ "('USA',90209,'Beverly Hills')\n");
}
@Test
@@ -554,6 +551,76 @@ public class CassandraInterpreterTest {
}
@Test
+ @Ignore
+ //TODO activate test when using Java 8 and C* 3.x
+ public void should_describe_function() throws Exception {
+ //Given
+ Properties properties = new Properties();
+ properties.setProperty(CASSANDRA_HOSTS, "127.0.0.1");
+ properties.setProperty(CASSANDRA_PORT, "9042");
+ Interpreter interpreter = new CassandraInterpreter(properties);
+ interpreter.open();
+
+ String createFunction = "CREATE FUNCTION zeppelin.maxof(val1 int,val2 int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java " +
+ "AS $$" +
+ " return Math.max(val1, val2);\n" +
+ "$$;";
+ interpreter.interpret(createFunction, intrContext);
+ String query = "DESCRIBE FUNCTION zeppelin.maxOf;";
+
+ //When
+ final InterpreterResult actual = interpreter.interpret(query, intrContext);
+
+ //Then
+ assertThat(actual.code()).isEqualTo(Code.SUCCESS);
+ assertThat(actual.message()).isEqualTo("xxxxx");
+ }
+
+ @Test
+ @Ignore
+ //TODO activate test when using Java 8 and C* 3.x
+ public void should_describe_aggregate() throws Exception {
+ //Given
+ Properties properties = new Properties();
+ properties.setProperty(CASSANDRA_HOSTS, "127.0.0.1");
+ properties.setProperty(CASSANDRA_PORT, "9042");
+ Interpreter interpreter = new CassandraInterpreter(properties);
+ interpreter.open();
+
+ final String query = "DESCRIBE AGGREGATES;";
+
+ //When
+ final InterpreterResult actual = interpreter.interpret(query, intrContext);
+
+ //Then
+ assertThat(actual.code()).isEqualTo(Code.SUCCESS);
+
+ }
+
+ @Test
+ @Ignore
+ //TODO activate test when using Java 8 and C* 3.x
+ public void should_describe_materialized_view() throws Exception {
+ //Given
+ Properties properties = new Properties();
+ properties.setProperty(CASSANDRA_HOSTS, "127.0.0.1");
+ properties.setProperty(CASSANDRA_PORT, "9042");
+ Interpreter interpreter = new CassandraInterpreter(properties);
+ interpreter.open();
+
+ final String query = "DESCRIBE MATERIALIZED VIEWS;";
+
+ //When
+ final InterpreterResult actual = interpreter.interpret(query, intrContext);
+
+ //Then
+ assertThat(actual.code()).isEqualTo(Code.SUCCESS);
+ }
+
+ @Test
public void should_describe_table() throws Exception {
//Given
String query = "DESCRIBE TABLE live_data.complex_table;";
@@ -601,6 +668,7 @@ public class CassandraInterpreterTest {
assertThat(reformatHtml(actual.message())).isEqualTo(expected);
}
+
@Test
public void should_error_describing_non_existing_table() throws Exception {
//Given
@@ -647,8 +715,8 @@ public class CassandraInterpreterTest {
return rawHtml
.replaceAll("\\s*\n\\s*","")
.replaceAll(">\\s+<", "><")
- .replaceAll("(?s)data-target=\"#[a-f0-9-]+(?:_asCQL)?\"", "")
- .replaceAll("(?s)id=\"[a-f0-9-]+(?:_asCQL)?\"", "")
+ .replaceAll("(?s)data-target=\"#[a-f0-9-]+(?:_asCQL|_indices_asCQL)?\"", "")
+ .replaceAll("(?s)id=\"[a-f0-9-]+(?:_asCQL|_indices_asCQL)?\"", "")
.trim();
}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/11a45e2e/cassandra/src/test/java/org/apache/zeppelin/cassandra/InterpreterLogicTest.java
----------------------------------------------------------------------
diff --git a/cassandra/src/test/java/org/apache/zeppelin/cassandra/InterpreterLogicTest.java b/cassandra/src/test/java/org/apache/zeppelin/cassandra/InterpreterLogicTest.java
index f7993fb..bf685f1 100644
--- a/cassandra/src/test/java/org/apache/zeppelin/cassandra/InterpreterLogicTest.java
+++ b/cassandra/src/test/java/org/apache/zeppelin/cassandra/InterpreterLogicTest.java
@@ -302,10 +302,10 @@ public class InterpreterLogicTest {
}
private <A> scala.collection.immutable.List<A> toScalaList(java.util.List<A> list) {
- return scala.collection.JavaConverters.asScalaBufferConverter(list).asScala().toList();
+ return scala.collection.JavaConversions.asScalaIterable(list).toList();
}
private <A> java.util.List<A> toJavaList(scala.collection.immutable.List<A> list){
- return scala.collection.JavaConverters.seqAsJavaListConverter(list).asJava();
+ return scala.collection.JavaConversions.asJavaList(list);
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/11a45e2e/cassandra/src/test/resources/scalate/DescribeCluster.html
----------------------------------------------------------------------
diff --git a/cassandra/src/test/resources/scalate/DescribeCluster.html b/cassandra/src/test/resources/scalate/DescribeCluster.html
index 5d32c7d..3a5c001 100644
--- a/cassandra/src/test/resources/scalate/DescribeCluster.html
+++ b/cassandra/src/test/resources/scalate/DescribeCluster.html
@@ -1,98 +1 @@
-<br/>
-<br/>
-<nav class="navbar navbar-default">
- <ul class="nav navbar-nav">
-
- <li>
- <a><strong>DESCRIBE CLUSTER;</strong></a>
- </li>
- </ul>
- <ul class="nav navbar-nav navbar-right">
- <li class="dropdown">
- <a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
- <strong>Legend</strong>
- <span class="caret"></span>
- </a>
- <ul class="dropdown-menu">
- <li>
- <a role="button">
- <i class="glyphicon glyphicon-dashboard text-muted" /> Cluster
- </a>
- </li>
- <li>
- <a role="button">
- <i class="glyphicon glyphicon-folder-open text-danger" /> Keyspace
- </a>
- </li>
- <li>
- <a role="button">
- <i class="glyphicon glyphicon-copyright-mark text-warning" /> UDT
- </a>
- </li>
- <li>
- <a role="button">
- <i class="glyphicon glyphicon-th-list text-primary" /> Table
- </a>
- </li>
- <li class="bg-info">
- <a role="button">
- <i class="glyphicon glyphicon-fullscreen" /> Partition Key
- </a>
- </li>
- <li class="bg-warning">
- <a role="button">
- <i class="glyphicon glyphicon-pushpin" /> Static Column
- </a>
- </li>
- <li class="bg-success">
- <a role="button">
- <i class="glyphicon glyphicon-sort" /> Clustering Column
- </a>
- </li>
- <li class="bg-success">
- <a role="button">
- <i class="glyphicon glyphicon-sort-by-attributes" /> Clustering Order ASC
- </a>
- </li>
- <li class="bg-success">
- <a role="button">
- <i class="glyphicon glyphicon-sort-by-attributes-alt" /> Clustering Order DESC
- </a>
- </li>
- <li>
- <a role="button">
- <i class="glyphicon glyphicon-info-sign" /> Indexed Column
- </a>
- </li>
- </ul>
- </li>
- <li>
- <a href="#"></a>
- </li>
- </ul>
-</nav>
-<hr/>
-<div class="row">
- <div class="col-md-4"></div>
- <div class="col-md-4 col-offset-md-4">
- <div class="table-responsive table-bordered">
- <table class="table">
- <caption>
- <h4 class="text-muted">
- <i class="glyphicon glyphicon-dashboard"/> Test Cluster
- </h4>
- </caption>
- <thead>
- <tr>
- <th>Partitioner</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>org.apache.cassandra.dht.Murmur3Partitioner</td>
- </tr>
- <tbody>
- </table>
- </div>
- </div>
-</div>
\ No newline at end of file
+<br/><br/><nav class="navbar navbar-default"><ul class="nav navbar-nav"><li><a><strong>DESCRIBE CLUSTER;</strong></a></li></ul><ul class="nav navbar-nav navbar-right"><li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><strong>Legend</strong><span class="caret"></span></a><ul class="dropdown-menu"><li><a role="button"><i class="glyphicon glyphicon-dashboard text-muted" /> Cluster</a></li><li><a role="button"><i class="glyphicon glyphicon-folder-open text-danger" /> Keyspace</a></li><li><a role="button"><i class="glyphicon glyphicon-copyright-mark text-warning" /> UDT</a></li><li><a role="button"><i class="glyphicon glyphicon-th-list text-primary" /> Table</a></li><li><a role="button"><i class="glyphicon glyphicon-eye-open text-primary" /> Materialized View</a></li><li><a role="button"><i class="glyphicon glyphicon-random text-success" /> Function</a
></li><li><a role="button"><i class="glyphicon glyphicon-retweet text-success" /> Aggregate</a></li><li role="separator" class="divider text-muted"></li><li class="dropdown-header"><span class="text-primary">Table icons</span></li><li class="bg-info"><a role="button"><i class="glyphicon glyphicon-fullscreen" /> Partition Key</a></li><li class="bg-warning"><a role="button"><i class="glyphicon glyphicon-pushpin" /> Static Column</a></li><li class="bg-success"><a role="button"><i class="glyphicon glyphicon-sort" /> Clustering Column</a></li><li class="bg-success"><a role="button"><i class="glyphicon glyphicon-sort-by-attributes" /> Clustering Order ASC</a></li><li class="bg-success"><a role="button"><i class="glyphicon glyphicon-sort-by-attributes-alt" /> Clustering Order DESC</a></li></ul></li><li><a href="#"></a></li></ul></nav><hr/><div class="row"><div class="col-md-4"></div><div class="col-md-4 col-offset-md-4"><div
class="table-responsive table-bordered"><table class="table"><caption><h4 class="text-muted"><i class="glyphicon glyphicon-dashboard"/> Test Cluster</h4></caption><thead><tr><th>Partitioner</th></tr></thead><tbody><tr><td>org.apache.cassandra.dht.Murmur3Partitioner</td></tr><tbody></table></div></div></div>
\ No newline at end of file