diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso index 718ebc3eb1da..6435797d380e 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso @@ -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. diff --git a/test/Table_Tests/src/In_Memory/Table_Spec.enso b/test/Table_Tests/src/In_Memory/Table_Spec.enso index fecd48c0ff0c..934b3dabdb86 100644 --- a/test/Table_Tests/src/In_Memory/Table_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Table_Spec.enso @@ -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]]]"