mirror of
https://github.com/enso-org/enso.git
synced 2024-11-22 11:52:59 +03:00
Wip/mk/drive drilldown from enso (#10724)
This moves some of the drilldown logic to the enso code and utilises the new 'get_rows' method for Table
This commit is contained in:
parent
b277132950
commit
0d5d01a294
@ -60,6 +60,7 @@ interface Matrix {
|
||||
all_rows_count: number
|
||||
json: unknown[][]
|
||||
value_type: ValueType[]
|
||||
get_child_node: string
|
||||
}
|
||||
|
||||
interface Excel_Workbook {
|
||||
@ -68,6 +69,7 @@ interface Excel_Workbook {
|
||||
all_rows_count: number
|
||||
sheet_names: string[]
|
||||
json: unknown[][]
|
||||
get_child_node: string
|
||||
}
|
||||
|
||||
interface ObjectMatrix {
|
||||
@ -76,6 +78,7 @@ interface ObjectMatrix {
|
||||
all_rows_count: number
|
||||
json: object[]
|
||||
value_type: ValueType[]
|
||||
get_child_node: string
|
||||
}
|
||||
|
||||
interface UnknownTable {
|
||||
@ -90,6 +93,7 @@ interface UnknownTable {
|
||||
value_type: ValueType[]
|
||||
has_index_col: boolean | undefined
|
||||
links: string[] | undefined
|
||||
get_child_node: string
|
||||
}
|
||||
|
||||
export enum TextFormatOptions {
|
||||
@ -187,32 +191,20 @@ const selectableRowLimits = computed(() => {
|
||||
})
|
||||
|
||||
const newNodeSelectorValues = computed(() => {
|
||||
let selector
|
||||
let identifierAction
|
||||
let tooltipValue
|
||||
let headerName
|
||||
switch (config.nodeType) {
|
||||
case COLUMN_NODE_TYPE:
|
||||
case VECTOR_NODE_TYPE:
|
||||
selector = INDEX_FIELD_NAME
|
||||
identifierAction = 'at'
|
||||
tooltipValue = 'value'
|
||||
break
|
||||
case ROW_NODE_TYPE:
|
||||
selector = 'column'
|
||||
identifierAction = 'at'
|
||||
tooltipValue = 'value'
|
||||
break
|
||||
case EXCEL_WORKBOOK_NODE_TYPE:
|
||||
selector = 'Value'
|
||||
identifierAction = 'read'
|
||||
tooltipValue = 'sheet'
|
||||
headerName = 'Sheets'
|
||||
break
|
||||
case SQLITE_CONNECTIONS_NODE_TYPE:
|
||||
case POSTGRES_CONNECTIONS_NODE_TYPE:
|
||||
selector = 'Value'
|
||||
identifierAction = 'query'
|
||||
tooltipValue = 'table'
|
||||
headerName = 'Tables'
|
||||
break
|
||||
@ -221,8 +213,6 @@ const newNodeSelectorValues = computed(() => {
|
||||
tooltipValue = 'row'
|
||||
}
|
||||
return {
|
||||
selector,
|
||||
identifierAction,
|
||||
tooltipValue,
|
||||
headerName,
|
||||
}
|
||||
@ -432,61 +422,37 @@ function toRowField(name: string, valueType?: ValueType | null | undefined) {
|
||||
}
|
||||
}
|
||||
|
||||
function getAstPattern(selector: string | number, action: string) {
|
||||
return Pattern.new((ast) =>
|
||||
Ast.App.positional(
|
||||
Ast.PropertyAccess.new(ast.module, ast, Ast.identifier(action)!),
|
||||
typeof selector === 'number' ?
|
||||
Ast.tryNumberToEnso(selector, ast.module)!
|
||||
: Ast.TextLiteral.new(selector, ast.module),
|
||||
),
|
||||
)
|
||||
function getAstPattern(selector: string | number, action?: string) {
|
||||
const identifierAction =
|
||||
config.nodeType === (COLUMN_NODE_TYPE || VECTOR_NODE_TYPE) ? 'at' : action
|
||||
if (identifierAction) {
|
||||
return Pattern.new((ast) =>
|
||||
Ast.App.positional(
|
||||
Ast.PropertyAccess.new(ast.module, ast, Ast.identifier(identifierAction)!),
|
||||
typeof selector === 'number' ?
|
||||
Ast.tryNumberToEnso(selector, ast.module)!
|
||||
: Ast.TextLiteral.new(selector, ast.module),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const getTablePattern = (index: number) =>
|
||||
Pattern.new((ast) =>
|
||||
Ast.OprApp.new(
|
||||
ast.module,
|
||||
Ast.App.positional(
|
||||
Ast.PropertyAccess.new(ast.module, ast, Ast.identifier('rows')!),
|
||||
Ast.parse('(..All_Rows)'),
|
||||
),
|
||||
'.',
|
||||
Ast.App.positional(
|
||||
Ast.Ident.new(ast.module, Ast.identifier('get')!),
|
||||
Ast.tryNumberToEnso(index, ast.module)!,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
function createNode(params: CellClickedEvent) {
|
||||
if (config.nodeType === TABLE_NODE_TYPE || config.nodeType === DB_TABLE_NODE_TYPE) {
|
||||
function createNode(params: CellClickedEvent, selector: string, action?: string) {
|
||||
const pattern = getAstPattern(params.data[selector], action)
|
||||
if (pattern) {
|
||||
config.createNodes({
|
||||
content: getTablePattern(params.data[INDEX_FIELD_NAME]),
|
||||
commit: true,
|
||||
})
|
||||
}
|
||||
if (
|
||||
newNodeSelectorValues.value.selector !== undefined &&
|
||||
newNodeSelectorValues.value.selector !== null &&
|
||||
newNodeSelectorValues.value.identifierAction
|
||||
) {
|
||||
config.createNodes({
|
||||
content: getAstPattern(
|
||||
params.data[newNodeSelectorValues.value.selector],
|
||||
newNodeSelectorValues.value.identifierAction,
|
||||
),
|
||||
content: pattern,
|
||||
commit: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function toLinkField(fieldName: string): ColDef {
|
||||
function toLinkField(fieldName: string, getChildAction?: string): ColDef {
|
||||
return {
|
||||
headerName:
|
||||
newNodeSelectorValues.value.headerName ? newNodeSelectorValues.value.headerName : fieldName,
|
||||
field: fieldName,
|
||||
onCellDoubleClicked: (params) => createNode(params),
|
||||
onCellDoubleClicked: (params) => createNode(params, fieldName, getChildAction),
|
||||
tooltipValueGetter: () => {
|
||||
return `Double click to view this ${newNodeSelectorValues.value.tooltipValue} in a separate component`
|
||||
},
|
||||
@ -515,6 +481,8 @@ watchEffect(() => {
|
||||
// eslint-disable-next-line camelcase
|
||||
has_index_col: false,
|
||||
links: undefined,
|
||||
// eslint-disable-next-line camelcase
|
||||
get_child_node: undefined,
|
||||
}
|
||||
const options = agGridOptions.value
|
||||
if (options.api == null) {
|
||||
@ -533,14 +501,14 @@ watchEffect(() => {
|
||||
]
|
||||
rowData = [{ Error: data_.error }]
|
||||
} else if (data_.type === 'Matrix') {
|
||||
columnDefs.push(toLinkField(INDEX_FIELD_NAME))
|
||||
columnDefs.push(toLinkField(INDEX_FIELD_NAME, data_.get_child_node))
|
||||
for (let i = 0; i < data_.column_count; i++) {
|
||||
columnDefs.push(toField(i.toString()))
|
||||
}
|
||||
rowData = addRowIndex(data_.json)
|
||||
isTruncated.value = data_.all_rows_count !== data_.json.length
|
||||
} else if (data_.type === 'Object_Matrix') {
|
||||
columnDefs.push(toLinkField(INDEX_FIELD_NAME))
|
||||
columnDefs.push(toLinkField(INDEX_FIELD_NAME, data_.get_child_node))
|
||||
let keys = new Set<string>()
|
||||
for (const val of data_.json) {
|
||||
if (val != null) {
|
||||
@ -555,14 +523,14 @@ watchEffect(() => {
|
||||
rowData = addRowIndex(data_.json)
|
||||
isTruncated.value = data_.all_rows_count !== data_.json.length
|
||||
} else if (data_.type === 'Excel_Workbook') {
|
||||
columnDefs = [toLinkField('Value')]
|
||||
columnDefs = [toLinkField('Value', data_.get_child_node)]
|
||||
rowData = data_.sheet_names.map((name) => ({ Value: name }))
|
||||
} else if (Array.isArray(data_.json)) {
|
||||
columnDefs = [toLinkField(INDEX_FIELD_NAME), toField('Value')]
|
||||
columnDefs = [toLinkField(INDEX_FIELD_NAME, data_.get_child_node), toField('Value')]
|
||||
rowData = data_.json.map((row, i) => ({ [INDEX_FIELD_NAME]: i, Value: toRender(row) }))
|
||||
isTruncated.value = data_.all_rows_count ? data_.all_rows_count !== data_.json.length : false
|
||||
} else if (data_.json !== undefined) {
|
||||
columnDefs = data_.links ? [toLinkField('Value')] : [toField('Value')]
|
||||
columnDefs = data_.links ? [toLinkField('Value', data_.get_child_node)] : [toField('Value')]
|
||||
rowData =
|
||||
data_.links ?
|
||||
data_.links.map((link) => ({
|
||||
@ -574,12 +542,15 @@ watchEffect(() => {
|
||||
('header' in data_ ? data_.header : [])?.map((v, i) => {
|
||||
const valueType = data_.value_type ? data_.value_type[i] : null
|
||||
if (config.nodeType === ROW_NODE_TYPE) {
|
||||
return v === 'column' ? toLinkField(v) : toRowField(v, valueType)
|
||||
return v === 'column' ? toLinkField(v, data_.get_child_node) : toRowField(v, valueType)
|
||||
}
|
||||
return toField(v, valueType)
|
||||
}) ?? []
|
||||
|
||||
columnDefs = data_.has_index_col ? [toLinkField(INDEX_FIELD_NAME), ...dataHeader] : dataHeader
|
||||
columnDefs =
|
||||
data_.has_index_col ?
|
||||
[toLinkField(INDEX_FIELD_NAME, data_.get_child_node), ...dataHeader]
|
||||
: dataHeader
|
||||
const rows = data_.data && data_.data.length > 0 ? data_.data[0]?.length ?? 0 : 0
|
||||
rowData = Array.from({ length: rows }, (_, i) => {
|
||||
const shift = data_.has_index_col ? 1 : 0
|
||||
|
@ -306,7 +306,7 @@ type Postgres_Connection
|
||||
Converts this value to a JSON serializable object.
|
||||
to_js_object : JS_Object
|
||||
to_js_object self =
|
||||
JS_Object.from_pairs [["type", "Postgres_Connection"], ["links", self.connection.tables.at "Name" . to_vector]]
|
||||
JS_Object.from_pairs [["type", "Postgres_Connection"], ["links", self.connection.tables.at "Name" . to_vector], ["get_child_node", "query"]]
|
||||
|
||||
## PRIVATE
|
||||
get_encoding_name : JDBC_Connection.JDBC_Connection -> Text
|
||||
|
@ -287,4 +287,4 @@ type SQLite_Connection
|
||||
Converts this value to a JSON serializable object.
|
||||
to_js_object : JS_Object
|
||||
to_js_object self =
|
||||
JS_Object.from_pairs [["type", "SQLite_Connection"], ["links", self.connection.tables.at "Name" . to_vector]]
|
||||
JS_Object.from_pairs [["type", "SQLite_Connection"], ["links", self.connection.tables.at "Name" . to_vector], ["get_child_node", "query"]]
|
||||
|
@ -48,7 +48,7 @@ prepare_visualization y max_rows=1000 =
|
||||
JS_Object.from_pairs [["json", make_json_for_value x]]
|
||||
_ : Excel_Workbook ->
|
||||
js_value = x.to_js_object
|
||||
JS_Object.from_pairs [["json", js_value], ["sheet_names", x . sheet_names], ["type", "Excel_Workbook"]]
|
||||
JS_Object.from_pairs [["json", js_value], ["sheet_names", x . sheet_names], ["get_child_node", "read"], ["type", "Excel_Workbook"]]
|
||||
_ : XML_Document -> make_json_for_xml_element x.root_element max_rows "XML_Document"
|
||||
_ : XML_Element -> make_json_for_xml_element x max_rows
|
||||
_ -> make_json_for_other x
|
||||
@ -64,14 +64,15 @@ max_columns = 250
|
||||
make_json_for_vector : Vector -> Integer -> JS_Object
|
||||
make_json_for_vector vector max_rows =
|
||||
all_rows = ["all_rows_count", vector.length]
|
||||
get_child_node = ["get_child_node", "at"]
|
||||
truncated = vector.take max_rows
|
||||
some_values = truncated.any (v->v.is_nothing.not)
|
||||
if some_values.not then JS_Object.from_pairs [["type", "Vector"], all_rows, ["json", truncated.map make_json_for_value]] else
|
||||
if some_values.not then JS_Object.from_pairs [["type", "Vector"], all_rows, ["json", truncated.map make_json_for_value], get_child_node] else
|
||||
matrix = make_json_for_matrix (Builder.new truncated.length) truncated
|
||||
if matrix.is_nothing.not then JS_Object.from_pairs [["type", "Matrix"], all_rows, ["json", matrix], ["column_count", matrix.fold 0 c->v-> if v.is_nothing then c else c.max v.length]] else
|
||||
if matrix.is_nothing.not then JS_Object.from_pairs [["type", "Matrix"], all_rows, ["json", matrix], ["column_count", matrix.fold 0 c->v-> if v.is_nothing then c else c.max v.length], get_child_node] else
|
||||
object_matrix = make_json_for_object_matrix (Builder.new truncated.length) truncated
|
||||
if object_matrix.is_nothing.not then JS_Object.from_pairs [["type", "Object_Matrix"], all_rows, ["json", object_matrix]] else
|
||||
JS_Object.from_pairs [["type", "Vector"], all_rows, ["json", truncated.map make_json_for_value]]
|
||||
if object_matrix.is_nothing.not then JS_Object.from_pairs [["type", "Object_Matrix"], all_rows, ["json", object_matrix], get_child_node] else
|
||||
JS_Object.from_pairs [["type", "Vector"], all_rows, ["json", truncated.map make_json_for_value], get_child_node]
|
||||
|
||||
## PRIVATE
|
||||
Render Vector of Vector / Array to JSON
|
||||
@ -124,7 +125,8 @@ make_json_for_dictionary dict max_items key_name="key" =
|
||||
as_vector = Warning.clear (dict.to_vector.take max_items)
|
||||
mapped = as_vector . map p-> [p.first.to_text, make_json_for_value p.second]
|
||||
data = ["data", [mapped.map .first, mapped.map .second]]
|
||||
JS_Object.from_pairs [header, data, all_rows, ["type", "Map"]]
|
||||
links = ["get_child_node", "at"]
|
||||
JS_Object.from_pairs [header, data, all_rows, links, ["type", "Map"]]
|
||||
|
||||
## PRIVATE
|
||||
Render JS_Object to JSON
|
||||
@ -177,7 +179,8 @@ make_json_for_table dataframe all_rows_count include_index_col =
|
||||
data = ["data", columns.map get_vector]
|
||||
all_rows = ["all_rows_count", all_rows_count]
|
||||
has_index_col = ["has_index_col", include_index_col]
|
||||
pairs = [header, value_type, data, all_rows, has_index_col, ["type", "Table"]]
|
||||
links = ["get_child_node", "get_row"]
|
||||
pairs = [header, value_type, data, all_rows, has_index_col, links, ["type", "Table"]]
|
||||
JS_Object.from_pairs pairs
|
||||
|
||||
## PRIVATE
|
||||
@ -188,9 +191,11 @@ make_json_for_other x =
|
||||
value = if js_value.is_a JS_Object . not then js_value else
|
||||
pairs = [['_display_text_', x.to_display_text]] + js_value.field_names.map f-> [f, make_json_for_value (js_value.get f)]
|
||||
JS_Object.from_pairs pairs
|
||||
additional_fields = if js_value.is_a JS_Object . not then [] else
|
||||
link_fields = if js_value.is_a JS_Object . not then [] else
|
||||
if js_value.contains_key 'links' then [["links", js_value.get 'links']] else []
|
||||
JS_Object.from_pairs <| [["json", value]] + additional_fields
|
||||
additional_fields = if js_value.is_a JS_Object . not then [] else
|
||||
if js_value.contains_key 'get_child_node' then [["get_child_node", js_value.get 'get_child_node']] else []
|
||||
JS_Object.from_pairs <| [["json", value]] + additional_fields + link_fields
|
||||
|
||||
## PRIVATE
|
||||
Create JSON serialization of values for the table.
|
||||
|
@ -40,17 +40,17 @@ type Foo_Link
|
||||
Value x
|
||||
|
||||
to_js_object : JS_Object
|
||||
to_js_object self = JS_Object.from_pairs [["x", self.x], ["links", ["a", "b", "c"]]]
|
||||
|
||||
to_js_object self = JS_Object.from_pairs [["x", self.x], ["links", ["a", "b", "c"]]]
|
||||
|
||||
add_specs suite_builder =
|
||||
make_json header data all_rows value_type has_index_col =
|
||||
make_json header data all_rows value_type has_index_col get_child_node =
|
||||
p_header = ["header", header]
|
||||
p_data = ["data", data]
|
||||
p_all_rows = ["all_rows_count", all_rows]
|
||||
p_value_type = ["value_type", value_type]
|
||||
p_has_index_col = ["has_index_col", has_index_col]
|
||||
pairs = [p_header, p_value_type, p_data, p_all_rows, p_has_index_col, ["type", "Table"]]
|
||||
p_get_child_node = ["get_child_node", get_child_node]
|
||||
pairs = [p_header, p_value_type, p_data, p_all_rows, p_has_index_col, p_get_child_node, ["type", "Table"]]
|
||||
JS_Object.from_pairs pairs . to_text
|
||||
|
||||
suite_builder.group "Table Visualization" group_builder->
|
||||
@ -60,45 +60,45 @@ add_specs suite_builder =
|
||||
vis = Visualization.prepare_visualization data.t 1
|
||||
value_type_int = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Integer"], ["display_text", "Integer (64 bits)"], ["bits", 64]]
|
||||
value_type_char = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Char"], ["display_text", "Char (variable length, max_size=unlimited)"], ["size", Nothing], ["variable_length", True]]
|
||||
json = make_json header=["A", "B", "C"] data=[['a'], [2], [3]] all_rows=3 value_type=[value_type_char, value_type_int, value_type_int] has_index_col=True
|
||||
json = make_json header=["A", "B", "C"] data=[['a'], [2], [3]] all_rows=3 value_type=[value_type_char, value_type_int, value_type_int] has_index_col=True get_child_node="get_row"
|
||||
vis . should_equal json
|
||||
|
||||
group_builder.specify "should visualize database columns" <|
|
||||
vis = Visualization.prepare_visualization (data.t.at "A") 2
|
||||
value_type_char = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Char"], ["display_text", "Char (variable length, max_size=unlimited)"], ["size", Nothing], ["variable_length", True]]
|
||||
value_type_float = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Float"], ["display_text", "Float (64 bits)"], ["bits", 64]]
|
||||
json = make_json header=["A"] data=[['a', 'a']] all_rows=3 value_type=[value_type_char] has_index_col=True
|
||||
json = make_json header=["A"] data=[['a', 'a']] all_rows=3 value_type=[value_type_char] has_index_col=True get_child_node="get_row"
|
||||
vis . should_equal json
|
||||
|
||||
g = data.t.aggregate ["A", "B"] [Aggregate_Column.Average "C"] . at "Average C"
|
||||
vis2 = Visualization.prepare_visualization g 1
|
||||
json2 = make_json header=["Average C"] data=[[4.0]] all_rows=2 value_type=[value_type_float] has_index_col=True
|
||||
json2 = make_json header=["Average C"] data=[[4.0]] all_rows=2 value_type=[value_type_float] has_index_col=True get_child_node="get_row"
|
||||
vis2 . should_equal json2
|
||||
|
||||
group_builder.specify "should visualize dataframe tables" <|
|
||||
vis = Visualization.prepare_visualization data.t2 1
|
||||
value_type_int = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Integer"], ["display_text", "Integer (64 bits)"], ["bits", 64]]
|
||||
json = make_json header=["A", "B", "C"] data=[[1], [4], [7]] all_rows=3 value_type=[value_type_int, value_type_int, value_type_int] has_index_col=True
|
||||
json = make_json header=["A", "B", "C"] data=[[1], [4], [7]] all_rows=3 value_type=[value_type_int, value_type_int, value_type_int] has_index_col=True get_child_node="get_row"
|
||||
vis . should_equal json
|
||||
|
||||
group_builder.specify "should visualize dataframe columns" <|
|
||||
vis = Visualization.prepare_visualization (data.t2.at "A") 2
|
||||
value_type_int = JS_Object.from_pairs [["type", "Value_Type"], ["constructor", "Integer"], ["display_text", "Integer (64 bits)"], ["bits", 64]]
|
||||
json = make_json header=["A"] data=[[1, 2]] all_rows=3 value_type=[value_type_int] has_index_col=True
|
||||
json = make_json header=["A"] data=[[1, 2]] all_rows=3 value_type=[value_type_int] has_index_col=True get_child_node="get_row"
|
||||
vis . should_equal json
|
||||
|
||||
group_builder.specify "should handle Vectors" <|
|
||||
vis = Visualization.prepare_visualization [1, 2, 3] 2
|
||||
json = JS_Object.from_pairs [["type", "Vector"], ["all_rows_count", 3], ["json", [1, 2]]]
|
||||
json = JS_Object.from_pairs [["type", "Vector"], ["all_rows_count", 3], ["json", [1, 2]], ["get_child_node", "at"]]
|
||||
vis . should_equal json.to_text
|
||||
|
||||
vis2 = Visualization.prepare_visualization [[1, 2], [3, 4]] 2
|
||||
json2 = JS_Object.from_pairs [["type", "Matrix"], ["all_rows_count", 2], ["json", [[1, 2], [3, 4]]], ["column_count", 2]]
|
||||
json2 = JS_Object.from_pairs [["type", "Matrix"], ["all_rows_count", 2], ["json", [[1, 2], [3, 4]]], ["column_count", 2], ["get_child_node", "at"]]
|
||||
vis2 . should_equal json2.to_text
|
||||
|
||||
group_builder.specify "should handle Arrays" <|
|
||||
vis = Visualization.prepare_visualization ([1, 2, 3] . to_array) 2
|
||||
json = JS_Object.from_pairs [["type", "Vector"], ["all_rows_count", 3], ["json", [1, 2]]]
|
||||
json = JS_Object.from_pairs [["type", "Vector"], ["all_rows_count", 3], ["json", [1, 2]], ["get_child_node", "at"]]
|
||||
vis . should_equal json.to_text
|
||||
|
||||
group_builder.specify "should handle other datatypes" <|
|
||||
|
Loading…
Reference in New Issue
Block a user