Skip to content

Commit

Permalink
#1434 adding column value provider functions for getting it from view…
Browse files Browse the repository at this point in the history
… port columns
  • Loading branch information
naleeha authored and keikeicheung committed Sep 5, 2024
1 parent e30db48 commit f02203e
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class ViewPortTypeAheadRpcHandler(tableContainer: TableContainer) extends Defaul
tableContainer.getTable(tableName) match {
case dataTable: DataTable =>
val columValueProvider = dataTable.getColumnValueProvider
columValueProvider.getUniqueValues(column)
columValueProvider.getUniqueValuesVPColumn(column)
case null =>
throw new Exception("Could not find table by name:" + tableName)
}
Expand All @@ -45,7 +45,7 @@ class ViewPortTypeAheadRpcHandler(tableContainer: TableContainer) extends Defaul
tableContainer.getTable(tableName) match {
case dataTable: DataTable =>
val columValueProvider = dataTable.getColumnValueProvider
columValueProvider.getUniqueValuesStartingWith(column, starts)
columValueProvider.getUniqueValuesStartingWithVPColumn(column, starts)
case null =>
throw new Exception("Could not find table by name:" + tableName)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package org.finos.vuu.core.table

import com.typesafe.scalalogging.StrictLogging
import org.finos.vuu.viewport.ViewPortColumns

trait ColumnValueProvider {
def getUniqueValues(columnName:String):Array[String]
def getUniqueValuesStartingWith(columnName:String, starts: String):Array[String]
}

class EmptyColumnValueProvider extends ColumnValueProvider {
override def getUniqueValues(columnName: String): Array[String] = Array.empty
def getUniqueValuesVPColumn(columnName: String): Array[String]
def getUniqueValuesStartingWithVPColumn(columnName: String, starts: String): Array[String]

@deprecated("to be replaced by getUniqueValuesVPColumn")
def getUniqueValues(columnName: String): Array[String]
@deprecated("to be replaced by getUniqueValuesStartingWithVPColumn")
def getUniqueValuesStartingWith(columnName: String, starts: String): Array[String]

override def getUniqueValuesStartingWith(columnName: String, starts: String): Array[String] = Array.empty
}


object InMemColumnValueProvider {
def apply(dataTable: DataTable): InMemColumnValueProvider = {
dataTable match {
Expand All @@ -25,32 +28,61 @@ object InMemColumnValueProvider {
class InMemColumnValueProvider(dataTable: InMemDataTable) extends ColumnValueProvider with StrictLogging {
private val get10DistinctValues = DistinctValuesGetter(10)

def getUniqueValuesVPColumn(columnName: String): Array[String] = {
val viewPortColumns = ViewPortColumnCreator.create(dataTable, List(columnName))
viewPortColumns.getColumnForName(columnName) match {
case Some(column) => get10DistinctValues.fromVP(viewPortColumns, column)
case None => logger.error(s"Column $columnName not found in table ${dataTable.name}"); Array.empty;
}
}

def getUniqueValuesStartingWithVPColumn(columnName: String, starts: String): Array[String] = {
val viewPortColumns = ViewPortColumnCreator.create(dataTable, List(columnName))
viewPortColumns.getColumnForName(columnName) match {
case Some(column) => get10DistinctValues.fromVP(viewPortColumns, column, _.toLowerCase.startsWith(starts.toLowerCase))
case None => logger.error(s"Column $columnName not found in table ${dataTable.name}"); Array.empty;
}
}

override def getUniqueValues(columnName: String): Array[String] =
dataTable.columnForName(columnName) match {
case c: Column => get10DistinctValues(c)
case null => logger.error(s"Column $columnName not found in table ${dataTable.name}"); Array.empty;
}
case c: Column => get10DistinctValues.fromTable(c)
case null => logger.error(s"Column $columnName not found in table ${dataTable.name}"); Array.empty;
}

override def getUniqueValuesStartingWith(columnName: String, starts: String): Array[String] =
dataTable.columnForName(columnName) match {
case c: Column => get10DistinctValues(c, _.toLowerCase.startsWith(starts.toLowerCase))
case null => logger.error(s"Column $columnName not found in table ${dataTable.name}"); Array.empty;
case c: Column => get10DistinctValues.fromTable(c, _.toLowerCase.startsWith(starts.toLowerCase))
case null => logger.error(s"Column $columnName not found in table ${dataTable.name}"); Array.empty;
}


private case class DistinctValuesGetter(n: Int) {
private type Filter = String => Boolean

def apply(c: Column, filter: Filter = _ => true): Array[String] = getDistinctValues(c, filter).take(n).toArray
def fromTable(c: Column, filter: Filter = _ => true): Array[String] =
getDistinctValues(c, filter).take(n).toArray

def fromVP(viewPortColumns: ViewPortColumns, c: Column, filter: Filter = _ => true): Array[String] =
getDistinctValues(viewPortColumns, c, filter).take(n).toArray

private def getDistinctValues(c: Column, filter: Filter): Iterator[String] = {
private def getDistinctValues(c: Column, filter: Filter): Iterator[String] =
dataTable.primaryKeys
.iterator
.map(dataTable.pullRow(_).get(c))
.distinct
.flatMap(valueToString)
.filter(filter)
}


//todo if vp column doesnt have table column, return emtpy or error
private def getDistinctValues(viewPortColumns: ViewPortColumns, column: Column, filter: Filter): Iterator[String] =
dataTable.primaryKeys
.iterator
.map(dataTable.pullRow(_, viewPortColumns).get(column))
.distinct
.flatMap(valueToString)
.filter(filter)

private def valueToString(value: Any): Option[String] = Option(value).map(_.toString)
}
Expand Down
85 changes: 61 additions & 24 deletions vuu/src/test/scala/org/finos/vuu/wsapi/TypeAheadWSApiTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,23 @@ class TypeAheadWSApiTest extends WebSocketApiTestBase {
assertResponseReturns(response, List.empty)
}

Scenario("Type ahead request for a column that is not in view port") {

Given("a view port exist")
val viewPortId: String = createViewPort

When("request typeahead for column that is hidden")
val getTypeAheadRequest = createTypeAheadRequest(viewPortId, tableName, "HiddenColumn")
vuuClient.send(sessionId, tokenId, getTypeAheadRequest)

Then("return success response with empty list")
val response = vuuClient.awaitForMsgWithBody[ViewPortRpcResponse]

response.isDefined shouldBe true
response.get.method shouldEqual "getUniqueFieldValues"
assertResponseReturns(response, List.empty)
}

Scenario("Type ahead request for a column that does not exist") {

Given("a view port exist")
Expand Down Expand Up @@ -122,6 +139,27 @@ class TypeAheadWSApiTest extends WebSocketApiTestBase {
assertResponseReturns(response, List.empty)
}

Scenario("Type ahead request when there is multiple viewports and multiple requests") {

Given("multiple view port exist")
val viewPortId1: String = createViewPort
val viewPortId2: String = createViewPort

When("request typeahead for different view ports")
val getTypeAheadRequest1 = createTypeAheadStartWithRequest(viewPortId1, tableName, "Name", "S")
val getTypeAheadRequest2 = createTypeAheadStartWithRequest(viewPortId2, tableName, "Name", "T")
vuuClient.send(sessionId, tokenId, getTypeAheadRequest1)
vuuClient.send(sessionId, tokenId, getTypeAheadRequest2)

Then("return success response for each request")
val response1 = vuuClient.awaitForMsgWithBody[ViewPortRpcResponse]
val response2 = vuuClient.awaitForMsgWithBody[ViewPortRpcResponse]

response1.isDefined shouldBe true
response2.isDefined shouldBe true
assertResponseReturns(response1, List("Sid Sawyer","Sally Phelps"))
assertResponseReturns(response2, List("Tom Sawyer","Tom Thatcher"))
}
}

protected def defineModuleWithTestTables(): ViewServerModule = {
Expand All @@ -133,17 +171,7 @@ class TypeAheadWSApiTest extends WebSocketApiTestBase {
.addString("Id")
.addString("Name")
.addInt("Account")
.build()
)

val tableDef2 = TableDef(
name = tableNameEmpty,
keyField = "Id",
columns =
new ColumnBuilder()
.addString("Id")
.addString("Name")
.addInt("Account")
.addInt("HiddenColumn")
.build()
)

Expand All @@ -159,22 +187,31 @@ class TypeAheadWSApiTest extends WebSocketApiTestBase {
)

val dataSource = new FakeDataSource(ListMap(
"row1" -> Map("Id" -> "row1", "Name" -> "Becky Thatcher", "Account" -> 12355),
"row2" -> Map("Id" -> "row2", "Name" -> "Tom Sawyer", "Account" -> 45321),
"row3" -> Map("Id" -> "row3", "Name" -> "Huckleberry Finn", "Account" -> 89564),
"row4" -> Map("Id" -> "row4", "Name" -> "Tom Thatcher", "Account" -> 12355),
"row5" -> Map("Id" -> "row5", "Name" -> "Sid Sawyer", "Account" -> 42262),
"row6" -> Map("Id" -> "row6", "Name" -> "Joe Harper", "Account" -> 65879),
"row7" -> Map("Id" -> "row7", "Name" -> "Jim Baker", "Account" -> 88875),
"row8" -> Map("Id" -> "row8", "Name" -> "Amy Lawrence", "Account" -> 45897),
"row9" -> Map("Id" -> "row9", "Name" -> "Ben Rodgers", "Account" -> 23564),
"row10" -> Map("Id" -> "row10", "Name" -> "John Murrell", "Account" -> 33657),
"row11" -> Map("Id" -> "row11", "Name" -> "Sally Phelps", "Account" -> 99854),
"row12" -> Map("Id" -> "row12", "Name" -> "Polly Phelps", "Account" -> 78458),
"row13" -> Map("Id" -> "row13", "Name" -> "Polly Phelps", "Account" -> 54874),
"row1" -> Map("Id" -> "row1", "Name" -> "Becky Thatcher", "Account" -> 12355, "HiddenColumn" -> 10),
"row2" -> Map("Id" -> "row2", "Name" -> "Tom Sawyer", "Account" -> 45321, "HiddenColumn" -> 10),
"row3" -> Map("Id" -> "row3", "Name" -> "Huckleberry Finn", "Account" -> 89564, "HiddenColumn" -> 11),
"row4" -> Map("Id" -> "row4", "Name" -> "Tom Thatcher", "Account" -> 12355, "HiddenColumn" -> 10),
"row5" -> Map("Id" -> "row5", "Name" -> "Sid Sawyer", "Account" -> 42262, "HiddenColumn" -> 10),
"row6" -> Map("Id" -> "row6", "Name" -> "Joe Harper", "Account" -> 65879, "HiddenColumn" -> 10),
"row7" -> Map("Id" -> "row7", "Name" -> "Jim Baker", "Account" -> 88875, "HiddenColumn" -> 10),
"row8" -> Map("Id" -> "row8", "Name" -> "Amy Lawrence", "Account" -> 45897, "HiddenColumn" -> 15),
"row9" -> Map("Id" -> "row9", "Name" -> "Ben Rodgers", "Account" -> 23564, "HiddenColumn" -> 10),
"row10" -> Map("Id" -> "row10", "Name" -> "John Murrell", "Account" -> 33657, "HiddenColumn" -> 10),
"row11" -> Map("Id" -> "row11", "Name" -> "Sally Phelps", "Account" -> 99854, "HiddenColumn" -> 10),
"row12" -> Map("Id" -> "row12", "Name" -> "Polly Phelps", "Account" -> 78458, "HiddenColumn" -> 10),
"row13" -> Map("Id" -> "row13", "Name" -> "Polly Phelps", "Account" -> 54874, "HiddenColumn" -> 10),
))
val providerFactory = (table: DataTable, _: IVuuServer) => new TestProvider(table, dataSource)

val tableDef2 = TableDef(
name = tableNameEmpty,
keyField = "Id",
columns =
new ColumnBuilder()
.addString("Id")
.build()
)

ModuleFactory.withNamespace(moduleName)
.addTableForTest(tableDef, viewPortDefFactory, providerFactory)
.addTableForTest(tableDef2)
Expand Down

0 comments on commit f02203e

Please sign in to comment.