diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Table.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Table.enso index 843c3196d66a..ee10a13a0759 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Table.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Table.enso @@ -56,6 +56,7 @@ import project.Internal.Aggregate_Helper import project.Internal.Base_Generator import project.Internal.Common.Database_Join_Helper import project.Internal.Common.Lookup_Query_Helper +import project.Internal.Common.Offset_Helpers import project.Internal.Common.Row_Number_Helpers import project.Internal.DB_Data_Link_Helpers import project.Internal.Helpers @@ -3180,9 +3181,38 @@ type DB_Table @default (self-> Widget_Helpers.make_fill_default_value_selector2) @group_by Widget_Helpers.make_column_name_multi_selector @order_by Widget_Helpers.make_order_by_selector - 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 = - _ = [columns, n, fill_with, group_by, order_by, set_mode, on_problems] - Error.throw (Unsupported_Database_Operation.Error "offset") + 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) -> DB_Table = + Feature.Offset.if_supported_else_throw self.connection.dialect "offset" <| + problem_builder = Problem_Builder.new error_on_missing_columns=True + grouping_columns = self.columns_helper.select_columns_helper group_by Case_Sensitivity.Default True problem_builder + grouping_columns.each column-> + if column.value_type.is_floating_point then + problem_builder.report_other_warning (Floating_Point_Equality.Error column.name) + ordering = Table_Helpers.resolve_order_by self.columns order_by problem_builder + resolved_columns = self.columns_helper.select_columns_helper columns Case_Sensitivity.Default True problem_builder + problem_builder.attach_problems_before on_problems <| if columns.is_empty then self else + order_descriptors = case ordering.is_empty of + False -> ordering.map element-> + column = element.column + associated_selector = element.associated_selector + self.connection.dialect.prepare_order_descriptor column associated_selector.direction text_ordering=Nothing + True -> case self.default_ordering of + Nothing -> Error.throw (Illegal_Argument.Error "The table has no existing ordering (e.g. from a `sort` operation or primary key). `offset` requires an ordering in database.") + descriptors -> descriptors + grouping_expressions = (grouping_columns.map _.as_internal).map .expression + new_exprs = resolved_columns.map c->(Offset_Helpers.make_offset n (c.as_internal) order_descriptors grouping_expressions) + + type_mapping = self.connection.dialect.get_type_mapping + infer_from_database_callback expression = + SQL_Type_Reference.new self.connection self.context expression + new_type_refs = new_exprs.map expr->(type_mapping.infer_return_type infer_from_database_callback "OFFSET" [] expr) + + new_names = resolved_columns.map c->(if set_mode==Set_Mode.Add then self.column_naming_helper.function_name "offset" [c, n, fill_with] else c.name) + new_columns = (new_names.zip new_type_refs).zip new_exprs a->b->(Internal_Column.Value a.first a.second b) + + updated_table = new_columns.fold self t-> col-> + t.set (self.make_column col) + updated_table.as_subquery ## PRIVATE diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso index 0e829a6994fc..a52773c17fed 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso @@ -195,7 +195,7 @@ type SQL_Generator order_part = (SQL_Builder.join ", " orders) . prefix_if_present " ORDER BY " limit_part = case ctx.limit of - Nothing -> "" + Nothing -> "TOP 100 PERCENT " _ : Integer -> dialect.get_limit_sql_modifier ctx.limit extensions = ctx.extensions.map extension-> @@ -467,7 +467,7 @@ base_dialect_operations = nulls = [["IS_NULL", make_right_unary_op "IS NULL"], ["FILL_NULL", make_function "COALESCE"]] contains = [["IS_IN", make_is_in], ["IS_IN_COLUMN", make_is_in_column]] types = [simple_cast] - windows = [["ROW_NUMBER", make_row_number], ["ROW_NUMBER_IN_GROUP", make_row_number_in_group]] + windows = [["ROW_NUMBER", make_row_number], ["ROW_NUMBER_IN_GROUP", make_row_number_in_group], ["LEAD", make_lead_lag "LEAD"], ["LAG", make_lead_lag "LAG"]] base_dict = Dictionary.from_vector (arith + logic + compare + functions + agg + counts + text + nulls + contains + types + windows) Dialect_Operations.Value base_dict @@ -554,6 +554,20 @@ make_row_number (arguments : Vector) (metadata : Row_Number_Metadata) = if argum SQL_Builder.code "PARTITION BY " ++ SQL_Builder.join ", " grouping SQL_Builder.code "(row_number() OVER (" ++ group_part ++ " ORDER BY " ++ SQL_Builder.join ", " ordering ++ ") * " ++ step.paren ++ " + " ++ offset.paren ++ ")" +## PRIVATE +make_lead_lag lead_lag:Text arguments:Vector metadata:Row_Number_Metadata -> SQL_Builder = if arguments.length < 3 then Error.throw (Illegal_State.Error "Wrong amount of parameters in LEAD/LAG IR. This is a bug in the Database library.") else + n = arguments.at 0 + colName = arguments.at 1 + + ordering_and_grouping = arguments.drop 2 + ordering = ordering_and_grouping.drop (..Last metadata.groupings_count) + grouping = ordering_and_grouping.take (..Last metadata.groupings_count) + + group_part = if grouping.length == 0 then "" else + SQL_Builder.code "PARTITION BY " ++ SQL_Builder.join ", " grouping + + SQL_Builder.code "(" ++ lead_lag ++ "(" ++ colName ++ ", " ++ n ++ ", NULL) OVER (" ++ group_part ++ " ORDER BY " ++ SQL_Builder.join ", " ordering ++ "))" + ## PRIVATE A helper for `lookup_and_replace`, and perhaps other operation. It creates an expression that returns a row number within a group. diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Common/Offset_Helpers.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Common/Offset_Helpers.enso new file mode 100644 index 000000000000..f90bfbb9c34c --- /dev/null +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Common/Offset_Helpers.enso @@ -0,0 +1,13 @@ +from Standard.Base import all + +import project.Internal.IR.Operation_Metadata +import project.Internal.IR.Order_Descriptor.Order_Descriptor +import project.Internal.IR.SQL_Expression.SQL_Expression +import project.Internal.IR.Internal_Column.Internal_Column + +## PRIVATE +make_offset (n : Integer) (colName: Internal_Column) (order_descriptors : Vector Order_Descriptor) (grouping_expressions : Vector SQL_Expression) -> SQL_Expression = + params = [SQL_Expression.Literal n.abs.to_text, colName.expression] + order_descriptors + grouping_expressions + metadata = Operation_Metadata.Row_Number_Metadata.Value grouping_expressions.length + lead_lag = if n<0 then "LAG" else "LEAD" + SQL_Expression.Operation lead_lag params metadata diff --git a/distribution/lib/Standard/Microsoft/0.0.0-dev/src/Internal/SQLServer_Dialect.enso b/distribution/lib/Standard/Microsoft/0.0.0-dev/src/Internal/SQLServer_Dialect.enso index db420cb41ed8..17c1475d307d 100644 --- a/distribution/lib/Standard/Microsoft/0.0.0-dev/src/Internal/SQLServer_Dialect.enso +++ b/distribution/lib/Standard/Microsoft/0.0.0-dev/src/Internal/SQLServer_Dialect.enso @@ -292,6 +292,7 @@ type SQLServer_Dialect Feature.Join -> True Feature.Union -> True Feature.Aggregate -> True + Feature.Offset -> True _ -> False ## PRIVATE 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 2aaaf63716a2..1b3adbf81b99 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 @@ -147,9 +147,10 @@ type Table Error.throw (Illegal_Argument.Error "Each column must be represented by a pair whose first element is the column name and the second element is a vector of elements that will constitute that column, or an existing column. Got: "+columns.to_text) cols = columns.map on_problems=No_Wrap.Value c-> case c of - v : Vector -> - if v.length != 2 then invalid_input_shape else - Column.from_vector (v.at 0) (v.at 1) . java_column + v : Vector -> case v.length of + 2 -> Column.from_vector (v.at 0) (v.at 1) . java_column + 3 -> Column.from_vector (v.at 0) (v.at 1) (v.at 2) . java_column + _ -> invalid_input_shape col : Column -> col.java_column _ -> invalid_input_shape Panic.recover Illegal_Argument <| diff --git a/test/Table_Tests/src/Common_Table_Operations/Offset_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Offset_Spec.enso index 1ab77de5a6d7..3ee90a83cf91 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Offset_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Offset_Spec.enso @@ -9,6 +9,7 @@ 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 @@ -31,7 +32,7 @@ add_offset_specs suite_builder setup = c = t.at 0 c_nothings = t.at 1 c_zero_rows = t.take 0 . at 0 - suite_builder.group prefix+"Column.Offset with default fill strategy" group_builder-> + if setup.is_database.not then suite_builder.group prefix+"Column.Offset with default fill strategy" group_builder-> group_builder.specify "Works with default values" <| r = c.offset r.to_vector . should_equal [Nothing, 1, 2] @@ -54,7 +55,7 @@ add_offset_specs suite_builder setup = group_builder.specify "Works with zero rows" <| r = c_zero_rows.offset r.to_vector . should_equal [] - suite_builder.group prefix+"Column.Offset with closest value fill strategy" group_builder-> + if setup.is_database.not then suite_builder.group prefix+"Column.Offset with closest value fill strategy" group_builder-> group_builder.specify "Negative n shifts the values down" <| r = c.offset -1 ..Closest_Value r.to_vector . should_equal [1, 1, 2] @@ -79,7 +80,7 @@ add_offset_specs suite_builder setup = group_builder.specify "Works with positive n and column of nothings" <| r = c_nothings.offset 1 ..Closest_Value r.to_vector . should_equal [Nothing, Nothing, Nothing] - suite_builder.group prefix+"Column.Offset with wrap around fill strategy" group_builder-> + if setup.is_database.not then suite_builder.group prefix+"Column.Offset with wrap around fill strategy" group_builder-> group_builder.specify "Negative n shifts the values down" <| r = c.offset -1 ..Wrap_Around r.to_vector . should_equal [3, 1, 2] @@ -110,7 +111,7 @@ add_offset_specs suite_builder setup = group_builder.specify "Works with positive n and column of nothings" <| r = c_nothings.offset 1 ..Wrap_Around r.to_vector . should_equal [Nothing, Nothing, Nothing] - suite_builder.group prefix+"Column.Offset with constant fill strategy" pending="TODO - constant fill strategy" group_builder-> + if setup.is_database.not then suite_builder.group prefix+"Column.Offset with constant fill strategy" pending="TODO - constant fill strategy" group_builder-> group_builder.specify "Negative n shifts the values down" <| r = c.offset -1 42 r.to_vector . should_equal [42, 1, 2] @@ -138,7 +139,7 @@ add_offset_specs suite_builder setup = group_builder.specify "Can create mixed colums" <| r = c.offset -1 "42" r.to_vector . should_equal ["42", 1, 2] - suite_builder.group prefix+"Works in Table.set expressions with default" group_builder-> + if setup.is_database.not then suite_builder.group prefix+"Works in Table.set expressions with default" group_builder-> group_builder.specify "Works with default values" <| r = t.set (expr 'offset([A])') . at "offset([A])" r.to_vector . should_equal [Nothing, 1, 2] @@ -158,326 +159,331 @@ add_offset_specs suite_builder setup = r = t.set (expr 'offset([A], 1024)') . at "offset([A], 1024)" r.to_vector . should_equal [Nothing, Nothing, Nothing] suite_builder.group prefix+"Table.Offset with default fill strategy" group_builder-> + colA = ["A", [1, 2, 3]] + t1 = build_sorted_table [colA] group_builder.specify "Works with default values" <| - r = t.offset ["A"] - r . at "offset([A], -1, Fill_With.Nothing)" . to_vector . should_equal [Nothing, 1, 2] + t1.offset ["A"] . should_equal ignore_order=setup.is_database + Table.input [colA, ["offset([A], -1, Fill_With.Nothing)", [Nothing, 1, 2]]] group_builder.specify "Works with negative n values" <| - r = t.offset ["A"] -2 - r . at "offset([A], -2, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, 1] + t1.offset ["A"] -2 . should_equal ignore_order=setup.is_database + Table.input [colA, ["offset([A], -2, Fill_With.Nothing)", [Nothing, Nothing, 1]]] group_builder.specify "Works with positive n values (n=1)" <| - r = t.offset ["A"] 1 - r . at "offset([A], 1, Fill_With.Nothing)" . to_vector . should_equal [2, 3, Nothing] + t1.offset ["A"] 1 . should_equal ignore_order=setup.is_database + Table.input [colA, ["offset([A], 1, Fill_With.Nothing)", [2, 3, Nothing]]] group_builder.specify "Works with positive n values (n=2)" <| - r = t.offset ["A"] 2 - r . at "offset([A], 2, Fill_With.Nothing)" . to_vector . should_equal [3, Nothing, Nothing] + t1.offset ["A"] 2 . should_equal ignore_order=setup.is_database + Table.input [colA, ["offset([A], 2, Fill_With.Nothing)", [3, Nothing, Nothing]]] group_builder.specify "Zero n is a no-op" <| - r = t.offset ["A"] 0 - r . at "offset([A], 0, Fill_With.Nothing)" . to_vector . should_equal [1, 2, 3] + t1.offset ["A"] 0 . should_equal ignore_order=setup.is_database + Table.input [colA, ["offset([A], 0, Fill_With.Nothing)" , [1, 2, 3]]] group_builder.specify "Large negative n values work" <| - r = t.offset ["A"] -1024 - r . at "offset([A], -1024, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, Nothing] + t1.offset ["A"] -1024 . should_equal ignore_order=setup.is_database + Table.input [colA, ["offset([A], -1024, Fill_With.Nothing)", [Nothing, Nothing, Nothing], Value_Type.Integer]] group_builder.specify "Large positive n values work" <| - r = t.offset ["A"] 1024 - r . at "offset([A], 1024, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, Nothing] + t1.offset ["A"] 1024 . should_equal ignore_order=setup.is_database + Table.input [colA, ["offset([A], 1024, Fill_With.Nothing)", [Nothing, Nothing, Nothing], Value_Type.Integer]] group_builder.specify "Works with zero rows" <| - r = t.take 0 . offset ["A"] - r . at "offset([A], -1, Fill_With.Nothing)" . to_vector . should_equal [] + build_sorted_table [["A",[], Value_Type.Integer],["B",[], Value_Type.Integer]] . sort ["B"] . offset ["A"] -1 . should_equal ignore_order=setup.is_database + Table.input [["A", [], Value_Type.Integer], ["B", [], Value_Type.Integer], ["offset([A], -1, Fill_With.Nothing)", [], Value_Type.Integer]] suite_builder.group prefix+"Table.Offset with default fill strategy (Text Values)" group_builder-> + colText = ["Text Values", ["A", "B", "C"]] + t1 = build_sorted_table [colText] group_builder.specify "Works with default values" <| - r = t.offset ["Text Values"] - r . at "offset([Text Values], -1, Fill_With.Nothing)" . to_vector . should_equal [Nothing, "A", "B"] + t1.offset ["Text Values"] . should_equal ignore_order=setup.is_database + Table.input [colText, ["offset([Text Values], -1, Fill_With.Nothing)", [Nothing, "A", "B"]]] group_builder.specify "Works with negative n values" <| - r = t.offset ["Text Values"] -2 - r . at "offset([Text Values], -2, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, "A"] + t1.offset ["Text Values"] -2 . should_equal ignore_order=setup.is_database + Table.input [colText, ["offset([Text Values], -2, Fill_With.Nothing)", [Nothing, Nothing, "A"]]] group_builder.specify "Works with positive n values (n=1)" <| - r = t.offset ["Text Values"] 1 - r . at "offset([Text Values], 1, Fill_With.Nothing)" . to_vector . should_equal ["B", "C", Nothing] + t1.offset ["Text Values"] 1 . should_equal ignore_order=setup.is_database + Table.input [colText, ["offset([Text Values], 1, Fill_With.Nothing)", ["B", "C", Nothing]]] group_builder.specify "Works with positive n values (n=2)" <| - r = t.offset ["Text Values"] 2 - r . at "offset([Text Values], 2, Fill_With.Nothing)" . to_vector . should_equal ["C", Nothing, Nothing] + t1.offset ["Text Values"] 2 . should_equal ignore_order=setup.is_database + Table.input [colText, ["offset([Text Values], 2, Fill_With.Nothing)", ["C", Nothing, Nothing]]] suite_builder.group prefix+"Table.Offset with closest value fill strategy" group_builder-> - group_builder.specify "Negative n shifts the values down" <| - r = t.offset ["A"] -1 ..Closest_Value - r . at "offset([A], -1, Fill_With.Closest_Value)" . to_vector . should_equal [1, 1, 2] + colA = ["A", [1, 2, 3]] + colB = ["B", [Nothing, Nothing, Nothing], Value_Type.Integer] + t1 = build_sorted_table [colA, colB] + group_builder.specify "Negative n shifts the values downX" <| + t1.offset ["A"] -1 ..Closest_Value . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], -1, Fill_With.Closest_Value)", [1, 1, 2]]] group_builder.specify "Positive n shifts the values up" <| - r = t.offset ["A"] 1 ..Closest_Value - r . at "offset([A], 1, Fill_With.Closest_Value)" . to_vector . should_equal [2, 3, 3] + t1.offset ["A"] 1 ..Closest_Value . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], 1, Fill_With.Closest_Value)", [2, 3, 3]]] group_builder.specify "Zero n is a no-op" <| - r = t.offset ["A"] 0 ..Closest_Value - r . at "offset([A], 0, Fill_With.Closest_Value)" . to_vector . should_equal [1, 2, 3] + t1.offset ["A"] 0 ..Closest_Value . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], 0, Fill_With.Closest_Value)", [1, 2, 3]]] group_builder.specify "Large negative n values work" <| - r = t.offset ["A"] -1024 ..Closest_Value - r . at "offset([A], -1024, Fill_With.Closest_Value)" . to_vector . should_equal [1, 1, 1] + t1.offset ["A"] -1024 ..Closest_Value . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], -1024, Fill_With.Closest_Value)", [1, 1, 1]]] group_builder.specify "Large positive n values work" <| - r = t.offset ["A"] 1024 ..Closest_Value - r . at "offset([A], 1024, Fill_With.Closest_Value)" . to_vector . should_equal [3, 3, 3] + t1.offset ["A"] 1024 ..Closest_Value . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], 1024, Fill_With.Closest_Value)", [3, 3, 3]]] group_builder.specify "Works with zero rows" <| - r = t.take 0 . offset ["A"] -1 ..Closest_Value - r . at "offset([A], -1, Fill_With.Closest_Value)" . to_vector . should_equal [] + build_sorted_table [["A",[], Value_Type.Integer],["B",[], Value_Type.Integer]] . sort ["B"] . offset ["A"] -1 ..Closest_Value . should_equal ignore_order=setup.is_database + Table.input [["A", [], Value_Type.Integer], ["B", [], Value_Type.Integer], ["offset([A], -1, Fill_With.Closest_Value)", [], Value_Type.Integer]] group_builder.specify "Works with negative n and column of nothings" <| - r = t.offset ["B"] -1 ..Closest_Value - r . at "offset([B], -1, Fill_With.Closest_Value)" . to_vector . should_equal [Nothing, Nothing, Nothing] + t1.offset ["B"] -1 ..Closest_Value . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([B], -1, Fill_With.Closest_Value)", [Nothing, Nothing, Nothing], Value_Type.Integer]] group_builder.specify "Works with positive n and column of nothings" <| - r = t.offset ["B"] 1 ..Closest_Value - r . at "offset([B], 1, Fill_With.Closest_Value)" . to_vector . should_equal [Nothing, Nothing, Nothing] + t1.offset ["B"] 1 ..Closest_Value . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([B], 1, Fill_With.Closest_Value)", [Nothing, Nothing, Nothing], Value_Type.Integer]] suite_builder.group prefix+"Table.Offset with wrap around fill strategy" group_builder-> + colA = ["A", [1, 2, 3]] + colB = ["B", [Nothing, Nothing, Nothing], Value_Type.Integer] + t1 = build_sorted_table [colA, colB] group_builder.specify "Negative n shifts the values down" <| - r = t.offset ["A"] -1 ..Wrap_Around - r . at "offset([A], -1, Fill_With.Wrap_Around)" . to_vector . should_equal [3, 1, 2] + t1.offset ["A"] -1 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], -1, Fill_With.Wrap_Around)", [3, 1, 2]]] group_builder.specify "Positive n shifts the values up" <| - r = t.offset ["A"] 1 ..Wrap_Around - r . at "offset([A], 1, Fill_With.Wrap_Around)" . to_vector . should_equal [2, 3, 1] + t1.offset ["A"] 1 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], 1, Fill_With.Wrap_Around)", [2, 3, 1]]] group_builder.specify "Negative n shifts the values down (n=2)" <| - r = t.offset ["A"] -2 ..Wrap_Around - r . at "offset([A], -2, Fill_With.Wrap_Around)" . to_vector . should_equal [2, 3, 1] + t1.offset ["A"] -2 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], -2, Fill_With.Wrap_Around)", [2, 3, 1]]] group_builder.specify "Positive n shifts the values up (n=2)" <| - r = t.offset ["A"] 2 ..Wrap_Around - r . at "offset([A], 2, Fill_With.Wrap_Around)" . to_vector . should_equal [3, 1, 2] + t1.offset ["A"] 2 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], 2, Fill_With.Wrap_Around)", [3, 1, 2]]] group_builder.specify "Zero n is a no-op" <| - r = t.offset ["A"] 0 ..Wrap_Around - r . at "offset([A], 0, Fill_With.Wrap_Around)" . to_vector . should_equal [1, 2, 3] + t1.offset ["A"] 0 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], 0, Fill_With.Wrap_Around)", [1, 2, 3]]] group_builder.specify "Larger than num rows negative n values work" <| - r = t.offset ["A"] -4 ..Wrap_Around - r . at "offset([A], -4, Fill_With.Wrap_Around)" . to_vector . should_equal [3, 1, 2] + t1.offset ["A"] -4 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], -4, Fill_With.Wrap_Around)", [3, 1, 2]]] group_builder.specify "Larger than num rows positive n values work" <| - r = t.offset ["A"] 4 ..Wrap_Around - r . at "offset([A], 4, Fill_With.Wrap_Around)" . to_vector . should_equal [2, 3, 1] + t1.offset ["A"] 4 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], 4, Fill_With.Wrap_Around)", [2, 3, 1]]] group_builder.specify "Large negative n values work" <| - r = t.offset ["A"] -1024 ..Wrap_Around - r . at "offset([A], -1024, Fill_With.Wrap_Around)" . to_vector . should_equal [3, 1, 2] + t1.offset ["A"] -1024 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], -1024, Fill_With.Wrap_Around)", [3, 1, 2]]] group_builder.specify "Large positive n values work" <| - r = t.offset ["A"] 1024 ..Wrap_Around - r . at "offset([A], 1024, Fill_With.Wrap_Around)" . to_vector . should_equal [2, 3, 1] + t1.offset ["A"] 1024 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([A], 1024, Fill_With.Wrap_Around)", [2, 3, 1]]] group_builder.specify "Works with zero rows" <| - r = t.take 0 . offset ["A"] -1 ..Wrap_Around - r . at "offset([A], -1, Fill_With.Wrap_Around)" . to_vector . should_equal [] + build_sorted_table [["A",[], Value_Type.Integer],["B",[], Value_Type.Integer]] . sort ["B"] . offset ["A"] -1 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [["A", [], Value_Type.Integer], ["B", [], Value_Type.Integer], ["offset([A], -1, Fill_With.Wrap_Around)", [], Value_Type.Integer]] group_builder.specify "Works with negative n and column of nothings" <| - r = t.offset ["B"] -1 ..Wrap_Around - r . at "offset([B], -1, Fill_With.Wrap_Around)" . to_vector . should_equal [Nothing, Nothing, Nothing] + t1.offset ["B"] -1 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([B], -1, Fill_With.Wrap_Around)", [Nothing, Nothing, Nothing], Value_Type.Integer]] group_builder.specify "Works with positive n and column of nothings" <| - r = t.offset ["B"] 1 ..Wrap_Around - r . at "offset([B], 1, Fill_With.Wrap_Around)" . to_vector . should_equal [Nothing, Nothing, Nothing] + t1.offset ["B"] 1 ..Wrap_Around . should_equal ignore_order=setup.is_database + Table.input [colA, colB, ["offset([B], 1, Fill_With.Wrap_Around)", [Nothing, Nothing, Nothing], Value_Type.Integer]] suite_builder.group prefix+"Table.Offset works with grouping - default fill strategy" group_builder-> - t2 = build_sorted_table [["Group", ["A", "A", "A", "B", "B", "B", "B", "C", "C"]], ["Col", [1, 2, 3, 1, 2, 3, 4, 1, 2]]] + groupColumn = ["Group", ["A", "A", "A", "B", "B", "B", "B", "C", "C"]] + dataCol = ["Col", [1, 2, 3, 1, 2, 3, 4, 1, 2]] + t2 = build_sorted_table [groupColumn, dataCol] group_builder.specify "Negative n shifts the values down" <| - r = t2.offset ["Col"] -1 ..Nothing group_by=["Group"] - r . at "offset([Col], -1, Fill_With.Nothing)" . to_vector . should_equal [Nothing, 1, 2, Nothing, 1, 2, 3, Nothing, 1] + t2.offset ["Col"] -1 ..Nothing group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], -1, Fill_With.Nothing)", [Nothing, 1, 2, Nothing, 1, 2, 3, Nothing, 1]]] group_builder.specify "Positive n shifts the values up" <| - r = t2.offset ["Col"] 1 ..Nothing group_by=["Group"] - r . at "offset([Col], 1, Fill_With.Nothing)" . to_vector . should_equal [2, 3, Nothing, 2, 3, 4, Nothing, 2, Nothing] + t2.offset ["Col"] 1 ..Nothing group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 1, Fill_With.Nothing)", [2, 3, Nothing, 2, 3, 4, Nothing, 2, Nothing]]] group_builder.specify "Negative n shifts the values down (n=2)" <| - r = t2.offset ["Col"] -2 ..Nothing group_by=["Group"] - r . at "offset([Col], -2, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, 1, Nothing, Nothing, 1, 2, Nothing, Nothing] + t2.offset ["Col"] -2 ..Nothing group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], -2, Fill_With.Nothing)", [Nothing, Nothing, 1, Nothing, Nothing, 1, 2, Nothing, Nothing]]] group_builder.specify "Positive n shifts the values up (n=2)" <| - r = t2.offset ["Col"] 2 ..Nothing group_by=["Group"] - r . at "offset([Col], 2, Fill_With.Nothing)" . to_vector . should_equal [3, Nothing, Nothing, 3, 4, Nothing, Nothing, Nothing, Nothing] + t2.offset ["Col"] 2 ..Nothing group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 2, Fill_With.Nothing)", [3, Nothing, Nothing, 3, 4, Nothing, Nothing, Nothing, Nothing]]] group_builder.specify "Zero n is a no-op" <| - r = t2.offset ["Col"] 0 ..Nothing group_by=["Group"] - r . at "offset([Col], 0, Fill_With.Nothing)" . to_vector . should_equal [1, 2, 3, 1, 2, 3, 4, 1, 2] + t2.offset ["Col"] 0 ..Nothing group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 0, Fill_With.Nothing)", [1, 2, 3, 1, 2, 3, 4, 1, 2]]] group_builder.specify "Large negative n values work" <| - r = t2.offset ["Col"] -1024 ..Nothing group_by=["Group"] - r . at "offset([Col], -1024, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing] + t2.offset ["Col"] -1024 ..Nothing group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], -1024, Fill_With.Nothing)", [Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing], Value_Type.Integer]] group_builder.specify "Large positive n values work" <| - r = t2.offset ["Col"] 1024 ..Nothing group_by=["Group"] - r . at "offset([Col], 1024, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing] + t2.offset ["Col"] 1024 ..Nothing group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 1024, Fill_With.Nothing)", [Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing], Value_Type.Integer]] suite_builder.group prefix+"Table.Offset works with grouping - closest fill strategy" group_builder-> - t2 = build_sorted_table [["Group", ["A", "A", "A", "B", "B", "B", "B", "C", "C"]], ["Col", [1, 2, 3, 1, 2, 3, 4, 1, 2]]] + groupColumn = ["Group", ["A", "A", "A", "B", "B", "B", "B", "C", "C"]] + dataCol = ["Col", [1, 2, 3, 1, 2, 3, 4, 1, 2]] + t2 = build_sorted_table [groupColumn, dataCol] group_builder.specify "Negative n shifts the values down" <| - r = t2.offset ["Col"] -1 ..Closest_Value group_by=["Group"] - r . at "offset([Col], -1, Fill_With.Closest_Value)" . to_vector . should_equal [1, 1, 2, 1, 1, 2, 3, 1, 1] + t2.offset ["Col"] -1 ..Closest_Value group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], -1, Fill_With.Closest_Value)", [1, 1, 2, 1, 1, 2, 3, 1, 1]]] group_builder.specify "Positive n shifts the values up" <| - r = t2.offset ["Col"] 1 ..Closest_Value group_by=["Group"] - r . at "offset([Col], 1, Fill_With.Closest_Value)" . to_vector . should_equal [2, 3, 3, 2, 3, 4, 4, 2, 2] + t2.offset ["Col"] 1 ..Closest_Value group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 1, Fill_With.Closest_Value)", [2, 3, 3, 2, 3, 4, 4, 2, 2]]] group_builder.specify "Negative n shifts the values down (n=2)" <| - r = t2.offset ["Col"] -2 ..Closest_Value group_by=["Group"] - r . at "offset([Col], -2, Fill_With.Closest_Value)" . to_vector . should_equal [1, 1, 1, 1, 1, 1, 2, 1, 1] + t2.offset ["Col"] -2 ..Closest_Value group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], -2, Fill_With.Closest_Value)", [1, 1, 1, 1, 1, 1, 2, 1, 1]]] group_builder.specify "Positive n shifts the values up (n=2)" <| - r = t2.offset ["Col"] 2 ..Closest_Value group_by=["Group"] - r . at "offset([Col], 2, Fill_With.Closest_Value)" . to_vector . should_equal [3, 3, 3, 3, 4, 4, 4, 2, 2] + t2.offset ["Col"] 2 ..Closest_Value group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 2, Fill_With.Closest_Value)", [3, 3, 3, 3, 4, 4, 4, 2, 2]]] group_builder.specify "Zero n is a no-op" <| - r = t2.offset ["Col"] 0 ..Closest_Value group_by=["Group"] - r . at "offset([Col], 0, Fill_With.Closest_Value)" . to_vector . should_equal [1, 2, 3, 1, 2, 3, 4, 1, 2] + t2.offset ["Col"] 0 ..Closest_Value group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 0, Fill_With.Closest_Value)", [1, 2, 3, 1, 2, 3, 4, 1, 2]]] group_builder.specify "Large negative n values work" <| - r = t2.offset ["Col"] -1024 ..Closest_Value group_by=["Group"] - r . at "offset([Col], -1024, Fill_With.Closest_Value)" . to_vector . should_equal [1, 1, 1, 1, 1, 1, 1, 1, 1] + t2.offset ["Col"] -1024 ..Closest_Value group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], -1024, Fill_With.Closest_Value)", [1, 1, 1, 1, 1, 1, 1, 1, 1]]] group_builder.specify "Large positive n values work" <| - r = t2.offset ["Col"] 1024 ..Closest_Value group_by=["Group"] - r . at "offset([Col], 1024, Fill_With.Closest_Value)" . to_vector . should_equal [3, 3, 3, 4, 4, 4, 4, 2, 2] + t2.offset ["Col"] 1024 ..Closest_Value group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 1024, Fill_With.Closest_Value)", [3, 3, 3, 4, 4, 4, 4, 2, 2]]] suite_builder.group prefix+"Table.Offset works with grouping - wrap around fill strategy" group_builder-> - t2 = build_sorted_table [["Group", ["A", "A", "A", "B", "B", "B", "B", "C", "C"]], ["Col", [1, 2, 3, 1, 2, 3, 4, 1, 2]]] + groupColumn = ["Group", ["A", "A", "A", "B", "B", "B", "B", "C", "C"]] + dataCol = ["Col", [1, 2, 3, 1, 2, 3, 4, 1, 2]] + t2 = build_sorted_table [groupColumn, dataCol] group_builder.specify "Negative n shifts the values down" <| - r = t2.offset ["Col"] -1 ..Wrap_Around group_by=["Group"] - r . at "offset([Col], -1, Fill_With.Wrap_Around)" . to_vector . should_equal [3, 1, 2, 4, 1, 2, 3, 2, 1] + t2.offset ["Col"] -1 ..Wrap_Around group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], -1, Fill_With.Wrap_Around)", [3, 1, 2, 4, 1, 2, 3, 2, 1]]] group_builder.specify "Positive n shifts the values up" <| - r = t2.offset ["Col"] 1 ..Wrap_Around group_by=["Group"] - r . at "offset([Col], 1, Fill_With.Wrap_Around)" . to_vector . should_equal [2, 3, 1, 2, 3, 4, 1, 2, 1] + t2.offset ["Col"] 1 ..Wrap_Around group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 1, Fill_With.Wrap_Around)", [2, 3, 1, 2, 3, 4, 1, 2, 1]]] group_builder.specify "Negative n shifts the values down (n=2)" <| - r = t2.offset ["Col"] -2 ..Wrap_Around group_by=["Group"] - r . at "offset([Col], -2, Fill_With.Wrap_Around)" . to_vector . should_equal [2, 3, 1, 3, 4, 1, 2, 1, 2] + t2.offset ["Col"] -2 ..Wrap_Around group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], -2, Fill_With.Wrap_Around)", [2, 3, 1, 3, 4, 1, 2, 1, 2]]] group_builder.specify "Positive n shifts the values up (n=2)" <| - r = t2.offset ["Col"] 2 ..Wrap_Around group_by=["Group"] - r . at "offset([Col], 2, Fill_With.Wrap_Around)" . to_vector . should_equal [3, 1, 2, 3, 4, 1, 2, 1, 2] + t2.offset ["Col"] 2 ..Wrap_Around group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 2, Fill_With.Wrap_Around)", [3, 1, 2, 3, 4, 1, 2, 1, 2]]] group_builder.specify "Zero n is a no-op" <| - r = t2.offset ["Col"] 0 ..Wrap_Around group_by=["Group"] - r . at "offset([Col], 0, Fill_With.Wrap_Around)" . to_vector . should_equal [1, 2, 3, 1, 2, 3, 4, 1, 2] + t2.offset ["Col"] 0 ..Wrap_Around group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 0, Fill_With.Wrap_Around)", [1, 2, 3, 1, 2, 3, 4, 1, 2]]] group_builder.specify "Large negative n values work" <| - r = t2.offset ["Col"] -1022 ..Wrap_Around group_by=["Group"] - r . at "offset([Col], -1022, Fill_With.Wrap_Around)" . to_vector . should_equal [2, 3, 1, 3, 4, 1, 2, 1, 2] + t2.offset ["Col"] -1022 ..Wrap_Around group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], -1022, Fill_With.Wrap_Around)", [2, 3, 1, 3, 4, 1, 2, 1, 2]]] group_builder.specify "Large positive n values work" <| - r = t2.offset ["Col"] 1022 ..Wrap_Around group_by=["Group"] - r . at "offset([Col], 1022, Fill_With.Wrap_Around)" . to_vector . should_equal [3, 1, 2, 3, 4, 1, 2, 1, 2] + t2.offset ["Col"] 1022 ..Wrap_Around group_by=["Group"] . should_equal ignore_order=setup.is_database + Table.input [groupColumn, dataCol, ["offset([Col], 1022, Fill_With.Wrap_Around)", [3, 1, 2, 3, 4, 1, 2, 1, 2]]] suite_builder.group prefix+"Table.Offset works with ordering - default fill strategy" group_builder-> - t2 = build_sorted_table [["Order", [1, 4, 2, 5, 3]], ["Col", ["A", "D", "B", "E", "C"]]] - group_builder.specify "Negative n shifts the values down" <| - r = t2.offset ["Col"] -1 ..Nothing order_by=["Order"] - r . at "offset([Col], -1, Fill_With.Nothing)" . to_vector . should_equal [Nothing, "C", "A", "D", "B"] + orderColumn = ["Order", [1, 4, 2, 5, 3]] + dataCol = ["Col", ["A", "D", "B", "E", "C"]] + t2 = build_sorted_table [orderColumn, dataCol] + group_builder.specify "Negative n shifts the values downX" <| + t2.offset ["Col"] -1 ..Nothing order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], -1, Fill_With.Nothing)", [Nothing, "C", "A", "D", "B"]]] group_builder.specify "Positive n shifts the values up" <| - r = t2.offset ["Col"] 1 ..Nothing order_by=["Order"] - r . at "offset([Col], 1, Fill_With.Nothing)" . to_vector . should_equal ["B", "E", "C", Nothing, "D"] + t2.offset ["Col"] 1 ..Nothing order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 1, Fill_With.Nothing)", ["B", "E", "C", Nothing, "D"]]] group_builder.specify "Negative n shifts the values down (n=2)" <| - r = t2.offset ["Col"] -2 ..Nothing order_by=["Order"] - r . at "offset([Col], -2, Fill_With.Nothing)" . to_vector . should_equal [Nothing, "B", Nothing, "C", "A"] + t2.offset ["Col"] -2 ..Nothing order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], -2, Fill_With.Nothing)", [Nothing, "B", Nothing, "C", "A"]]] group_builder.specify "Positive n shifts the values up (n=2)" <| - r = t2.offset ["Col"] 2 ..Nothing order_by=["Order"] - r . at "offset([Col], 2, Fill_With.Nothing)" . to_vector . should_equal ["C", Nothing, "D", Nothing, "E"] + t2.offset ["Col"] 2 ..Nothing order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 2, Fill_With.Nothing)", ["C", Nothing, "D", Nothing, "E"]]] group_builder.specify "Zero n is a no-op" <| - r = t2.offset ["Col"] 0 ..Nothing order_by=["Order"] - r . at "offset([Col], 0, Fill_With.Nothing)" . to_vector . should_equal ["A", "D", "B", "E", "C"] + t2.offset ["Col"] 0 ..Nothing order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 0, Fill_With.Nothing)", ["A", "D", "B", "E", "C"]]] group_builder.specify "Large negative n values work" <| - r = t2.offset ["Col"] -1024 ..Nothing order_by=["Order"] - r . at "offset([Col], -1024, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing, Nothing] + t2.offset ["Col"] -1024 ..Nothing order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], -1024, Fill_With.Nothing)", [Nothing, Nothing, Nothing, Nothing, Nothing], Value_Type.Char]] group_builder.specify "Large positive n values work" <| - r = t2.offset ["Col"] 1024 ..Nothing order_by=["Order"] - r . at "offset([Col], 1024, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing, Nothing] + t2.offset ["Col"] 1024 ..Nothing order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 1024, Fill_With.Nothing)", [Nothing, Nothing, Nothing, Nothing, Nothing], Value_Type.Char]] suite_builder.group prefix+"Table.Offset works with ordering - closest fill strategy" group_builder-> - t2 = build_sorted_table [["Order", [1, 4, 2, 5, 3]], ["Col", ["A", "D", "B", "E", "C"]]] + orderColumn = ["Order", [1, 4, 2, 5, 3]] + dataCol = ["Col", ["A", "D", "B", "E", "C"]] + t2 = build_sorted_table [orderColumn, dataCol] group_builder.specify "Negative n shifts the values down" <| - r = t2.offset ["Col"] -1 ..Closest_Value order_by=["Order"] - r . at "offset([Col], -1, Fill_With.Closest_Value)" . to_vector . should_equal ["A", "C", "A", "D", "B"] + t2.offset ["Col"] -1 ..Closest_Value order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], -1, Fill_With.Closest_Value)", ["A", "C", "A", "D", "B"]]] group_builder.specify "Positive n shifts the values up" <| - r = t2.offset ["Col"] 1 ..Closest_Value order_by=["Order"] - r . at "offset([Col], 1, Fill_With.Closest_Value)" . to_vector . should_equal ["B", "E", "C", "E", "D"] + t2.offset ["Col"] 1 ..Closest_Value order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 1, Fill_With.Closest_Value)", ["B", "E", "C", "E", "D"]]] group_builder.specify "Negative n shifts the values down (n=2)" <| - r = t2.offset ["Col"] -2 ..Closest_Value order_by=["Order"] - r . at "offset([Col], -2, Fill_With.Closest_Value)" . to_vector . should_equal ["A", "B", "A", "C", "A"] + t2.offset ["Col"] -2 ..Closest_Value order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], -2, Fill_With.Closest_Value)", ["A", "B", "A", "C", "A"]]] group_builder.specify "Positive n shifts the values up (n=2)" <| - r = t2.offset ["Col"] 2 ..Closest_Value order_by=["Order"] - r . at "offset([Col], 2, Fill_With.Closest_Value)" . to_vector . should_equal ["C", "E", "D", "E", "E"] + t2.offset ["Col"] 2 ..Closest_Value order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 2, Fill_With.Closest_Value)", ["C", "E", "D", "E", "E"]]] group_builder.specify "Zero n is a no-op" <| - r = t2.offset ["Col"] 0 ..Closest_Value order_by=["Order"] - r . at "offset([Col], 0, Fill_With.Closest_Value)" . to_vector . should_equal ["A", "D", "B", "E", "C"] + t2.offset ["Col"] 0 ..Closest_Value order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 0, Fill_With.Closest_Value)", ["A", "D", "B", "E", "C"]]] group_builder.specify "Large negative n values work" <| - r = t2.offset ["Col"] -1024 ..Closest_Value order_by=["Order"] - r . at "offset([Col], -1024, Fill_With.Closest_Value)" . to_vector . should_equal ["A", "A", "A", "A", "A"] + t2.offset ["Col"] -1024 ..Closest_Value order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], -1024, Fill_With.Closest_Value)", ["A", "A", "A", "A", "A"]]] group_builder.specify "Large positive n values work" <| - r = t2.offset ["Col"] 1024 ..Closest_Value order_by=["Order"] - r . at "offset([Col], 1024, Fill_With.Closest_Value)" . to_vector . should_equal ["E", "E", "E", "E", "E"] + t2.offset ["Col"] 1024 ..Closest_Value order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 1024, Fill_With.Closest_Value)", ["E", "E", "E", "E", "E"]]] suite_builder.group prefix+"Table.Offset works with ordering - wrap around fill strategy" group_builder-> - t2 = build_sorted_table [["Order", [1, 4, 2, 5, 3]], ["Col", ["A", "D", "B", "E", "C"]]] + orderColumn = ["Order", [1, 4, 2, 5, 3]] + dataCol = ["Col", ["A", "D", "B", "E", "C"]] + t2 = build_sorted_table [orderColumn, dataCol] group_builder.specify "Negative n shifts the values down" <| - r = t2.offset ["Col"] -1 ..Wrap_Around order_by=["Order"] - r . at "offset([Col], -1, Fill_With.Wrap_Around)" . to_vector . should_equal ["E", "C", "A", "D", "B"] + t2.offset ["Col"] -1 ..Wrap_Around order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], -1, Fill_With.Wrap_Around)", ["E", "C", "A", "D", "B"]]] group_builder.specify "Positive n shifts the values up" <| - r = t2.offset ["Col"] 1 ..Wrap_Around order_by=["Order"] - r . at "offset([Col], 1, Fill_With.Wrap_Around)" . to_vector . should_equal ["B", "E", "C", "A", "D"] + t2.offset ["Col"] 1 ..Wrap_Around order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 1, Fill_With.Wrap_Around)", ["B", "E", "C", "A", "D"]]] group_builder.specify "Negative n shifts the values down (n=2)" <| - r = t2.offset ["Col"] -2 ..Wrap_Around order_by=["Order"] - r . at "offset([Col], -2, Fill_With.Wrap_Around)" . to_vector . should_equal ["D", "B", "E", "C", "A"] + t2.offset ["Col"] -2 ..Wrap_Around order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], -2, Fill_With.Wrap_Around)", ["D", "B", "E", "C", "A"]]] group_builder.specify "Positive n shifts the values up (n=2)" <| - r = t2.offset ["Col"] 2 ..Wrap_Around order_by=["Order"] - r . at "offset([Col], 2, Fill_With.Wrap_Around)" . to_vector . should_equal ["C", "A", "D", "B", "E"] + t2.offset ["Col"] 2 ..Wrap_Around order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 2, Fill_With.Wrap_Around)", ["C", "A", "D", "B", "E"]]] group_builder.specify "Zero n is a no-op" <| - r = t2.offset ["Col"] 0 ..Wrap_Around order_by=["Order"] - r . at "offset([Col], 0, Fill_With.Wrap_Around)" . to_vector . should_equal ["A", "D", "B", "E", "C"] + t2.offset ["Col"] 0 ..Wrap_Around order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 0, Fill_With.Wrap_Around)", ["A", "D", "B", "E", "C"]]] group_builder.specify "Large negative n values work" <| - r = t2.offset ["Col"] -1024 ..Wrap_Around order_by=["Order"] - r . at "offset([Col], -1024, Fill_With.Wrap_Around)" . to_vector . should_equal ["B", "E", "C", "A", "D"] + t2.offset ["Col"] -1024 ..Wrap_Around order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], -1024, Fill_With.Wrap_Around)", ["B", "E", "C", "A", "D"]]] group_builder.specify "Large positive n values work" <| - r = t2.offset ["Col"] 1024 ..Wrap_Around order_by=["Order"] - r . at "offset([Col], 1024, Fill_With.Wrap_Around)" . to_vector . should_equal ["E", "C", "A", "D", "B"] + t2.offset ["Col"] 1024 ..Wrap_Around order_by=["Order"] . should_equal ignore_order=setup.is_database + Table.input [orderColumn, dataCol, ["offset([Col], 1024, Fill_With.Wrap_Around)", ["E", "C", "A", "D", "B"]]] suite_builder.group prefix+"Table.Offset works with multiple columns" group_builder-> - t2 = build_sorted_table [["Col1", ["A", "B", "C", "D"]], ["Col2", [1, 2, 3, 4]]] + col1 = ["Col1", ["A", "B", "C", "D"]] + col2 = ["Col2", [1, 2, 3, 4]] + t2 = build_sorted_table [col1, col2] group_builder.specify "Negative n shifts the values down" <| - r = t2.offset ["Col1", "Col2"] -1 ..Nothing - r . at "offset([Col1], -1, Fill_With.Nothing)" . to_vector . should_equal [Nothing, "A", "B", "C"] - r . at "offset([Col2], -1, Fill_With.Nothing)" . to_vector . should_equal [Nothing, 1, 2, 3] + t2.offset ["Col1", "Col2"] -1 ..Nothing . should_equal ignore_order=setup.is_database + Table.input [col1, col2, ["offset([Col1], -1, Fill_With.Nothing)", [Nothing, "A", "B", "C"]], ["offset([Col2], -1, Fill_With.Nothing)", [Nothing, 1, 2, 3]]] group_builder.specify "Positive n shifts the values up" <| - r = t2.offset ["Col1", "Col2"] 1 ..Nothing - r . at "offset([Col1], 1, Fill_With.Nothing)" . to_vector . should_equal ["B", "C", "D", Nothing] - r . at "offset([Col2], 1, Fill_With.Nothing)" . to_vector . should_equal [2, 3, 4, Nothing] + t2.offset ["Col1", "Col2"] 1 ..Nothing . should_equal ignore_order=setup.is_database + Table.input [col1, col2, ["offset([Col1], 1, Fill_With.Nothing)", ["B", "C", "D", Nothing]], ["offset([Col2], 1, Fill_With.Nothing)", [2, 3, 4, Nothing]]] group_builder.specify "Negative n shifts the values down (n=2)" <| - r = t2.offset ["Col1", "Col2"] -2 ..Nothing - r . at "offset([Col1], -2, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, "A", "B"] - r . at "offset([Col2], -2, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, 1, 2] + t2.offset ["Col1", "Col2"] -2 ..Nothing . should_equal ignore_order=setup.is_database + Table.input [col1, col2, ["offset([Col1], -2, Fill_With.Nothing)", [Nothing, Nothing, "A", "B"]], ["offset([Col2], -2, Fill_With.Nothing)", [Nothing, Nothing, 1, 2]]] group_builder.specify "Positive n shifts the values up (n=2)" <| - r = t2.offset ["Col1", "Col2"] 2 ..Nothing - r . at "offset([Col1], 2, Fill_With.Nothing)" . to_vector . should_equal ["C", "D", Nothing, Nothing] - r . at "offset([Col2], 2, Fill_With.Nothing)" . to_vector . should_equal [3, 4, Nothing, Nothing] + t2.offset ["Col1", "Col2"] 2 ..Nothing . should_equal ignore_order=setup.is_database + Table.input [col1, col2, ["offset([Col1], 2, Fill_With.Nothing)", ["C", "D", Nothing, Nothing]], ["offset([Col2], 2, Fill_With.Nothing)", [3, 4, Nothing, Nothing]]] group_builder.specify "Zero n is a no-op" <| - r = t2.offset ["Col1", "Col2"] 0 ..Nothing - r . at "offset([Col1], 0, Fill_With.Nothing)" . to_vector . should_equal ["A", "B", "C", "D"] - r . at "offset([Col2], 0, Fill_With.Nothing)" . to_vector . should_equal [1, 2, 3, 4] + t2.offset ["Col1", "Col2"] 0 ..Nothing . should_equal ignore_order=setup.is_database + Table.input [col1, col2, ["offset([Col1], 0, Fill_With.Nothing)", ["A", "B", "C", "D"]], ["offset([Col2], 0, Fill_With.Nothing)", [1, 2, 3, 4]]] group_builder.specify "Large negative n values work" <| - r = t2.offset ["Col1", "Col2"] -1024 ..Nothing - r . at "offset([Col1], -1024, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing] - r . at "offset([Col2], -1024, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing] + t2.offset ["Col1", "Col2"] -1024 ..Nothing . should_equal ignore_order=setup.is_database + Table.input [col1, col2, ["offset([Col1], -1024, Fill_With.Nothing)", [Nothing, Nothing, Nothing, Nothing], Value_Type.Char], ["offset([Col2], -1024, Fill_With.Nothing)", [Nothing, Nothing, Nothing, Nothing], Value_Type.Integer]] group_builder.specify "Large positive n values work" <| - r = t2.offset ["Col1", "Col2"] 1024 ..Nothing - r . at "offset([Col1], 1024, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing] - r . at "offset([Col2], 1024, Fill_With.Nothing)" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing] + t2.offset ["Col1", "Col2"] 1024 ..Nothing . should_equal ignore_order=setup.is_database + Table.input [col1, col2, ["offset([Col1], 1024, Fill_With.Nothing)", [Nothing, Nothing, Nothing, Nothing], Value_Type.Char], ["offset([Col2], 1024, Fill_With.Nothing)", [Nothing, Nothing, Nothing, Nothing], Value_Type.Integer]] suite_builder.group prefix+"Table.Offset works with multiple columns - updating in place" group_builder-> - t2 = build_sorted_table [["Col1", ["A", "B", "C", "D"]], ["Col2", [1, 2, 3, 4]]] + col1 = ["Col1", ["A", "B", "C", "D"]] + col2 = ["Col2", [1, 2, 3, 4]] + t2 = build_sorted_table [col1, col2] group_builder.specify "Negative n shifts the values down" <| - r = t2.offset ["Col1", "Col2"] -1 ..Nothing set_mode=..Update - r . at "Col1" . to_vector . should_equal [Nothing, "A", "B", "C"] - r . at "Col2" . to_vector . should_equal [Nothing, 1, 2, 3] + t2.offset ["Col1", "Col2"] -1 ..Nothing set_mode=..Update . should_equal ignore_order=setup.is_database + Table.input [["Col1", [Nothing, "A", "B", "C"]], ["Col2", [Nothing, 1, 2, 3]]] group_builder.specify "Positive n shifts the values up" <| - r = t2.offset ["Col1", "Col2"] 1 ..Nothing set_mode=..Update - r . at "Col1" . to_vector . should_equal ["B", "C", "D", Nothing] - r . at "Col2" . to_vector . should_equal [2, 3, 4, Nothing] + t2.offset ["Col1", "Col2"] 1 ..Nothing set_mode=..Update . should_equal ignore_order=setup.is_database + Table.input [["Col1", ["B", "C", "D", Nothing]], ["Col2", [2, 3, 4, Nothing]]] group_builder.specify "Negative n shifts the values down (n=2)" <| - r = t2.offset ["Col1", "Col2"] -2 ..Nothing set_mode=..Update - r . at "Col1" . to_vector . should_equal [Nothing, Nothing, "A", "B"] - r . at "Col2" . to_vector . should_equal [Nothing, Nothing, 1, 2] + t2.offset ["Col1", "Col2"] -2 ..Nothing set_mode=..Update . should_equal ignore_order=setup.is_database + Table.input [["Col1", [Nothing, Nothing, "A", "B"]], ["Col2", [Nothing, Nothing, 1, 2]]] group_builder.specify "Positive n shifts the values up (n=2)" <| - r = t2.offset ["Col1", "Col2"] 2 ..Nothing set_mode=..Update - r . at "Col1" . to_vector . should_equal ["C", "D", Nothing, Nothing] - r . at "Col2" . to_vector . should_equal [3, 4, Nothing, Nothing] + t2.offset ["Col1", "Col2"] 2 ..Nothing set_mode=..Update . should_equal ignore_order=setup.is_database + Table.input [["Col1", ["C", "D", Nothing, Nothing]], ["Col2", [3, 4, Nothing, Nothing]]] group_builder.specify "Zero n is a no-op" <| - r = t2.offset ["Col1", "Col2"] 0 ..Nothing set_mode=..Update - r . at "Col1" . to_vector . should_equal ["A", "B", "C", "D"] - r . at "Col2" . to_vector . should_equal [1, 2, 3, 4] + t2.offset ["Col1", "Col2"] 0 ..Nothing set_mode=..Update . should_equal ignore_order=setup.is_database + Table.input [["Col1", ["A", "B", "C", "D"]], ["Col2", [1, 2, 3, 4]]] group_builder.specify "Large negative n values work" <| - r = t2.offset ["Col1", "Col2"] -1024 ..Nothing set_mode=..Update - r . at "Col1" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing] - r . at "Col2" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing] + t2.offset ["Col1", "Col2"] -1024 ..Nothing set_mode=..Update . should_equal ignore_order=setup.is_database + Table.input [["Col1", [Nothing, Nothing, Nothing, Nothing], Value_Type.Char], ["Col2", [Nothing, Nothing, Nothing, Nothing], Value_Type.Integer]] group_builder.specify "Large positive n values work" <| - r = t2.offset ["Col1", "Col2"] 1024 ..Nothing set_mode=..Update - r . at "Col1" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing] - r . at "Col2" . to_vector . should_equal [Nothing, Nothing, Nothing, Nothing] + t2.offset ["Col1", "Col2"] 1024 ..Nothing set_mode=..Update . should_equal ignore_order=setup.is_database + Table.input [["Col1", [Nothing, Nothing, Nothing, Nothing], Value_Type.Char], ["Col2", [Nothing, Nothing, Nothing, Nothing], Value_Type.Integer]] group_builder.specify "Add_Or_Update equivalent to update" <| - r = t2.offset ["Col1", "Col2"] -1 ..Nothing set_mode=..Add_Or_Update - r . at "Col1" . to_vector . should_equal [Nothing, "A", "B", "C"] - r . at "Col2" . to_vector . should_equal [Nothing, 1, 2, 3] + t2.offset ["Col1", "Col2"] -1 ..Nothing set_mode=..Add_Or_Update . should_equal ignore_order=setup.is_database + Table.input [["Col1", [Nothing, "A", "B", "C"]], ["Col2", [Nothing, 1, 2, 3]]] suite_builder.group prefix+"Table.Offset handles bad inputs gracefully" group_builder-> t2 = build_sorted_table [["Col1", ["A", "B", "C", "D"]], ["Col2", [1, 2, 3, 4]]] t3 = build_sorted_table [["Group", [1.1, 1.1, 1.1, 1.1]], ["Col2", [1, 2, 3, 4]]] group_builder.specify "Missing offset columns error" <| - r = t2.offset - r.should_fail_with (Missing_Argument.Error "columns") + t2.offset . should_fail_with (Missing_Argument.Error "columns") group_builder.specify "Empty offset columns is a no-op" <| - r = t2.offset [] - r . at "Col1" . to_vector . should_equal ["A", "B", "C", "D"] - r . at "Col2" . to_vector . should_equal [1, 2, 3, 4] + t2.offset [] . should_equal t2 group_builder.specify "Missing column is an error" <| - r = t2.offset ["NotAColumn"] - r.should_fail_with (Missing_Input_Columns.Error ["NotAColumn"]) + t2.offset ["NotAColumn"] . should_fail_with (Missing_Input_Columns.Error ["NotAColumn"]) group_builder.specify "Missing column is an error - grouping" <| - r = t2.offset [] group_by=["NotAColumn"] - r.should_fail_with (Missing_Input_Columns.Error ["NotAColumn"]) + t2.offset [] group_by=["NotAColumn"] . should_fail_with (Missing_Input_Columns.Error ["NotAColumn"]) group_builder.specify "Missing column is an error - ordering" <| - r = t2.offset [] order_by=["NotAColumn"] - r.should_fail_with (Missing_Input_Columns.Error ["NotAColumn"]) + t2.offset [] order_by=["NotAColumn"] . should_fail_with (Missing_Input_Columns.Error ["NotAColumn"]) group_builder.specify "Grouping by float warns" <| r = t3.offset ["Col2"] group_by=["Group"] Problems.expect_warning Floating_Point_Equality r diff --git a/test/Table_Tests/src/Common_Table_Operations/Util.enso b/test/Table_Tests/src/Common_Table_Operations/Util.enso index 8c63931ae62e..bf7dfc3b58bb 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Util.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Util.enso @@ -83,7 +83,7 @@ Error.should_equal_tz_agnostic self other = Builds a table ensuring that the rows are in the order as given. build_sorted_table setup table_structure = # Workaround for https://github.com/enso-org/enso/issues/10321 - if setup.prefix.contains "Snowflake" . not then setup.table_builder table_structure else + if setup.prefix.contains "Snowflake" then setup.table_builder table_structure else row_count = case table_structure.first of def : Vector -> def.second.length col : Column -> col.length diff --git a/test/Table_Tests/src/Util.enso b/test/Table_Tests/src/Util.enso index 9fdd0dfc6fc7..5f1447e7a637 100644 --- a/test/Table_Tests/src/Util.enso +++ b/test/Table_Tests/src/Util.enso @@ -9,11 +9,11 @@ from Standard.Test import all polyglot java import org.enso.base_test_helpers.FileSystemHelper -Table.should_equal : Any -> Integer -> Any -Table.should_equal self expected frames_to_skip=0 = +Table.should_equal : Any -> Integer -> Boolean -> Any +Table.should_equal self expected frames_to_skip=0 ignore_order=False = loc = Test.get_source_location 1+frames_to_skip rhs_error_check expected - Panic.catch Test_Failure_Error (table_should_equal_impl self expected loc) error-> + Panic.catch Test_Failure_Error (table_should_equal_impl self expected loc ignore_order) error-> Test.fail error.payload.message Column.should_equal : Any -> Integer -> Any @@ -23,12 +23,12 @@ Column.should_equal self expected frames_to_skip=0 = Panic.catch Test_Failure_Error (column_should_equal_impl self expected loc) error-> Test.fail error.payload.message -DB_Table.should_equal : DB_Table -> Integer -> Any -DB_Table.should_equal self expected frames_to_skip=0 = +DB_Table.should_equal : DB_Table|Table -> Integer -> Boolean -> Any +DB_Table.should_equal self expected frames_to_skip=0 ignore_order=False = rhs_error_check expected t0 = self.read t1 = expected.read - t0 . should_equal t1 frames_to_skip+1 + t0 . should_equal t1 frames_to_skip+1 ignore_order DB_Column.should_equal : DB_Column -> Integer -> Any DB_Column.should_equal self expected frames_to_skip=0 = @@ -50,15 +50,17 @@ type Test_Failure_Error to_display_text self = "Test failure error: "+self.message ## PRIVATE -table_should_equal_impl actual expected loc = - case expected of +table_should_equal_impl actual_table expected_table loc ignore_order = + case expected_table of _ : Table -> + actual = if ignore_order then actual_table.sort else actual_table + expected = if ignore_order then expected_table.sort else expected_table if actual.columns.length != expected.columns.length then Panic.throw (Test_Failure_Error.Error 'Tables differ at '+loc+'.\nActual:\n'+actual.display+'\nExpected:\n'+expected.display+'\nExpected '+expected.columns.length.to_text+" columns, but got "+actual.columns.length.to_text+'.') Panic.catch Test_Failure_Error (actual.columns.zip expected.columns a-> e->(column_should_equal_impl a e)) error-> msg = 'Tables differ at '+loc+'.\nActual:\n'+actual.display+'\nExpected:\n'+expected.display+'\n'+error.payload.message Panic.throw (Test_Failure_Error.Error msg) - _ -> Panic.throw (Test_Failure_Error.Error "Got a Table, but expected a "+expected.to_display_text+(display_loc loc)+'.') + _ -> Panic.throw (Test_Failure_Error.Error "Got a Table, but expected a "+expected_table.to_display_text+(display_loc loc)+'.') ## PRIVATE column_should_equal_impl actual expected loc='' = @@ -70,20 +72,20 @@ column_should_equal_impl actual expected loc='' = Panic.throw (Test_Failure_Error.Error "Expected column length "+expected.length.to_text+", but got "+actual.length.to_text+(display_loc loc)+'.') if actual.value_type != expected.value_type then Panic.throw (Test_Failure_Error.Error "Expected column type "+expected.value_type.to_text+", but got "+actual.value_type.to_text+(display_loc loc)+'.') - actual.zip expected a-> e-> - if values_equal a e then + actual.zip expected skip_nothing=False a-> e-> + if values_not_equal a e then report_fail actual expected loc _ -> Panic.throw (Test_Failure_Error.Error "Got a Column, but expected a "+expected.to_display_text+(display_loc loc)+'.') ## PRIVATE -values_equal a e = +values_not_equal a e = a != e && (a.is_a Number && e.is_a Number && a.is_nan && e.is_nan).not ## PRIVATE report_fail actual expected loc = - indexed = actual.zip (0.up_to actual.length) a-> i-> Pair.new a i - indexed.zip expected a-> e-> - if values_equal a.first e then + indexed = actual.zip (0.up_to actual.length) skip_nothing=False a-> i-> Pair.new a i + indexed.zip expected skip_nothing=False a-> e-> + if values_not_equal a.first e then Panic.throw (Test_Failure_Error.Error "Column: "+actual.name+" differs at row "+a.second.to_text+'.\n\t Actual : '+a.first.to_text+'\n\t Expected: '+e.to_text+'\n\t'+(display_loc loc)+'.') ## PRIVATE diff --git a/test/Table_Tests/src/Util_Spec.enso b/test/Table_Tests/src/Util_Spec.enso index d51f3a6c8d9c..d0561d24405e 100644 --- a/test/Table_Tests/src/Util_Spec.enso +++ b/test/Table_Tests/src/Util_Spec.enso @@ -88,40 +88,68 @@ add_specs suite_builder = actual_column = Column.from_vector "Col" [1, 2, 3, 4] res = Panic.recover Test_Failure_Error (column_should_equal_impl actual_column expected_column "LOCATION_PATH") res.catch.message.should_equal "Got a Column, but expected a 42 (at LOCATION_PATH)." - group_builder.specify "Two Columns Containg NaNs Are Equal" <| + group_builder.specify "Two Columns Containing NaNs Are Equal" <| # This is somewhat of a special case, as NaN != NaN but for the purposes of testing we consider them equal expected_column = Column.from_vector "Col" [1.0, 2.0, Number.nan] actual_column = Column.from_vector "Col" [1.0, 2.0, Number.nan] actual_column.should_equal expected_column + group_builder.specify "Two Columns Containing Nothing Are Equal" <| + expected_column = Column.from_vector "Col" [1.0, 2.0, Nothing] + actual_column = Column.from_vector "Col" [1.0, 2.0, Nothing] + actual_column.should_equal expected_column + group_builder.specify "Comparing to Actual Nothing Value should fail" <| + expected_column = Column.from_vector "Col" [1.0, 2.0, 3.0] + actual_column = Column.from_vector "Col" [1.0, 2.0, Nothing] + res = Panic.recover Test_Failure_Error (column_should_equal_impl actual_column expected_column "LOCATION_PATH") + res.catch.message.should_equal 'Column: Col differs at row 2.\n\t Actual : Nothing\n\t Expected: 3.0\n\t (at LOCATION_PATH).' + group_builder.specify "Comparing to Expected Nothing Value should fail" <| + expected_column = Column.from_vector "Col" [1.0, 2.0, Nothing] + actual_column = Column.from_vector "Col" [1.0, 2.0, 3.0] + res = Panic.recover Test_Failure_Error (column_should_equal_impl actual_column expected_column "LOCATION_PATH") + res.catch.message.should_equal 'Column: Col differs at row 2.\n\t Actual : 3.0\n\t Expected: Nothing\n\t (at LOCATION_PATH).' + group_builder.specify "Comparing to Actual Nothing Value to Expected NaN Value should fail" <| + expected_column = Column.from_vector "Col" [1.0, 2.0, Number.nan] + actual_column = Column.from_vector "Col" [1.0, 2.0, Nothing] + res = Panic.recover Test_Failure_Error (column_should_equal_impl actual_column expected_column "LOCATION_PATH") + res.catch.message.should_equal 'Column: Col differs at row 2.\n\t Actual : Nothing\n\t Expected: NaN\n\t (at LOCATION_PATH).' + group_builder.specify "Comparing to Actual NaN Value to Expected Nothing Value should fail" <| + expected_column = Column.from_vector "Col" [1.0, 2.0, Nothing] + actual_column = Column.from_vector "Col" [1.0, 2.0, Number.nan] + res = Panic.recover Test_Failure_Error (column_should_equal_impl actual_column expected_column "LOCATION_PATH") + res.catch.message.should_equal 'Column: Col differs at row 2.\n\t Actual : NaN\n\t Expected: Nothing\n\t (at LOCATION_PATH).' group_builder.specify "Two Tables Are Equal" <| expected_table = Table.new [Column.from_vector "Col1" ["Quis", "custodiet", "ipsos", "custodes?"], Column.from_vector "Col2" ["Who", "guards", "the", "guards?"]] actual_table = Table.new [Column.from_vector "Col1" ["Quis", "custodiet", "ipsos", "custodes?"], Column.from_vector "Col2" ["Who", "guards", "the", "guards?"]] - actual_table.should_equal expected_table + actual_table.should_equal expected_table + group_builder.specify "Two Tables Are Equal Ignoring Order" <| + expected_table = Table.new [Column.from_vector "Col1" ["Quis", "custodiet", "ipsos", "custodes?"], Column.from_vector "Col2" ["Who", "guards", "the", "guards?"]] + actual_table = Table.new [Column.from_vector "Col1" ["ipsos", "custodiet", "custodes?", "Quis"], Column.from_vector "Col2" ["the" , "guards", "guards?", "Who"]] + actual_table.should_equal expected_table ignore_order=True group_builder.specify "Two Tables With Different Values" <| expected_table = Table.new [Column.from_vector "Col1" ["Quis", "custodiet", "ipsos", "custodes?"], Column.from_vector "Col2" ["Who", "guards", "the", "guards?"]] actual_table = Table.new [Column.from_vector "Col1" ["Quis", "custodiet", "ipsos", "custodes?"], Column.from_vector "Col2" ["Who", "guards", "teh", "guards?"]] - res = Panic.recover Test_Failure_Error (table_should_equal_impl actual_table expected_table "LOCATION_PATH") + res = Panic.recover Test_Failure_Error (table_should_equal_impl actual_table expected_table "LOCATION_PATH" False) res.catch.message.should_end_with 'Column: Col2 differs at row 2.\n\t Actual : teh\n\t Expected: the\n\t.' group_builder.specify "Tables different number of columns" <| expected_table = Table.new [Column.from_vector "Col1" ["Quis", "custodiet", "ipsos", "custodes?"]] actual_table = Table.new [Column.from_vector "Col1" ["Quis", "custodiet", "ipsos", "custodes?"], Column.from_vector "Col2" ["Who", "guards", "the", "guards?"]] - res = Panic.recover Test_Failure_Error (table_should_equal_impl actual_table expected_table "LOCATION_PATH") + res = Panic.recover Test_Failure_Error (table_should_equal_impl actual_table expected_table "LOCATION_PATH" False) res.catch.message.should_end_with "Expected 1 columns, but got 2." group_builder.specify "Tables different number of columns2" <| expected_table = Table.new [Column.from_vector "Col1" ["Quis", "custodiet", "ipsos", "custodes?"], Column.from_vector "Col2" ["Who", "guards", "the", "guards?"]] actual_table = Table.new [Column.from_vector "Col1" ["Quis", "custodiet", "ipsos", "custodes?"]] - res = Panic.recover Test_Failure_Error (table_should_equal_impl actual_table expected_table "LOCATION_PATH") + res = Panic.recover Test_Failure_Error (table_should_equal_impl actual_table expected_table "LOCATION_PATH" False) res.catch.message.should_end_with "Expected 2 columns, but got 1." group_builder.specify "Tables With Mismatched Column names" <| expected_table = Table.new [Column.from_vector "Col1" ["Quis", "custodiet", "ipsos", "custodes?"], Column.from_vector "Col2" ["Who", "guards", "the", "guards?"]] actual_table = Table.new [Column.from_vector "Col" ["Quis", "custodiet", "ipsos", "custodes?"], Column.from_vector "Col2" ["Who", "guards", "the", "guards?"]] - res = Panic.recover Test_Failure_Error (table_should_equal_impl actual_table expected_table "LOCATION_PATH") + res = Panic.recover Test_Failure_Error (table_should_equal_impl actual_table expected_table "LOCATION_PATH" False) res.catch.message.should_end_with "Expected column name Col1, but got Col." group_builder.specify "Comparing a Table to non Table" <| expected_table = 42 actual_table = Table.new [Column.from_vector "Col1" ["Quis", "custodiet", "ipsos", "custodes?"]] - res = Panic.recover Test_Failure_Error (table_should_equal_impl actual_table expected_table "LOCATION_PATH") + res = Panic.recover Test_Failure_Error (table_should_equal_impl actual_table expected_table "LOCATION_PATH" False) res.catch.message.should_equal "Got a Table, but expected a 42 (at LOCATION_PATH)." type DB_Tables