diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Duplicate_Rows_Method.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Duplicate_Rows_Method.enso new file mode 100644 index 000000000000..044164cda813 --- /dev/null +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Duplicate_Rows_Method.enso @@ -0,0 +1,29 @@ +from Standard.Base import all +import project.Internal.Widget_Helpers +import Standard.Base.Errors.Common.Missing_Argument +import Standard.Base.Errors.Deprecated.Deprecated +import Standard.Base.Metadata.Display +import Standard.Base.Metadata.Widget +from Standard.Base.Metadata.Choice import Option +from Standard.Base.Metadata.Widget import Single_Choice +from Standard.Base.Widget_Helpers import make_any_selector, make_format_chooser + +import project.Column_Ref.Column_Ref +import project.Expression.Expression +import project.Internal.Table_Ref.Table_Ref +import project.Internal.Widget_Helpers +from project.Internal.Filter_Condition_Helpers import make_filter_column + +type Duplicate_Rows_Method + Integer_Range from:(Integer | Column_Ref | Expression) to:(Integer | Column_Ref | Expression) step:Integer=1 + + Date_Range from to step:Integer=1 period:Date_Period + + ## PRIVATE + Create a widget for operation + default_widget table:Table_Ref display:Display=..Always -> Widget = + integer_input_column = Widget_Helpers.make_column_ref_by_name_selector table add_number=True + integer_range = Option "..Integer_Range" "..Integer_Range" [["from", integer_input_column], ["to", integer_input_column]] + date_input_column = Widget_Helpers.make_column_ref_by_name_selector table add_date=True + date_range = Option "..Date_Range" "..Date_Range" [["from", date_input_column], ["to", date_input_column]] + Single_Choice [integer_range, date_range] display=display diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Main.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Main.enso index 74e5ca8d432f..419e590dcf1a 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Main.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Main.enso @@ -18,6 +18,8 @@ export project.Data_Formatter.Data_Formatter export project.Delimited.Delimited_Format.Delimited_Format export project.Delimited.Quote_Style.Quote_Style +export project.Duplicate_Rows_Method.Duplicate_Rows_Method + export project.Excel.Excel_Format.Excel_Format export project.Excel.Excel_Range.Excel_Range export project.Excel.Excel_Workbook.Excel_Workbook 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 6c9551c5d21d..9a221bd4f8bd 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 @@ -31,6 +31,7 @@ import project.Columns_To_Keep.Columns_To_Keep import project.Constants.Previous_Value import project.Constants.Report_Unmatched import project.Data_Formatter.Data_Formatter +import project.Duplicate_Rows_Method.Duplicate_Rows_Method import project.Delimited.Delimited_Format.Delimited_Format import project.Expression.Expression import project.Expression.Expression_Error @@ -3779,6 +3780,23 @@ type Table offset self (columns : Vector (Integer | Text | Regex | By_Type) = Missing_Argument.throw "columns") n:Integer=-1 fill_with:Fill_With=..Nothing (group_by : Vector | Text | Integer | Regex = []) (order_by : Vector | Text = []) set_mode:Set_Mode=..Add on_problems:Problem_Behavior=..Report_Warning -> Table = Offset_Helper.table_offset_impl self columns n fill_with group_by order_by set_mode on_problems + @over Duplicate_Rows_Method.default_widget + generate_rows self over:Duplicate_Rows_Method as:Text="" = + resolved_as = if as.is_empty then "generate_rows_id" else as + resolve_to_from value = + case value of + _ : Integer -> self.make_constant_column value + _ : Column_Ref -> (self:Table_Ref).resolve value + _ : Expression -> self.evaluate_expression value ..Report_Warning + + x = case over of + Duplicate_Rows_Method.Integer_Range from to step -> + from_column = resolve_to_from from + to_column = resolve_to_from to + range_col = from_column.zip to_column f->t->(f.up_to t step=step) + self.set range_col as=resolved_as + x.expand_to_rows resolved_as + ## PRIVATE column_naming_helper : Column_Naming_Helper column_naming_helper self = Column_Naming_Helper.in_memory diff --git a/test/Table_Tests/src/Common_Table_Operations/Generate_Rows_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Generate_Rows_Spec.enso new file mode 100644 index 000000000000..31aa29cead52 --- /dev/null +++ b/test/Table_Tests/src/Common_Table_Operations/Generate_Rows_Spec.enso @@ -0,0 +1,71 @@ +from Standard.Base import all +from Standard.Test import all +from Standard.Table import all + +from Standard.Database.Errors import Unsupported_Database_Operation +import Standard.Database.Feature.Feature +from Standard.Base.Errors.Common import Missing_Argument, Floating_Point_Equality +from Standard.Table.Errors import Missing_Input_Columns + +from project.Common_Table_Operations.Util import run_default_backend +import project.Common_Table_Operations.Util +import project.Util as Test_Utils + +main filter=Nothing = run_default_backend add_specs filter + +add_specs suite_builder setup = + if setup.is_feature_supported Feature.Offset then (add_offset_specs suite_builder setup) else + suite_builder.group setup.prefix+"Table.offset" group_builder-> + group_builder.specify "offset should report unsupported" <| + table_builder = setup.light_table_builder + t = table_builder [["ix", [1, 2, 3, 4, 5]], ["X", [100, 3, Nothing, 4, 12]], ["Y", [100, 4, 2, Nothing, 11]]] + t2 = t.offset ["X"] + t2.should_fail_with (Unsupported_Database_Operation.Error "offset") + c = t.at 0 + c2 = c.offset + c2.should_fail_with (Unsupported_Database_Operation.Error "offset") + +add_offset_specs suite_builder setup = + prefix = setup.prefix + build_sorted_table = Util.build_sorted_table setup + suite_builder.group prefix+"Table.Offset with default fill strategy (Text Values)" group_builder-> + t1 = build_sorted_table [["Text Values", ["A", "B", "C"]]] + t2 = build_sorted_table [["Text Values", ["A", "B", "C"]], ["NumRows", [1, 0, 2]]] + t3 = build_sorted_table [["Text Values", ["A", "B", "C"]], ["Start", [1, 0, 2]], ["Stop", [3, 0, 3]]] + t4 = build_sorted_table [["Text Values", ["A", "B", "C"]], ["Start", [1, 0, 2]], ["Stop", [5, 0, 5]]] + group_builder.specify "Works with Integer_Range constant values and default step" <| + t1.generate_rows (..Integer_Range 0 2) . should_equal ignore_order=setup.is_database + Table.new [["Text Values", ["A", "A", "B", "B", "C", "C"]], ["generate_rows_id", [0, 1, 0, 1, 0, 1]]] + group_builder.specify "Works with Integer_Range constant and column value" <| + t2.generate_rows (..Integer_Range 0 (..Name 'NumRows')) . should_equal ignore_order=setup.is_database + Table.new [["Text Values", ["A", "C", "C"]], ["NumRows", [1, 2, 2]], ["generate_rows_id", [0, 0, 1]]] + group_builder.specify "Works with Integer_Range column value and constant" <| + t2.generate_rows (..Integer_Range (..Name 'NumRows') 2) . should_equal ignore_order=setup.is_database + Table.new [["Text Values", ["A", "B", "B"]], ["NumRows", [1, 0, 0]], ["generate_rows_id", [1, 0, 1]]] + group_builder.specify "Works with Integer_Range 2 columns" <| + t3.generate_rows (..Integer_Range (..Name 'Start') (..Name 'Stop')) . should_equal ignore_order=setup.is_database + Table.new [["Text Values", ["A", "A", "C"]], ["Start", [1, 1, 2]], ["Stop", [3, 3, 3]], ["generate_rows_id", [1, 2, 2]]] + + group_builder.specify "Works with Integer_Range constant values and a 2 step" <| + t1.generate_rows (..Integer_Range 0 4 2) . should_equal ignore_order=setup.is_database + Table.new [["Text Values", ["A", "A", "B", "B", "C", "C"]], ["generate_rows_id", [0, 2, 0, 2, 0, 2]]] + group_builder.specify "Works with Integer_Range constant and column value and a 2 step" <| + t2.generate_rows (..Integer_Range -2 (..Name 'NumRows') 2) . should_equal ignore_order=setup.is_database + Table.new [["Text Values", ["A", "A", "B", "C", "C"]], ["NumRows", [1, 1, 0, 2, 2]], ["generate_rows_id", [-2, 0, -2, -2, 0]]] + group_builder.specify "Works with Integer_Range column value and constant and a 2 step" <| + t2.generate_rows (..Integer_Range (..Name 'NumRows') 4 2) . should_equal ignore_order=setup.is_database + Table.new [["Text Values", ["A", "A", "B", "B", "C"]], ["NumRows", [1, 1, 0, 0, 2]], ["generate_rows_id", [1, 3, 0, 2, 2]]] + group_builder.specify "Works with Integer_Range 2 columns and a 2 step" <| + t4.generate_rows (..Integer_Range (..Name 'Start') (..Name 'Stop') 2) . should_equal ignore_order=setup.is_database + Table.new [["Text Values", ["A", "A", "C", "C"]], ["Start", [1, 1, 2, 2]], ["Stop", [5, 5, 5, 5]], ["generate_rows_id", [1, 3, 2, 4]]] + + group_builder.specify "Works with Integer_Range column and expression" <| + t3.generate_rows (..Integer_Range (..Name 'Start') (expr '[Stop]+1')) . should_equal ignore_order=setup.is_database + Table.new [["Text Values", ["A", "A", "A", "B", "C", "C"]], ["Start", [1, 1, 1, 0, 2, 2]], ["Stop", [3, 3, 3, 0, 3, 3]], ["generate_rows_id", [1, 2, 3, 0, 2, 3]]] + + group_builder.specify "Can rename generated id colummn" <| + t3.generate_rows (..Integer_Range (..Name 'Start') (expr '[Stop]+1')) "MyColumnName" . should_equal ignore_order=setup.is_database + Table.new [["Text Values", ["A", "A", "A", "B", "C", "C"]], ["Start", [1, 1, 1, 0, 2, 2]], ["Stop", [3, 3, 3, 0, 3, 3]], ["MyColumnName", [1, 2, 3, 0, 2, 3]]] + + +