Skip to content

Commit

Permalink
New Table.input function for GUI allowing auto parsing and type control
Browse files Browse the repository at this point in the history
  • Loading branch information
jdunkerley committed Nov 14, 2024
1 parent 19f4242 commit 250b25c
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
42 changes: 42 additions & 0 deletions distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,48 @@ type Table
columns = header.map_with_index i-> name-> [name, rows.map (_.at i)]
Table.new columns

## GROUP Standard.Base.Constants
ICON table_edit
Creates a new table from a set of columns parsing the resulting table.

Arguments:
- columns: A set of either Column objects or set of name, data and
optionally type to construct a column from from. If the data is passed
as Vector Text then it will be parsed into the specified type (defaults
to auto detect).

Returns:
- A Table of all of the input data.

! Error Conditions

- If the vector is improperly defined, an error is returned.
- If there are no columns, an error is returned.
- If column names are not distinct, an error is returned.
- If any columns have an inconsistent number of records, an error is returned.

? Unique Names
Column names must be unique. If a column name is repeated, an error is
thrown.

? Consistent Row Count
All columns must have the same number of rows. If a column has a
different number of entries, an error is thrown.
input : Vector (Vector | Column) -> Table
input columns =
throw_bad_column = Error.throw (Illegal_Argument.Error "Each column must be represented as a Vector of column name (Text), data (vector like elements) and optionally a type (Value_Type), or an existing column.")
resolved_columns = columns.map c-> case c of
_ : Column -> c
_ : Vector -> if c.length < 2 || (c.first . is_a Text).not then throw_bad_column else
raw_column = Column.from_vector c.first (c.at 1)
target_type = c.get 2 Auto
if target_type != Auto && (target_type.is_a Value_Type).not then throw_bad_column else
case raw_column.value_type.is_text of
True -> if target_type != Auto && target_type.is_text then raw_column.cast target_type else raw_column.parse target_type
False -> if target_type == Auto then raw_column else raw_column.cast target_type
_ -> throw_bad_column
resolved_columns.if_not_error <| Table.new resolved_columns

## PRIVATE

A table.
Expand Down
38 changes: 38 additions & 0 deletions test/Table_Tests/src/In_Memory/Table_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,44 @@ add_specs suite_builder =
r2.at "foo" . to_vector . should_equal []
r2.at "bar" . to_vector . should_equal []

group_builder.specify "should allow inputting a table without types" <|
r = Table.input [["foo", [1, 2, 3]], ["bar", [False, True, False]]]
r.column_names . should_equal ["foo", "bar"]
r.columns.map .value_type . should_equal [Value_Type.Integer, Value_Type.Boolean]

r_2 = Table.input [["foo", ["1", "2", "3"]], ["bar", ["False", "True", "false"]]]
r_2.column_names . should_equal ["foo", "bar"]
r_2.columns.map .value_type . should_equal [Value_Type.Integer, Value_Type.Boolean]

r_3 = Table.input [["foo", ["1.0", "2.0", "3.0"]], ["bar", [False, True, False]]]
r_3.column_names . should_equal ["foo", "bar"]
r_3.columns.map .value_type . should_equal [Value_Type.Float, Value_Type.Boolean]

r_4 = Table.input [["foo", ["1", "2", "3"]], ["bar", [Date.new 2023 1 4, Nothing, Date.new 2024 10 2]], ["baz", ["1.0", "2.0", "3.0"]]]
r_4.column_names . should_equal ["foo", "bar", "baz"]
r_4.columns.map .value_type . should_equal [Value_Type.Integer, Value_Type.Date, Value_Type.Float]

r_5 = Table.input [["foo", ["2023-01-04", "2024-10-02"]], ["bar", ["1.0", "2.0"]], ["baz", ["12:34:56", "23:45"]]]
r_5.column_names . should_equal ["foo", "bar", "baz"]
r_5.columns.map .value_type . should_equal [Value_Type.Date, Value_Type.Float, Value_Type.Time]

group_builder.specify "should allow inputting a table with types" <|
r = Table.input [["foo", [1, 2, 3], Value_Type.Float], ["bar", [False, True, False]]]
r.column_names . should_equal ["foo", "bar"]
r.columns.map .value_type . should_equal [Value_Type.Float, Value_Type.Boolean]

r_2 = Table.input [["foo", ["1", "2", "3"], Value_Type.Float], ["bar", ["False", "True", "false"], Value_Type.Text]]
r_2.column_names . should_equal ["foo", "bar"]
r_2.columns.map .value_type . should_equal [Value_Type.Float, Value_Type.Text]

r_3 = Table.input [["foo", ["1.0", "2.0", "3.0"], Value_Type.Integer], ["bar", ["False", "True", "False"], Auto]]
r_3.column_names . should_equal ["foo", "bar"]
r_3.columns.map .value_type . should_equal [Value_Type.Float, Value_Type.Boolean]

r_4 = Table.input [["foo", ["2023-01-04", "2024-10-02"], Value_Type.Date], ["bar", ["1.0", "2.0"], Value_Type.Text], ["baz", ["12:34:56", "23:45"]]]
r_4.column_names . should_equal ["foo", "bar", "baz"]
r_4.columns.map .value_type . should_equal [Value_Type.Date, Value_Type.Text, Value_Type.Time]

group_builder.specify "should allow creating Enso code from a Table" <|
r = Table.new [["foo", [1, 2, 3]], ["bar", [False, True, False]]]
r.pretty . should_equal "Table.new [['foo', [1, 2, 3]], ['bar', [False, True, False]]]"
Expand Down

0 comments on commit 250b25c

Please sign in to comment.