Small changes from Book Club issues (#6533)

- Add dropdown to tokenize and split `column`.
- Remove the custom `Join_Kind` dropdown.
- Adjust split and tokenize names to start numbering from 1, not 0.
- Add JS_Object serialization for Period.
- Add `days_until` and `until` to `Date`.
- Add `Date_Period.Day` and create `next` and `previous` on `Date`.
- Use simple names with `File_Format` dropdown.
- Avoid using `Main.enso` based imports in `Standard.Base.Data.Map` and `Standard.Base.Data.Text.Helpers`.
- Remove an incorrect import from `Standard.Database.Data.Table`.

From #6587:

A few small changes, lots of lines because this affected lots of tests:
- `Table.join` now defaults to `Join_Kind.Left_Outer`, to avoid losing rows in the left table unexpectedly. If the user really wants to have an Inner join, they can switch to it.
- `Table.join` now defaults to joining columns by name not by index - it looks in the right table for a column with the same name as the first column in left table.
- Missing Input Column errors now specify which table they refer to in the join.
- The unique name suffix in column renaming / default column names when loading from file is now a space instead of underscore.
This commit is contained in:
James Dunkerley 2023-05-06 11:10:24 +01:00 committed by GitHub
parent f7282b7cff
commit bc0db18a6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 643 additions and 418 deletions

View File

@ -1,13 +1,16 @@
import project.Any.Any
import project.Data.Numbers.Integer import project.Data.Numbers.Integer
import project.Data.Vector.Vector import project.Data.Vector.Vector
import project.Data.Pair.Pair import project.Data.Pair.Pair
import project.Data.Text.Extensions import project.Data.Text.Extensions
import project.Data.Text.Text import project.Data.Text.Text
import project.Error.Error
import project.Errors.Illegal_Argument.Illegal_Argument import project.Errors.Illegal_Argument.Illegal_Argument
import project.Errors.No_Such_Key.No_Such_Key import project.Errors.No_Such_Key.No_Such_Key
import project.Nothing.Nothing
import project.Panic.Panic
from project.Data.Boolean import Boolean, True, False from project.Data.Boolean import Boolean, True, False
from project import Error, Nothing, Any, Panic
## A key-value store. It is possible to use any type as keys and values and mix them in ## A key-value store. It is possible to use any type as keys and values and mix them in
one Map. Keys are checked for equality based on their hash code and `==` operator, which one Map. Keys are checked for equality based on their hash code and `==` operator, which

View File

@ -900,7 +900,7 @@ Text.repeat : Integer -> Text
Text.repeat self count=1 = Text.repeat self count=1 =
0.up_to count . fold "" acc-> _-> acc + self 0.up_to count . fold "" acc-> _-> acc + self
## ALIAS first, last, left, right, mid, substring ## ALIAS first, last, left, right, mid, substring, slice
Creates a new Text by selecting the specified range of the input. Creates a new Text by selecting the specified range of the input.
This can select a section of text from the beginning, end, or middle of the This can select a section of text from the beginning, end, or middle of the

View File

@ -1,8 +1,6 @@
from Standard.Base import all
import project.Any.Any import project.Any.Any
import project.Data.Locale.Locale import project.Data.Text.Text
import project.Data.Text.Case_Sensitivity.Case_Sensitivity import project.Error.Error
import project.Errors.Common.Type_Error import project.Errors.Common.Type_Error
import project.Meta import project.Meta

View File

@ -314,6 +314,54 @@ type Date
end_of : Date_Period -> Date end_of : Date_Period -> Date
end_of self period=Date_Period.Month = period.adjust_end self end_of self period=Date_Period.Month = period.adjust_end self
## Returns the next date adding the `Date_Period` to self.
Produces a warning for a Date that is before epoch start.
See `Date_Time.enso_epoch_start`.
Arguments:
- period: the period to add to self.
next : Date_Period -> Date
next self period=Date_Period.Day = self + period.to_period
## Returns the previous date subtracting the `Date_Period` from self.
Produces a warning for a Date that is before epoch start.
See `Date_Time.enso_epoch_start`.
Arguments:
- period: the period to add to self.
previous : Date_Period -> Date
previous self period=Date_Period.Day = self - period.to_period
## Creates a `Period` between self and the provided end date.
Produces a warning for a Date that is before epoch start.
See `Date_Time.enso_epoch_start`.
Arguments:
- end: the end date of the interval to count workdays in.
until : Date -> Period
until self end =
ensure_in_epoch self <| ensure_in_epoch end <|
Period.between self end
## Counts the days between self (inclusive) and the provided end date
(exclusive).
Produces a warning for a Date that is before epoch start.
See `Date_Time.enso_epoch_start`.
Arguments:
- end: the end date of the interval to count workdays in.
- include_end_date: whether to include the end date in the count.
By default the end date is not included in the interval.
days_until : Date -> Boolean -> Integer
days_until self end include_end_date=False =
if end < self then -(end.days_until self include_end_date) else
ensure_in_epoch self <| ensure_in_epoch end <|
(Time_Utils.days_between self end) + if include_end_date then 1 else 0
## Counts workdays between self (inclusive) and the provided end date ## Counts workdays between self (inclusive) and the provided end date
(exclusive). (exclusive).
@ -331,7 +379,7 @@ type Date
end-exclusive manner), by default the end date is not included in the end-exclusive manner), by default the end date is not included in the
count. This has the nice property that for example to count the work count. This has the nice property that for example to count the work
days within the next week you can do days within the next week you can do
`date.work_days_until (date + (Period.new days=7)` and it will look at `date.work_days_until (date + (Period.new days=7))` and it will look at
the 7 days starting from the current `date` and not 8 days. This also the 7 days starting from the current `date` and not 8 days. This also
gives us a property that gives us a property that
`date.work_days_until (date.add_work_days N) == N` for any non-negative `date.work_days_until (date.add_work_days N) == N` for any non-negative

View File

@ -1,4 +1,5 @@
import project.Data.Time.Date.Date import project.Data.Time.Date.Date
import project.Data.Time.Period.Period
import project.Data.Time.Date_Time.Date_Time import project.Data.Time.Date_Time.Date_Time
import project.Data.Time.Day_Of_Week.Day_Of_Week import project.Data.Time.Day_Of_Week.Day_Of_Week
from project.Data.Boolean import Boolean, True, False from project.Data.Boolean import Boolean, True, False
@ -22,6 +23,8 @@ type Date_Period
to any other day. to any other day.
Week (first_day:Day_Of_Week = Day_Of_Week.Monday) Week (first_day:Day_Of_Week = Day_Of_Week.Monday)
Day
## PRIVATE ## PRIVATE
This method could be replaced with matching on `Date_Period` supertype This method could be replaced with matching on `Date_Period` supertype
if/when that is supported. if/when that is supported.
@ -36,14 +39,25 @@ type Date_Period
Date_Period.Quarter -> Date_Period_Utils.quarter_start Date_Period.Quarter -> Date_Period_Utils.quarter_start
Date_Period.Month -> TemporalAdjusters.firstDayOfMonth Date_Period.Month -> TemporalAdjusters.firstDayOfMonth
Date_Period.Week first_day -> TemporalAdjusters.previousOrSame first_day.to_java Date_Period.Week first_day -> TemporalAdjusters.previousOrSame first_day.to_java
Date_Period.Day -> Date_Period_Utils.day_start
(Time_Utils.utils_for date).apply_adjuster date adjuster (Time_Utils.utils_for date).apply_adjuster date adjuster
## PRIVATE ## PRIVATE
adjust_end : (Date | Date_Time) -> (Date | Date_Time) adjust_end : (Date | Date_Time) -> (Date | Date_Time)
adjust_end self date = adjust_end self date = if self == Date_Period.Day then date else
adjuster = case self of adjuster = case self of
Date_Period.Year -> TemporalAdjusters.lastDayOfYear Date_Period.Year -> TemporalAdjusters.lastDayOfYear
Date_Period.Quarter -> Date_Period_Utils.quarter_end Date_Period.Quarter -> Date_Period_Utils.quarter_end
Date_Period.Month -> TemporalAdjusters.lastDayOfMonth Date_Period.Month -> TemporalAdjusters.lastDayOfMonth
Date_Period.Week first_day -> Date_Period_Utils.end_of_week first_day.to_java Date_Period.Week first_day -> Date_Period_Utils.end_of_week first_day.to_java
Date_Period.Day -> Date_Period_Utils.day_end
(Time_Utils.utils_for date).apply_adjuster date adjuster (Time_Utils.utils_for date).apply_adjuster date adjuster
## PRIVATE
to_period : Period
to_period self = case self of
Date_Period.Year -> Period.new years=1
Date_Period.Quarter -> Period.new months=3
Date_Period.Month -> Period.new months=1
Date_Period.Week _ -> Period.new days=7
Date_Period.Day -> Period.new days=1

View File

@ -1,10 +1,12 @@
import project.Any.Any import project.Any.Any
import project.Data.Json.JS_Object
import project.Data.Numbers.Integer import project.Data.Numbers.Integer
import project.Data.Ordering.Comparable import project.Data.Ordering.Comparable
import project.Data.Text.Extensions import project.Data.Text.Extensions
import project.Data.Text.Text import project.Data.Text.Text
import project.Data.Time.Date.Date import project.Data.Time.Date.Date
import project.Data.Time.Duration.Duration import project.Data.Time.Duration.Duration
import project.Data.Vector.Vector
import project.Error.Error import project.Error.Error
import project.Errors.Illegal_Argument.Illegal_Argument import project.Errors.Illegal_Argument.Illegal_Argument
import project.Errors.Time_Error.Time_Error import project.Errors.Time_Error.Time_Error
@ -144,3 +146,20 @@ type Period
m = if months == 0 && (y=="" || d=="") then "" else months.to_text + "M " m = if months == 0 && (y=="" || d=="") then "" else months.to_text + "M "
(y + m + d) . trim (y + m + d) . trim
## PRIVATE
Convert to a JavaScript Object representing a Period.
> Example
Convert a period of 10 months to a JS_Object.
example_to_json = (Period.new months=10).to_js_object
to_js_object : JS_Object
to_js_object self =
b = Vector.new_builder 7
b.append ["type", "Period"]
b.append ["constructor", "new"]
if self.years==0 . not then b.append ["years", self.years]
if self.months==0 . not then b.append ["months", self.months]
if self.days==0 . not then b.append ["days", self.days]
JS_Object.from_pairs b.to_vector

View File

@ -45,7 +45,7 @@ format_widget : Single_Choice
format_widget = format_widget =
all_types = [Auto_Detect] + format_types all_types = [Auto_Detect] + format_types
make_ctor type_obj = make_ctor type_obj =
type_name = Meta.get_qualified_type_name type_obj type_name = Meta.get_simple_type_name type_obj
ctors = Meta.meta type_obj . constructors ctors = Meta.meta type_obj . constructors
is_singleton_type = ctors.length == 0 is_singleton_type = ctors.length == 0
if is_singleton_type then type_name else if is_singleton_type then type_name else

View File

@ -8,7 +8,7 @@ import Standard.Base.Errors.Illegal_Argument.Illegal_Argument
import Standard.Base.Errors.Illegal_State.Illegal_State import Standard.Base.Errors.Illegal_State.Illegal_State
import Standard.Base.Errors.Unimplemented.Unimplemented import Standard.Base.Errors.Unimplemented.Unimplemented
from Standard.Table import Auto_Detect, Aggregate_Column, Data_Formatter, Column_Selector, Sort_Column, Match_Columns, Position, Set_Mode, Auto, Value_Type from Standard.Table import Aggregate_Column, Data_Formatter, Column_Selector, Sort_Column, Match_Columns, Position, Set_Mode, Auto, Value_Type
import Standard.Table.Data.Expression.Expression import Standard.Table.Data.Expression.Expression
import Standard.Table.Data.Expression.Expression_Error import Standard.Table.Data.Expression.Expression_Error
import Standard.Table.Data.Join_Condition.Join_Condition import Standard.Table.Data.Join_Condition.Join_Condition
@ -23,6 +23,7 @@ import Standard.Table.Internal.Java_Exports
import Standard.Table.Internal.Table_Helpers import Standard.Table.Internal.Table_Helpers
import Standard.Table.Internal.Table_Helpers.Table_Column_Helper import Standard.Table.Internal.Table_Helpers.Table_Column_Helper
import Standard.Table.Internal.Problem_Builder.Problem_Builder import Standard.Table.Internal.Problem_Builder.Problem_Builder
import Standard.Table.Internal.Unique_Name_Strategy.Unique_Name_Strategy
import Standard.Table.Internal.Widget_Helpers import Standard.Table.Internal.Widget_Helpers
from Standard.Table.Data.Column import get_item_string, normalize_string_for_display from Standard.Table.Data.Column import get_item_string, normalize_string_for_display
from Standard.Table.Data.Table import print_table from Standard.Table.Data.Table import print_table
@ -187,6 +188,7 @@ type Table
table.select_columns [-1, 0, 1] reorder=True table.select_columns [-1, 0, 1] reorder=True
Icon: select_column Icon: select_column
@columns Widget_Helpers.make_column_name_vector_selector
select_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Boolean -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range select_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Boolean -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range
select_columns self (columns = [0]) (reorder = False) (error_on_missing_columns = True) (on_problems = Report_Warning) = select_columns self (columns = [0]) (reorder = False) (error_on_missing_columns = True) (on_problems = Report_Warning) =
new_columns = self.columns_helper.select_columns selectors=columns reorder=reorder error_on_missing_columns=error_on_missing_columns on_problems=on_problems new_columns = self.columns_helper.select_columns selectors=columns reorder=reorder error_on_missing_columns=error_on_missing_columns on_problems=on_problems
@ -239,6 +241,7 @@ type Table
Remove the first two columns and the last column. Remove the first two columns and the last column.
table.remove_columns [-1, 0, 1] table.remove_columns [-1, 0, 1]
@columns Widget_Helpers.make_column_name_vector_selector
remove_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range remove_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range
remove_columns self (columns = [0]) (error_on_missing_columns = False) (on_problems = Report_Warning) = remove_columns self (columns = [0]) (error_on_missing_columns = False) (on_problems = Report_Warning) =
new_columns = self.columns_helper.remove_columns selectors=columns error_on_missing_columns=error_on_missing_columns on_problems=on_problems new_columns = self.columns_helper.remove_columns selectors=columns error_on_missing_columns=error_on_missing_columns on_problems=on_problems
@ -294,6 +297,7 @@ type Table
Move the first column to back. Move the first column to back.
table.reorder_columns [0] position=Position.After_Other_Columns table.reorder_columns [0] position=Position.After_Other_Columns
@columns Widget_Helpers.make_column_name_vector_selector
reorder_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Position -> Boolean -> Problem_Behavior -> Table ! Missing_Input_Columns | Column_Indexes_Out_Of_Range reorder_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Position -> Boolean -> Problem_Behavior -> Table ! Missing_Input_Columns | Column_Indexes_Out_Of_Range
reorder_columns self (columns = [0]) (position = Position.Before_Other_Columns) (error_on_missing_columns = False) (on_problems = Report_Warning) = reorder_columns self (columns = [0]) (position = Position.Before_Other_Columns) (error_on_missing_columns = False) (on_problems = Report_Warning) =
new_columns = self.columns_helper.reorder_columns selectors=columns position=position error_on_missing_columns on_problems=on_problems new_columns = self.columns_helper.reorder_columns selectors=columns position=position error_on_missing_columns on_problems=on_problems
@ -617,6 +621,7 @@ type Table
double_inventory = table.at "total_stock" * 2 double_inventory = table.at "total_stock" * 2
table.set double_inventory new_name="total_stock" table.set double_inventory new_name="total_stock"
table.set "2 * [total_stock]" new_name="total_stock_expr" table.set "2 * [total_stock]" new_name="total_stock_expr"
@new_name Widget_Helpers.make_column_name_selector
set : Column | Text -> Text | Nothing -> Set_Mode -> Problem_Behavior -> Table ! Unsupported_Name | Existing_Column | Missing_Column | No_Such_Column | Expression_Error set : Column | Text -> Text | Nothing -> Set_Mode -> Problem_Behavior -> Table ! Unsupported_Name | Existing_Column | Missing_Column | No_Such_Column | Expression_Error
set self column new_name=Nothing set_mode=Set_Mode.Add_Or_Update on_problems=Report_Warning = set self column new_name=Nothing set_mode=Set_Mode.Add_Or_Update on_problems=Report_Warning =
resolved = case column of resolved = case column of
@ -794,6 +799,7 @@ type Table
Sort the table by columns whose names start with letter `a`. Sort the table by columns whose names start with letter `a`.
table.order_by [(Sort_Column.Select_By_Name "a.*" use_regex=True case_sensitivity=Case_Sensitivity.Insensitive)] table.order_by [(Sort_Column.Select_By_Name "a.*" use_regex=True case_sensitivity=Case_Sensitivity.Insensitive)]
@columns Widget_Helpers.make_order_by_selector
order_by : Text | Sort_Column | Vector (Text | Sort_Column) -> Text_Ordering -> Boolean -> Problem_Behavior -> Table ! Incomparable_Values | No_Input_Columns_Selected | Missing_Input_Columns | Column_Indexes_Out_Of_Range order_by : Text | Sort_Column | Vector (Text | Sort_Column) -> Text_Ordering -> Boolean -> Problem_Behavior -> Table ! Incomparable_Values | No_Input_Columns_Selected | Missing_Input_Columns | Column_Indexes_Out_Of_Range
order_by self (columns = ([(Sort_Column.Name (self.columns.at 0 . name))])) text_ordering=Text_Ordering.Default error_on_missing_columns=True on_problems=Problem_Behavior.Report_Warning = Panic.handle_wrapped_dataflow_error <| order_by self (columns = ([(Sort_Column.Name (self.columns.at 0 . name))])) text_ordering=Text_Ordering.Default error_on_missing_columns=True on_problems=Problem_Behavior.Report_Warning = Panic.handle_wrapped_dataflow_error <|
problem_builder = Problem_Builder.new error_on_missing_columns=error_on_missing_columns types_to_always_throw=[No_Input_Columns_Selected] problem_builder = Problem_Builder.new error_on_missing_columns=error_on_missing_columns types_to_always_throw=[No_Input_Columns_Selected]
@ -843,6 +849,7 @@ type Table
- If floating points values are present in the distinct columns, a - If floating points values are present in the distinct columns, a
`Floating_Point_Equality` is reported according to the `on_problems` `Floating_Point_Equality` is reported according to the `on_problems`
setting. setting.
@columns Widget_Helpers.make_column_name_vector_selector
distinct : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | No_Input_Columns_Selected | Floating_Point_Equality distinct : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | No_Input_Columns_Selected | Floating_Point_Equality
distinct self columns=self.column_names case_sensitivity=Case_Sensitivity.Default error_on_missing_columns=True on_problems=Report_Warning = distinct self columns=self.column_names case_sensitivity=Case_Sensitivity.Default error_on_missing_columns=True on_problems=Report_Warning =
key_columns = self.columns_helper.select_columns selectors=columns reorder=True error_on_missing_columns=error_on_missing_columns on_problems=on_problems . catch No_Output_Columns _-> key_columns = self.columns_helper.select_columns selectors=columns reorder=True error_on_missing_columns=error_on_missing_columns on_problems=on_problems . catch No_Output_Columns _->
@ -855,12 +862,15 @@ type Table
Arguments: Arguments:
- right: The table to join with. - right: The table to join with.
- join_kind: The `Join_Kind` for the joining the two tables. - join_kind: The `Join_Kind` for the joining the two tables. It defaults
to `Left_Outer`.
- on: A single condition or a common column name, or a list thereof, on - on: A single condition or a common column name, or a list thereof, on
which to correlate rows from the two tables. If multiple conditions which to correlate rows from the two tables. If multiple conditions
are supplied, rows are correlated only if all are true. are supplied, rows are correlated only if all are true.
If common column names are provided, these columns should be present If common column names are provided, these columns should be present
in both tables and an equality condition is added for each of them. in both tables and an equality condition is added for each of them.
By default, the join is performed on the first column of the left table
correlated with a column in the right table with the same name.
- right_prefix: The prefix added to right table column names in case of - right_prefix: The prefix added to right table column names in case of
name conflict. name conflict.
- on_problems: Specifies how to handle problems if they occur, reporting - on_problems: Specifies how to handle problems if they occur, reporting
@ -908,10 +918,9 @@ type Table
allows to join the two tables on equality of corresponding columns with allows to join the two tables on equality of corresponding columns with
the same name. So `table.join other on=["A", "B"]` is a shorthand for: the same name. So `table.join other on=["A", "B"]` is a shorthand for:
table.join other on=[Join_Condition.Equals "A" "A", Join_Condition.Equals "B" "B"] table.join other on=[Join_Condition.Equals "A" "A", Join_Condition.Equals "B" "B"]
@join_kind Widget_Helpers.join_kind_selector
@on Widget_Helpers.make_column_name_selector @on Widget_Helpers.make_column_name_selector
join : Table -> Join_Kind -> Join_Condition | Text | Vector (Join_Condition | Text) -> Text -> Problem_Behavior -> Table join : Table -> Join_Kind -> Join_Condition | Text | Vector (Join_Condition | Text) -> Text -> Problem_Behavior -> Table
join self right join_kind=Join_Kind.Inner on=[Join_Condition.Equals 0 0] right_prefix="Right_" on_problems=Report_Warning = join self right join_kind=Join_Kind.Left_Outer on=[Join_Condition.Equals self.column_names.first] right_prefix="Right " on_problems=Report_Warning =
can_proceed = if Table_Helpers.is_table right . not then Error.throw (Type_Error.Error Table right "right") else can_proceed = if Table_Helpers.is_table right . not then Error.throw (Type_Error.Error Table right "right") else
same_backend = case right of same_backend = case right of
_ : Table -> True _ : Table -> True
@ -996,7 +1005,7 @@ type Table
example, by sorting the table; in-memory tables will keep the memory example, by sorting the table; in-memory tables will keep the memory
layout order while for database tables the order may be unspecified). layout order while for database tables the order may be unspecified).
cross_join : Table -> Integer | Nothing -> Text -> Problem_Behavior -> Table cross_join : Table -> Integer | Nothing -> Text -> Problem_Behavior -> Table
cross_join self right right_row_limit=100 right_prefix="Right_" on_problems=Report_Warning = cross_join self right right_row_limit=100 right_prefix="Right " on_problems=Report_Warning =
_ = [right, right_row_limit, right_prefix, on_problems] _ = [right, right_row_limit, right_prefix, on_problems]
Error.throw (Unsupported_Database_Operation.Error "Table.cross_join is not implemented yet for the Database backends.") Error.throw (Unsupported_Database_Operation.Error "Table.cross_join is not implemented yet for the Database backends.")
@ -1045,7 +1054,7 @@ type Table
order of columns is undefined and the operation will fail, reporting a order of columns is undefined and the operation will fail, reporting a
`Undefined_Column_Order` problem and returning an empty table. `Undefined_Column_Order` problem and returning an empty table.
zip : Table -> Boolean | Report_Unmatched -> Text -> Problem_Behavior -> Table zip : Table -> Boolean | Report_Unmatched -> Text -> Problem_Behavior -> Table
zip self right keep_unmatched=Report_Unmatched right_prefix="Right_" on_problems=Report_Warning = zip self right keep_unmatched=Report_Unmatched right_prefix="Right " on_problems=Report_Warning =
_ = [right, keep_unmatched, right_prefix, on_problems] _ = [right, keep_unmatched, right_prefix, on_problems]
Error.throw (Unsupported_Database_Operation.Error "Table.zip is not implemented yet for the Database backends.") Error.throw (Unsupported_Database_Operation.Error "Table.zip is not implemented yet for the Database backends.")
@ -1340,6 +1349,7 @@ type Table
- If any column names in the new table are clashing, a - If any column names in the new table are clashing, a
`Duplicate_Output_Column_Names` is reported according to the `Duplicate_Output_Column_Names` is reported according to the
`on_problems` setting. `on_problems` setting.
@id_fields Widget_Helpers.make_column_name_vector_selector
transpose : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Text -> Text -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range | Duplicate_Output_Column_Names transpose : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Text -> Text -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range | Duplicate_Output_Column_Names
transpose self id_fields=[] (name_field="Name") (value_field="Value") (error_on_missing_columns=True) (on_problems = Report_Warning) = transpose self id_fields=[] (name_field="Name") (value_field="Value") (error_on_missing_columns=True) (on_problems = Report_Warning) =
## Avoid unused arguments warning. We cannot rename arguments to `_`, ## Avoid unused arguments warning. We cannot rename arguments to `_`,
@ -1382,6 +1392,9 @@ type Table
an `Unquoted_Delimiter` an `Unquoted_Delimiter`
- If there are more than 10 issues with a single column, - If there are more than 10 issues with a single column,
an `Additional_Warnings`. an `Additional_Warnings`.
@group_by Widget_Helpers.make_column_name_vector_selector
@name_column Widget_Helpers.make_column_name_selector
@values (Widget_Helpers.make_aggregate_column_selector include_group_by=False)
cross_tab : Aggregate_Column | Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector | Aggregate_Column) -> (Text | Integer | Column) -> Vector Aggregate_Column -> Problem_Behavior -> Table ! Missing_Input_Columns | Column_Indexes_Out_Of_Range | Invalid_Aggregate_Column | Floating_Point_Equality | Invalid_Aggregation | Unquoted_Delimiter | Additional_Warnings cross_tab : Aggregate_Column | Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector | Aggregate_Column) -> (Text | Integer | Column) -> Vector Aggregate_Column -> Problem_Behavior -> Table ! Missing_Input_Columns | Column_Indexes_Out_Of_Range | Invalid_Aggregate_Column | Floating_Point_Equality | Invalid_Aggregation | Unquoted_Delimiter | Additional_Warnings
cross_tab self group_by=[] name_column=self.column_names.first values=Aggregate_Column.Count (on_problems=Report_Warning) = cross_tab self group_by=[] name_column=self.column_names.first values=Aggregate_Column.Count (on_problems=Report_Warning) =
## Avoid unused arguments warning. We cannot rename arguments to `_`, ## Avoid unused arguments warning. We cannot rename arguments to `_`,
@ -1392,6 +1405,8 @@ type Table
## Parsing values is not supported in database tables, the table has to be ## Parsing values is not supported in database tables, the table has to be
loaded into memory first with `read`. loaded into memory first with `read`.
@type Widget_Helpers.parse_type_selector
@columns Widget_Helpers.make_column_name_vector_selector
parse : Text | Integer | Column_Selector | Vector (Text | Integer | Column_Selector) -> Value_Type | Auto -> Text | Data_Formatter -> Boolean -> Problem_Behavior -> Table parse : Text | Integer | Column_Selector | Vector (Text | Integer | Column_Selector) -> Value_Type | Auto -> Text | Data_Formatter -> Boolean -> Problem_Behavior -> Table
parse columns=(self.columns . filter (c-> c.value_type.is_text) . map .name) type=Auto format=Data_Formatter.Value error_on_missing_columns=True on_problems=Report_Warning = parse columns=(self.columns . filter (c-> c.value_type.is_text) . map .name) type=Auto format=Data_Formatter.Value error_on_missing_columns=True on_problems=Report_Warning =
## Avoid unused arguments warning. We cannot rename arguments to `_`, ## Avoid unused arguments warning. We cannot rename arguments to `_`,
@ -1415,6 +1430,7 @@ type Table
! Error Conditions ! Error Conditions
If the data exceeds the `column_count`, a `Column_Count_Exceeded` will If the data exceeds the `column_count`, a `Column_Count_Exceeded` will
be reported according to the `on_problems` behavior. be reported according to the `on_problems` behavior.
@column Widget_Helpers.make_column_name_selector
split_to_columns : Text | Integer -> Text -> Integer | Nothing -> Problem_Behavior -> Table split_to_columns : Text | Integer -> Text -> Integer | Nothing -> Problem_Behavior -> Table
split_to_columns self column delimiter="," column_count=Nothing on_problems=Report_Error = split_to_columns self column delimiter="," column_count=Nothing on_problems=Report_Error =
_ = [column delimiter column_count on_problems] _ = [column delimiter column_count on_problems]
@ -1426,6 +1442,7 @@ type Table
Arguments: Arguments:
- column: The name or index of the column to split the text of. - column: The name or index of the column to split the text of.
- delimiter: The term or terms used to split the text. - delimiter: The term or terms used to split the text.
@column Widget_Helpers.make_column_name_selector
split_to_rows : Text | Integer -> Text -> Table split_to_rows : Text | Integer -> Text -> Table
split_to_rows self column delimiter="," = split_to_rows self column delimiter="," =
_ = [column delimiter] _ = [column delimiter]
@ -1451,6 +1468,7 @@ type Table
! Error Conditions ! Error Conditions
If the data exceeds the `column_count`, a `Column_Count_Exceeded` will If the data exceeds the `column_count`, a `Column_Count_Exceeded` will
be reported according to the `on_problems` behavior. be reported according to the `on_problems` behavior.
@column Widget_Helpers.make_column_name_selector
tokenize_to_columns : Text | Integer -> Text -> Case_Sensitivity -> Integer | Nothing -> Problem_Behavior -> Table tokenize_to_columns : Text | Integer -> Text -> Case_Sensitivity -> Integer | Nothing -> Problem_Behavior -> Table
tokenize_to_columns self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive column_count=Nothing on_problems=Report_Error = tokenize_to_columns self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive column_count=Nothing on_problems=Report_Error =
_ = [column pattern case_sensitivity column_count on_problems] _ = [column pattern case_sensitivity column_count on_problems]
@ -1470,6 +1488,7 @@ type Table
- at_least_one_row: If True, a tokenization that returns no values will still - at_least_one_row: If True, a tokenization that returns no values will still
produce at least one row, with `Nothing` for the output column values. produce at least one row, with `Nothing` for the output column values.
Equivalent to converting a tokenization output of [] to [Nothing]. Equivalent to converting a tokenization output of [] to [Nothing].
@column Widget_Helpers.make_column_name_selector
tokenize_to_rows : Text | Integer -> Text -> Case_Sensitivity -> Boolean -> Table tokenize_to_rows : Text | Integer -> Text -> Case_Sensitivity -> Boolean -> Table
tokenize_to_rows self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive at_least_one_row=False = tokenize_to_rows self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive at_least_one_row=False =
_ = [column, pattern, case_sensitivity, at_least_one_row] _ = [column, pattern, case_sensitivity, at_least_one_row]
@ -1499,6 +1518,7 @@ type Table
will be named `<Input Column> <N>` where `N` is the number of the marked group. will be named `<Input Column> <N>` where `N` is the number of the marked group.
If the new name is already in use it will be renamed following the normal If the new name is already in use it will be renamed following the normal
suffixing strategy. suffixing strategy.
@column Widget_Helpers.make_column_name_selector
parse_to_columns : Text | Integer -> Text -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Table parse_to_columns : Text | Integer -> Text -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Table
parse_to_columns self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive parse_values=True on_problems=Report_Error = parse_to_columns self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive parse_values=True on_problems=Report_Error =
_ = [column, pattern, case_sensitivity, parse_values, on_problems] _ = [column, pattern, case_sensitivity, parse_values, on_problems]
@ -1554,6 +1574,7 @@ type Table
If the backend does not support the requested target type, the closest If the backend does not support the requested target type, the closest
supported type is chosen and a `Inexact_Type_Coercion` problem is supported type is chosen and a `Inexact_Type_Coercion` problem is
reported. reported.
@columns Widget_Helpers.make_column_name_vector_selector
cast : (Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector)) -> Value_Type -> Problem_Behavior -> Table ! Illegal_Argument | Inexact_Type_Coercion | Lossy_Conversion cast : (Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector)) -> Value_Type -> Problem_Behavior -> Table ! Illegal_Argument | Inexact_Type_Coercion | Lossy_Conversion
cast self columns=[0] value_type=Value_Type.Char on_problems=Problem_Behavior.Report_Warning = cast self columns=[0] value_type=Value_Type.Char on_problems=Problem_Behavior.Report_Warning =
selected = self.select_columns columns selected = self.select_columns columns
@ -1593,9 +1614,7 @@ type Table
table = self.connection.read_statement sql table = self.connection.read_statement sql
table.at column_name . at 0 table.at column_name . at 0
## UNSTABLE ## Returns a materialized dataframe containing rows of this table.
Returns a materialized dataframe containing rows of this table.
Arguments: Arguments:
- max_rows: specifies a maximum amount of rows to fetch; if not set, all - max_rows: specifies a maximum amount of rows to fetch; if not set, all
@ -1859,16 +1878,9 @@ display_dataframe df indices_count all_rows_count format_terminal =
is, otherwise numerical suffixes are added. is, otherwise numerical suffixes are added.
fresh_names : Vector Text -> Vector Text -> Vector Text fresh_names : Vector Text -> Vector Text -> Vector Text
fresh_names used_names preferred_names = fresh_names used_names preferred_names =
freshen currently_used name ix = unique = Unique_Name_Strategy.new
new_name = if ix == 0 then name else name+"_"+ix.to_text unique.mark_used used_names
case currently_used.contains new_name of unique.make_all_unique preferred_names
False -> new_name
True -> freshen currently_used name ix+1
res = preferred_names . fold [used_names, []] acc-> name->
used = acc.first
new_name = freshen used name 0
[used_names + [new_name], acc.second + [new_name]]
res.second
## PRIVATE ## PRIVATE

View File

@ -6,6 +6,7 @@ import project.Connection.Database
import project.Connection.Postgres_Details.Postgres_Details import project.Connection.Postgres_Details.Postgres_Details
import project.Connection.SQLite_Details.SQLite_Details import project.Connection.SQLite_Details.SQLite_Details
import project.Connection.SQLite_Details.In_Memory import project.Connection.SQLite_Details.In_Memory
import project.Connection.SQLite_Format.SQLite_Format
import project.Connection.SSL_Mode.SSL_Mode import project.Connection.SSL_Mode.SSL_Mode
import project.Data.SQL_Query.SQL_Query import project.Data.SQL_Query.SQL_Query
import project.Extensions.Upload_Table import project.Extensions.Upload_Table
@ -21,6 +22,7 @@ export project.Connection.Database
export project.Connection.Postgres_Details.Postgres_Details export project.Connection.Postgres_Details.Postgres_Details
export project.Connection.SQLite_Details.SQLite_Details export project.Connection.SQLite_Details.SQLite_Details
export project.Connection.SQLite_Details.In_Memory export project.Connection.SQLite_Details.In_Memory
export project.Connection.SQLite_Format.SQLite_Format
export project.Connection.SSL_Mode.SSL_Mode export project.Connection.SSL_Mode.SSL_Mode
export project.Data.SQL_Query.SQL_Query export project.Data.SQL_Query.SQL_Query
export project.Extensions.Upload_Table export project.Extensions.Upload_Table

View File

@ -311,6 +311,7 @@ type Table
table.select_columns [-1, 0, 1] reorder=True table.select_columns [-1, 0, 1] reorder=True
Icon: select_column Icon: select_column
@columns Widget_Helpers.make_column_name_vector_selector
select_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Boolean -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range select_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Boolean -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range
select_columns self columns=[0] (reorder = False) (error_on_missing_columns = True) (on_problems = Report_Warning) = select_columns self columns=[0] (reorder = False) (error_on_missing_columns = True) (on_problems = Report_Warning) =
new_columns = self.columns_helper.select_columns selectors=columns reorder=reorder error_on_missing_columns=error_on_missing_columns on_problems=on_problems new_columns = self.columns_helper.select_columns selectors=columns reorder=reorder error_on_missing_columns=error_on_missing_columns on_problems=on_problems
@ -363,7 +364,7 @@ type Table
Remove the first two columns and the last column. Remove the first two columns and the last column.
table.remove_columns [-1, 0, 1] table.remove_columns [-1, 0, 1]
@columns Widget_Helpers.make_column_name_vector_selector
remove_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range remove_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range
remove_columns self (columns=[0]) (error_on_missing_columns = False) (on_problems = Report_Warning) = remove_columns self (columns=[0]) (error_on_missing_columns = False) (on_problems = Report_Warning) =
new_columns = self.columns_helper.remove_columns selectors=columns error_on_missing_columns=error_on_missing_columns on_problems=on_problems new_columns = self.columns_helper.remove_columns selectors=columns error_on_missing_columns=error_on_missing_columns on_problems=on_problems
@ -419,7 +420,7 @@ type Table
Move the first column to back. Move the first column to back.
table.reorder_columns [0] position=Position.After_Other_Columns table.reorder_columns [0] position=Position.After_Other_Columns
@columns Widget_Helpers.make_column_name_vector_selector
reorder_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Position -> Boolean -> Problem_Behavior -> Table ! Missing_Input_Columns | Column_Indexes_Out_Of_Range reorder_columns : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Position -> Boolean -> Problem_Behavior -> Table ! Missing_Input_Columns | Column_Indexes_Out_Of_Range
reorder_columns self (columns = [0]) (position = Position.Before_Other_Columns) (error_on_missing_columns = False) (on_problems = Report_Warning) = reorder_columns self (columns = [0]) (position = Position.Before_Other_Columns) (error_on_missing_columns = False) (on_problems = Report_Warning) =
new_columns = self.columns_helper.reorder_columns selectors=columns position=position error_on_missing_columns=error_on_missing_columns on_problems=on_problems new_columns = self.columns_helper.reorder_columns selectors=columns position=position error_on_missing_columns=error_on_missing_columns on_problems=on_problems
@ -681,6 +682,7 @@ type Table
Sort the table by columns whose names start with letter `a`. Sort the table by columns whose names start with letter `a`.
table.order_by [(Sort_Column.Select_By_Name "a.*" use_regex=True case_sensitivity=Case_Sensitivity.Insensitive)] table.order_by [(Sort_Column.Select_By_Name "a.*" use_regex=True case_sensitivity=Case_Sensitivity.Insensitive)]
@columns Widget_Helpers.make_order_by_selector
order_by : Text | Sort_Column | Vector (Text | Sort_Column) -> Text_Ordering -> Boolean -> Problem_Behavior -> Table ! Incomparable_Values | No_Input_Columns_Selected | Missing_Input_Columns | Column_Indexes_Out_Of_Range order_by : Text | Sort_Column | Vector (Text | Sort_Column) -> Text_Ordering -> Boolean -> Problem_Behavior -> Table ! Incomparable_Values | No_Input_Columns_Selected | Missing_Input_Columns | Column_Indexes_Out_Of_Range
order_by self (columns = ([(Sort_Column.Name (self.columns.at 0 . name))])) text_ordering=Text_Ordering.Default error_on_missing_columns=True on_problems=Problem_Behavior.Report_Warning = order_by self (columns = ([(Sort_Column.Name (self.columns.at 0 . name))])) text_ordering=Text_Ordering.Default error_on_missing_columns=True on_problems=Problem_Behavior.Report_Warning =
problem_builder = Problem_Builder.new error_on_missing_columns=error_on_missing_columns types_to_always_throw=[No_Input_Columns_Selected] problem_builder = Problem_Builder.new error_on_missing_columns=error_on_missing_columns types_to_always_throw=[No_Input_Columns_Selected]
@ -739,6 +741,7 @@ type Table
- If floating points values are present in the distinct columns, a - If floating points values are present in the distinct columns, a
`Floating_Point_Equality` is reported according to the `on_problems` `Floating_Point_Equality` is reported according to the `on_problems`
setting. setting.
@columns Widget_Helpers.make_column_name_vector_selector
distinct : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | No_Input_Columns_Selected | Floating_Point_Equality distinct : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | No_Input_Columns_Selected | Floating_Point_Equality
distinct self (columns = self.column_names) case_sensitivity=Case_Sensitivity.Default error_on_missing_columns=True on_problems=Report_Warning = distinct self (columns = self.column_names) case_sensitivity=Case_Sensitivity.Default error_on_missing_columns=True on_problems=Report_Warning =
key_columns = self.columns_helper.select_columns selectors=columns reorder=True error_on_missing_columns=error_on_missing_columns on_problems=on_problems . catch No_Output_Columns _-> key_columns = self.columns_helper.select_columns selectors=columns reorder=True error_on_missing_columns=error_on_missing_columns on_problems=on_problems . catch No_Output_Columns _->
@ -833,6 +836,8 @@ type Table
Parse all columns inferring their types, using `,` as the decimal point for numbers. Parse all columns inferring their types, using `,` as the decimal point for numbers.
table.parse format=(Data_Formatter.Value.with_number_formatting decimal_point=',') table.parse format=(Data_Formatter.Value.with_number_formatting decimal_point=',')
@type Widget_Helpers.parse_type_selector
@columns Widget_Helpers.make_column_name_vector_selector
parse : Text | Integer | Column_Selector | Vector (Text | Integer | Column_Selector) -> Value_Type | Auto -> Text | Data_Formatter -> Boolean -> Problem_Behavior -> Table parse : Text | Integer | Column_Selector | Vector (Text | Integer | Column_Selector) -> Value_Type | Auto -> Text | Data_Formatter -> Boolean -> Problem_Behavior -> Table
parse self columns=(self.columns . filter (c-> c.value_type.is_text) . map .name) type=Auto format=Data_Formatter.Value error_on_missing_columns=True on_problems=Report_Warning = parse self columns=(self.columns . filter (c-> c.value_type.is_text) . map .name) type=Auto format=Data_Formatter.Value error_on_missing_columns=True on_problems=Report_Warning =
formatter = case format of formatter = case format of
@ -918,6 +923,7 @@ type Table
If the backend does not support the requested target type, the closest If the backend does not support the requested target type, the closest
supported type is chosen and a `Inexact_Type_Coercion` problem is supported type is chosen and a `Inexact_Type_Coercion` problem is
reported. reported.
@columns Widget_Helpers.make_column_name_vector_selector
cast : (Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector)) -> Value_Type -> Problem_Behavior -> Table ! Illegal_Argument | Inexact_Type_Coercion | Lossy_Conversion cast : (Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector)) -> Value_Type -> Problem_Behavior -> Table ! Illegal_Argument | Inexact_Type_Coercion | Lossy_Conversion
cast self columns=[0] value_type=Value_Type.Char on_problems=Problem_Behavior.Report_Warning = cast self columns=[0] value_type=Value_Type.Char on_problems=Problem_Behavior.Report_Warning =
_ = [columns, value_type, on_problems] _ = [columns, value_type, on_problems]
@ -939,6 +945,7 @@ type Table
! Error Conditions ! Error Conditions
If the data exceeds the `column_count`, a `Column_Count_Exceeded` will If the data exceeds the `column_count`, a `Column_Count_Exceeded` will
be reported according to the `on_problems` behavior. be reported according to the `on_problems` behavior.
@column Widget_Helpers.make_column_name_selector
split_to_columns : Text | Integer -> Text -> Integer | Nothing -> Problem_Behavior -> Table split_to_columns : Text | Integer -> Text -> Integer | Nothing -> Problem_Behavior -> Table
split_to_columns self column delimiter="," column_count=Nothing on_problems=Report_Error = split_to_columns self column delimiter="," column_count=Nothing on_problems=Report_Error =
Split_Tokenize.split_to_columns self column delimiter column_count on_problems Split_Tokenize.split_to_columns self column delimiter column_count on_problems
@ -949,6 +956,7 @@ type Table
Arguments: Arguments:
- column: The name or index of the column to split the text of. - column: The name or index of the column to split the text of.
- delimiter: The term or terms used to split the text. - delimiter: The term or terms used to split the text.
@column Widget_Helpers.make_column_name_selector
split_to_rows : Text | Integer -> Text -> Table split_to_rows : Text | Integer -> Text -> Table
split_to_rows self column delimiter="," = split_to_rows self column delimiter="," =
Split_Tokenize.split_to_rows self column delimiter Split_Tokenize.split_to_rows self column delimiter
@ -973,6 +981,7 @@ type Table
! Error Conditions ! Error Conditions
If the data exceeds the `column_count`, a `Column_Count_Exceeded` will If the data exceeds the `column_count`, a `Column_Count_Exceeded` will
be reported according to the `on_problems` behavior. be reported according to the `on_problems` behavior.
@column Widget_Helpers.make_column_name_selector
tokenize_to_columns : Text | Integer -> Text -> Case_Sensitivity -> Integer | Nothing -> Problem_Behavior -> Table tokenize_to_columns : Text | Integer -> Text -> Case_Sensitivity -> Integer | Nothing -> Problem_Behavior -> Table
tokenize_to_columns self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive column_count=Nothing on_problems=Report_Error = tokenize_to_columns self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive column_count=Nothing on_problems=Report_Error =
Split_Tokenize.tokenize_to_columns self column pattern case_sensitivity column_count on_problems Split_Tokenize.tokenize_to_columns self column pattern case_sensitivity column_count on_problems
@ -991,6 +1000,7 @@ type Table
- at_least_one_row: If True, a tokenization that returns no values will still - at_least_one_row: If True, a tokenization that returns no values will still
produce at least one row, with `Nothing` for the output column values. produce at least one row, with `Nothing` for the output column values.
Equivalent to converting a tokenization output of [] to [Nothing]. Equivalent to converting a tokenization output of [] to [Nothing].
@column Widget_Helpers.make_column_name_selector
tokenize_to_rows : Text | Integer -> Text -> Case_Sensitivity -> Boolean -> Table tokenize_to_rows : Text | Integer -> Text -> Case_Sensitivity -> Boolean -> Table
tokenize_to_rows self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive at_least_one_row=False = tokenize_to_rows self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive at_least_one_row=False =
Split_Tokenize.tokenize_to_rows self column pattern case_sensitivity at_least_one_row Split_Tokenize.tokenize_to_rows self column pattern case_sensitivity at_least_one_row
@ -1019,6 +1029,7 @@ type Table
will be named `<Input Column> <N>` where `N` is the number of the marked group. will be named `<Input Column> <N>` where `N` is the number of the marked group.
If the new name is already in use it will be renamed following the normal If the new name is already in use it will be renamed following the normal
suffixing strategy. suffixing strategy.
@column Widget_Helpers.make_column_name_selector
parse_to_columns : Text | Integer -> Text -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Table parse_to_columns : Text | Integer -> Text -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Table
parse_to_columns self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive parse_values=True on_problems=Report_Error = parse_to_columns self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive parse_values=True on_problems=Report_Error =
Split_Tokenize.parse_to_columns self column pattern case_sensitivity parse_values on_problems Split_Tokenize.parse_to_columns self column pattern case_sensitivity parse_values on_problems
@ -1208,6 +1219,7 @@ type Table
double_inventory = table.at "total_stock" * 2 double_inventory = table.at "total_stock" * 2
table.set double_inventory new_name="total_stock" table.set double_inventory new_name="total_stock"
table.set "2 * [total_stock]" new_name="total_stock_expr" table.set "2 * [total_stock]" new_name="total_stock_expr"
@new_name Widget_Helpers.make_column_name_selector
set : Column | Text -> Text | Nothing -> Set_Mode -> Problem_Behavior -> Table ! Existing_Column | Missing_Column | No_Such_Column | Expression_Error set : Column | Text -> Text | Nothing -> Set_Mode -> Problem_Behavior -> Table ! Existing_Column | Missing_Column | No_Such_Column | Expression_Error
set self column new_name=Nothing set_mode=Set_Mode.Add_Or_Update on_problems=Report_Warning = set self column new_name=Nothing set_mode=Set_Mode.Add_Or_Update on_problems=Report_Warning =
resolved = case column of resolved = case column of
@ -1322,12 +1334,15 @@ type Table
Arguments: Arguments:
- right: The table to join with. - right: The table to join with.
- join_kind: The `Join_Kind` for the joining the two tables. - join_kind: The `Join_Kind` for the joining the two tables. It defaults
to `Left_Outer`.
- on: A single condition or a common column name, or a list thereof, on - on: A single condition or a common column name, or a list thereof, on
which to correlate rows from the two tables. If multiple conditions which to correlate rows from the two tables. If multiple conditions
are supplied, rows are correlated only if all are true. are supplied, rows are correlated only if all are true.
If common column names are provided, these columns should be present If common column names are provided, these columns should be present
in both tables and an equality condition is added for each of them. in both tables and an equality condition is added for each of them.
By default, the join is performed on the first column of the left table
correlated with a column in the right table with the same name.
- right_prefix: The prefix added to right table column names in case of - right_prefix: The prefix added to right table column names in case of
name conflict. name conflict.
- on_problems: Specifies how to handle problems if they occur, reporting - on_problems: Specifies how to handle problems if they occur, reporting
@ -1375,10 +1390,9 @@ type Table
allows to join the two tables on equality of corresponding columns with allows to join the two tables on equality of corresponding columns with
the same name. So `table.join other on=["A", "B"]` is a shorthand for: the same name. So `table.join other on=["A", "B"]` is a shorthand for:
table.join other on=[Join_Condition.Equals "A" "A", Join_Condition.Equals "B" "B"] table.join other on=[Join_Condition.Equals "A" "A", Join_Condition.Equals "B" "B"]
@join_kind Widget_Helpers.join_kind_selector
@on Widget_Helpers.make_column_name_selector @on Widget_Helpers.make_column_name_selector
join : Table -> Join_Kind -> Join_Condition | Text | Vector (Join_Condition | Text) -> Text -> Problem_Behavior -> Table join : Table -> Join_Kind -> Join_Condition | Text | Vector (Join_Condition | Text) -> Text -> Problem_Behavior -> Table
join self right join_kind=Join_Kind.Inner on=[Join_Condition.Equals 0 0] right_prefix="Right_" on_problems=Report_Warning = join self right join_kind=Join_Kind.Left_Outer on=[Join_Condition.Equals self.column_names.first] right_prefix="Right " on_problems=Report_Warning =
if check_table "right" right then if check_table "right" right then
# [left_unmatched, matched, right_unmatched] # [left_unmatched, matched, right_unmatched]
rows_to_keep = case join_kind of rows_to_keep = case join_kind of
@ -1439,7 +1453,7 @@ type Table
example, by sorting the table; in-memory tables will keep the memory example, by sorting the table; in-memory tables will keep the memory
layout order while for database tables the order may be unspecified). layout order while for database tables the order may be unspecified).
cross_join : Table -> Integer | Nothing -> Text -> Problem_Behavior -> Table cross_join : Table -> Integer | Nothing -> Text -> Problem_Behavior -> Table
cross_join self right right_row_limit=100 right_prefix="Right_" on_problems=Report_Warning = cross_join self right right_row_limit=100 right_prefix="Right " on_problems=Report_Warning =
if check_table "right" right then if check_table "right" right then
limit_problems = case right_row_limit.is_nothing.not && (right.row_count > right_row_limit) of limit_problems = case right_row_limit.is_nothing.not && (right.row_count > right_row_limit) of
True -> True ->
@ -1495,7 +1509,7 @@ type Table
order of columns is undefined and the operation will fail, reporting a order of columns is undefined and the operation will fail, reporting a
`Undefined_Column_Order` problem and returning an empty table. `Undefined_Column_Order` problem and returning an empty table.
zip : Table -> Boolean | Report_Unmatched -> Text -> Problem_Behavior -> Table zip : Table -> Boolean | Report_Unmatched -> Text -> Problem_Behavior -> Table
zip self right keep_unmatched=Report_Unmatched right_prefix="Right_" on_problems=Report_Warning = zip self right keep_unmatched=Report_Unmatched right_prefix="Right " on_problems=Report_Warning =
if check_table "right" right then if check_table "right" right then
keep_unmatched_bool = case keep_unmatched of keep_unmatched_bool = case keep_unmatched of
Report_Unmatched -> True Report_Unmatched -> True
@ -1694,6 +1708,7 @@ type Table
- If any column names in the new table are clashing, a - If any column names in the new table are clashing, a
`Duplicate_Output_Column_Names` is reported according to the `Duplicate_Output_Column_Names` is reported according to the
`on_problems` setting. `on_problems` setting.
@id_fields Widget_Helpers.make_column_name_vector_selector
transpose : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Text -> Text -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range | Duplicate_Output_Column_Names transpose : Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector) -> Text -> Text -> Boolean -> Problem_Behavior -> Table ! No_Output_Columns | Missing_Input_Columns | Column_Indexes_Out_Of_Range | Duplicate_Output_Column_Names
transpose self (id_fields = []) (name_field="Name") (value_field="Value") (error_on_missing_columns=True) (on_problems = Report_Warning) = transpose self (id_fields = []) (name_field="Name") (value_field="Value") (error_on_missing_columns=True) (on_problems = Report_Warning) =
columns_helper = self.columns_helper columns_helper = self.columns_helper
@ -1749,7 +1764,10 @@ type Table
an `Unquoted_Delimiter` an `Unquoted_Delimiter`
- If there are more than 10 issues with a single column, - If there are more than 10 issues with a single column,
an `Additional_Warnings`. an `Additional_Warnings`.
cross_tab : Aggregate_Column | Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector | Aggregate_Column) -> (Text | Integer) -> Vector Aggregate_Column -> Problem_Behavior -> Table ! Missing_Input_Columns | Column_Indexes_Out_Of_Range | Invalid_Aggregate_Column | Floating_Point_Equality | Invalid_Aggregation | Unquoted_Delimiter | Additional_Warnings @group_by Widget_Helpers.make_column_name_vector_selector
@name_column Widget_Helpers.make_column_name_selector
@values (Widget_Helpers.make_aggregate_column_selector include_group_by=False)
cross_tab : Aggregate_Column | Text | Integer | Column_Selector | Vector (Integer | Text | Column_Selector | Aggregate_Column) -> (Text | Integer) -> Aggregate_Column | Vector Aggregate_Column -> Problem_Behavior -> Table ! Missing_Input_Columns | Column_Indexes_Out_Of_Range | Invalid_Aggregate_Column | Floating_Point_Equality | Invalid_Aggregation | Unquoted_Delimiter | Additional_Warnings
cross_tab self group_by=[] name_column=self.column_names.first values=Aggregate_Column.Count (on_problems=Report_Warning) = cross_tab self group_by=[] name_column=self.column_names.first values=Aggregate_Column.Count (on_problems=Report_Warning) =
columns_helper = self.columns_helper columns_helper = self.columns_helper
problem_builder = Problem_Builder.new error_on_missing_columns=True problem_builder = Problem_Builder.new error_on_missing_columns=True

View File

@ -49,7 +49,7 @@ type Delimited_Format
character if it anywhere else than at the beginning of the line. This character if it anywhere else than at the beginning of the line. This
option is only applicable for read mode and does not affect writing. It option is only applicable for read mode and does not affect writing. It
defaults to `Nothing` which means that comments are disabled. defaults to `Nothing` which means that comments are disabled.
Delimited (delimiter:Text) (encoding:Encoding=Encoding.utf_8) (skip_rows:Integer=0) (row_limit:Integer|Nothing=Nothing) (quote_style:Quote_Style=Quote_Style.With_Quotes) (headers:Boolean|Infer=Infer) (value_formatter:Data_Formatter|Nothing=Data_Formatter.Value) (keep_invalid_rows:Boolean=True) (line_endings:Line_Ending_Style=Infer) (comment_character:Text|Nothing=Nothing) Delimited (delimiter:Text=',') (encoding:Encoding=Encoding.utf_8) (skip_rows:Integer=0) (row_limit:Integer|Nothing=Nothing) (quote_style:Quote_Style=Quote_Style.With_Quotes) (headers:Boolean|Infer=Infer) (value_formatter:Data_Formatter|Nothing=Data_Formatter.Value) (keep_invalid_rows:Boolean=True) (line_endings:Line_Ending_Style=Infer) (comment_character:Text|Nothing=Nothing)
## PRIVATE ## PRIVATE
ADVANCED ADVANCED

View File

@ -12,14 +12,17 @@ polyglot java import org.enso.table.error.EmptySheetException
type Missing_Input_Columns type Missing_Input_Columns
## PRIVATE ## PRIVATE
One or more columns not found in the input table. One or more columns not found in the input table.
Error (criteria : [Text]) Error (criteria : [Text]) (where:Text|Nothing = Nothing)
## PRIVATE ## PRIVATE
Convert a missing input error to a human-readable form. Convert a missing input error to a human-readable form.
to_display_text : Text to_display_text : Text
to_display_text self = to_display_text self =
"The criteria "+self.criteria.to_text+" did not match any columns." where = case self.where of
Nothing -> "."
location : Text -> " in "+location+"."
"The criteria "+self.criteria.to_text+" did not match any columns"+where
type Column_Indexes_Out_Of_Range type Column_Indexes_Out_Of_Range
## PRIVATE ## PRIVATE

View File

@ -23,9 +23,10 @@ type Join_Condition_Resolver
resolve : Join_Condition | Text | Vector (Join_Condition | Text) -> Problem_Behavior -> Join_Condition_Resolution resolve : Join_Condition | Text | Vector (Join_Condition | Text) -> Problem_Behavior -> Join_Condition_Resolution
resolve self conditions on_problems = resolve self conditions on_problems =
redundant_names = Vector.new_builder redundant_names = Vector.new_builder
problem_builder = Problem_Builder.new types_to_always_throw=[Missing_Input_Columns, Column_Indexes_Out_Of_Range] left_problem_builder = Problem_Builder.new missing_input_columns_location="the left table" types_to_always_throw=[Missing_Input_Columns, Column_Indexes_Out_Of_Range]
right_problem_builder = Problem_Builder.new missing_input_columns_location="the right table" types_to_always_throw=[Missing_Input_Columns, Column_Indexes_Out_Of_Range]
resolve_selector resolver selector = resolve_selector problem_builder resolver selector =
r_1 = resolver selector r_1 = resolver selector
r_2 = r_1.catch No_Such_Column _-> r_2 = r_1.catch No_Such_Column _->
problem_builder.report_missing_input_columns [selector] problem_builder.report_missing_input_columns [selector]
@ -33,9 +34,10 @@ type Join_Condition_Resolver
r_2.catch Index_Out_Of_Bounds _-> r_2.catch Index_Out_Of_Bounds _->
problem_builder.report_oob_indices [selector] problem_builder.report_oob_indices [selector]
Nothing Nothing
resolve_left = resolve_selector self.left_at resolve_left = resolve_selector left_problem_builder self.left_at
resolve_right = resolve_selector self.right_at resolve_right = resolve_selector right_problem_builder self.right_at
problem_builder = Problem_Builder.new
is_nothing column = case column of is_nothing column = case column of
Nothing -> True Nothing -> True
_ -> False _ -> False
@ -70,7 +72,12 @@ type Join_Condition_Resolver
Value_Type.expect_comparable left right_lower <| Value_Type.expect_comparable left right_lower <|
Value_Type.expect_comparable left right_upper <| Value_Type.expect_comparable left right_upper <|
self.make_between problem_builder left right_lower right_upper self.make_between problem_builder left right_lower right_upper
problem_builder.attach_problems_before on_problems <| attach_problems ~result =
left_problem_builder.attach_problems_before on_problems <|
right_problem_builder.attach_problems_before on_problems <|
problem_builder.attach_problems_before on_problems <|
result
attach_problems <|
if converted.contains Nothing then Panic.throw (Illegal_State.Error "Impossible: unresolved columns remaining in the join resolution. This should have raised a dataflow error. This is a bug in the Table library.") else if converted.contains Nothing then Panic.throw (Illegal_State.Error "Impossible: unresolved columns remaining in the join resolution. This should have raised a dataflow error. This is a bug in the Table library.") else
Join_Condition_Resolution.Result converted redundant_names.to_vector Join_Condition_Resolution.Result converted redundant_names.to_vector

View File

@ -8,7 +8,7 @@ from project.Errors import Missing_Input_Columns, Column_Indexes_Out_Of_Range, D
## PRIVATE ## PRIVATE
type Problem_Builder type Problem_Builder
## PRIVATE ## PRIVATE
Value types_to_always_throw oob_indices missing_input_columns other Value types_to_always_throw oob_indices missing_input_columns missing_input_columns_location other
## PRIVATE ## PRIVATE
report_oob_indices self indices = report_oob_indices self indices =
@ -39,7 +39,7 @@ type Problem_Builder
if vec.not_empty then if vec.not_empty then
problems.append (problem_creator vec) problems.append (problem_creator vec)
build_vector_and_append self.missing_input_columns Missing_Input_Columns.Error build_vector_and_append self.missing_input_columns (Missing_Input_Columns.Error _ where=self.missing_input_columns_location)
build_vector_and_append self.oob_indices Column_Indexes_Out_Of_Range.Error build_vector_and_append self.oob_indices Column_Indexes_Out_Of_Range.Error
self.other.to_vector.each problems.append self.other.to_vector.each problems.append
@ -91,10 +91,12 @@ type Problem_Builder
methods regardless of the `Problem_Behavior` used. Defaults to `False`. methods regardless of the `Problem_Behavior` used. Defaults to `False`.
Setting this to `True` is essentially a shorthand for adding these two Setting this to `True` is essentially a shorthand for adding these two
problem types to `types_to_always_throw`. problem types to `types_to_always_throw`.
- missing_input_columns_location: The location to add to the missing
input column error to make it more informative. Defaults to `Nothing`.
new : Vector -> Boolean -> Problem_Builder new : Vector -> Boolean -> Problem_Builder
new types_to_always_throw=[] error_on_missing_columns=False = new types_to_always_throw=[] error_on_missing_columns=False missing_input_columns_location=Nothing =
additional_types_to_throw = if error_on_missing_columns then [Missing_Input_Columns, Column_Indexes_Out_Of_Range, Invalid_Aggregate_Column] else [] additional_types_to_throw = if error_on_missing_columns then [Missing_Input_Columns, Column_Indexes_Out_Of_Range, Invalid_Aggregate_Column] else []
Problem_Builder.Value types_to_always_throw+additional_types_to_throw (Ref.new Vector_Builder.empty) (Ref.new Vector_Builder.empty) other=Vector.new_builder Problem_Builder.Value types_to_always_throw+additional_types_to_throw (Ref.new Vector_Builder.empty) (Ref.new Vector_Builder.empty) missing_input_columns_location other=Vector.new_builder
## PRIVATE ## PRIVATE
Appends a `Vector` to a `Vector_Builder` stored in a `Ref`. Appends a `Vector` to a `Vector_Builder` stored in a `Ref`.

View File

@ -173,7 +173,7 @@ fan_out_to_rows table input_column_id function at_least_one_row=False on_problem
x | 12 34 56 | y ===> x | 12 34 56 | y ===>
... | ... | ... ... | ... | ...
foo | bar 0 | bar 1 | baz foo | bar 1 | bar 2 | baz
----+-------+-------+---- ----+-------+-------+----
x | 1 | 2 | y x | 1 | 2 | y
x | 3 | 4 | y x | 3 | 4 | y
@ -367,7 +367,7 @@ repeat_each n ~action = 0.up_to n . each _-> action
## PRIVATE ## PRIVATE
Name a column by appending an integer to a base column name. Name a column by appending an integer to a base column name.
default_column_namer : Text -> Integer -> Text default_column_namer : Text -> Integer -> Text
default_column_namer base_name i = base_name + " " + i.to_text default_column_namer base_name i = base_name + " " + (i+1).to_text
## PRIVATE ## PRIVATE
Pad or truncate a vector to be a specified length; if altered, report Pad or truncate a vector to be a specified length; if altered, report

View File

@ -56,10 +56,10 @@ type Unique_Name_Strategy
> Example > Example
Rename names from a second list to avoid clashing with the first one. Rename names from a second list to avoid clashing with the first one.
first = ["A", "B", "second_A"] first = ["A", "B", "second A"]
second = ["A", "B", "second_A_1", "C"] second = ["A", "B", "second A 1", "C"]
unique_second = Unique_Name_Strategy.combine_with_prefix first second "second_" unique_second = Unique_Name_Strategy.combine_with_prefix first second "second_"
unique_second == ["second_A_2", "second_B", "second_A_1", "C"] unique_second == ["second A 2", "second_B", "second A 1", "C"]
combine_with_prefix : Vector Text -> Vector Text -> Text -> Unique_Name_Strategy combine_with_prefix : Vector Text -> Vector Text -> Text -> Unique_Name_Strategy
combine_with_prefix self first second second_prefix = combine_with_prefix self first second second_prefix =
Vector.from_polyglot_array <| Vector.from_polyglot_array <|
@ -110,7 +110,7 @@ type Unique_Name_Strategy
> Example > Example
strategy = Unique_Name_Strategy.new strategy = Unique_Name_Strategy.new
strategy.make_unique "A" # returns "A" strategy.make_unique "A" # returns "A"
strategy.make_unique "A" # returns "A_1" strategy.make_unique "A" # returns "A 1"
make_unique : Text -> Text make_unique : Text -> Text
make_unique self name = self.deduplicator.makeUnique name make_unique self name = self.deduplicator.makeUnique name

View File

@ -1,16 +1,72 @@
from Standard.Base import all from Standard.Base import all
from Standard.Base.Metadata.Widget import Single_Choice, Vector_Editor
from Standard.Base.Metadata.Widget import Single_Choice
from Standard.Base.Metadata.Choice import Option from Standard.Base.Metadata.Choice import Option
import Standard.Base.Metadata.Display import Standard.Base.Metadata.Display
from project.Data.Table import Table import project.Data.Table.Table
import project.Data.Aggregate_Column.Aggregate_Column
## PRIVATE
Make an aggregate column selector.
make_aggregate_column_selector : Table -> Display -> Boolean -> Single_Choice
make_aggregate_column_selector table display=Display.Always include_group_by=True =
col_names_selector = make_column_name_selector table display=Display.Always
column_widget = Pair.new "column" col_names_selector
col_list_selector = make_column_name_vector_selector table display=Display.Always
group_by = if include_group_by then [Option "Group By" "(Aggregate_Column.Group_By)" [column_widget]] else []
count = Option "Count" "Aggregate_Column.Count"
count_distinct = Option "Count Distinct" "(Aggregate_Column.Count_Distinct)" [Pair.new "columns" (col_list_selector)]
first = Option "First" "(Aggregate_Column.First)" [column_widget, Pair.new "order_by" (col_list_selector)]
last = Option "Last" "(Aggregate_Column.Last)" [column_widget, Pair.new "order_by" (col_list_selector)]
count_not_nothing = Option "Count Not Nothing" "(Aggregate_Column.Count_Not_Nothing)" [column_widget]
count_nothing = Option "Count Nothing" "(Aggregate_Column.Count_Nothing)" [column_widget]
## Should be a list of Text columns only
count_not_empty = Option "Count Not Empty" "(Aggregate_Column.Count_Not_Empty)" [column_widget]
count_empty = Option "Count Empty" "(Aggregate_Column.Count_Empty)" [column_widget]
concatenate = Option "Concatenate" "(Aggregate_Column.Concatenate)" [column_widget]
shortest = Option "Shortest" "(Aggregate_Column.Shortest)" [column_widget]
longest = Option "Longest" "(Aggregate_Column.Longest)" [column_widget]
## Should be a list of Numeric columns only
sum = Option "Sum" "(Aggregate_Column.Sum)" [column_widget]
average = Option "Average" "(Aggregate_Column.Average)" [column_widget]
median = Option "Median" "(Aggregate_Column.Median)" [column_widget]
percentile = Option "Percentile" "(Aggregate_Column.Percentile)" [column_widget]
mode = Option "Mode" "(Aggregate_Column.Mode)" [column_widget]
standard_deviation = Option "Standard Deviation" "(Aggregate_Column.Standard_Deviation)" [column_widget]
# Should be a list of comparable columns only
maximum = Option "Maximum" "(Aggregate_Column.Maximum)" [column_widget]
minimum = Option "Minimum" "(Aggregate_Column.Minimum)" [column_widget]
Single_Choice display=display values=(group_by+[count, count_distinct, first, last, count_not_nothing, count_nothing, count_not_empty, count_empty, concatenate, shortest, longest, sum, average, median, percentile, mode, standard_deviation, maximum, minimum])
## PRIVATE ## PRIVATE
Make a column name selector. Make a column name selector.
make_column_name_selector : Table -> Display -> Single_Choice make_column_name_selector : Table -> Display -> Single_Choice
make_column_name_selector table display=Display.Always = make_column_name_selector table display=Display.Always =
Single_Choice display=display values=(table.column_names.map n->(Option n n.pretty)) col_names = table.column_names
names = col_names.map n-> Option n n.pretty
Single_Choice display=display values=names
## PRIVATE
Make a multiple column name selector.
make_column_name_vector_selector : Table -> Display -> Vector_Editor
make_column_name_vector_selector table display=Display.Always =
item_editor = make_column_name_selector table display=Display.Always
Vector_Editor item_editor=item_editor item_default=table.column_names.first.pretty display=display
## PRIVATE
Make a column name selector.
make_order_by_selector : Table -> Display -> Single_Choice
make_order_by_selector table display=Display.Always =
col_names = table.column_names
names = col_names.fold [] c-> n-> c + [Option n+" (Asc)" n.pretty, Option n+" (Desc)" "(Sort_Column.Name "+n.pretty+" Sort_Direction.Descending)"]
Single_Choice display=display values=names
## PRIVATE ## PRIVATE
Selector for type argument on `Column.parse`. Selector for type argument on `Column.parse`.
@ -21,11 +77,3 @@ parse_type_selector =
options = names.zip choice . map pair-> Option pair.first pair.second options = names.zip choice . map pair-> Option pair.first pair.second
Single_Choice display=Display.Always values=options Single_Choice display=Display.Always values=options
## PRIVATE
Selector for type argument on `Column.parse`.
join_kind_selector : Single_Choice
join_kind_selector =
choice = ['Join_Kind.Inner','Join_Kind.Left_Outer','Join_Kind.Right_Outer','Join_Kind.Full','Join_Kind.Left_Exclusive','Join_Kind.Right_Exclusive']
names = ['Inner', 'Left Outer', 'Right Outer', 'Full', 'Left Exclusive', 'Right Exclusive']
options = names.zip choice . map pair-> Option pair.first pair.second
Single_Choice display=Display.Always values=options

View File

@ -5,6 +5,20 @@ import java.time.YearMonth;
import java.time.temporal.*; import java.time.temporal.*;
public class Date_Period_Utils implements TimeUtilsBase { public class Date_Period_Utils implements TimeUtilsBase {
private static final long NANOSECONDS_IN_DAY = 86_400_000_000_000L;
public static TemporalAdjuster day_start =
(Temporal temporal) -> {
return temporal.isSupported(ChronoField.NANO_OF_DAY)
? temporal.with(ChronoField.NANO_OF_DAY, 0)
: temporal;
};
public static TemporalAdjuster day_end =
(Temporal temporal) -> {
return temporal.isSupported(ChronoField.NANO_OF_DAY)
? temporal.with(ChronoField.NANO_OF_DAY, NANOSECONDS_IN_DAY - 1)
: temporal;
};
public static TemporalAdjuster quarter_start = public static TemporalAdjuster quarter_start =
(Temporal temporal) -> { (Temporal temporal) -> {

View File

@ -334,7 +334,7 @@ public class DelimitedReader {
private WithProblems<List<String>> generateDefaultHeaders(int columnCount) { private WithProblems<List<String>> generateDefaultHeaders(int columnCount) {
List<String> headerNames = new ArrayList<>(columnCount); List<String> headerNames = new ArrayList<>(columnCount);
for (int i = 0; i < columnCount; ++i) { for (int i = 0; i < columnCount; ++i) {
headerNames.add(COLUMN_NAME + "_" + (i + 1)); headerNames.add(COLUMN_NAME + " " + (i + 1));
} }
return new WithProblems<>(headerNames, Collections.emptyList()); return new WithProblems<>(headerNames, Collections.emptyList());
} }

View File

@ -87,7 +87,7 @@ public class NameDeduplicator {
if (index == 0) { if (index == 0) {
return name; return name;
} }
return name + "_" + index; return name + " " + index;
} }
public String[] getInvalidNames() { public String[] getInvalidNames() {
@ -134,7 +134,7 @@ public class NameDeduplicator {
String name = second.get(i); String name = second.get(i);
if (output.get(i) == null) { if (output.get(i) == null) {
var prefixed = secondPrefix + name; var prefixed = secondPrefix + name;
output.set(i, makeUnique(secondPrefix + name)); output.set(i, makeUnique(prefixed));
} }
} }
return output; return output;

View File

@ -111,9 +111,9 @@ spec setup =
materialized.columns.at 0 . at 0 . should_equal 56.708660 epsilon=0.000001 materialized.columns.at 0 . at 0 . should_equal 56.708660 epsilon=0.000001
materialized.columns.at 1 . name . should_equal "Standard Deviation ValueWithNothing" materialized.columns.at 1 . name . should_equal "Standard Deviation ValueWithNothing"
materialized.columns.at 1 . at 0 . should_equal 58.588610 epsilon=0.000001 materialized.columns.at 1 . at 0 . should_equal 58.588610 epsilon=0.000001
materialized.columns.at 2 . name . should_equal "Standard Deviation Value_1" materialized.columns.at 2 . name . should_equal "Standard Deviation Value 1"
materialized.columns.at 2 . at 0 . should_equal 56.697317 epsilon=0.000001 materialized.columns.at 2 . at 0 . should_equal 56.697317 epsilon=0.000001
materialized.columns.at 3 . name . should_equal "Standard Deviation ValueWithNothing_1" materialized.columns.at 3 . name . should_equal "Standard Deviation ValueWithNothing 1"
materialized.columns.at 3 . at 0 . should_equal 58.575554 epsilon=0.000001 materialized.columns.at 3 . at 0 . should_equal 58.575554 epsilon=0.000001
Test.specify "should be able to create median, mode and percentile values" (pending = resolve_pending test_selection.advanced_stats) <| Test.specify "should be able to create median, mode and percentile values" (pending = resolve_pending test_selection.advanced_stats) <|
@ -153,7 +153,7 @@ spec setup =
materialized.column_count . should_equal 3 materialized.column_count . should_equal 3
materialized.columns.at 0 . name . should_equal "First TextWithNothing" materialized.columns.at 0 . name . should_equal "First TextWithNothing"
materialized.columns.at 0 . at 0 . should_equal "riwaiqq1io" materialized.columns.at 0 . at 0 . should_equal "riwaiqq1io"
materialized.columns.at 1 . name . should_equal "First TextWithNothing_1" materialized.columns.at 1 . name . should_equal "First TextWithNothing 1"
materialized.columns.at 1 . at 0 . should_equal "j4i2ua7uft" materialized.columns.at 1 . at 0 . should_equal "j4i2ua7uft"
materialized.columns.at 2 . name . should_equal "Last ValueWithNothing" materialized.columns.at 2 . name . should_equal "Last ValueWithNothing"
materialized.columns.at 2 . at 0 . should_equal -38.56 epsilon=0.000001 materialized.columns.at 2 . at 0 . should_equal -38.56 epsilon=0.000001
@ -236,7 +236,7 @@ spec setup =
materialized.column_count . should_equal 2 materialized.column_count . should_equal 2
materialized.columns.at 0 . name . should_equal "Count Distinct Code" materialized.columns.at 0 . name . should_equal "Count Distinct Code"
materialized.columns.at 0 . at 0 . should_equal 0 materialized.columns.at 0 . at 0 . should_equal 0
materialized.columns.at 1 . name . should_equal "Count Distinct Code_1" materialized.columns.at 1 . name . should_equal "Count Distinct Code 1"
materialized.columns.at 1 . at 0 . should_equal 0 materialized.columns.at 1 . at 0 . should_equal 0
Test.specify "should be able to compute sum and average of values" <| Test.specify "should be able to compute sum and average of values" <|
@ -527,9 +527,9 @@ spec setup =
materialized.columns.at 1 . at idx . should_equal 60.272158 epsilon=0.000001 materialized.columns.at 1 . at idx . should_equal 60.272158 epsilon=0.000001
materialized.columns.at 2 . name . should_equal "Standard Deviation ValueWithNothing" materialized.columns.at 2 . name . should_equal "Standard Deviation ValueWithNothing"
materialized.columns.at 2 . at idx . should_equal 56.798691 epsilon=0.000001 materialized.columns.at 2 . at idx . should_equal 56.798691 epsilon=0.000001
materialized.columns.at 3 . name . should_equal "Standard Deviation Value_1" materialized.columns.at 3 . name . should_equal "Standard Deviation Value 1"
materialized.columns.at 3 . at idx . should_equal 60.156583 epsilon=0.000001 materialized.columns.at 3 . at idx . should_equal 60.156583 epsilon=0.000001
materialized.columns.at 4 . name . should_equal "Standard Deviation ValueWithNothing_1" materialized.columns.at 4 . name . should_equal "Standard Deviation ValueWithNothing 1"
materialized.columns.at 4 . at idx . should_equal 56.677714 epsilon=0.000001 materialized.columns.at 4 . at idx . should_equal 56.677714 epsilon=0.000001
Test.specify "should be able to create median values" (pending = resolve_pending test_selection.advanced_stats) <| Test.specify "should be able to create median values" (pending = resolve_pending test_selection.advanced_stats) <|
@ -735,9 +735,9 @@ spec setup =
materialized.columns.at 2 . at idx . should_equal 58.979275 epsilon=0.000001 materialized.columns.at 2 . at idx . should_equal 58.979275 epsilon=0.000001
materialized.columns.at 3 . name . should_equal "Standard Deviation ValueWithNothing" materialized.columns.at 3 . name . should_equal "Standard Deviation ValueWithNothing"
materialized.columns.at 3 . at idx . should_equal 57.561756 epsilon=0.000001 materialized.columns.at 3 . at idx . should_equal 57.561756 epsilon=0.000001
materialized.columns.at 4 . name . should_equal "Standard Deviation Value_1" materialized.columns.at 4 . name . should_equal "Standard Deviation Value 1"
materialized.columns.at 4 . at idx . should_equal 58.746614 epsilon=0.000001 materialized.columns.at 4 . at idx . should_equal 58.746614 epsilon=0.000001
materialized.columns.at 5 . name . should_equal "Standard Deviation ValueWithNothing_1" materialized.columns.at 5 . name . should_equal "Standard Deviation ValueWithNothing 1"
materialized.columns.at 5 . at idx . should_equal 57.306492 epsilon=0.000001 materialized.columns.at 5 . at idx . should_equal 57.306492 epsilon=0.000001
Test.specify "should be able to create median values" (pending = resolve_pending test_selection.advanced_stats) <| Test.specify "should be able to create median values" (pending = resolve_pending test_selection.advanced_stats) <|
@ -1366,25 +1366,25 @@ spec setup =
Test.specify "should raise a warning when an invalid output name" <| Test.specify "should raise a warning when an invalid output name" <|
action = table.aggregate [Group_By "Index" ""] on_problems=_ action = table.aggregate [Group_By "Index" ""] on_problems=_
problems = [Invalid_Output_Column_Names.Error [""]] problems = [Invalid_Output_Column_Names.Error [""]]
tester = expect_column_names ["Column_1"] tester = expect_column_names ["Column 1"]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
Test.specify "should raise a warning when a duplicate column name" <| Test.specify "should raise a warning when a duplicate column name" <|
action = table.aggregate [Group_By "Index", Group_By 0] on_problems=_ action = table.aggregate [Group_By "Index", Group_By 0] on_problems=_
problems = [Duplicate_Output_Column_Names.Error ["Index"]] problems = [Duplicate_Output_Column_Names.Error ["Index"]]
tester = expect_column_names ["Index", "Index_1"] tester = expect_column_names ["Index", "Index 1"]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
Test.specify "should raise a warning when a duplicate column name and rename default names first" <| Test.specify "should raise a warning when a duplicate column name and rename default names first" <|
action = table.aggregate [Group_By "Value", Group_By "Index" "Value"] on_problems=_ action = table.aggregate [Group_By "Value", Group_By "Index" "Value"] on_problems=_
problems = [Duplicate_Output_Column_Names.Error ["Value"]] problems = [Duplicate_Output_Column_Names.Error ["Value"]]
tester = expect_column_names ["Value_1", "Value"] tester = expect_column_names ["Value 1", "Value"]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
Test.specify "should raise a warning when duplicate column names" <| Test.specify "should raise a warning when duplicate column names" <|
action = table.aggregate [Sum "Value" new_name="AGG1", Count new_name="AGG1"] on_problems=_ action = table.aggregate [Sum "Value" new_name="AGG1", Count new_name="AGG1"] on_problems=_
problems = [Duplicate_Output_Column_Names.Error ["AGG1"]] problems = [Duplicate_Output_Column_Names.Error ["AGG1"]]
tester = expect_column_names ["AGG1", "AGG1_1"] tester = expect_column_names ["AGG1", "AGG1 1"]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
Test.specify "should allow partial matches on Count_Distinct" <| Test.specify "should allow partial matches on Count_Distinct" <|

View File

@ -21,8 +21,8 @@ spec setup =
col1 = ["foo", [1,2,3]] col1 = ["foo", [1,2,3]]
col2 = ["bar", [4,5,6]] col2 = ["bar", [4,5,6]]
col3 = ["Baz", [7,8,9]] col3 = ["Baz", [7,8,9]]
col4 = ["foo_1", [10,11,12]] col4 = ["foo 1", [10,11,12]]
col5 = ["foo_2", [13,14,15]] col5 = ["foo 2", [13,14,15]]
col6 = ["ab.+123", [16,17,18]] col6 = ["ab.+123", [16,17,18]]
col7 = ["abcd123", [19,20,21]] col7 = ["abcd123", [19,20,21]]
table_builder [col1, col2, col3, col4, col5, col6, col7] table_builder [col1, col2, col3, col4, col5, col6, col7]
@ -100,11 +100,11 @@ spec setup =
Test.specify "should allow adding a column" <| Test.specify "should allow adding a column" <|
bar2 = table.get "bar" . rename "bar2" bar2 = table.get "bar" . rename "bar2"
t2 = table.set bar2 t2 = table.set bar2
t2.column_names . should_equal ["foo", "bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "bar2"] t2.column_names . should_equal ["foo", "bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123", "bar2"]
t2.get "bar2" . to_vector . should_equal [4, 5, 6] t2.get "bar2" . to_vector . should_equal [4, 5, 6]
t3 = t2.set bar2 "bar3" t3 = t2.set bar2 "bar3"
t3.column_names . should_equal ["foo", "bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "bar2", "bar3"] t3.column_names . should_equal ["foo", "bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123", "bar2", "bar3"]
Test.specify "should not allow illegal column names" <| Test.specify "should not allow illegal column names" <|
table.set (table.get "bar") new_name="" . should_fail_with Illegal_Argument table.set (table.get "bar") new_name="" . should_fail_with Illegal_Argument
@ -113,11 +113,11 @@ spec setup =
Test.specify "should allow replacing a column" <| Test.specify "should allow replacing a column" <|
foo = table.get "bar" . rename "foo" foo = table.get "bar" . rename "foo"
t2 = table.set foo t2 = table.set foo
t2.column_names . should_equal ["foo", "bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] t2.column_names . should_equal ["foo", "bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123"]
t2.get "foo" . to_vector . should_equal [4, 5, 6] t2.get "foo" . to_vector . should_equal [4, 5, 6]
t3 = t2.set foo "bar3" t3 = t2.set foo "bar3"
t3.column_names . should_equal ["foo", "bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "bar3"] t3.column_names . should_equal ["foo", "bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123", "bar3"]
Test.specify "should allow adding a column" <| Test.specify "should allow adding a column" <|
bar2 = table.get "bar" . rename "bar2" bar2 = table.get "bar" . rename "bar2"
@ -166,7 +166,7 @@ spec setup =
Test.group prefix+"Table.column_names" <| Test.group prefix+"Table.column_names" <|
Test.specify "should return the names of all columns" <| Test.specify "should return the names of all columns" <|
table.column_names . should_equal ["foo", "bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] table.column_names . should_equal ["foo", "bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123"]
Test.specify "should allow weird column names in all backends" <| Test.specify "should allow weird column names in all backends" <|
columns = weird_names.map_with_index ix-> name-> columns = weird_names.map_with_index ix-> name->

View File

@ -149,14 +149,14 @@ spec setup =
Test.specify "should gracefully handle duplicate aggregate names" <| Test.specify "should gracefully handle duplicate aggregate names" <|
action = table.cross_tab [] "Key" values=[Count new_name="Agg1", Sum "Value" new_name="Agg1"] on_problems=_ action = table.cross_tab [] "Key" values=[Count new_name="Agg1", Sum "Value" new_name="Agg1"] on_problems=_
tester table = tester table =
table.column_names . should_equal ["x Agg1", "x Agg1_1", "y Agg1", "y Agg1_1", "z Agg1", "z Agg1_1"] table.column_names . should_equal ["x Agg1", "x Agg1 1", "y Agg1", "y Agg1 1", "z Agg1", "z Agg1 1"]
problems = [Duplicate_Output_Column_Names.Error ["x Agg1", "y Agg1", "z Agg1"]] problems = [Duplicate_Output_Column_Names.Error ["x Agg1", "y Agg1", "z Agg1"]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
table3 = table2.rename_columns (Map.from_vector [["Group", "x"]]) table3 = table2.rename_columns (Map.from_vector [["Group", "x"]])
action3 = table3.cross_tab ["x"] "Key" on_problems=_ action3 = table3.cross_tab ["x"] "Key" on_problems=_
tester3 table = tester3 table =
table.column_names . should_equal ["x", "x_1", "y", "z"] table.column_names . should_equal ["x", "x 1", "y", "z"]
problems3 = [Duplicate_Output_Column_Names.Error ["x"]] problems3 = [Duplicate_Output_Column_Names.Error ["x"]]
Problems.test_problem_handling action3 problems3 tester3 Problems.test_problem_handling action3 problems3 tester3

View File

@ -37,7 +37,7 @@ spec setup =
t3 = t2.aggregate [Group_By "Letter", Count] t3 = t2.aggregate [Group_By "Letter", Count]
t4 = t3.join t1 on="Count" join_kind=Join_Kind.Left_Outer |> materialize |> _.order_by "Letter" t4 = t3.join t1 on="Count" join_kind=Join_Kind.Left_Outer |> materialize |> _.order_by "Letter"
t4.columns.map .name . should_equal ["Letter", "Count", "Right_Count", "Class"] t4.columns.map .name . should_equal ["Letter", "Count", "Right Count", "Class"]
rows = t4.rows . map .to_vector rows = t4.rows . map .to_vector
rows.at 0 . should_equal ["A", 4, Nothing, Nothing] rows.at 0 . should_equal ["A", 4, Nothing, Nothing]
rows.at 1 . should_equal ["B", 3, 3, "Z"] rows.at 1 . should_equal ["B", 3, 3, "Z"]

View File

@ -94,7 +94,7 @@ spec setup =
t1 = table_builder [["X", [1, 2]], ["Y", [4, 5]]] t1 = table_builder [["X", [1, 2]], ["Y", [4, 5]]]
t2 = t1.cross_join t1 t2 = t1.cross_join t1
expect_column_names ["X", "Y", "Right_X", "Right_Y"] t2 expect_column_names ["X", "Y", "Right X", "Right Y"] t2
t2.row_count . should_equal 4 t2.row_count . should_equal 4
r = materialize t2 . rows . map .to_vector r = materialize t2 . rows . map .to_vector
r.length . should_equal 4 r.length . should_equal 4
@ -108,26 +108,26 @@ spec setup =
False -> r.should_equal expected_rows False -> r.should_equal expected_rows
Test.specify "should rename columns of the right table to avoid duplicates" <| Test.specify "should rename columns of the right table to avoid duplicates" <|
t1 = table_builder [["X", [1]], ["Y", [5]], ["Right_Y", [10]]] t1 = table_builder [["X", [1]], ["Y", [5]], ["Right Y", [10]]]
t2 = table_builder [["X", ['a']], ["Y", ['d']]] t2 = table_builder [["X", ['a']], ["Y", ['d']]]
t3 = t1.cross_join t2 t3 = t1.cross_join t2
expect_column_names ["X", "Y", "Right_Y", "Right_X", "Right_Y_1"] t3 expect_column_names ["X", "Y", "Right Y", "Right X", "Right Y 1"] t3
Problems.get_attached_warnings t3 . should_equal [Duplicate_Output_Column_Names.Error ["Right_Y"]] Problems.get_attached_warnings t3 . should_equal [Duplicate_Output_Column_Names.Error ["Right Y"]]
t3.row_count . should_equal 1 t3.row_count . should_equal 1
t3.at "X" . to_vector . should_equal [1] t3.at "X" . to_vector . should_equal [1]
t3.at "Y" . to_vector . should_equal [5] t3.at "Y" . to_vector . should_equal [5]
t3.at "Right_Y" . to_vector . should_equal [10] t3.at "Right Y" . to_vector . should_equal [10]
t3.at "Right_X" . to_vector . should_equal ['a'] t3.at "Right X" . to_vector . should_equal ['a']
t3.at "Right_Y_1" . to_vector . should_equal ['d'] t3.at "Right Y 1" . to_vector . should_equal ['d']
t1.cross_join t2 on_problems=Problem_Behavior.Report_Error . should_fail_with Duplicate_Output_Column_Names t1.cross_join t2 on_problems=Problem_Behavior.Report_Error . should_fail_with Duplicate_Output_Column_Names
expect_column_names ["X", "Y", "Right_Y", "X_1", "Y_1"] (t1.cross_join t2 right_prefix="") expect_column_names ["X", "Y", "Right Y", "X 1", "Y 1"] (t1.cross_join t2 right_prefix="")
t4 = table_builder [["X", [1]], ["Right_X", [5]]] t4 = table_builder [["X", [1]], ["Right X", [5]]]
expect_column_names ["X", "Y", "Right_Y", "Right_X_1", "Right_X"] (t1.cross_join t4) expect_column_names ["X", "Y", "Right Y", "Right X 1", "Right X"] (t1.cross_join t4)
expect_column_names ["X", "Right_X", "Right_X_1", "Y", "Right_Y"] (t4.cross_join t1) expect_column_names ["X", "Right X", "Right X 1", "Y", "Right Y"] (t4.cross_join t1)
Test.specify "should respect the column ordering" <| Test.specify "should respect the column ordering" <|
t1 = table_builder [["X", [100, 2]], ["Y", [4, 5]]] t1 = table_builder [["X", [100, 2]], ["Y", [4, 5]]]

View File

@ -34,9 +34,18 @@ spec setup =
Test.group prefix+"Table.join" <| Test.group prefix+"Table.join" <|
t1 = table_builder [["X", [1, 2, 3]], ["Y", [4, 5, 6]]] t1 = table_builder [["X", [1, 2, 3]], ["Y", [4, 5, 6]]]
t2 = table_builder [["Z", [2, 3, 2, 4]], ["W", [4, 5, 6, 7]]] t2 = table_builder [["Z", [2, 3, 2, 4]], ["W", [4, 5, 6, 7]]]
Test.specify "should allow to Inner join on equality of a the first column by default" <|
t3 = t1.join t2 Test.specify "should by default do a Left Outer join on equality of first column in the left table, correlated with column of the same name in the right one" <|
t3 = table_builder [["Z", [4, 5, 6, 7]], ["X", [2, 3, 2, 4]]]
t4 = t1.join t3 |> materialize |> _.order_by ["X", "Z"]
expect_column_names ["X", "Y", "Z", "Right X"] t4
t4.at "X" . to_vector . should_equal [1, 2, 2, 3]
t4.at "Y" . to_vector . should_equal [4, 5, 5, 6]
t4.at "Right X" . to_vector . should_equal [Nothing, 2, 2, 3]
t4.at "Z" . to_vector . should_equal [Nothing, 4, 6, 5]
Test.specify "should allow Inner join" <|
t3 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Equals 0 0)
expect_column_names ["X", "Y", "Z", "W"] t3 expect_column_names ["X", "Y", "Z", "W"] t3
t4 = t3 |> materialize |> _.order_by ["X", "W"] t4 = t3 |> materialize |> _.order_by ["X", "W"]
t4.at "X" . to_vector . should_equal [2, 2, 3] t4.at "X" . to_vector . should_equal [2, 2, 3]
@ -45,23 +54,15 @@ spec setup =
t4.at "W" . to_vector . should_equal [4, 6, 5] t4.at "W" . to_vector . should_equal [4, 6, 5]
Test.specify "should allow Full join" <| Test.specify "should allow Full join" <|
t3 = t1.join t2 join_kind=Join_Kind.Full |> materialize |> _.order_by ["X", "W"] t3 = t1.join t2 join_kind=Join_Kind.Full on=(Join_Condition.Equals 0 0) |> materialize |> _.order_by ["X", "W"]
expect_column_names ["X", "Y", "Z", "W"] t3 expect_column_names ["X", "Y", "Z", "W"] t3
t3.at "X" . to_vector . should_equal [Nothing, 1, 2, 2, 3] t3.at "X" . to_vector . should_equal [Nothing, 1, 2, 2, 3]
t3.at "Y" . to_vector . should_equal [Nothing, 4, 5, 5, 6] t3.at "Y" . to_vector . should_equal [Nothing, 4, 5, 5, 6]
t3.at "Z" . to_vector . should_equal [4, Nothing, 2, 2, 3] t3.at "Z" . to_vector . should_equal [4, Nothing, 2, 2, 3]
t3.at "W" . to_vector . should_equal [7, Nothing, 4, 6, 5] t3.at "W" . to_vector . should_equal [7, Nothing, 4, 6, 5]
Test.specify "should allow Left Outer join" <|
t4 = t1.join t2 join_kind=Join_Kind.Left_Outer |> materialize |> _.order_by ["X", "W"]
expect_column_names ["X", "Y", "Z", "W"] t4
t4.at "X" . to_vector . should_equal [1, 2, 2, 3]
t4.at "Y" . to_vector . should_equal [4, 5, 5, 6]
t4.at "Z" . to_vector . should_equal [Nothing, 2, 2, 3]
t4.at "W" . to_vector . should_equal [Nothing, 4, 6, 5]
Test.specify "should allow Right Outer join" <| Test.specify "should allow Right Outer join" <|
t5 = t1.join t2 join_kind=Join_Kind.Right_Outer |> materialize |> _.order_by ["X", "W"] t5 = t1.join t2 join_kind=Join_Kind.Right_Outer on=(Join_Condition.Equals 0 0) |> materialize |> _.order_by ["X", "W"]
expect_column_names ["X", "Y", "Z", "W"] t5 expect_column_names ["X", "Y", "Z", "W"] t5
t5.at "X" . to_vector . should_equal [Nothing, 2, 2, 3] t5.at "X" . to_vector . should_equal [Nothing, 2, 2, 3]
t5.at "Y" . to_vector . should_equal [Nothing, 5, 5, 6] t5.at "Y" . to_vector . should_equal [Nothing, 5, 5, 6]
@ -69,12 +70,12 @@ spec setup =
t5.at "W" . to_vector . should_equal [7, 4, 6, 5] t5.at "W" . to_vector . should_equal [7, 4, 6, 5]
Test.specify "should allow to perform anti-joins" <| Test.specify "should allow to perform anti-joins" <|
t6 = t1.join t2 join_kind=Join_Kind.Left_Exclusive |> materialize |> _.order_by ["X"] t6 = t1.join t2 join_kind=Join_Kind.Left_Exclusive on=(Join_Condition.Equals 0 0) |> materialize |> _.order_by ["X"]
t6.columns.map .name . should_equal ["X", "Y"] t6.columns.map .name . should_equal ["X", "Y"]
t6.at "X" . to_vector . should_equal [1] t6.at "X" . to_vector . should_equal [1]
t6.at "Y" . to_vector . should_equal [4] t6.at "Y" . to_vector . should_equal [4]
t7 = t1.join t2 join_kind=Join_Kind.Right_Exclusive |> materialize |> _.order_by ["Z"] t7 = t1.join t2 join_kind=Join_Kind.Right_Exclusive on=(Join_Condition.Equals 0 0) |> materialize |> _.order_by ["Z"]
t7.columns.map .name . should_equal ["Z", "W"] t7.columns.map .name . should_equal ["Z", "W"]
t7.at "Z" . to_vector . should_equal [4] t7.at "Z" . to_vector . should_equal [4]
t7.at "W" . to_vector . should_equal [7] t7.at "W" . to_vector . should_equal [7]
@ -82,39 +83,39 @@ spec setup =
t3 = table_builder [["X", [1, 1, 1, 2, 2, 2]], ["Y", ["A", "B", "B", "C", "C", "A"]], ["Z", [1, 2, 3, 4, 5, 6]]] t3 = table_builder [["X", [1, 1, 1, 2, 2, 2]], ["Y", ["A", "B", "B", "C", "C", "A"]], ["Z", [1, 2, 3, 4, 5, 6]]]
t4 = table_builder [["X", [1, 1, 3, 2, 2, 4]], ["Y", ["B", "B", "C", "C", "D", "A"]], ["Z", [1, 2, 3, 4, 5, 6]]] t4 = table_builder [["X", [1, 1, 3, 2, 2, 4]], ["Y", ["B", "B", "C", "C", "D", "A"]], ["Z", [1, 2, 3, 4, 5, 6]]]
check_xy_joined r = check_xy_joined r =
expect_column_names ["X", "Y", "Z", "Right_Z"] r expect_column_names ["X", "Y", "Z", "Right Z"] r
r.at "X" . to_vector . should_equal [1, 1, 1, 1, 2, 2] r.at "X" . to_vector . should_equal [1, 1, 1, 1, 2, 2]
r.at "Y" . to_vector . should_equal ["B", "B", "B", "B", "C", "C"] r.at "Y" . to_vector . should_equal ["B", "B", "B", "B", "C", "C"]
r.at "Z" . to_vector . should_equal [2, 2, 3, 3, 4, 5] r.at "Z" . to_vector . should_equal [2, 2, 3, 3, 4, 5]
r.at "Right_Z" . to_vector . should_equal [1, 2, 1, 2, 4, 4] r.at "Right Z" . to_vector . should_equal [1, 2, 1, 2, 4, 4]
Test.specify "should allow to join on equality of multiple columns and drop redundant columns if Inner join" <| Test.specify "should allow to join on equality of multiple columns and drop redundant columns if Inner join" <|
conditions = [Join_Condition.Equals "Y" "Y", Join_Condition.Equals "X" "X"] conditions = [Join_Condition.Equals "Y" "Y", Join_Condition.Equals "X" "X"]
r = t3.join t4 on=conditions |> materialize |> _.order_by ["X", "Y", "Z", "Right_Z"] r = t3.join t4 join_kind=Join_Kind.Inner on=conditions |> materialize |> _.order_by ["X", "Y", "Z", "Right Z"]
check_xy_joined r check_xy_joined r
[Join_Kind.Full, Join_Kind.Left_Outer, Join_Kind.Right_Outer].each kind-> [Join_Kind.Full, Join_Kind.Left_Outer, Join_Kind.Right_Outer].each kind->
r2 = t3.join t4 join_kind=kind on=conditions r2 = t3.join t4 join_kind=kind on=conditions
expect_column_names ["X", "Y", "Z", "Right_X", "Right_Y", "Right_Z"] r2 expect_column_names ["X", "Y", "Z", "Right X", "Right Y", "Right Z"] r2
Test.specify "should support same-name column join shorthand" <| Test.specify "should support same-name column join shorthand" <|
r = t3.join t4 on=["X", "Y"] |> materialize |> _.order_by ["X", "Y", "Z", "Right_Z"] r = t3.join t4 join_kind=Join_Kind.Inner on=["X", "Y"] |> materialize |> _.order_by ["X", "Y", "Z", "Right Z"]
check_xy_joined r check_xy_joined r
Test.specify "should allow to join on text equality ignoring case" <| Test.specify "should allow to join on text equality ignoring case" <|
t1 = table_builder [["X", ["a", "B"]], ["Y", [1, 2]]] t1 = table_builder [["X", ["a", "B"]], ["Y", [1, 2]]]
t2 = table_builder [["X", ["A", "a", "b"]], ["Z", [1, 2, 3]]] t2 = table_builder [["X", ["A", "a", "b"]], ["Z", [1, 2, 3]]]
r1 = t1.join t2 r1 = t1.join t2 join_kind=Join_Kind.Inner
expect_column_names ["X", "Y", "Z"] r1 expect_column_names ["X", "Y", "Z"] r1
r1 . at "X" . to_vector . should_equal ["a"] r1 . at "X" . to_vector . should_equal ["a"]
r1 . at "Y" . to_vector . should_equal [1] r1 . at "Y" . to_vector . should_equal [1]
r1 . at "Z" . to_vector . should_equal [2] r1 . at "Z" . to_vector . should_equal [2]
r2 = t1.join t2 on=(Join_Condition.Equals_Ignore_Case "X") |> materialize |> _.order_by ["Z"] r2 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Equals_Ignore_Case "X") |> materialize |> _.order_by ["Z"]
expect_column_names ["X", "Y", "Right_X", "Z"] r2 expect_column_names ["X", "Y", "Right X", "Z"] r2
r2 . at "X" . to_vector . should_equal ["a", "a", "B"] r2 . at "X" . to_vector . should_equal ["a", "a", "B"]
r2 . at "Right_X" . to_vector . should_equal ["A", "a", "b"] r2 . at "Right X" . to_vector . should_equal ["A", "a", "b"]
r2 . at "Y" . to_vector . should_equal [1, 1, 2] r2 . at "Y" . to_vector . should_equal [1, 1, 2]
r2 . at "Z" . to_vector . should_equal [1, 2, 3] r2 . at "Z" . to_vector . should_equal [1, 2, 3]
@ -123,16 +124,16 @@ spec setup =
t1 = table_builder [["X", ['s\u0301', 'S\u0301']], ["Y", [1, 2]]] t1 = table_builder [["X", ['s\u0301', 'S\u0301']], ["Y", [1, 2]]]
t2 = table_builder [["X", ['s', 'S', 'ś']], ["Z", [1, 2, 3]]] t2 = table_builder [["X", ['s', 'S', 'ś']], ["Z", [1, 2, 3]]]
r1 = t1.join t2 r1 = t1.join t2 join_kind=Join_Kind.Inner
expect_column_names ["X", "Y", "Z"] r1 expect_column_names ["X", "Y", "Z"] r1
r1 . at "X" . to_vector . should_equal ['ś'] r1 . at "X" . to_vector . should_equal ['ś']
r1 . at "Y" . to_vector . should_equal [1] r1 . at "Y" . to_vector . should_equal [1]
r1 . at "Z" . to_vector . should_equal [3] r1 . at "Z" . to_vector . should_equal [3]
r2 = t1.join t2 on=(Join_Condition.Equals_Ignore_Case "X") |> materialize |> _.order_by ["Y"] r2 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Equals_Ignore_Case "X") |> materialize |> _.order_by ["Y"]
expect_column_names ["X", "Y", "Right_X", "Z"] r2 expect_column_names ["X", "Y", "Right X", "Z"] r2
r2 . at "X" . to_vector . should_equal ['s\u0301', 'S\u0301'] r2 . at "X" . to_vector . should_equal ['s\u0301', 'S\u0301']
r2 . at "Right_X" . to_vector . should_equal ['ś', 'ś'] r2 . at "Right X" . to_vector . should_equal ['ś', 'ś']
r2 . at "Y" . to_vector . should_equal [1, 2] r2 . at "Y" . to_vector . should_equal [1, 2]
r2 . at "Z" . to_vector . should_equal [3, 3] r2 . at "Z" . to_vector . should_equal [3, 3]
@ -141,7 +142,7 @@ spec setup =
t1 = table_builder [["X", [1, 2]], ["Y", [10, 20]]] t1 = table_builder [["X", [1, 2]], ["Y", [10, 20]]]
t2 = table_builder [["X", [2.0, 2.1, 0.0]], ["Z", [1, 2, 3]]] t2 = table_builder [["X", [2.0, 2.1, 0.0]], ["Z", [1, 2, 3]]]
r1 = t1.join t2 r1 = t1.join t2 join_kind=Join_Kind.Inner
expect_column_names ["X", "Y", "Z"] r1 expect_column_names ["X", "Y", "Z"] r1
r1 . at "X" . to_vector . should_equal [2] r1 . at "X" . to_vector . should_equal [2]
r1 . at "Y" . to_vector . should_equal [20] r1 . at "Y" . to_vector . should_equal [20]
@ -152,14 +153,14 @@ spec setup =
t1 = table_builder [["X", [My_Type.Value 1 2, My_Type.Value 2 3]], ["Y", [1, 2]]] t1 = table_builder [["X", [My_Type.Value 1 2, My_Type.Value 2 3]], ["Y", [1, 2]]]
t2 = table_builder [["X", [My_Type.Value 5 0, My_Type.Value 2 1]], ["Z", [10, 20]]] t2 = table_builder [["X", [My_Type.Value 5 0, My_Type.Value 2 1]], ["Z", [10, 20]]]
r1 = t1.join t2 |> materialize |> _.order_by ["Y"] r1 = t1.join t2 join_kind=Join_Kind.Inner |> materialize |> _.order_by ["Y"]
expect_column_names ["X", "Y", "Z"] r1 expect_column_names ["X", "Y", "Z"] r1
r1 . at "X" . to_vector . should_equal [My_Type.Value 1 2, My_Type.Value 2 3] r1 . at "X" . to_vector . should_equal [My_Type.Value 1 2, My_Type.Value 2 3]
## We don't keep the other column, because the values in both ## We don't keep the other column, because the values in both
are equal. However, with custom comparators, they may not be are equal. However, with custom comparators, they may not be
the same values, so we may consider keeping it. For not it is the same values, so we may consider keeping it. For not it is
dropped though for consistency. dropped though for consistency.
# r1 . at "Right_X" . to_vector . should_equal [My_Type.Value 1 2, My_Type.Value 2 3] # r1 . at "Right X" . to_vector . should_equal [My_Type.Value 1 2, My_Type.Value 2 3]
r1 . at "Y" . to_vector . should_equal [1, 2] r1 . at "Y" . to_vector . should_equal [1, 2]
r1 . at "Z" . to_vector . should_equal [20, 10] r1 . at "Z" . to_vector . should_equal [20, 10]
@ -167,7 +168,7 @@ spec setup =
t1 = table_builder [["X", [1, 10, 12]], ["Y", [1, 2, 3]]] t1 = table_builder [["X", [1, 10, 12]], ["Y", [1, 2, 3]]]
t2 = table_builder [["lower", [1, 10, 8, 12]], ["upper", [1, 12, 30, 0]], ["Z", [1, 2, 3, 4]]] t2 = table_builder [["lower", [1, 10, 8, 12]], ["upper", [1, 12, 30, 0]], ["Z", [1, 2, 3, 4]]]
r1 = t1.join t2 on=(Join_Condition.Between "X" "lower" "upper") |> materialize |> _.order_by ["X", "Z"] r1 = t1.join join_kind=Join_Kind.Inner t2 on=(Join_Condition.Between "X" "lower" "upper") |> materialize |> _.order_by ["X", "Z"]
expect_column_names ["X", "Y", "lower", "upper", "Z"] r1 expect_column_names ["X", "Y", "lower", "upper", "Z"] r1
r1 . at "X" . to_vector . should_equal [1, 10, 10, 12, 12] r1 . at "X" . to_vector . should_equal [1, 10, 10, 12, 12]
r1 . at "Y" . to_vector . should_equal [1, 2, 2, 3, 3] r1 . at "Y" . to_vector . should_equal [1, 2, 2, 3, 3]
@ -179,7 +180,7 @@ spec setup =
t1 = table_builder [["X", ["a", "b", "c"]], ["Y", [1, 2, 3]]] t1 = table_builder [["X", ["a", "b", "c"]], ["Y", [1, 2, 3]]]
t2 = table_builder [["lower", ["a", "b"]], ["upper", ["a", "ccc"]], ["Z", [10, 20]]] t2 = table_builder [["lower", ["a", "b"]], ["upper", ["a", "ccc"]], ["Z", [10, 20]]]
r1 = t1.join t2 on=(Join_Condition.Between "X" "lower" "upper") |> materialize |> _.order_by ["X", "Z"] r1 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Between "X" "lower" "upper") |> materialize |> _.order_by ["X", "Z"]
expect_column_names ["X", "Y", "lower", "upper", "Z"] r1 expect_column_names ["X", "Y", "lower", "upper", "Z"] r1
r1 . at "X" . to_vector . should_equal ["a", "b", "c"] r1 . at "X" . to_vector . should_equal ["a", "b", "c"]
r1 . at "Y" . to_vector . should_equal [1, 2, 3] r1 . at "Y" . to_vector . should_equal [1, 2, 3]
@ -192,7 +193,7 @@ spec setup =
t1 = table_builder [["X", ['s\u0301', 's']], ["Y", [1, 2]]] t1 = table_builder [["X", ['s\u0301', 's']], ["Y", [1, 2]]]
t2 = table_builder [["lower", ['s', 'ś']], ["upper", ['sa', 'ś']], ["Z", [10, 20]]] t2 = table_builder [["lower", ['s', 'ś']], ["upper", ['sa', 'ś']], ["Z", [10, 20]]]
r1 = t1.join t2 on=(Join_Condition.Between "X" "lower" "upper") |> materialize |> _.order_by ["Y"] r1 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Between "X" "lower" "upper") |> materialize |> _.order_by ["Y"]
expect_column_names ["X", "Y", "lower", "upper", "Z"] r1 expect_column_names ["X", "Y", "lower", "upper", "Z"] r1
r1 . at "X" . to_vector . should_equal ['s\u0301', 's'] r1 . at "X" . to_vector . should_equal ['s\u0301', 's']
r1 . at "Y" . to_vector . should_equal [1, 2] r1 . at "Y" . to_vector . should_equal [1, 2]
@ -205,7 +206,7 @@ spec setup =
t1 = table_builder [["X", [My_Type.Value 20 30, My_Type.Value 1 2]], ["Y", [1, 2]]] t1 = table_builder [["X", [My_Type.Value 20 30, My_Type.Value 1 2]], ["Y", [1, 2]]]
t2 = table_builder [["lower", [My_Type.Value 3 0, My_Type.Value 10 10]], ["upper", [My_Type.Value 2 1, My_Type.Value 100 0]], ["Z", [10, 20]]] t2 = table_builder [["lower", [My_Type.Value 3 0, My_Type.Value 10 10]], ["upper", [My_Type.Value 2 1, My_Type.Value 100 0]], ["Z", [10, 20]]]
r1 = t1.join t2 on=(Join_Condition.Between "X" "lower" "upper") |> materialize |> _.order_by ["Z"] r1 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Between "X" "lower" "upper") |> materialize |> _.order_by ["Z"]
expect_column_names ["X", "Y", "lower", "upper", "Z"] r1 expect_column_names ["X", "Y", "lower", "upper", "Z"] r1
r1 . at "X" . to_vector . to_text . should_equal "[(My_Type.Value 1 2), (My_Type.Value 20 30)]" r1 . at "X" . to_vector . to_text . should_equal "[(My_Type.Value 1 2), (My_Type.Value 20 30)]"
r1 . at "Y" . to_vector . should_equal [2, 1] r1 . at "Y" . to_vector . should_equal [2, 1]
@ -217,25 +218,25 @@ spec setup =
t1 = table_builder [["X", [1, 12, 12, 0]], ["Y", [1, 2, 3, 4]], ["Z", ["a", "A", "a", "ą"]], ["W", [1, 2, 3, 4]]] t1 = table_builder [["X", [1, 12, 12, 0]], ["Y", [1, 2, 3, 4]], ["Z", ["a", "A", "a", "ą"]], ["W", [1, 2, 3, 4]]]
t2 = table_builder [["X", [12, 12, 1]], ["l", [0, 100, 100]], ["u", [10, 100, 100]], ["Z", ["A", "A", "A"]], ["W'", [10, 20, 30]]] t2 = table_builder [["X", [12, 12, 1]], ["l", [0, 100, 100]], ["u", [10, 100, 100]], ["Z", ["A", "A", "A"]], ["W'", [10, 20, 30]]]
r1 = t1.join t2 on=[Join_Condition.Between "Y" "l" "u", Join_Condition.Equals_Ignore_Case "Z" "Z", Join_Condition.Equals "X" "X"] |> materialize |> _.order_by ["Y"] r1 = t1.join t2 join_kind=Join_Kind.Inner on=[Join_Condition.Between "Y" "l" "u", Join_Condition.Equals_Ignore_Case "Z" "Z", Join_Condition.Equals "X" "X"] |> materialize |> _.order_by ["Y"]
expect_column_names ["X", "Y", "Z", "W", "l", "u", "Right_Z", "W'"] r1 expect_column_names ["X", "Y", "Z", "W", "l", "u", "Right Z", "W'"] r1
r1.at "X" . to_vector . should_equal [12, 12] r1.at "X" . to_vector . should_equal [12, 12]
r1.at "Y" . to_vector . should_equal [2, 3] r1.at "Y" . to_vector . should_equal [2, 3]
r1.at "Z" . to_vector . should_equal ["A", "a"] r1.at "Z" . to_vector . should_equal ["A", "a"]
r1.at "W" . to_vector . should_equal [2, 3] r1.at "W" . to_vector . should_equal [2, 3]
r1.at "l" . to_vector . should_equal [0, 0] r1.at "l" . to_vector . should_equal [0, 0]
r1.at "u" . to_vector . should_equal [10, 10] r1.at "u" . to_vector . should_equal [10, 10]
r1.at "Right_Z" . to_vector . should_equal ["A", "A"] r1.at "Right Z" . to_vector . should_equal ["A", "A"]
r1.at "W'" . to_vector . should_equal [10, 10] r1.at "W'" . to_vector . should_equal [10, 10]
Test.specify "should work fine if the same condition is specified multiple times" <| Test.specify "should work fine if the same condition is specified multiple times" <|
r = t3.join t4 on=["X", "X", "Y", "X", "Y"] |> materialize |> _.order_by ["X", "Y", "Z", "Right_Z"] r = t3.join t4 join_kind=Join_Kind.Inner on=["X", "X", "Y", "X", "Y"] |> materialize |> _.order_by ["X", "Y", "Z", "Right Z"]
check_xy_joined r check_xy_joined r
t5 = table_builder [["X", [1, 10, 12]], ["Y", [1, 2, 3]]] t5 = table_builder [["X", [1, 10, 12]], ["Y", [1, 2, 3]]]
t6 = table_builder [["lower", [1, 10, 8, 12]], ["upper", [1, 12, 30, 0]], ["Z", [1, 2, 3, 4]]] t6 = table_builder [["lower", [1, 10, 8, 12]], ["upper", [1, 12, 30, 0]], ["Z", [1, 2, 3, 4]]]
r1 = t5.join t6 on=[Join_Condition.Between "X" "lower" "upper", Join_Condition.Between "X" "lower" "upper", Join_Condition.Between "X" "lower" "upper"] |> materialize |> _.order_by ["X", "Z"] r1 = t5.join t6 join_kind=Join_Kind.Inner on=[Join_Condition.Between "X" "lower" "upper", Join_Condition.Between "X" "lower" "upper", Join_Condition.Between "X" "lower" "upper"] |> materialize |> _.order_by ["X", "Z"]
r1 . at "X" . to_vector . should_equal [1, 10, 10, 12, 12] r1 . at "X" . to_vector . should_equal [1, 10, 10, 12, 12]
r1 . at "Y" . to_vector . should_equal [1, 2, 2, 3, 3] r1 . at "Y" . to_vector . should_equal [1, 2, 2, 3, 3]
r1 . at "Z" . to_vector . should_equal [1, 2, 3, 2, 3] r1 . at "Z" . to_vector . should_equal [1, 2, 3, 2, 3]
@ -243,64 +244,71 @@ spec setup =
t7 = table_builder [["X", ["a", "B"]], ["Y", [1, 2]]] t7 = table_builder [["X", ["a", "B"]], ["Y", [1, 2]]]
t8 = table_builder [["X", ["A", "a", "b"]], ["Z", [1, 2, 3]]] t8 = table_builder [["X", ["A", "a", "b"]], ["Z", [1, 2, 3]]]
r2 = t7.join t8 on=[Join_Condition.Equals_Ignore_Case "X", Join_Condition.Equals_Ignore_Case "X", Join_Condition.Equals_Ignore_Case "X" "X"] |> materialize |> _.order_by ["Z"] r2 = t7.join t8 join_kind=Join_Kind.Inner on=[Join_Condition.Equals_Ignore_Case "X", Join_Condition.Equals_Ignore_Case "X", Join_Condition.Equals_Ignore_Case "X" "X"] |> materialize |> _.order_by ["Z"]
r2 . at "X" . to_vector . should_equal ["a", "a", "B"] r2 . at "X" . to_vector . should_equal ["a", "a", "B"]
r2 . at "Right_X" . to_vector . should_equal ["A", "a", "b"] r2 . at "Right X" . to_vector . should_equal ["A", "a", "b"]
r2 . at "Z" . to_vector . should_equal [1, 2, 3] r2 . at "Z" . to_vector . should_equal [1, 2, 3]
Test.specify "should correctly handle joining a table with itself" <| Test.specify "should correctly handle joining a table with itself" <|
t1 = table_builder [["X", [0, 1, 2, 3, 2]], ["Y", [1, 2, 3, 4, 100]], ["A", ["B", "C", "D", "E", "X"]]] t1 = table_builder [["X", [0, 1, 2, 3, 2]], ["Y", [1, 2, 3, 4, 100]], ["A", ["B", "C", "D", "E", "X"]]]
t2 = t1.join t1 on=(Join_Condition.Equals left="X" right="Y") |> materialize |> _.order_by ["X", "Y"] t2 = t1.join t1 join_kind=Join_Kind.Inner on=(Join_Condition.Equals left="X" right="Y") |> materialize |> _.order_by ["X", "Y"]
expect_column_names ["X", "Y", "A", "Right_X", "Right_Y", "Right_A"] t2 expect_column_names ["X", "Y", "A", "Right X", "Right Y", "Right A"] t2
t2.at "X" . to_vector . should_equal [1, 2, 2, 3] t2.at "X" . to_vector . should_equal [1, 2, 2, 3]
t2.at "Right_Y" . to_vector . should_equal [1, 2, 2, 3] t2.at "Right Y" . to_vector . should_equal [1, 2, 2, 3]
t2.at "Y" . to_vector . should_equal [2, 3, 100, 4] t2.at "Y" . to_vector . should_equal [2, 3, 100, 4]
t2.at "A" . to_vector . should_equal ["C", "D", "X", "E"] t2.at "A" . to_vector . should_equal ["C", "D", "X", "E"]
t2.at "Right_X" . to_vector . should_equal [0, 1, 1, 2] t2.at "Right X" . to_vector . should_equal [0, 1, 1, 2]
t2.at "Right_A" . to_vector . should_equal ["B", "C", "C", "D"] t2.at "Right A" . to_vector . should_equal ["B", "C", "C", "D"]
t3 = t1.join t1 join_kind=Join_Kind.Full on=(Join_Condition.Equals left="X" right="Y") |> materialize |> _.order_by ["X", "Y", "Right_X"] t3 = t1.join t1 join_kind=Join_Kind.Full on=(Join_Condition.Equals left="X" right="Y") |> materialize |> _.order_by ["X", "Y", "Right X"]
expect_column_names ["X", "Y", "A", "Right_X", "Right_Y", "Right_A"] t3 expect_column_names ["X", "Y", "A", "Right X", "Right Y", "Right A"] t3
t3.at "X" . to_vector . should_equal [Nothing, Nothing, 0, 1, 2, 2, 3] t3.at "X" . to_vector . should_equal [Nothing, Nothing, 0, 1, 2, 2, 3]
t3.at "Right_Y" . to_vector . should_equal [100, 4, Nothing, 1, 2, 2, 3] t3.at "Right Y" . to_vector . should_equal [100, 4, Nothing, 1, 2, 2, 3]
t3.at "Y" . to_vector . should_equal [Nothing, Nothing, 1, 2, 3, 100, 4] t3.at "Y" . to_vector . should_equal [Nothing, Nothing, 1, 2, 3, 100, 4]
t3.at "A" . to_vector . should_equal [Nothing, Nothing, "B", "C", "D", "X", "E"] t3.at "A" . to_vector . should_equal [Nothing, Nothing, "B", "C", "D", "X", "E"]
t3.at "Right_X" . to_vector . should_equal [2, 3, Nothing, 0, 1, 1, 2] t3.at "Right X" . to_vector . should_equal [2, 3, Nothing, 0, 1, 1, 2]
t3.at "Right_A" . to_vector . should_equal ["X", "E", Nothing, "B", "C", "C", "D"] t3.at "Right A" . to_vector . should_equal ["X", "E", Nothing, "B", "C", "C", "D"]
t4 = table_builder [["X", [Nothing, "a", "B"]], ["Y", ["ą", "b", Nothing]], ["Z", [1, 2, 3]]] t4 = table_builder [["X", [Nothing, "a", "B"]], ["Y", ["ą", "b", Nothing]], ["Z", [1, 2, 3]]]
t5 = t4.join t4 on=(Join_Condition.Equals_Ignore_Case left="Y" right="X") |> materialize |> _.order_by ["Y"] t5 = t4.join t4 join_kind=Join_Kind.Inner on=(Join_Condition.Equals_Ignore_Case left="Y" right="X") |> materialize |> _.order_by ["Y"]
expect_column_names ["X", "Y", "Z", "Right_X", "Right_Y", "Right_Z"] t5 expect_column_names ["X", "Y", "Z", "Right X", "Right Y", "Right Z"] t5
# TODO enable once we handle nothing properly # TODO enable once we handle nothing properly
# t5.at "Y" . to_vector . should_equal [Nothing, "b"] # t5.at "Y" . to_vector . should_equal [Nothing, "b"]
# t5.at "Right_X" . to_vector . should_equal [Nothing, "B"] # t5.at "Right X" . to_vector . should_equal [Nothing, "B"]
# t5.at "X" . to_vector . should_equal ["B", "a"] # t5.at "X" . to_vector . should_equal ["B", "a"]
# t5.at "Z" . to_vector . should_equal [3, 2] # t5.at "Z" . to_vector . should_equal [3, 2]
# t5.at "Right_Y" . to_vector . should_equal ["ą", Nothing] # t5.at "Right Y" . to_vector . should_equal ["ą", Nothing]
# t5.at "Right_Z" . to_vector . should_equal [1, 3] # t5.at "Right Z" . to_vector . should_equal [1, 3]
Test.specify "should gracefully handle unmatched columns in Join_Conditions" <| Test.specify "should gracefully handle unmatched columns in Join_Conditions" <|
t1 = table_builder [["X", [1, 2]], ["Y", [3, 4]]] t1 = table_builder [["X", [1, 2]], ["Y", [3, 4]]]
t2 = table_builder [["Z", [2, 1]], ["W", [5, 6]]] t2 = table_builder [["Z", [2, 1]], ["W", [5, 6]]]
# Report error if the default fails - the right table does not have a column with same name as first column of left one:
r1 = t1.join t2
r1.should_fail_with Missing_Input_Columns
r1.catch.criteria.should_equal ["X"]
r1.catch.to_display_text.should_equal "The criteria [X] did not match any columns in the right table."
conditions = [Join_Condition.Equals "foo" 42, Join_Condition.Equals "X" -3, Join_Condition.Equals -1 "baz"] conditions = [Join_Condition.Equals "foo" 42, Join_Condition.Equals "X" -3, Join_Condition.Equals -1 "baz"]
r1 = t1.join t2 on=conditions on_problems=Problem_Behavior.Ignore r2 = t1.join t2 on=conditions on_problems=Problem_Behavior.Ignore
## We have both ## We have both
- Column_Indexes_Out_Of_Range.Error [42, -3] - Column_Indexes_Out_Of_Range.Error [42, -3]
- Missing_Input_Columns.Error ["foo", "baz"] - Missing_Input_Columns.Error ["foo", "baz"]
here, but we can throw only one error. I think column names error here, but we can throw only one error. I think column names error
will be more useful, so I'd prioritize it. will be more useful, so I'd prioritize it.
r1.should_fail_with Missing_Input_Columns r2.should_fail_with Missing_Input_Columns
r1.catch.criteria.should_equal ["foo", "baz"] r2.catch.criteria.should_equal ["foo"]
r2.catch.to_display_text.should_equal "The criteria [foo] did not match any columns in the left table."
r2 = t1.join t2 on=[Join_Condition.Equals 42 0] on_problems=Problem_Behavior.Ignore r3 = t1.join t2 on=[Join_Condition.Equals 42 0] on_problems=Problem_Behavior.Ignore
r2.should_fail_with Column_Indexes_Out_Of_Range r3.should_fail_with Column_Indexes_Out_Of_Range
r2.catch.indexes.should_equal [42] r3.catch.indexes.should_equal [42]
Test.specify "should report Invalid_Value_Type if non-text columns are provided to Equals_Ignore_Case" <| Test.specify "should report Invalid_Value_Type if non-text columns are provided to Equals_Ignore_Case" <|
t1 = table_builder [["X", ["1", "2", "c"]], ["Y", [1, 2, 3]]] t1 = table_builder [["X", ["1", "2", "c"]], ["Y", [1, 2, 3]]]
@ -317,7 +325,7 @@ spec setup =
Test.specify "should report Invalid_Value_Type if incompatible types are correlated" <| Test.specify "should report Invalid_Value_Type if incompatible types are correlated" <|
t1 = table_builder [["X", ["1", "2", "c"]]] t1 = table_builder [["X", ["1", "2", "c"]]]
t2 = table_builder [["Y", [1, 2, 3]]] t2 = table_builder [["X", [1, 2, 3]]]
r1 = t1.join t2 on_problems=Problem_Behavior.Ignore r1 = t1.join t2 on_problems=Problem_Behavior.Ignore
r1.should_fail_with Invalid_Value_Type r1.should_fail_with Invalid_Value_Type
@ -334,7 +342,7 @@ spec setup =
t1 = table_builder [["X", [1.5, 2.0, 2.00000000001]], ["Y", [10, 20, 30]]] t1 = table_builder [["X", [1.5, 2.0, 2.00000000001]], ["Y", [10, 20, 30]]]
t2 = table_builder [["Z", [2.0, 1.5, 2.0]], ["W", [1, 2, 3]]] t2 = table_builder [["Z", [2.0, 1.5, 2.0]], ["W", [1, 2, 3]]]
action1 = t1.join t2 on=(Join_Condition.Equals "X" "Z") on_problems=_ action1 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Equals "X" "Z") on_problems=_
tester1 table = tester1 table =
expect_column_names ["X", "Y", "Z", "W"] table expect_column_names ["X", "Y", "Z", "W"] table
t1 = table.order_by ["Y", "W"] t1 = table.order_by ["Y", "W"]
@ -345,7 +353,7 @@ spec setup =
problems1 = [Floating_Point_Equality.Error "X", Floating_Point_Equality.Error "Z"] problems1 = [Floating_Point_Equality.Error "X", Floating_Point_Equality.Error "Z"]
Problems.test_problem_handling action1 problems1 tester1 Problems.test_problem_handling action1 problems1 tester1
action2 = t1.join t2 on=(Join_Condition.Equals "X" "W") on_problems=_ action2 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Equals "X" "W") on_problems=_
tester2 table = tester2 table =
expect_column_names ["X", "Y", "Z", "W"] table expect_column_names ["X", "Y", "Z", "W"] table
t1 = table.order_by ["Y", "W"] t1 = table.order_by ["Y", "W"]
@ -363,7 +371,7 @@ spec setup =
if setup.supports_custom_objects then if setup.supports_custom_objects then
t1 = table_builder [["X", [My_Type.Value 1 2, 2.0, 2]], ["Y", [10, 20, 30]]] t1 = table_builder [["X", [My_Type.Value 1 2, 2.0, 2]], ["Y", [10, 20, 30]]]
t2 = table_builder [["Z", [2.0, 1.5, 2.0]], ["W", [1, 2, 3]]] t2 = table_builder [["Z", [2.0, 1.5, 2.0]], ["W", [1, 2, 3]]]
action3 = t1.join t2 on=(Join_Condition.Equals "X" "Z") on_problems=_ action3 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Equals "X" "Z") on_problems=_
tester3 table = tester3 table =
expect_column_names ["X", "Y", "Z", "W"] table expect_column_names ["X", "Y", "Z", "W"] table
t1 = table.order_by ["Y", "W"] t1 = table.order_by ["Y", "W"]
@ -378,7 +386,7 @@ spec setup =
t1 = table_builder [["X", ["A", Nothing, "a", Nothing, "ą"]], ["Y", [0, 1, 2, 3, 4]]] t1 = table_builder [["X", ["A", Nothing, "a", Nothing, "ą"]], ["Y", [0, 1, 2, 3, 4]]]
t2 = table_builder [["X", ["a", Nothing, Nothing]], ["Z", [10, 20, 30]]] t2 = table_builder [["X", ["a", Nothing, Nothing]], ["Z", [10, 20, 30]]]
r1 = t1.join t2 |> materialize |> _.order_by ["Y"] r1 = t1.join t2 join_kind=Join_Kind.Inner |> materialize |> _.order_by ["Y"]
expect_column_names ["X", "Y", "Z"] r1 expect_column_names ["X", "Y", "Z"] r1
r1.at "X" . to_vector . should_equal [Nothing, Nothing, "a", Nothing, Nothing] r1.at "X" . to_vector . should_equal [Nothing, Nothing, "a", Nothing, Nothing]
r1.at "Y" . to_vector . should_equal [1, 1, 2, 3, 3] r1.at "Y" . to_vector . should_equal [1, 1, 2, 3, 3]
@ -388,10 +396,10 @@ spec setup =
t1 = table_builder [["X", ["A", Nothing, "a", Nothing, "ą"]], ["Y", [0, 1, 2, 3, 4]]] t1 = table_builder [["X", ["A", Nothing, "a", Nothing, "ą"]], ["Y", [0, 1, 2, 3, 4]]]
t2 = table_builder [["X", ["a", Nothing, Nothing]], ["Z", [10, 20, 30]]] t2 = table_builder [["X", ["a", Nothing, Nothing]], ["Z", [10, 20, 30]]]
r1 = t1.join t2 on=(Join_Condition.Equals_Ignore_Case "X") |> materialize |> _.order_by ["Y"] r1 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Equals_Ignore_Case "X") |> materialize |> _.order_by ["Y"]
expect_column_names ["X", "Y", "Right_X", "Z"] r1 expect_column_names ["X", "Y", "Right X", "Z"] r1
r1.at "X" . to_vector . should_equal ["A", Nothing, Nothing, "a", Nothing, Nothing] r1.at "X" . to_vector . should_equal ["A", Nothing, Nothing, "a", Nothing, Nothing]
r1.at "Right_X" . to_vector . should_equal ["a", Nothing, Nothing, "a", Nothing, Nothing] r1.at "Right X" . to_vector . should_equal ["a", Nothing, Nothing, "a", Nothing, Nothing]
r1.at "Y" . to_vector . should_equal [0, 1, 1, 2, 3, 3] r1.at "Y" . to_vector . should_equal [0, 1, 1, 2, 3, 3]
r1.at "Z" . to_vector . should_equal [10, 20, 30, 10, 20, 30] r1.at "Z" . to_vector . should_equal [10, 20, 30, 10, 20, 30]
@ -399,7 +407,7 @@ spec setup =
t1 = table_builder [["X", [1, Nothing, 2, Nothing]], ["Y", [0, 1, 2, 3]]] t1 = table_builder [["X", [1, Nothing, 2, Nothing]], ["Y", [0, 1, 2, 3]]]
t2 = table_builder [["l", [Nothing, 0, 1]], ["u", [100, 10, Nothing]], ["Z", [10, 20, 30]]] t2 = table_builder [["l", [Nothing, 0, 1]], ["u", [100, 10, Nothing]], ["Z", [10, 20, 30]]]
r1 = t1.join t2 on=(Join_Condition.Between "X" "l" "u") |> materialize |> _.order_by ["Y"] r1 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Between "X" "l" "u") |> materialize |> _.order_by ["Y"]
expect_column_names ["X", "Y", "l", "u", "Z"] r1 expect_column_names ["X", "Y", "l", "u", "Z"] r1
r1.at "X" . to_vector . should_equal [1, 2] r1.at "X" . to_vector . should_equal [1, 2]
r1.at "Y" . to_vector . should_equal [0, 2] r1.at "Y" . to_vector . should_equal [0, 2]
@ -408,51 +416,55 @@ spec setup =
r1.at "Z" . to_vector . should_equal [20, 20] r1.at "Z" . to_vector . should_equal [20, 20]
Test.specify "should rename columns of the right table to avoid duplicates" <| Test.specify "should rename columns of the right table to avoid duplicates" <|
t1 = table_builder [["X", [1, 2]], ["Y", [3, 4]], ["Right_Y", [5, 6]]] t1 = table_builder [["X", [1, 2]], ["Y", [3, 4]], ["Right Y", [5, 6]]]
t2 = table_builder [["X", [2, 1]], ["Y", [2, 2]]] t2 = table_builder [["X", [2, 1]], ["Y", [2, 2]]]
t3 = t1.join t2 on=(Join_Condition.Equals "X" "Y") |> materialize |> _.order_by ["Right_X"] t3 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Equals "X" "Y") |> materialize |> _.order_by ["Right X"]
Problems.get_attached_warnings t3 . should_equal [Duplicate_Output_Column_Names.Error ["Right_Y"]] Problems.get_attached_warnings t3 . should_equal [Duplicate_Output_Column_Names.Error ["Right Y"]]
expect_column_names ["X", "Y", "Right_Y", "Right_X", "Right_Y_1"] t3 t3.column_names.should_equal ["X", "Y", "Right Y", "Right X", "Right Y 1"]
t3.at "X" . to_vector . should_equal [2, 2] t3.at "X" . to_vector . should_equal [2, 2]
t3.at "Y" . to_vector . should_equal [4, 4] t3.at "Y" . to_vector . should_equal [4, 4]
t3.at "Right_Y" . to_vector . should_equal [6, 6] t3.at "Right Y" . to_vector . should_equal [6, 6]
t3.at "Right_X" . to_vector . should_equal [1, 2] t3.at "Right X" . to_vector . should_equal [1, 2]
t3.at "Right_Y_1" . to_vector . should_equal [2, 2] t3.at "Right Y 1" . to_vector . should_equal [2, 2]
err1 = t1.join t2 on=(Join_Condition.Equals "X" "Y") on_problems=Problem_Behavior.Report_Error err1 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Equals "X" "Y") on_problems=Problem_Behavior.Report_Error
err1.should_fail_with Duplicate_Output_Column_Names err1.should_fail_with Duplicate_Output_Column_Names
err1.catch.column_names . should_equal ["Right_Y"] err1.catch.column_names . should_equal ["Right Y"]
t4 = table_builder [["Right_X", [1, 1]], ["X", [1, 2]], ["Y", [3, 4]], ["Right_Y_2", [2, 2]]] t4 = table_builder [["Right X", [1, 1]], ["X", [1, 2]], ["Y", [3, 4]], ["Right Y 2", [2, 2]]]
t5 = table_builder [["Right_X", [2, 1]], ["X", [2, 2]], ["Y", [2, 2]], ["Right_Y", [2, 2]], ["Right_Y_1", [2, 2]], ["Right_Y_4", [2, 2]]] t5 = table_builder [["Right X", [2, 1]], ["X", [2, 2]], ["Y", [2, 2]], ["Right Y", [2, 2]], ["Right Y 1", [2, 2]], ["Right Y 4", [2, 2]]]
t6 = t4.join t5 on=(Join_Condition.Equals "X" "Y") t6 = t4.join t5 on=(Join_Condition.Equals "X" "Y")
expect_column_names ["Right_X", "X", "Y", "Right_Y_2"]+["Right_Right_X", "Right_X_1", "Right_Y_3", "Right_Y", "Right_Y_1", "Right_Y_4"] t6 t6.column_names.should_equal ["Right X", "X", "Y", "Right Y 2"]+["Right Right X", "Right X 1", "Right Y 3", "Right Y", "Right Y 1", "Right Y 4"]
action = t1.join t2 right_prefix="" on_problems=_ action = t1.join t2 right_prefix="" on_problems=_
tester = expect_column_names ["X", "Y", "Right_Y", "Y_1"] tester = expect_column_names ["X", "Y", "Right Y", "X 1", "Y 1"]
problems = [Duplicate_Output_Column_Names.Error ["Y"]] problems = [Duplicate_Output_Column_Names.Error ["X", "Y"]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
t8 = t1.join t2 right_prefix="P" action_2 = t1.join t2 join_kind=Join_Kind.Inner right_prefix="" on_problems=_
expect_column_names ["X", "Y", "Right_Y", "PY"] t8 tester_2 = expect_column_names ["X", "Y", "Right Y", "Y 1"]
problems_2 = [Duplicate_Output_Column_Names.Error ["Y"]]
Problems.test_problem_handling action_2 problems_2 tester_2
t8 = t1.join t2 join_kind=Join_Kind.Inner right_prefix="P"
t8.column_names.should_equal ["X", "Y", "Right Y", "PY"]
Test.specify "should warn about renamed columns" <| Test.specify "should warn about renamed columns" <|
t1 = table_builder [["X", [1, 2]], ["Y", [3, 4]]] t1 = table_builder [["X", [1, 2]], ["Y", [3, 4]]]
t2 = table_builder [["X", [2, 1]], ["Y", [2, 2]], ["Right_Y", [2, 44]]] t2 = table_builder [["X", [2, 1]], ["Y", [2, 2]], ["Right Y", [2, 44]]]
action1 = t1.join t2 on=(Join_Condition.Equals "X" "Y") on_problems=_ action1 = t1.join t2 on=(Join_Condition.Equals "X" "Y") on_problems=_
tester1 table = tester1 table =
expect_column_names ["X", "Y", "Right_X", "Right_Y_1", "Right_Y"] table expect_column_names ["X", "Y", "Right X", "Right Y 1", "Right Y"] table
problems1 = [Duplicate_Output_Column_Names.Error ["Right_Y"]] problems1 = [Duplicate_Output_Column_Names.Error ["Right Y"]]
Problems.test_problem_handling action1 problems1 tester1 Problems.test_problem_handling action1 problems1 tester1
action2 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Equals "X" "X") on_problems=_
action2 = t1.join t2 on=(Join_Condition.Equals "X" "X") on_problems=_
tester2 table = tester2 table =
expect_column_names ["X", "Y", "Right_Y_1", "Right_Y"] table expect_column_names ["X", "Y", "Right Y 1", "Right Y"] table
problems2 = [Duplicate_Output_Column_Names.Error ["Right_Y"]] problems2 = [Duplicate_Output_Column_Names.Error ["Right Y"]]
Problems.test_problem_handling action2 problems2 tester2 Problems.test_problem_handling action2 problems2 tester2
Test.specify "should pass dataflow errors through" <| Test.specify "should pass dataflow errors through" <|
@ -527,13 +539,13 @@ spec setup =
t7 = table_builder [["A", [Nothing, 2]], ["B", [Nothing, 3]]] t7 = table_builder [["A", [Nothing, 2]], ["B", [Nothing, 3]]]
t8 = table_builder [["C", [2, 3]], ["D", [4, 5]]] t8 = table_builder [["C", [2, 3]], ["D", [4, 5]]]
t9 = t7.join t8 join_kind=Join_Kind.Inner t9 = t7.join t8 on=[Join_Condition.Equals "A" "C"] join_kind=Join_Kind.Inner
r9 = materialize t9 . order_by ["A", "B", "D"] . rows . map .to_vector r9 = materialize t9 . order_by ["A", "B", "D"] . rows . map .to_vector
within_table t9 <| within_table t9 <|
r9.length . should_equal 1 r9.length . should_equal 1
r9.at 0 . should_equal [2, 3, 2, 4] r9.at 0 . should_equal [2, 3, 2, 4]
t10 = t7.join t8 join_kind=Join_Kind.Full t10 = t7.join t8 on=[Join_Condition.Equals "A" "C"] join_kind=Join_Kind.Full
r10 = materialize t10 . order_by ["A", "C"] . rows . map .to_vector r10 = materialize t10 . order_by ["A", "C"] . rows . map .to_vector
within_table t10 <| within_table t10 <|
r10.length . should_equal 3 r10.length . should_equal 3
@ -541,27 +553,27 @@ spec setup =
r10.at 1 . should_equal [Nothing, Nothing, 3, 5] r10.at 1 . should_equal [Nothing, Nothing, 3, 5]
r10.at 2 . should_equal [2, 3, 2, 4] r10.at 2 . should_equal [2, 3, 2, 4]
t10_2 = t7.join t8 join_kind=Join_Kind.Left_Outer t10_2 = t7.join t8 on=[Join_Condition.Equals "A" "C"] join_kind=Join_Kind.Left_Outer
r10_2 = materialize t10_2 . order_by ["A", "C"] . rows . map .to_vector r10_2 = materialize t10_2 . order_by ["A", "C"] . rows . map .to_vector
within_table t10_2 <| within_table t10_2 <|
r10_2.length . should_equal 2 r10_2.length . should_equal 2
r10_2.at 0 . should_equal [Nothing, Nothing, Nothing, Nothing] r10_2.at 0 . should_equal [Nothing, Nothing, Nothing, Nothing]
r10_2.at 1 . should_equal [2, 3, 2, 4] r10_2.at 1 . should_equal [2, 3, 2, 4]
t10_3 = t7.join t8 join_kind=Join_Kind.Right_Outer t10_3 = t7.join t8 on=[Join_Condition.Equals "A" "C"] join_kind=Join_Kind.Right_Outer
r10_3 = materialize t10_3 . order_by ["A", "C"] . rows . map .to_vector r10_3 = materialize t10_3 . order_by ["A", "C"] . rows . map .to_vector
within_table t10_3 <| within_table t10_3 <|
r10_3.length . should_equal 2 r10_3.length . should_equal 2
r10_3.at 0 . should_equal [Nothing, Nothing, 3, 5] r10_3.at 0 . should_equal [Nothing, Nothing, 3, 5]
r10_3.at 1 . should_equal [2, 3, 2, 4] r10_3.at 1 . should_equal [2, 3, 2, 4]
t11 = t7.join t8 join_kind=Join_Kind.Left_Exclusive t11 = t7.join t8 on=[Join_Condition.Equals "A" "C"] join_kind=Join_Kind.Left_Exclusive
r11 = materialize t11 . rows . map .to_vector r11 = materialize t11 . rows . map .to_vector
within_table t11 <| within_table t11 <|
r11.length . should_equal 1 r11.length . should_equal 1
r11.at 0 . should_equal [Nothing, Nothing] r11.at 0 . should_equal [Nothing, Nothing]
t12 = t7.join t8 join_kind=Join_Kind.Right_Exclusive t12 = t7.join t8 on=[Join_Condition.Equals "A" "C"] join_kind=Join_Kind.Right_Exclusive
r12 = materialize t12 . rows . map .to_vector r12 = materialize t12 . rows . map .to_vector
within_table t12 <| within_table t12 <|
r12.length . should_equal 1 r12.length . should_equal 1
@ -585,18 +597,18 @@ spec setup =
t1_2 = t1.set "10*[X]+1" new_name="A" t1_2 = t1.set "10*[X]+1" new_name="A"
t1_3 = t1.set "[X]+20" new_name="B" t1_3 = t1.set "[X]+20" new_name="B"
t2 = t1_2.join t1_3 on=(Join_Condition.Equals "A" "B") t2 = t1_2.join t1_3 join_kind=Join_Kind.Inner on=(Join_Condition.Equals "A" "B")
t2.at "A" . to_vector . should_equal [21] t2.at "A" . to_vector . should_equal [21]
t2.at "X" . to_vector . should_equal [2] t2.at "X" . to_vector . should_equal [2]
t2.at "B" . to_vector . should_equal [21] t2.at "B" . to_vector . should_equal [21]
t2.at "Right_X" . to_vector . should_equal [1] t2.at "Right X" . to_vector . should_equal [1]
t4 = table_builder [["X", [1, 2, 3]], ["Y", [10, 20, 30]]] t4 = table_builder [["X", [1, 2, 3]], ["Y", [10, 20, 30]]]
t5 = table_builder [["X", [5, 7, 1]], ["Z", [100, 200, 300]]] t5 = table_builder [["X", [5, 7, 1]], ["Z", [100, 200, 300]]]
t4_2 = t4.set "2*[X]+1" new_name="C" t4_2 = t4.set "2*[X]+1" new_name="C"
t6 = t4_2.join t5 on=(Join_Condition.Equals "C" "X") join_kind=Join_Kind.Inner t6 = t4_2.join t5 on=(Join_Condition.Equals "C" "X") join_kind=Join_Kind.Inner
expect_column_names ["X", "Y", "C", "Right_X", "Z"] t6 expect_column_names ["X", "Y", "C", "Right X", "Z"] t6
r2 = materialize t6 . order_by ["Y"] . rows . map .to_vector r2 = materialize t6 . order_by ["Y"] . rows . map .to_vector
r2.length . should_equal 2 r2.length . should_equal 2
r2.at 0 . should_equal [2, 20, 5, 5, 100] r2.at 0 . should_equal [2, 20, 5, 5, 100]
@ -607,7 +619,7 @@ spec setup =
t2 = table_builder [["X", ["Ć", "A", "b"]], ["Z", [100, 200, 300]]] t2 = table_builder [["X", ["Ć", "A", "b"]], ["Z", [100, 200, 300]]]
t3 = t1.join t2 on=(Join_Condition.Equals_Ignore_Case "X") join_kind=Join_Kind.Full t3 = t1.join t2 on=(Join_Condition.Equals_Ignore_Case "X") join_kind=Join_Kind.Full
expect_column_names ["X", "Y", "Right_X", "Z"] t3 expect_column_names ["X", "Y", "Right X", "Z"] t3
r = materialize t3 . order_by ["Y"] . rows . map .to_vector r = materialize t3 . order_by ["Y"] . rows . map .to_vector
r.length . should_equal 4 r.length . should_equal 4
r.at 0 . should_equal [Nothing, Nothing, "Ć", 100] r.at 0 . should_equal [Nothing, Nothing, "Ć", 100]
@ -620,7 +632,7 @@ spec setup =
t4_2 = t4.set "2*[X]+1" new_name="C" t4_2 = t4.set "2*[X]+1" new_name="C"
t6 = t4_2.join t5 on=(Join_Condition.Equals "C" "X") join_kind=Join_Kind.Full t6 = t4_2.join t5 on=(Join_Condition.Equals "C" "X") join_kind=Join_Kind.Full
expect_column_names ["X", "Y", "C", "Right_X", "Z"] t6 expect_column_names ["X", "Y", "C", "Right X", "Z"] t6
r2 = materialize t6 . order_by ["Y"] . rows . map .to_vector r2 = materialize t6 . order_by ["Y"] . rows . map .to_vector
r2.length . should_equal 4 r2.length . should_equal 4
r2.at 0 . should_equal [Nothing, Nothing, Nothing, 1, 300] r2.at 0 . should_equal [Nothing, Nothing, Nothing, 1, 300]
@ -632,8 +644,8 @@ spec setup =
t4_4 = t4_3.set (t4_3.at "X" . fill_nothing 7) new_name="C" t4_4 = t4_3.set (t4_3.at "X" . fill_nothing 7) new_name="C"
t7 = t4_4.join t5 on=(Join_Condition.Equals "C" "X") join_kind=Join_Kind.Full t7 = t4_4.join t5 on=(Join_Condition.Equals "C" "X") join_kind=Join_Kind.Full
within_table t7 <| within_table t7 <|
expect_column_names ["X", "Y", "C", "Right_X", "Z"] t7 expect_column_names ["X", "Y", "C", "Right X", "Z"] t7
r3 = materialize t7 . order_by ["Y", "Right_X"] . rows . map .to_vector r3 = materialize t7 . order_by ["Y", "Right X"] . rows . map .to_vector
r3.length . should_equal 5 r3.length . should_equal 5
r3.at 0 . should_equal [Nothing, Nothing, Nothing, 1, 300] r3.at 0 . should_equal [Nothing, Nothing, Nothing, 1, 300]
r3.at 1 . should_equal [Nothing, Nothing, Nothing, 5, 100] r3.at 1 . should_equal [Nothing, Nothing, Nothing, 5, 100]

View File

@ -148,33 +148,33 @@ spec setup =
t3.at "W" . to_vector . should_equal ['b', Nothing, Nothing] t3.at "W" . to_vector . should_equal ['b', Nothing, Nothing]
Test.specify "should rename columns of the right table to avoid duplicates" <| Test.specify "should rename columns of the right table to avoid duplicates" <|
t1 = table_builder [["X", [1, 2]], ["Y", [5, 6]], ["Right_Y", [7, 8]]] t1 = table_builder [["X", [1, 2]], ["Y", [5, 6]], ["Right Y", [7, 8]]]
t2 = table_builder [["X", ['a']], ["Y", ['d']]] t2 = table_builder [["X", ['a']], ["Y", ['d']]]
t3 = t1.zip t2 keep_unmatched=True t3 = t1.zip t2 keep_unmatched=True
expect_column_names ["X", "Y", "Right_Y", "Right_X", "Right_Y_1"] t3 expect_column_names ["X", "Y", "Right Y", "Right X", "Right Y 1"] t3
Problems.get_attached_warnings t3 . should_equal [Duplicate_Output_Column_Names.Error ["Right_Y"]] Problems.get_attached_warnings t3 . should_equal [Duplicate_Output_Column_Names.Error ["Right Y"]]
t3.row_count . should_equal 2 t3.row_count . should_equal 2
t3.at "X" . to_vector . should_equal [1, 2] t3.at "X" . to_vector . should_equal [1, 2]
t3.at "Y" . to_vector . should_equal [5, 6] t3.at "Y" . to_vector . should_equal [5, 6]
t3.at "Right_Y" . to_vector . should_equal [7, 8] t3.at "Right Y" . to_vector . should_equal [7, 8]
t3.at "Right_X" . to_vector . should_equal ['a', Nothing] t3.at "Right X" . to_vector . should_equal ['a', Nothing]
t3.at "Right_Y_1" . to_vector . should_equal ['d', Nothing] t3.at "Right Y 1" . to_vector . should_equal ['d', Nothing]
t1.zip t2 keep_unmatched=False on_problems=Problem_Behavior.Report_Error . should_fail_with Duplicate_Output_Column_Names t1.zip t2 keep_unmatched=False on_problems=Problem_Behavior.Report_Error . should_fail_with Duplicate_Output_Column_Names
expect_column_names ["X", "Y", "Right_Y", "X_1", "Y_1"] (t1.zip t2 right_prefix="") expect_column_names ["X", "Y", "Right Y", "X 1", "Y 1"] (t1.zip t2 right_prefix="")
t4 = table_builder [["X", [1]], ["Right_X", [5]]] t4 = table_builder [["X", [1]], ["Right X", [5]]]
expect_column_names ["X", "Y", "Right_Y", "Right_X_1", "Right_X"] (t1.zip t4) expect_column_names ["X", "Y", "Right Y", "Right X 1", "Right X"] (t1.zip t4)
expect_column_names ["X", "Right_X", "Right_X_1", "Y", "Right_Y"] (t4.zip t1) expect_column_names ["X", "Right X", "Right X 1", "Y", "Right Y"] (t4.zip t1)
Test.specify "should report both row count mismatch and duplicate column warnings at the same time" <| Test.specify "should report both row count mismatch and duplicate column warnings at the same time" <|
t1 = table_builder [["X", [1, 2]], ["Right_X", [5, 6]]] t1 = table_builder [["X", [1, 2]], ["Right X", [5, 6]]]
t2 = table_builder [["X", ['a']], ["Z", ['d']]] t2 = table_builder [["X", ['a']], ["Z", ['d']]]
t3 = t1.zip t2 t3 = t1.zip t2
expected_problems = [Row_Count_Mismatch.Error 2 1, Duplicate_Output_Column_Names.Error ["Right_X"]] expected_problems = [Row_Count_Mismatch.Error 2 1, Duplicate_Output_Column_Names.Error ["Right X"]]
Problems.get_attached_warnings t3 . should_contain_the_same_elements_as expected_problems Problems.get_attached_warnings t3 . should_contain_the_same_elements_as expected_problems
Test.specify "should allow to zip the table with itself" <| Test.specify "should allow to zip the table with itself" <|
@ -183,12 +183,12 @@ spec setup =
the Database backend. the Database backend.
t1 = table_builder [["X", [1, 2]], ["Y", [4, 5]]] t1 = table_builder [["X", [1, 2]], ["Y", [4, 5]]]
t2 = t1.zip t1 t2 = t1.zip t1
expect_column_names ["X", "Y", "Right_X", "Right_Y"] t2 expect_column_names ["X", "Y", "Right X", "Right Y"] t2
t2.row_count . should_equal 2 t2.row_count . should_equal 2
t2.at "X" . to_vector . should_equal [1, 2] t2.at "X" . to_vector . should_equal [1, 2]
t2.at "Y" . to_vector . should_equal [4, 5] t2.at "Y" . to_vector . should_equal [4, 5]
t2.at "Right_X" . to_vector . should_equal [1, 2] t2.at "Right X" . to_vector . should_equal [1, 2]
t2.at "Right_Y" . to_vector . should_equal [4, 5] t2.at "Right Y" . to_vector . should_equal [4, 5]
if setup.is_database.not then if setup.is_database.not then
Test.specify "should correctly pad/truncate all kinds of column types" <| Test.specify "should correctly pad/truncate all kinds of column types" <|

View File

@ -19,8 +19,8 @@ spec setup =
col1 = ["foo", [1,2,3]] col1 = ["foo", [1,2,3]]
col2 = ["bar", [4,5,6]] col2 = ["bar", [4,5,6]]
col3 = ["Baz", [7,8,9]] col3 = ["Baz", [7,8,9]]
col4 = ["foo_1", [10,11,12]] col4 = ["foo 1", [10,11,12]]
col5 = ["foo_2", [13,14,15]] col5 = ["foo 2", [13,14,15]]
col6 = ["ab.+123", [16,17,18]] col6 = ["ab.+123", [16,17,18]]
col7 = ["abcd123", [19,20,21]] col7 = ["abcd123", [19,20,21]]
table_builder [col1, col2, col3, col4, col5, col6, col7] table_builder [col1, col2, col3, col4, col5, col6, col7]
@ -28,7 +28,7 @@ spec setup =
Test.group prefix+"Table.select_columns" <| Test.group prefix+"Table.select_columns" <|
Test.specify "should work as shown in the doc examples" <| Test.specify "should work as shown in the doc examples" <|
expect_column_names ["foo", "bar"] <| table.select_columns ["bar", "foo"] expect_column_names ["foo", "bar"] <| table.select_columns ["bar", "foo"]
expect_column_names ["bar", "Baz", "foo_1", "foo_2"] <| table.select_columns [By_Name "foo.+" use_regex=True, By_Name "b.*" use_regex=True] expect_column_names ["bar", "Baz", "foo 1", "foo 2"] <| table.select_columns [By_Name "foo.+" use_regex=True, By_Name "b.*" use_regex=True]
expect_column_names ["abcd123", "foo", "bar"] <| table.select_columns [-1, 0, 1] reorder=True expect_column_names ["abcd123", "foo", "bar"] <| table.select_columns [-1, 0, 1] reorder=True
Test.specify "should allow to reorder columns if asked to" <| Test.specify "should allow to reorder columns if asked to" <|
@ -45,13 +45,13 @@ spec setup =
expect_column_names ["abcd123"] <| table.select_columns [By_Name "abcd123" Case_Sensitivity.Sensitive use_regex=True] expect_column_names ["abcd123"] <| table.select_columns [By_Name "abcd123" Case_Sensitivity.Sensitive use_regex=True]
Test.specify "should allow negative indices" <| Test.specify "should allow negative indices" <|
expect_column_names ["foo", "bar", "foo_2"] <| table.select_columns [-3, 0, 1] expect_column_names ["foo", "bar", "foo 2"] <| table.select_columns [-3, 0, 1]
Test.specify "should allow mixed names and indexes" <| Test.specify "should allow mixed names and indexes" <|
expect_column_names ["foo", "bar", "foo_2"] <| table.select_columns [-3, "bar", 0] expect_column_names ["foo", "bar", "foo 2"] <| table.select_columns [-3, "bar", 0]
expect_column_names ["foo_2", "bar", "foo"] <| table.select_columns [-3, "bar", 0] reorder=True expect_column_names ["foo 2", "bar", "foo"] <| table.select_columns [-3, "bar", 0] reorder=True
expect_column_names ["foo", "bar", "foo_1", "foo_2", "abcd123"] <| table.select_columns [-1, "bar", By_Name "foo.*" Case_Sensitivity.Sensitive use_regex=True] expect_column_names ["foo", "bar", "foo 1", "foo 2", "abcd123"] <| table.select_columns [-1, "bar", By_Name "foo.*" Case_Sensitivity.Sensitive use_regex=True]
expect_column_names ["foo", "foo_1", "foo_2", "bar", "abcd123"] <| table.select_columns [By_Name "foo.*" Case_Sensitivity.Sensitive use_regex=True, "bar", "foo", -1] reorder=True expect_column_names ["foo", "foo 1", "foo 2", "bar", "abcd123"] <| table.select_columns [By_Name "foo.*" Case_Sensitivity.Sensitive use_regex=True, "bar", "foo", -1] reorder=True
if test_selection.supports_case_sensitive_columns then if test_selection.supports_case_sensitive_columns then
Test.specify "should correctly handle exact matches matching multiple names due to case insensitivity" <| Test.specify "should correctly handle exact matches matching multiple names due to case insensitivity" <|
@ -63,8 +63,8 @@ spec setup =
expect_column_names ["bar", "Bar"] <| table.select_columns [By_Name "bar"] expect_column_names ["bar", "Bar"] <| table.select_columns [By_Name "bar"]
Test.specify "should correctly handle regexes matching multiple names" <| Test.specify "should correctly handle regexes matching multiple names" <|
expect_column_names ["foo", "bar", "foo_1", "foo_2"] <| table.select_columns [By_Name "b.*" Case_Sensitivity.Sensitive use_regex=True, By_Name "f.+" Case_Sensitivity.Sensitive use_regex=True] expect_column_names ["foo", "bar", "foo 1", "foo 2"] <| table.select_columns [By_Name "b.*" Case_Sensitivity.Sensitive use_regex=True, By_Name "f.+" Case_Sensitivity.Sensitive use_regex=True]
expect_column_names ["bar", "foo", "foo_1", "foo_2"] <| table.select_columns [By_Name "b.*" Case_Sensitivity.Sensitive use_regex=True, By_Name "f.+" Case_Sensitivity.Sensitive use_regex=True] reorder=True expect_column_names ["bar", "foo", "foo 1", "foo 2"] <| table.select_columns [By_Name "b.*" Case_Sensitivity.Sensitive use_regex=True, By_Name "f.+" Case_Sensitivity.Sensitive use_regex=True] reorder=True
Test.specify "should correctly handle problems: out of bounds indices" <| Test.specify "should correctly handle problems: out of bounds indices" <|
selector = [1, 0, 100, -200, 300] selector = [1, 0, 100, -200, 300]
@ -142,21 +142,21 @@ spec setup =
Test.group prefix+"Table.remove_columns" <| Test.group prefix+"Table.remove_columns" <|
Test.specify "should work as shown in the doc examples" <| Test.specify "should work as shown in the doc examples" <|
expect_column_names ["Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] <| table.remove_columns ["bar", "foo"] expect_column_names ["Baz", "foo 1", "foo 2", "ab.+123", "abcd123"] <| table.remove_columns ["bar", "foo"]
expect_column_names ["foo", "ab.+123", "abcd123"] <| table.remove_columns [By_Name "foo.+" Case_Sensitivity.Insensitive use_regex=True, By_Name "b.*" Case_Sensitivity.Insensitive use_regex=True] expect_column_names ["foo", "ab.+123", "abcd123"] <| table.remove_columns [By_Name "foo.+" Case_Sensitivity.Insensitive use_regex=True, By_Name "b.*" Case_Sensitivity.Insensitive use_regex=True]
expect_column_names ["Baz", "foo_1", "foo_2", "ab.+123"] <| table.remove_columns [-1, 0, 1] expect_column_names ["Baz", "foo 1", "foo 2", "ab.+123"] <| table.remove_columns [-1, 0, 1]
Test.specify "should correctly handle regex matching" <| Test.specify "should correctly handle regex matching" <|
last_ones = table.columns.drop 1 . map .name last_ones = table.columns.drop 1 . map .name
expect_column_names last_ones <| table.remove_columns [By_Name "foo" Case_Sensitivity.Sensitive use_regex=True] expect_column_names last_ones <| table.remove_columns [By_Name "foo" Case_Sensitivity.Sensitive use_regex=True]
first_ones = ["foo", "bar", "Baz", "foo_1", "foo_2"] first_ones = ["foo", "bar", "Baz", "foo 1", "foo 2"]
expect_column_names first_ones <| table.remove_columns [By_Name "a.*" Case_Sensitivity.Sensitive use_regex=True] expect_column_names first_ones <| table.remove_columns [By_Name "a.*" Case_Sensitivity.Sensitive use_regex=True]
expect_column_names first_ones <| table.remove_columns [By_Name "ab.+123" Case_Sensitivity.Sensitive use_regex=True] expect_column_names first_ones <| table.remove_columns [By_Name "ab.+123" Case_Sensitivity.Sensitive use_regex=True]
expect_column_names first_ones+["abcd123"] <| table.remove_columns [By_Name "ab.+123"] expect_column_names first_ones+["abcd123"] <| table.remove_columns [By_Name "ab.+123"]
expect_column_names first_ones+["ab.+123"] <| table.remove_columns [By_Name "abcd123" Case_Sensitivity.Sensitive use_regex=True] expect_column_names first_ones+["ab.+123"] <| table.remove_columns [By_Name "abcd123" Case_Sensitivity.Sensitive use_regex=True]
Test.specify "should allow negative indices" <| Test.specify "should allow negative indices" <|
expect_column_names ["Baz", "foo_1", "ab.+123"] <| table.remove_columns [-1, -3, 0, 1] expect_column_names ["Baz", "foo 1", "ab.+123"] <| table.remove_columns [-1, -3, 0, 1]
if test_selection.supports_case_sensitive_columns then if test_selection.supports_case_sensitive_columns then
Test.specify "should correctly handle exact matches matching multiple names due to case insensitivity" <| Test.specify "should correctly handle exact matches matching multiple names due to case insensitivity" <|
@ -173,7 +173,7 @@ spec setup =
Test.specify "should correctly handle problems: out of bounds indices" <| Test.specify "should correctly handle problems: out of bounds indices" <|
selector = [1, 0, 100, -200, 300] selector = [1, 0, 100, -200, 300]
action = table.remove_columns selector on_problems=_ action = table.remove_columns selector on_problems=_
tester = expect_column_names ["Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] tester = expect_column_names ["Baz", "foo 1", "foo 2", "ab.+123", "abcd123"]
problems = [Column_Indexes_Out_Of_Range.Error [100, -200, 300]] problems = [Column_Indexes_Out_Of_Range.Error [100, -200, 300]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
@ -183,28 +183,28 @@ spec setup =
Test.specify "should correctly handle edge-cases: duplicate indices" <| Test.specify "should correctly handle edge-cases: duplicate indices" <|
selector = [0, 0, 0] selector = [0, 0, 0]
t = table.remove_columns selector on_problems=Problem_Behavior.Report_Error t = table.remove_columns selector on_problems=Problem_Behavior.Report_Error
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] t expect_column_names ["bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123"] t
Test.specify "should correctly handle edge-cases: aliased indices" <| Test.specify "should correctly handle edge-cases: aliased indices" <|
selector = [0, -7, -6, 1] selector = [0, -7, -6, 1]
t = table.remove_columns selector on_problems=Problem_Behavior.Report_Error t = table.remove_columns selector on_problems=Problem_Behavior.Report_Error
expect_column_names ["Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] t expect_column_names ["Baz", "foo 1", "foo 2", "ab.+123", "abcd123"] t
Test.specify "should correctly handle edge-cases: duplicate names" <| Test.specify "should correctly handle edge-cases: duplicate names" <|
selector = ["foo", "foo"] selector = ["foo", "foo"]
t = table.remove_columns selector on_problems=Problem_Behavior.Report_Error t = table.remove_columns selector on_problems=Problem_Behavior.Report_Error
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] t expect_column_names ["bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123"] t
Test.specify "should correctly handle edge-cases: duplicate matches due to case insensitivity" <| Test.specify "should correctly handle edge-cases: duplicate matches due to case insensitivity" <|
selector = [By_Name "FOO", By_Name "foo"] selector = [By_Name "FOO", By_Name "foo"]
t = table.remove_columns selector on_problems=Problem_Behavior.Report_Error t = table.remove_columns selector on_problems=Problem_Behavior.Report_Error
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] t expect_column_names ["bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123"] t
Test.specify "should correctly handle problems: unmatched names" <| Test.specify "should correctly handle problems: unmatched names" <|
weird_name = '.*?-!@#!"' weird_name = '.*?-!@#!"'
selector = ["foo", "hmm", weird_name] selector = ["foo", "hmm", weird_name]
action = table.remove_columns selector on_problems=_ action = table.remove_columns selector on_problems=_
tester = expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] tester = expect_column_names ["bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123"]
problems = [Missing_Input_Columns.Error ["hmm", weird_name]] problems = [Missing_Input_Columns.Error ["hmm", weird_name]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
@ -223,22 +223,22 @@ spec setup =
Test.group prefix+"Table.reorder_columns" <| Test.group prefix+"Table.reorder_columns" <|
Test.specify "should work as shown in the doc examples" <| Test.specify "should work as shown in the doc examples" <|
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo"] <| table.reorder_columns "foo" Position.After_Other_Columns expect_column_names ["bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123", "foo"] <| table.reorder_columns "foo" Position.After_Other_Columns
expect_column_names ["Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo", "bar"] <| table.reorder_columns ["foo", "bar"] Position.After_Other_Columns expect_column_names ["Baz", "foo 1", "foo 2", "ab.+123", "abcd123", "foo", "bar"] <| table.reorder_columns ["foo", "bar"] Position.After_Other_Columns
expect_column_names ["foo_1", "foo_2", "bar", "Baz", "foo", "ab.+123", "abcd123"] <| table.reorder_columns [By_Name "foo.+" Case_Sensitivity.Insensitive use_regex=True, By_Name "b.*" Case_Sensitivity.Insensitive use_regex=True] expect_column_names ["foo 1", "foo 2", "bar", "Baz", "foo", "ab.+123", "abcd123"] <| table.reorder_columns [By_Name "foo.+" Case_Sensitivity.Insensitive use_regex=True, By_Name "b.*" Case_Sensitivity.Insensitive use_regex=True]
expect_column_names ["bar", "foo", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] <| table.reorder_columns [1, 0] Position.Before_Other_Columns expect_column_names ["bar", "foo", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123"] <| table.reorder_columns [1, 0] Position.Before_Other_Columns
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo"] <| table.reorder_columns [0] Position.After_Other_Columns expect_column_names ["bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123", "foo"] <| table.reorder_columns [0] Position.After_Other_Columns
Test.specify "should correctly handle regex matching" <| Test.specify "should correctly handle regex matching" <|
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo"] <| table.reorder_columns [By_Name "foo" Case_Sensitivity.Sensitive use_regex=True] Position.After_Other_Columns expect_column_names ["bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123", "foo"] <| table.reorder_columns [By_Name "foo" Case_Sensitivity.Sensitive use_regex=True] Position.After_Other_Columns
rest = ["foo", "bar", "Baz", "foo_1", "foo_2"] rest = ["foo", "bar", "Baz", "foo 1", "foo 2"]
expect_column_names ["ab.+123", "abcd123"]+rest <| table.reorder_columns [By_Name "a.*" Case_Sensitivity.Sensitive use_regex=True] expect_column_names ["ab.+123", "abcd123"]+rest <| table.reorder_columns [By_Name "a.*" Case_Sensitivity.Sensitive use_regex=True]
expect_column_names ["ab.+123", "abcd123"]+rest <| table.reorder_columns [By_Name "ab.+123" Case_Sensitivity.Sensitive use_regex=True] expect_column_names ["ab.+123", "abcd123"]+rest <| table.reorder_columns [By_Name "ab.+123" Case_Sensitivity.Sensitive use_regex=True]
expect_column_names ["ab.+123"]+rest+["abcd123"] <| table.reorder_columns ["ab.+123"] expect_column_names ["ab.+123"]+rest+["abcd123"] <| table.reorder_columns ["ab.+123"]
expect_column_names ["abcd123"]+rest+["ab.+123"] <| table.reorder_columns [By_Name "abcd123" Case_Sensitivity.Sensitive use_regex=True] expect_column_names ["abcd123"]+rest+["ab.+123"] <| table.reorder_columns [By_Name "abcd123" Case_Sensitivity.Sensitive use_regex=True]
Test.specify "should allow negative indices" <| Test.specify "should allow negative indices" <|
expect_column_names ["abcd123", "foo_2", "foo", "bar", "Baz", "foo_1", "ab.+123"] <| table.reorder_columns [-1, -3, 0, 1] expect_column_names ["abcd123", "foo 2", "foo", "bar", "Baz", "foo 1", "ab.+123"] <| table.reorder_columns [-1, -3, 0, 1]
if test_selection.supports_case_sensitive_columns then if test_selection.supports_case_sensitive_columns then
Test.specify "should correctly handle exact matches matching multiple names due to case insensitivity" <| Test.specify "should correctly handle exact matches matching multiple names due to case insensitivity" <|
@ -250,12 +250,12 @@ spec setup =
expect_column_names ["bar", "Bar", "foo"] <| table.reorder_columns [By_Name "bar"] expect_column_names ["bar", "Bar", "foo"] <| table.reorder_columns [By_Name "bar"]
Test.specify "should correctly handle regexes matching multiple names" <| Test.specify "should correctly handle regexes matching multiple names" <|
expect_column_names ["bar", "foo", "foo_1", "foo_2", "Baz", "ab.+123", "abcd123"] <| table.reorder_columns [By_Name "b.*" Case_Sensitivity.Sensitive use_regex=True, By_Name "f.+" Case_Sensitivity.Sensitive use_regex=True] expect_column_names ["bar", "foo", "foo 1", "foo 2", "Baz", "ab.+123", "abcd123"] <| table.reorder_columns [By_Name "b.*" Case_Sensitivity.Sensitive use_regex=True, By_Name "f.+" Case_Sensitivity.Sensitive use_regex=True]
Test.specify "should correctly handle problems: out of bounds indices" <| Test.specify "should correctly handle problems: out of bounds indices" <|
selector = [1, 0, 100, -200, 300] selector = [1, 0, 100, -200, 300]
action = table.reorder_columns selector on_problems=_ action = table.reorder_columns selector on_problems=_
tester = expect_column_names ["bar", "foo", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] tester = expect_column_names ["bar", "foo", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123"]
problems = [Column_Indexes_Out_Of_Range.Error [100, -200, 300]] problems = [Column_Indexes_Out_Of_Range.Error [100, -200, 300]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
@ -265,23 +265,23 @@ spec setup =
Test.specify "should correctly handle edge-cases: duplicate indices" <| Test.specify "should correctly handle edge-cases: duplicate indices" <|
selector = [0, 0, 0] selector = [0, 0, 0]
t = table.reorder_columns selector Position.After_Other_Columns on_problems=Problem_Behavior.Report_Error t = table.reorder_columns selector Position.After_Other_Columns on_problems=Problem_Behavior.Report_Error
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo"] t expect_column_names ["bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123", "foo"] t
Test.specify "should correctly handle edge-cases: aliased indices" <| Test.specify "should correctly handle edge-cases: aliased indices" <|
selector = [0, -7, -6, 1] selector = [0, -7, -6, 1]
t = table.reorder_columns selector Position.After_Other_Columns on_problems=Problem_Behavior.Report_Error t = table.reorder_columns selector Position.After_Other_Columns on_problems=Problem_Behavior.Report_Error
expect_column_names ["Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo", "bar"] t expect_column_names ["Baz", "foo 1", "foo 2", "ab.+123", "abcd123", "foo", "bar"] t
Test.specify "should correctly handle edge-cases: duplicate names" <| Test.specify "should correctly handle edge-cases: duplicate names" <|
selector = ["foo", "foo"] selector = ["foo", "foo"]
t = table.reorder_columns selector Position.After_Other_Columns on_problems=Problem_Behavior.Report_Error t = table.reorder_columns selector Position.After_Other_Columns on_problems=Problem_Behavior.Report_Error
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo"] t expect_column_names ["bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123", "foo"] t
Test.specify "should correctly handle problems: unmatched names" <| Test.specify "should correctly handle problems: unmatched names" <|
weird_name = '.*?-!@#!"' weird_name = '.*?-!@#!"'
selector = ["foo", "hmm", weird_name] selector = ["foo", "hmm", weird_name]
action = table.reorder_columns selector Position.After_Other_Columns on_problems=_ action = table.reorder_columns selector Position.After_Other_Columns on_problems=_
tester = expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo"] tester = expect_column_names ["bar", "Baz", "foo 1", "foo 2", "ab.+123", "abcd123", "foo"]
problems = [Missing_Input_Columns.Error ["hmm", weird_name]] problems = [Missing_Input_Columns.Error ["hmm", weird_name]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
@ -290,31 +290,31 @@ spec setup =
Test.group prefix+"Table.sort_columns" <| Test.group prefix+"Table.sort_columns" <|
table = table =
col1 = ["foo_21", [1,2,3]] col1 = ["foo 21", [1,2,3]]
col2 = ["foo_100", [4,5,6]] col2 = ["foo 100", [4,5,6]]
col3 = ["foo_1", [7,8,9]] col3 = ["foo 1", [7,8,9]]
col4 = ["Foo_2", [10,11,12]] col4 = ["Foo 2", [10,11,12]]
col5 = ["foo_3", [13,14,15]] col5 = ["foo 3", [13,14,15]]
col6 = ["foo_001", [16,17,18]] col6 = ["foo 001", [16,17,18]]
col7 = ["bar", [19,20,21]] col7 = ["bar", [19,20,21]]
table_builder [col1, col2, col3, col4, col5, col6, col7] table_builder [col1, col2, col3, col4, col5, col6, col7]
Test.specify "should work as shown in the doc examples" <| Test.specify "should work as shown in the doc examples" <|
sorted = table.sort_columns sorted = table.sort_columns
expect_column_names ["Foo_2", "bar", "foo_001", "foo_1", "foo_100", "foo_21", "foo_3"] sorted expect_column_names ["Foo 2", "bar", "foo 001", "foo 1", "foo 100", "foo 21", "foo 3"] sorted
sorted.columns.first.to_vector . should_equal [10,11,12] sorted.columns.first.to_vector . should_equal [10,11,12]
expect_column_names ["bar", "foo_001", "foo_1", "Foo_2", "foo_3", "foo_21", "foo_100"] <| table.sort_columns text_ordering=(Text_Ordering.Case_Insensitive sort_digits_as_numbers=True) expect_column_names ["bar", "foo 001", "foo 1", "Foo 2", "foo 3", "foo 21", "foo 100"] <| table.sort_columns text_ordering=(Text_Ordering.Case_Insensitive sort_digits_as_numbers=True)
expect_column_names ["foo_3", "foo_21", "foo_100", "foo_1", "foo_001", "bar", "Foo_2"] <| table.sort_columns Sort_Direction.Descending expect_column_names ["foo 3", "foo 21", "foo 100", "foo 1", "foo 001", "bar", "Foo 2"] <| table.sort_columns Sort_Direction.Descending
Test.specify "should correctly handle case-insensitive sorting" <| Test.specify "should correctly handle case-insensitive sorting" <|
expect_column_names ["bar", "foo_001", "foo_1", "foo_100", "Foo_2", "foo_21", "foo_3"] <| table.sort_columns text_ordering=(Text_Ordering.Case_Insensitive) expect_column_names ["bar", "foo 001", "foo 1", "foo 100", "Foo 2", "foo 21", "foo 3"] <| table.sort_columns text_ordering=(Text_Ordering.Case_Insensitive)
Test.specify "should correctly handle natural order sorting" <| Test.specify "should correctly handle natural order sorting" <|
expect_column_names ["Foo_2", "bar", "foo_001", "foo_1", "foo_3", "foo_21", "foo_100"] <| table.sort_columns text_ordering=(Text_Ordering.Default sort_digits_as_numbers=True) expect_column_names ["Foo 2", "bar", "foo 001", "foo 1", "foo 3", "foo 21", "foo 100"] <| table.sort_columns text_ordering=(Text_Ordering.Default sort_digits_as_numbers=True)
Test.specify "should correctly handle various combinations of options" <| Test.specify "should correctly handle various combinations of options" <|
expect_column_names ["foo_100", "foo_21", "foo_3", "Foo_2", "foo_1", "foo_001", "bar"] <| table.sort_columns Sort_Direction.Descending text_ordering=(Text_Ordering.Case_Insensitive sort_digits_as_numbers=True) expect_column_names ["foo 100", "foo 21", "foo 3", "Foo 2", "foo 1", "foo 001", "bar"] <| table.sort_columns Sort_Direction.Descending text_ordering=(Text_Ordering.Case_Insensitive sort_digits_as_numbers=True)
Test.group prefix+"Table.rename_columns" <| Test.group prefix+"Table.rename_columns" <|
table = table =
@ -441,41 +441,41 @@ spec setup =
Test.specify "should correctly handle problems: invalid names ''" <| Test.specify "should correctly handle problems: invalid names ''" <|
map = Map.from_vector [[1, ""]] map = Map.from_vector [[1, ""]]
action = table.rename_columns map on_problems=_ action = table.rename_columns map on_problems=_
tester = expect_column_names ["alpha", "Column_1", "gamma", "delta"] tester = expect_column_names ["alpha", "Column 1", "gamma", "delta"]
problems = [Invalid_Output_Column_Names.Error [""]] problems = [Invalid_Output_Column_Names.Error [""]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
Test.specify "should correctly handle problems: invalid names Nothing" <| Test.specify "should correctly handle problems: invalid names Nothing" <|
map = ["alpha", Nothing] map = ["alpha", Nothing]
action = table.rename_columns map on_problems=_ action = table.rename_columns map on_problems=_
tester = expect_column_names ["alpha", "Column_1", "gamma", "delta"] tester = expect_column_names ["alpha", "Column 1", "gamma", "delta"]
problems = [Invalid_Output_Column_Names.Error [Nothing]] problems = [Invalid_Output_Column_Names.Error [Nothing]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
Test.specify "should correctly handle problems: invalid names null character" <| Test.specify "should correctly handle problems: invalid names null character" <|
map = ["alpha", 'a\0b'] map = ["alpha", 'a\0b']
action = table.rename_columns map on_problems=_ action = table.rename_columns map on_problems=_
tester = expect_column_names ["alpha", "Column_1", "gamma", "delta"] tester = expect_column_names ["alpha", "Column 1", "gamma", "delta"]
problems = [Invalid_Output_Column_Names.Error ['a\0b']] problems = [Invalid_Output_Column_Names.Error ['a\0b']]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
Test.specify "should correctly handle problems: duplicate names" <| Test.specify "should correctly handle problems: duplicate names" <|
map = ["Test", "Test", "Test", "Test"] map = ["Test", "Test", "Test", "Test"]
action = table.rename_columns map on_problems=_ action = table.rename_columns map on_problems=_
tester = expect_column_names ["Test", "Test_1", "Test_2", "Test_3"] tester = expect_column_names ["Test", "Test 1", "Test 2", "Test 3"]
problems = [Duplicate_Output_Column_Names.Error ["Test", "Test", "Test"]] problems = [Duplicate_Output_Column_Names.Error ["Test", "Test", "Test"]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
Test.specify "should correctly handle problems: new name is clashing with existing name of existing column" <| Test.specify "should correctly handle problems: new name is clashing with existing name of existing column" <|
map = Map.from_vector [["alpha", "beta"]] map = Map.from_vector [["alpha", "beta"]]
action = table.rename_columns map on_problems=_ action = table.rename_columns map on_problems=_
tester = expect_column_names ["beta", "beta_1", "gamma", "delta"] tester = expect_column_names ["beta", "beta 1", "gamma", "delta"]
problems = [Duplicate_Output_Column_Names.Error ["beta"]] problems = [Duplicate_Output_Column_Names.Error ["beta"]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
map2 = Map.from_vector [["beta", "alpha"]] map2 = Map.from_vector [["beta", "alpha"]]
action2 = table.rename_columns map2 on_problems=_ action2 = table.rename_columns map2 on_problems=_
tester2 = expect_column_names ["alpha_1", "alpha", "gamma", "delta"] tester2 = expect_column_names ["alpha 1", "alpha", "gamma", "delta"]
problems2 = [Duplicate_Output_Column_Names.Error ["alpha"]] problems2 = [Duplicate_Output_Column_Names.Error ["alpha"]]
Problems.test_problem_handling action2 problems2 tester2 Problems.test_problem_handling action2 problems2 tester2

View File

@ -73,18 +73,18 @@ spec setup =
Test.specify "should handle missing columns" <| Test.specify "should handle missing columns" <|
t1 = table_builder [["Key", ["x", "y", "z"]], ["Value", [1, 2, 3]], ["Another", [10, Nothing, 20]]] t1 = table_builder [["Key", ["x", "y", "z"]], ["Value", [1, 2, 3]], ["Another", [10, Nothing, 20]]]
err1 = t1.transpose ["Key", "Missing", "Missing_2"] err1 = t1.transpose ["Key", "Missing", "Missing 2"]
err1.should_fail_with Missing_Input_Columns err1.should_fail_with Missing_Input_Columns
err1.catch.criteria . should_equal ["Missing", "Missing_2"] err1.catch.criteria . should_equal ["Missing", "Missing 2"]
err2 = t1.transpose [0, -1, 42, -100] err2 = t1.transpose [0, -1, 42, -100]
err2.should_fail_with Column_Indexes_Out_Of_Range err2.should_fail_with Column_Indexes_Out_Of_Range
err2.catch.indexes . should_equal [42, -100] err2.catch.indexes . should_equal [42, -100]
action1 = t1.transpose ["Key", "Missing", "Missing_2"] error_on_missing_columns=False on_problems=_ action1 = t1.transpose ["Key", "Missing", "Missing 2"] error_on_missing_columns=False on_problems=_
tester1 table = tester1 table =
table.column_names . should_equal ["Key", "Name", "Value"] table.column_names . should_equal ["Key", "Name", "Value"]
problems1 = [Missing_Input_Columns.Error ["Missing", "Missing_2"]] problems1 = [Missing_Input_Columns.Error ["Missing", "Missing 2"]]
Problems.test_problem_handling action1 problems1 tester1 Problems.test_problem_handling action1 problems1 tester1
action2 = t1.transpose [0, -1, 42, -100] error_on_missing_columns=False on_problems=_ action2 = t1.transpose [0, -1, 42, -100] error_on_missing_columns=False on_problems=_
@ -98,13 +98,13 @@ spec setup =
action1 = t1.transpose ["X", "Y", "Z"] name_field="Y" value_field="Z" on_problems=_ action1 = t1.transpose ["X", "Y", "Z"] name_field="Y" value_field="Z" on_problems=_
tester1 table = tester1 table =
table.column_names . should_equal ["X", "Y", "Z", "Y_1", "Z_1"] table.column_names . should_equal ["X", "Y", "Z", "Y 1", "Z 1"]
problems1 = [Duplicate_Output_Column_Names.Error ["Y", "Z"]] problems1 = [Duplicate_Output_Column_Names.Error ["Y", "Z"]]
Problems.test_problem_handling action1 problems1 tester1 Problems.test_problem_handling action1 problems1 tester1
action2 = t1.transpose ["X"] name_field="F" value_field="F" on_problems=_ action2 = t1.transpose ["X"] name_field="F" value_field="F" on_problems=_
tester2 table = tester2 table =
table.column_names . should_equal ["X", "F", "F_1"] table.column_names . should_equal ["X", "F", "F 1"]
problems2 = [Duplicate_Output_Column_Names.Error ["F"]] problems2 = [Duplicate_Output_Column_Names.Error ["F"]]
Problems.test_problem_handling action2 problems2 tester2 Problems.test_problem_handling action2 problems2 tester2

View File

@ -115,9 +115,9 @@ spec =
Test.group "Helpers" <| Test.group "Helpers" <|
Test.specify "fresh_names should provide fresh names" <| Test.specify "fresh_names should provide fresh names" <|
used_names = ["A", "A_1"] used_names = ["A", "A 1"]
preferred_names = ["A", "A", "B"] preferred_names = ["A", "A", "B"]
fresh_names used_names preferred_names . should_equal ["A_2", "A_3", "B"] fresh_names used_names preferred_names . should_equal ["A 2", "A 3", "B"]
Test.group "[Codegen] Aggregation" <| Test.group "[Codegen] Aggregation" <|
Test.specify "should allow to count rows" <| Test.specify "should allow to count rows" <|

View File

@ -34,7 +34,7 @@ spec make_new_connection prefix persistent_connector=True =
Test.group prefix+"Uploading an in-memory Table" <| Test.group prefix+"Uploading an in-memory Table" <|
in_memory_table = Table.new [["X", [1, 2, 3]], ["Y", ['a', 'b', 'c']]] in_memory_table = Table.new [["X", [1, 2, 3]], ["Y", ['a', 'b', 'c']]]
Test.specify "should include the created table in the tables directory" <| Test.specify "should include the created table in the tables directory" <|
db_table = in_memory_table.create_database_table connection (Name_Generator.random_name "permanent_table_1") temporary=False db_table = in_memory_table.create_database_table connection (Name_Generator.random_name "permanent_table 1") temporary=False
Panic.with_finalizer (connection.drop_table db_table.name) <| Panic.with_finalizer (connection.drop_table db_table.name) <|
db_table.at "X" . to_vector . should_equal [1, 2, 3] db_table.at "X" . to_vector . should_equal [1, 2, 3]
@ -42,7 +42,7 @@ spec make_new_connection prefix persistent_connector=True =
connection.query db_table.name . at "X" . to_vector . should_equal [1, 2, 3] connection.query db_table.name . at "X" . to_vector . should_equal [1, 2, 3]
Test.specify "should include the temporary table in the tables directory" <| Test.specify "should include the temporary table in the tables directory" <|
db_table = in_memory_table.create_database_table connection (Name_Generator.random_name "temporary_table_1") temporary=True db_table = in_memory_table.create_database_table connection (Name_Generator.random_name "temporary_table 1") temporary=True
db_table.at "X" . to_vector . should_equal [1, 2, 3] db_table.at "X" . to_vector . should_equal [1, 2, 3]
connection.tables.at "Name" . to_vector . should_contain db_table.name connection.tables.at "Name" . to_vector . should_contain db_table.name
connection.query db_table.name . at "X" . to_vector . should_equal [1, 2, 3] connection.query db_table.name . at "X" . to_vector . should_equal [1, 2, 3]
@ -50,7 +50,7 @@ spec make_new_connection prefix persistent_connector=True =
if persistent_connector then if persistent_connector then
Test.specify "should drop the temporary table after the connection is closed" <| Test.specify "should drop the temporary table after the connection is closed" <|
tmp_connection = make_new_connection Nothing tmp_connection = make_new_connection Nothing
db_table = in_memory_table.create_database_table tmp_connection (Name_Generator.random_name "temporary_table_2") temporary=True db_table = in_memory_table.create_database_table tmp_connection (Name_Generator.random_name "temporary_table 2") temporary=True
name = db_table.name name = db_table.name
tmp_connection.query (SQL_Query.Table_Name name) . at "X" . to_vector . should_equal [1, 2, 3] tmp_connection.query (SQL_Query.Table_Name name) . at "X" . to_vector . should_equal [1, 2, 3]
tmp_connection.close tmp_connection.close
@ -58,7 +58,7 @@ spec make_new_connection prefix persistent_connector=True =
Test.specify "should preserve the regular table after the connection is closed" <| Test.specify "should preserve the regular table after the connection is closed" <|
tmp_connection = make_new_connection Nothing tmp_connection = make_new_connection Nothing
db_table = in_memory_table.create_database_table tmp_connection (Name_Generator.random_name "permanent_table_1") temporary=False db_table = in_memory_table.create_database_table tmp_connection (Name_Generator.random_name "permanent_table 1") temporary=False
name = db_table.name name = db_table.name
Panic.with_finalizer (connection.drop_table name) <| Panic.with_finalizer (connection.drop_table name) <|
tmp_connection.query (SQL_Query.Table_Name name) . at "X" . to_vector . should_equal [1, 2, 3] tmp_connection.query (SQL_Query.Table_Name name) . at "X" . to_vector . should_equal [1, 2, 3]
@ -143,11 +143,11 @@ spec make_new_connection prefix persistent_connector=True =
db_table_4 = db_table_2.join db_table_3 join_kind=Join_Kind.Left_Outer db_table_4 = db_table_2.join db_table_3 join_kind=Join_Kind.Left_Outer
copied_table = db_table_4.create_database_table connection (Name_Generator.random_name "copied-table") temporary=True primary_key=Nothing copied_table = db_table_4.create_database_table connection (Name_Generator.random_name "copied-table") temporary=True primary_key=Nothing
copied_table.column_names . should_equal ["X", "Y", "C1", "C2", "Right_X", "C3"] copied_table.column_names . should_equal ["X", "Y", "C1", "C2", "Right X", "C3"]
copied_table.at "X" . to_vector . should_equal [1, 1, 2] copied_table.at "X" . to_vector . should_equal [1, 1, 2]
copied_table.at "C1" . to_vector . should_equal [101, 102, 203] copied_table.at "C1" . to_vector . should_equal [101, 102, 203]
copied_table.at "C2" . to_vector . should_equal ["constant_text", "constant_text", "constant_text"] copied_table.at "C2" . to_vector . should_equal ["constant_text", "constant_text", "constant_text"]
copied_table.at "Right_X" . to_vector . should_equal [Nothing, Nothing, 2] copied_table.at "Right X" . to_vector . should_equal [Nothing, Nothing, 2]
copied_table.at "C3" . to_vector . should_equal [Nothing, Nothing, 5] copied_table.at "C3" . to_vector . should_equal [Nothing, Nothing, 5]
# We check that this is indeed querying a simple DB table and not a complex query like `db_table_4` would be, # We check that this is indeed querying a simple DB table and not a complex query like `db_table_4` would be,

View File

@ -30,28 +30,28 @@ spec =
Test.specify 'should rename duplicates names' <| Test.specify 'should rename duplicates names' <|
strategy = Unique_Name_Strategy.new strategy = Unique_Name_Strategy.new
strategy.make_unique "A" . should_equal "A" strategy.make_unique "A" . should_equal "A"
strategy.make_unique "A" . should_equal "A_1" strategy.make_unique "A" . should_equal "A 1"
strategy.make_unique "A" . should_equal "A_2" strategy.make_unique "A" . should_equal "A 2"
strategy.renames.length . should_equal 2 strategy.renames.length . should_equal 2
strategy.invalid_names.length . should_equal 0 strategy.invalid_names.length . should_equal 0
Test.specify 'should preserve existing suffix' <| Test.specify 'should preserve existing suffix' <|
strategy = Unique_Name_Strategy.new strategy = Unique_Name_Strategy.new
strategy.make_unique "A" . should_equal "A" strategy.make_unique "A" . should_equal "A"
strategy.make_unique "A_1" . should_equal "A_1" strategy.make_unique "A 1" . should_equal "A 1"
strategy.make_unique "A" . should_equal "A_2" strategy.make_unique "A" . should_equal "A 2"
strategy.make_unique "A_1" . should_equal "A_1_1" strategy.make_unique "A 1" . should_equal "A 1 1"
strategy.renames.length . should_equal 2 strategy.renames.length . should_equal 2
strategy.invalid_names.length . should_equal 0 strategy.invalid_names.length . should_equal 0
Test.specify "should always add a counter when renaming invalid names" <| Test.specify "should always add a counter when renaming invalid names" <|
strategy = Unique_Name_Strategy.new strategy = Unique_Name_Strategy.new
strategy.make_unique "" . should_equal "Column_1" strategy.make_unique "" . should_equal "Column 1"
strategy.make_unique "" . should_equal "Column_2" strategy.make_unique "" . should_equal "Column 2"
strategy.make_unique Nothing . should_equal "Column_3" strategy.make_unique Nothing . should_equal "Column 3"
strategy.make_unique "Foo" . should_equal "Foo" strategy.make_unique "Foo" . should_equal "Foo"
strategy.make_unique "Column" . should_equal "Column" strategy.make_unique "Column" . should_equal "Column"
strategy.make_unique "" . should_equal "Column_4" strategy.make_unique "" . should_equal "Column 4"
Test.specify 'should work as in examples' <| Test.specify 'should work as in examples' <|
unique_name_strategy = Unique_Name_Strategy.new unique_name_strategy = Unique_Name_Strategy.new
@ -60,19 +60,19 @@ spec =
invalid = unique_name_strategy.invalid_names invalid = unique_name_strategy.invalid_names
duplicates.should_equal ["A"] duplicates.should_equal ["A"]
invalid.should_equal [""] invalid.should_equal [""]
unique_names.should_equal ["A", "B", "A_1", "Column_1"] unique_names.should_equal ["A", "B", "A 1", "Column 1"]
strategy_1 = Unique_Name_Strategy.new strategy_1 = Unique_Name_Strategy.new
strategy_1.make_unique "A" . should_equal "A" strategy_1.make_unique "A" . should_equal "A"
strategy_1.make_unique "A" . should_equal "A_1" strategy_1.make_unique "A" . should_equal "A 1"
Test.group "Unique_Name_Strategy.combine_with_prefix" <| Test.group "Unique_Name_Strategy.combine_with_prefix" <|
Test.specify "should work as in examples" <| Test.specify "should work as in examples" <|
strategy = Unique_Name_Strategy.new strategy = Unique_Name_Strategy.new
first = ["A", "B", "second_A"] first = ["A", "B", "second_A"]
second = ["A", "B", "second_A_1", "C"] second = ["A", "B", "second_A 1", "C"]
unique_second = strategy.combine_with_prefix first second "second_" unique_second = strategy.combine_with_prefix first second "second_"
unique_second . should_equal ["second_A_2", "second_B", "second_A_1", "C"] unique_second . should_equal ["second_A 2", "second_B", "second_A 1", "C"]
strategy.invalid_names . should_equal [] strategy.invalid_names . should_equal []
strategy.renames . should_equal ["second_A"] strategy.renames . should_equal ["second_A"]
@ -81,7 +81,7 @@ spec =
second = ["B", "A", "C"] second = ["B", "A", "C"]
strategy = Unique_Name_Strategy.new strategy = Unique_Name_Strategy.new
r = strategy.combine_with_prefix first second "" r = strategy.combine_with_prefix first second ""
r . should_equal ["B_1", "A_1", "C"] r . should_equal ["B 1", "A 1", "C"]
Test.specify "should work for empty input" <| Test.specify "should work for empty input" <|
Unique_Name_Strategy.new.combine_with_prefix [] [] "" . should_equal [] Unique_Name_Strategy.new.combine_with_prefix [] [] "" . should_equal []
@ -89,34 +89,34 @@ spec =
Unique_Name_Strategy.new.combine_with_prefix [] ["a"] "" . should_equal ["a"] Unique_Name_Strategy.new.combine_with_prefix [] ["a"] "" . should_equal ["a"]
Test.specify "should find the first free spot" <| Test.specify "should find the first free spot" <|
Unique_Name_Strategy.new.combine_with_prefix ["A", "A_1", "A_2"] ["A"] "" . should_equal ["A_3"] Unique_Name_Strategy.new.combine_with_prefix ["A", "A 1", "A 2"] ["A"] "" . should_equal ["A 3"]
Unique_Name_Strategy.new.combine_with_prefix ["A", "A_1", "A_2"] ["A_4", "A_6", "A_100", "A", "A_3"] "" . should_equal ["A_4", "A_6", "A_100", "A_5", "A_3"] Unique_Name_Strategy.new.combine_with_prefix ["A", "A 1", "A 2"] ["A 4", "A 6", "A 100", "A", "A 3"] "" . should_equal ["A 4", "A 6", "A 100", "A 5", "A 3"]
Unique_Name_Strategy.new.combine_with_prefix ["A", "A_1", "A_2"] ["A"] "P_" . should_equal ["P_A"] Unique_Name_Strategy.new.combine_with_prefix ["A", "A 1", "A 2"] ["A"] "P_" . should_equal ["P_A"]
Unique_Name_Strategy.new.combine_with_prefix ["A", "A_1", "A_2", "P_A"] ["A"] "P_" . should_equal ["P_A_1"] Unique_Name_Strategy.new.combine_with_prefix ["A", "A 1", "A 2", "P_A"] ["A"] "P_" . should_equal ["P_A 1"]
Unique_Name_Strategy.new.combine_with_prefix ["A", "A_1", "A_2", "P_A_1"] ["A"] "P_" . should_equal ["P_A"] Unique_Name_Strategy.new.combine_with_prefix ["A", "A 1", "A 2", "P_A 1"] ["A"] "P_" . should_equal ["P_A"]
Unique_Name_Strategy.new.combine_with_prefix ["A", "A_1", "A_2", "P_A_1"] ["A", "P_A", "P_A_2"] "P_" . should_equal ["P_A_3", "P_A", "P_A_2"] Unique_Name_Strategy.new.combine_with_prefix ["A", "A 1", "A 2", "P_A 1"] ["A", "P_A", "P_A 2"] "P_" . should_equal ["P_A 3", "P_A", "P_A 2"]
Test.specify "will add a prefix/suffix, not increment an existing counter" <| Test.specify "will add a prefix/suffix, not increment an existing counter" <|
first = ["A", "A_1", "A_2", "A_3"] first = ["A", "A 1", "A 2", "A 3"]
Unique_Name_Strategy.new.combine_with_prefix first ["A_2"] "P_" . should_equal ["P_A_2"] Unique_Name_Strategy.new.combine_with_prefix first ["A 2"] "P_" . should_equal ["P_A 2"]
Unique_Name_Strategy.new.combine_with_prefix first ["A_2"] "" . should_equal ["A_2_1"] Unique_Name_Strategy.new.combine_with_prefix first ["A 2"] "" . should_equal ["A 2 1"]
Unique_Name_Strategy.new.combine_with_prefix first+["P_A_2"] ["A_2"] "P_" . should_equal ["P_A_2_1"] Unique_Name_Strategy.new.combine_with_prefix first+["P_A 2"] ["A 2"] "P_" . should_equal ["P_A 2 1"]
Test.specify "should prioritize existing names when renaming conflicts and rename only ones that are clashing with the other list" <| Test.specify "should prioritize existing names when renaming conflicts and rename only ones that are clashing with the other list" <|
first = ["A", "B"] first = ["A", "B"]
second = ["B", "A", "B_1", "C", "B_2", "B_4"] second = ["B", "A", "B 1", "C", "B 2", "B_4"]
strategy = Unique_Name_Strategy.new strategy = Unique_Name_Strategy.new
r = strategy.combine_with_prefix first second "" r = strategy.combine_with_prefix first second ""
r . should_equal ["B_3", "A_1", "B_1", "C", "B_2", "B_4"] r . should_equal ["B 3", "A 1", "B 1", "C", "B 2", "B_4"]
strategy.invalid_names . should_equal [] strategy.invalid_names . should_equal []
strategy.renames . should_equal ["B", "A"] strategy.renames . should_equal ["B", "A"]
r2 = Unique_Name_Strategy.new.combine_with_prefix first second "P_" r2 = Unique_Name_Strategy.new.combine_with_prefix first second "P_"
r2 . should_equal ["P_B", "P_A", "B_1", "C", "B_2", "B_4"] r2 . should_equal ["P_B", "P_A", "B 1", "C", "B 2", "B_4"]
third = ["B", "A", "P_B", "X", "P_B_1", "P_B_2"] third = ["B", "A", "P_B", "X", "P_B 1", "P_B 2"]
r3 = Unique_Name_Strategy.new.combine_with_prefix first third "P_" r3 = Unique_Name_Strategy.new.combine_with_prefix first third "P_"
r3 . should_equal ["P_B_3", "P_A", "P_B", "X", "P_B_1", "P_B_2"] r3 . should_equal ["P_B 3", "P_A", "P_B", "X", "P_B 1", "P_B 2"]
main = Test_Suite.run_main spec main = Test_Suite.run_main spec

View File

@ -29,13 +29,13 @@ spec =
Test.specify "should correctly infer types of varied-type columns" <| Test.specify "should correctly infer types of varied-type columns" <|
varied_column = (enso_project.data / "varied_column.csv") . read varied_column = (enso_project.data / "varied_column.csv") . read
c_1 = ["Column_1", ["2005-02-25", "2005-02-28", "4", "2005-03-02", Nothing, "2005-03-04", "2005-03-07", "2005-03-08"]] c_1 = ["Column 1", ["2005-02-25", "2005-02-28", "4", "2005-03-02", Nothing, "2005-03-04", "2005-03-07", "2005-03-08"]]
# We can re-enable this once date support is improved. # We can re-enable this once date support is improved.
#c_2 = ["Column_2", ["2005-02-25", "2005-02-28", "2005-03-01", Nothing, "2005-03-03", "2005-03-04", "2005-03-07", "2005-03-08"]] #c_2 = ["Column 2", ["2005-02-25", "2005-02-28", "2005-03-01", Nothing, "2005-03-03", "2005-03-04", "2005-03-07", "2005-03-08"]]
c_3 = ["Column_3", [1, 2, 3, 4, 5, Nothing, 7, 8]] c_3 = ["Column 3", [1, 2, 3, 4, 5, Nothing, 7, 8]]
c_4 = ["Column_4", [1, 2, 3, 4, 5, 6, 7, 8]] c_4 = ["Column 4", [1, 2, 3, 4, 5, 6, 7, 8]]
c_5 = ["Column_5", [1.0, 2.0, 3.0, 4.0, 5.0, 6.25, 7.0, 8.0]] c_5 = ["Column 5", [1.0, 2.0, 3.0, 4.0, 5.0, 6.25, 7.0, 8.0]]
c_6 = ["Column_6", ['1', '2', '3', '4', '5', '6.25', '7', 'osiem']] c_6 = ["Column 6", ['1', '2', '3', '4', '5', '6.25', '7', 'osiem']]
expected = Table.new [c_1, c_3, c_4, c_5, c_6] expected = Table.new [c_1, c_3, c_4, c_5, c_6]
varied_column.select_columns [0, 2, 3, 4, 5] . should_equal expected varied_column.select_columns [0, 2, 3, 4, 5] . should_equal expected
@ -45,14 +45,14 @@ spec =
name,x,y,x,y name,x,y,x,y
foo,10,20,30,20 foo,10,20,30,20
t = Table.from csv (format = Delimited ",") t = Table.from csv (format = Delimited ",")
t.columns.map .name . should_equal ['name', 'x', 'y', 'x_1', 'y_1'] t.columns.map .name . should_equal ['name', 'x', 'y', 'x 1', 'y 1']
Test.group 'Writing' <| Test.group 'Writing' <|
Test.specify 'should properly serialize simple tables' <| Test.specify 'should properly serialize simple tables' <|
varied_column = (enso_project.data / "varied_column.csv") . read varied_column = (enso_project.data / "varied_column.csv") . read
res = Text.from varied_column format=(Delimited ",") res = Text.from varied_column format=(Delimited ",")
exp = normalize_lines <| ''' exp = normalize_lines <| '''
Column_1,Column_2,Column_3,Column_4,Column_5,Column_6 Column 1,Column 2,Column 3,Column 4,Column 5,Column 6
2005-02-25,2005-02-25,1,1,1.0,1 2005-02-25,2005-02-25,1,1,1.0,1
2005-02-28,2005-02-28,2,2,2.0,2 2005-02-28,2005-02-28,2,2,2.0,2
4,2005-03-01,3,3,3.0,3 4,2005-03-01,3,3,3.0,3
@ -98,7 +98,7 @@ spec =
out.delete_if_exists out.delete_if_exists
varied_column.write out varied_column.write out
exp = normalize_lines <| ''' exp = normalize_lines <| '''
Column_1,Column_2,Column_3,Column_4,Column_5,Column_6 Column 1,Column 2,Column 3,Column 4,Column 5,Column 6
2005-02-25,2005-02-25,1,1,1.0,1 2005-02-25,2005-02-25,1,1,1.0,1
2005-02-28,2005-02-28,2,2,2.0,2 2005-02-28,2005-02-28,2,2,2.0,2
4,2005-03-01,3,3,3.0,3 4,2005-03-01,3,3,3.0,3

View File

@ -25,9 +25,9 @@ spec =
simple_empty.should_equal expected_table simple_empty.should_equal expected_table
Test.specify "should load a simple table without headers" <| Test.specify "should load a simple table without headers" <|
c_1 = ["Column_1", ['a', '1', '4', '7', '10']] c_1 = ["Column 1", ['a', '1', '4', '7', '10']]
c_2 = ["Column_2", ['b', '2', Nothing, '8', '11']] c_2 = ["Column 2", ['b', '2', Nothing, '8', '11']]
c_3 = ["Column_3", ['c', Nothing, '6', '9', '12']] c_3 = ["Column 3", ['c', Nothing, '6', '9', '12']]
expected_table = Table.new [c_1, c_2, c_3] expected_table = Table.new [c_1, c_2, c_3]
simple_empty = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False value_formatter=Nothing) simple_empty = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False value_formatter=Nothing)
simple_empty.should_equal expected_table simple_empty.should_equal expected_table
@ -35,11 +35,11 @@ spec =
Test.specify "should work in presence of missing headers" <| Test.specify "should work in presence of missing headers" <|
action on_problems = Data.read (enso_project.data / "missing_header.csv") (Delimited "," headers=True value_formatter=Nothing) on_problems action on_problems = Data.read (enso_project.data / "missing_header.csv") (Delimited "," headers=True value_formatter=Nothing) on_problems
tester table = tester table =
table.columns.map .name . should_equal ["a", "Column_1", "c", "Column_2", "d"] table.columns.map .name . should_equal ["a", "Column 1", "c", "Column 2", "d"]
table.at "a" . to_vector . should_equal ["1"] table.at "a" . to_vector . should_equal ["1"]
table.at "Column_1" . to_vector . should_equal ["2"] table.at "Column 1" . to_vector . should_equal ["2"]
table.at "c" . to_vector . should_equal ["3"] table.at "c" . to_vector . should_equal ["3"]
table.at "Column_2" . to_vector . should_equal ["4"] table.at "Column 2" . to_vector . should_equal ["4"]
table.at "d" . to_vector . should_equal ["5"] table.at "d" . to_vector . should_equal ["5"]
problems = [Invalid_Output_Column_Names.Error [Nothing, Nothing]] problems = [Invalid_Output_Column_Names.Error [Nothing, Nothing]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
@ -49,9 +49,9 @@ spec =
t1.columns.map .name . should_equal ["Code", "Index", "Flag", "Value", "ValueWithNothing", "TextWithNothing", "Hexadecimal", "Leading0s", "QuotedNumbers", "Mixed Types"] t1.columns.map .name . should_equal ["Code", "Index", "Flag", "Value", "ValueWithNothing", "TextWithNothing", "Hexadecimal", "Leading0s", "QuotedNumbers", "Mixed Types"]
t2 = Data.read (enso_project.data / "all_text.csv") (Delimited ",") t2 = Data.read (enso_project.data / "all_text.csv") (Delimited ",")
t2.columns.map .name . should_equal ["Column_1", "Column_2"] t2.columns.map .name . should_equal ["Column 1", "Column 2"]
t2.at "Column_1" . to_vector . should_equal ["a", "c", "e", "g"] t2.at "Column 1" . to_vector . should_equal ["a", "c", "e", "g"]
t2.at "Column_2" . to_vector . should_equal ["b", "d", "f", "h"] t2.at "Column 2" . to_vector . should_equal ["b", "d", "f", "h"]
t3 = Data.read (enso_project.data / "two_rows1.csv") (Delimited ",") t3 = Data.read (enso_project.data / "two_rows1.csv") (Delimited ",")
t3.columns.map .name . should_equal ["a", "b", "c"] t3.columns.map .name . should_equal ["a", "b", "c"]
@ -60,16 +60,16 @@ spec =
t3.at "c" . to_vector . should_equal [Nothing] t3.at "c" . to_vector . should_equal [Nothing]
t4 = Data.read (enso_project.data / "two_rows2.csv") (Delimited ",") t4 = Data.read (enso_project.data / "two_rows2.csv") (Delimited ",")
t4.columns.map .name . should_equal ["Column_1", "Column_2", "Column_3"] t4.columns.map .name . should_equal ["Column 1", "Column 2", "Column 3"]
t4.at "Column_1" . to_vector . should_equal ["a", "d"] t4.at "Column 1" . to_vector . should_equal ["a", "d"]
t4.at "Column_2" . to_vector . should_equal ["b", "e"] t4.at "Column 2" . to_vector . should_equal ["b", "e"]
t4.at "Column_3" . to_vector . should_equal ["c", "f"] t4.at "Column 3" . to_vector . should_equal ["c", "f"]
t5 = Data.read (enso_project.data / "numbers_in_header.csv") (Delimited ",") t5 = Data.read (enso_project.data / "numbers_in_header.csv") (Delimited ",")
t5.columns.map .name . should_equal ["Column_1", "Column_2", "Column_3"] t5.columns.map .name . should_equal ["Column 1", "Column 2", "Column 3"]
t5.at "Column_1" . to_vector . should_equal ["a", "1"] t5.at "Column 1" . to_vector . should_equal ["a", "1"]
t5.at "Column_2" . to_vector . should_equal ["b", "2"] t5.at "Column 2" . to_vector . should_equal ["b", "2"]
t5.at "Column_3" . to_vector . should_equal [0, 3] t5.at "Column 3" . to_vector . should_equal [0, 3]
t6 = Data.read (enso_project.data / "quoted_numbers_in_header.csv") (Delimited ",") t6 = Data.read (enso_project.data / "quoted_numbers_in_header.csv") (Delimited ",")
t6.columns.map .name . should_equal ["1", "x"] t6.columns.map .name . should_equal ["1", "x"]
@ -78,10 +78,10 @@ spec =
Test.specify "should not use the first row as headers if it is the only row, unless specifically asked to" <| Test.specify "should not use the first row as headers if it is the only row, unless specifically asked to" <|
t1 = Data.read (enso_project.data / "one_row.csv") (Delimited ",") t1 = Data.read (enso_project.data / "one_row.csv") (Delimited ",")
t1.columns.map .name . should_equal ["Column_1", "Column_2", "Column_3"] t1.columns.map .name . should_equal ["Column 1", "Column 2", "Column 3"]
t1.at "Column_1" . to_vector . should_equal ["x"] t1.at "Column 1" . to_vector . should_equal ["x"]
t1.at "Column_2" . to_vector . should_equal ["y"] t1.at "Column 2" . to_vector . should_equal ["y"]
t1.at "Column_3" . to_vector . should_equal ["z"] t1.at "Column 3" . to_vector . should_equal ["z"]
t2 = Data.read (enso_project.data / "one_row.csv") (Delimited "," headers=True) t2 = Data.read (enso_project.data / "one_row.csv") (Delimited "," headers=True)
t2.columns.map .name . should_equal ["x", "y", "z"] t2.columns.map .name . should_equal ["x", "y", "z"]
@ -138,10 +138,10 @@ spec =
format = Delimited ',' headers=False value_formatter=(Data_Formatter.Value trim_values=False) format = Delimited ',' headers=False value_formatter=(Data_Formatter.Value trim_values=False)
reference_table = Table.new [["Column_1", ["a", "d", "1"]], ["Column_2", ["b", "e", "2"]], ["Column_3", ["c", "f", "3"]]] reference_table = Table.new [["Column 1", ["a", "d", "1"]], ["Column 2", ["b", "e", "2"]], ["Column 3", ["c", "f", "3"]]]
collapsed_table = Table.new <| collapsed_table = Table.new <|
['a', 'b', 'c\nd', 'e', 'f\n1', 2, 3].map_with_index i-> v-> ['a', 'b', 'c\nd', 'e', 'f\n1', 2, 3].map_with_index i-> v->
["Column_" + (i+1).to_text, [v]] ["Column " + (i+1).to_text, [v]]
Data.read file format . should_equal reference_table Data.read file format . should_equal reference_table
Data.read file (format.with_line_endings Line_Ending_Style.Unix) . should_equal reference_table Data.read file (format.with_line_endings Line_Ending_Style.Unix) . should_equal reference_table
Data.read file (format.with_line_endings Line_Ending_Style.Mac_Legacy) . should_equal collapsed_table Data.read file (format.with_line_endings Line_Ending_Style.Mac_Legacy) . should_equal collapsed_table
@ -201,9 +201,9 @@ spec =
Test.specify "should handle duplicated columns" <| Test.specify "should handle duplicated columns" <|
action on_problems = Data.read (enso_project.data / "duplicated_columns.csv") (Delimited "," headers=True value_formatter=Nothing) on_problems action on_problems = Data.read (enso_project.data / "duplicated_columns.csv") (Delimited "," headers=True value_formatter=Nothing) on_problems
tester table = tester table =
table.columns.map .name . should_equal ['a', 'b', 'c', 'a_1'] table.columns.map .name . should_equal ['a', 'b', 'c', 'a 1']
table.at 'a' . to_vector . should_equal ['1'] table.at 'a' . to_vector . should_equal ['1']
table.at 'a_1' . to_vector . should_equal ['4'] table.at 'a 1' . to_vector . should_equal ['4']
problems = [Duplicate_Output_Column_Names.Error ['a']] problems = [Duplicate_Output_Column_Names.Error ['a']]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
@ -337,7 +337,7 @@ spec =
Test.specify "should allow to skip rows" <| Test.specify "should allow to skip rows" <|
t1 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False skip_rows=3 value_formatter=Nothing) t1 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False skip_rows=3 value_formatter=Nothing)
t1.at "Column_1" . to_vector . should_equal ['7', '10'] t1.at "Column 1" . to_vector . should_equal ['7', '10']
t2 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=True skip_rows=3 value_formatter=Nothing) t2 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=True skip_rows=3 value_formatter=Nothing)
t2.columns.map .name . should_equal ['7', '8', '9'] t2.columns.map .name . should_equal ['7', '8', '9']
@ -345,16 +345,16 @@ spec =
Test.specify "should allow to set a limit of rows to read" <| Test.specify "should allow to set a limit of rows to read" <|
t1 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False row_limit=2 value_formatter=Nothing) t1 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False row_limit=2 value_formatter=Nothing)
t1.at "Column_1" . to_vector . should_equal ['a', '1'] t1.at "Column 1" . to_vector . should_equal ['a', '1']
t2 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=True row_limit=2 value_formatter=Nothing) t2 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=True row_limit=2 value_formatter=Nothing)
t2.at "a" . to_vector . should_equal ['1', '4'] t2.at "a" . to_vector . should_equal ['1', '4']
t3 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False skip_rows=3 row_limit=1 value_formatter=Nothing) t3 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False skip_rows=3 row_limit=1 value_formatter=Nothing)
t3.at "Column_1" . to_vector . should_equal ['7'] t3.at "Column 1" . to_vector . should_equal ['7']
t4 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False row_limit=0 value_formatter=Nothing) t4 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False row_limit=0 value_formatter=Nothing)
t4.columns.map .name . should_equal ['Column_1', 'Column_2', 'Column_3'] t4.columns.map .name . should_equal ['Column 1', 'Column 2', 'Column 3']
t4.row_count . should_equal 0 t4.row_count . should_equal 0
t5 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=True row_limit=0 value_formatter=Nothing) t5 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=True row_limit=0 value_formatter=Nothing)
@ -363,7 +363,7 @@ spec =
t5.row_count . should_equal 0 t5.row_count . should_equal 0
t6 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False skip_rows=3 row_limit=1000 value_formatter=Nothing) t6 = Data.read (enso_project.data / "simple_empty.csv") (Delimited "," headers=False skip_rows=3 row_limit=1000 value_formatter=Nothing)
t6.at "Column_1" . to_vector . should_equal ['7', '10'] t6.at "Column 1" . to_vector . should_equal ['7', '10']
Test.specify "should check arguments" <| Test.specify "should check arguments" <|
path = (enso_project.data / "simple_empty.csv") path = (enso_project.data / "simple_empty.csv")

View File

@ -347,7 +347,7 @@ spec =
with_headers = base_format . with_headers with_headers = base_format . with_headers
expected_table_with_headers = Table.new [["A", [1,2,33,44]], ["B", [1.0,1.5,Nothing,0]], ["C", ["x","y","a","BB"]]] expected_table_with_headers = Table.new [["A", [1,2,33,44]], ["B", [1.0,1.5,Nothing,0]], ["C", ["x","y","a","BB"]]]
expected_table_without_headers = expected_table_with_headers.rename_columns ["Column_1", "Column_2", "Column_3"] expected_table_without_headers = expected_table_with_headers.rename_columns ["Column 1", "Column 2", "Column 3"]
test_append initial_file_format=with_headers append_format=no_headers expected_table_with_headers test_append initial_file_format=with_headers append_format=no_headers expected_table_with_headers
test_append initial_file_format=with_headers append_format=base_format expected_table_with_headers test_append initial_file_format=with_headers append_format=base_format expected_table_with_headers

View File

@ -47,8 +47,8 @@ spec_fmt header file read_method sheet_count=5 =
Test.specify "should gracefully handle duplicate column names and formulas" <| Test.specify "should gracefully handle duplicate column names and formulas" <|
t = read_method file (Excel (Worksheet "Duplicate Columns")) t = read_method file (Excel (Worksheet "Duplicate Columns"))
t.columns.map .name . should_equal ['Item', 'Price', 'Quantity', 'Price_1'] t.columns.map .name . should_equal ['Item', 'Price', 'Quantity', 'Price 1']
t.at 'Price_1' . to_vector . should_equal [20, 40, 0, 60, 0, 10] t.at 'Price 1' . to_vector . should_equal [20, 40, 0, 60, 0, 10]
Test.specify "should allow reading with cell range specified" <| Test.specify "should allow reading with cell range specified" <|
t_1 = read_method file (Excel (Cell_Range "Simple!B:C")) t_1 = read_method file (Excel (Cell_Range "Simple!B:C"))
@ -292,8 +292,8 @@ spec_write suffix test_sheet_name =
Test.specify 'should be able to append to a range by name after deduplication of names' <| Test.specify 'should be able to append to a range by name after deduplication of names' <|
out.delete_if_exists out.delete_if_exists
(enso_project.data / test_sheet_name) . copy_to out (enso_project.data / test_sheet_name) . copy_to out
extra_another = Table.new [['AA', ['d', 'e']], ['BB',[4, 5]], ['AA_1',[True, False]], ['BB_1', ['2022-01-20', '2022-01-21']]] extra_another = Table.new [['AA', ['d', 'e']], ['BB',[4, 5]], ['AA 1',[True, False]], ['BB 1', ['2022-01-20', '2022-01-21']]]
expected = Table.new [['AA', ['f', 'g', 'h', 'd', 'e']], ['BB',[1, 2, 3, 4, 5]], ['AA_1',[True, False, False, True, False]]] expected = Table.new [['AA', ['f', 'g', 'h', 'd', 'e']], ['BB',[1, 2, 3, 4, 5]], ['AA 1',[True, False, False, True, False]]]
extra_another.write out (Excel (Cell_Range "Random!S3")) on_existing_file=Existing_File_Behavior.Append on_problems=Report_Error . should_succeed extra_another.write out (Excel (Cell_Range "Random!S3")) on_existing_file=Existing_File_Behavior.Append on_problems=Report_Error . should_succeed
written = out.read (Excel (Cell_Range "Random!S3")) . select_columns [0, 1, 2] written = out.read (Excel (Cell_Range "Random!S3")) . select_columns [0, 1, 2]
written.should_equal expected written.should_equal expected
@ -725,10 +725,10 @@ spec =
check_table (file.read (Excel (Cell_Range "Sheet1!B2"))) ["B"] [["A","B","C","D","E","F"]] check_table (file.read (Excel (Cell_Range "Sheet1!B2"))) ["B"] [["A","B","C","D","E","F"]]
Test.specify "Patchy table" <| Test.specify "Patchy table" <|
check_table (file.read (Excel (Cell_Range "Sheet1!D1"))) ["A", "B", "Column_1"] [[1,2,4], [4,4,Nothing], [6,Nothing,6]] check_table (file.read (Excel (Cell_Range "Sheet1!D1"))) ["A", "B", "Column 1"] [[1,2,4], [4,4,Nothing], [6,Nothing,6]]
check_table (file.read (Excel (Cell_Range "Sheet1!D2"))) ["D", "E", "F"] [[1,2,4], [4,4,Nothing], [6,Nothing,6]] check_table (file.read (Excel (Cell_Range "Sheet1!D2"))) ["D", "E", "F"] [[1,2,4], [4,4,Nothing], [6,Nothing,6]]
check_table (file.read (Excel (Cell_Range "Sheet1!E"))) ["B"] [[4,4,Nothing,Nothing,Nothing,Nothing]] check_table (file.read (Excel (Cell_Range "Sheet1!E"))) ["B"] [[4,4,Nothing,Nothing,Nothing,Nothing]]
check_table (file.read (Excel (Cell_Range "Sheet1!E1"))) ["B", "Column_1"] [[4,4,Nothing], [6,Nothing,6]] check_table (file.read (Excel (Cell_Range "Sheet1!E1"))) ["B", "Column 1"] [[4,4,Nothing], [6,Nothing,6]]
check_table (file.read (Excel (Cell_Range "Sheet1!E2"))) ["E", "F"] [[4,4,Nothing], [6,Nothing,6]] check_table (file.read (Excel (Cell_Range "Sheet1!E2"))) ["E", "F"] [[4,4,Nothing], [6,Nothing,6]]
Test.specify "Single cell" <| Test.specify "Single cell" <|
@ -739,19 +739,19 @@ spec =
check_table (file.read (Excel (Cell_Range "Sheet1!J1"))) ["J", "K", "L"] [["Just"],["Some"],["Headers"]] check_table (file.read (Excel (Cell_Range "Sheet1!J1"))) ["J", "K", "L"] [["Just"],["Some"],["Headers"]]
Test.specify "Growing table" <| Test.specify "Growing table" <|
check_table (file.read (Excel (Cell_Range "Sheet1!N1"))) ["A", "Full", "Table", "Column_1"] [["Hello","World",Nothing,"Extend"],[1,Nothing,"Gap",3],[2,2,"Here",5],[Nothing,Nothing,"To","Hello"]] check_table (file.read (Excel (Cell_Range "Sheet1!N1"))) ["A", "Full", "Table", "Column 1"] [["Hello","World",Nothing,"Extend"],[1,Nothing,"Gap",3],[2,2,"Here",5],[Nothing,Nothing,"To","Hello"]]
check_table (file.read (Excel (Cell_Range "Sheet1!O1"))) ["Full", "Table", "Column_1"] [[1,Nothing,"Gap",3],[2,2,"Here",5],[Nothing,Nothing,"To","Hello"]] check_table (file.read (Excel (Cell_Range "Sheet1!O1"))) ["Full", "Table", "Column 1"] [[1,Nothing,"Gap",3],[2,2,"Here",5],[Nothing,Nothing,"To","Hello"]]
check_table (file.read (Excel (Cell_Range "Sheet1!O2"))) ["O", "P", "Q"] [[1,Nothing,"Gap",3],[2,2,"Here",5],[Nothing,Nothing,"To","Hello"]] check_table (file.read (Excel (Cell_Range "Sheet1!O2"))) ["O", "P", "Q"] [[1,Nothing,"Gap",3],[2,2,"Here",5],[Nothing,Nothing,"To","Hello"]]
Test.specify "Should handle invalid headers with warnings" <| Test.specify "Should handle invalid headers with warnings" <|
action = file.read (Excel (Cell_Range "Sheet1!D1")) on_problems=_ action = file.read (Excel (Cell_Range "Sheet1!D1")) on_problems=_
tester = check_table _ ["A", "B", "Column_1"] [[1,2,4], [4,4,Nothing], [6,Nothing,6]] tester = check_table _ ["A", "B", "Column 1"] [[1,2,4], [4,4,Nothing], [6,Nothing,6]]
problems = [Invalid_Output_Column_Names.Error [""]] problems = [Invalid_Output_Column_Names.Error [""]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
Test.specify "Should handle duplicate headers with warnings" <| Test.specify "Should handle duplicate headers with warnings" <|
action = file.read (Excel (Cell_Range "Sheet1!S1")) on_problems=_ action = file.read (Excel (Cell_Range "Sheet1!S1")) on_problems=_
tester = check_table _ ["DD", "DD_1"] [[1,3], [2,4]] tester = check_table _ ["DD", "DD 1"] [[1,3], [2,4]]
problems = [Duplicate_Output_Column_Names.Error ["DD"]] problems = [Duplicate_Output_Column_Names.Error ["DD"]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester

View File

@ -66,10 +66,10 @@ spec = Test.group "Columns" <|
r.to_vector . should_equal [0, 2, 4, 5, Nothing, 30] r.to_vector . should_equal [0, 2, 4, 5, Nothing, 30]
Test.specify "should allow to count duplicate value occurences" <| Test.specify "should allow to count duplicate value occurences" <|
c_1 = Column.from_vector "c_1" [0, 1, 2, 2, 1, 0, 2] c_1 = Column.from_vector "c 1" [0, 1, 2, 2, 1, 0, 2]
c_1.duplicate_count.to_vector.should_equal [0, 0, 0, 1, 1, 1, 2] c_1.duplicate_count.to_vector.should_equal [0, 0, 0, 1, 1, 1, 2]
c_2 = Column.from_vector "c_2" ["foo", "bar", "foo", "baz", "bar"] c_2 = Column.from_vector "c 2" ["foo", "bar", "foo", "baz", "bar"]
c_2.duplicate_count.to_vector.should_equal [0, 0, 1, 0, 1] c_2.duplicate_count.to_vector.should_equal [0, 0, 1, 0, 1]
Test.specify "should result in correct Storage if operation allows it" <| Test.specify "should result in correct Storage if operation allows it" <|

View File

@ -76,7 +76,7 @@ spec =
t4 = r2.second . order_by "N" t4 = r2.second . order_by "N"
t4.row_count . should_equal n t4.row_count . should_equal n
t4.at "X" . to_vector . should_equal lowers t4.at "X" . to_vector . should_equal lowers
t4.at "Right_X" . to_vector . should_equal uppers t4.at "Right X" . to_vector . should_equal uppers
t4.at "Z" . to_vector . should_equal <| 1.up_to n+1 . to_vector . reverse t4.at "Z" . to_vector . should_equal <| 1.up_to n+1 . to_vector . reverse
base_ms = r1.first.total_milliseconds base_ms = r1.first.total_milliseconds

View File

@ -14,7 +14,7 @@ spec =
cols = [["foo", [0, 1, 2]], ["bar", ["abc", "cbdbef", "ghbijbu"]]] cols = [["foo", [0, 1, 2]], ["bar", ["abc", "cbdbef", "ghbijbu"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "a", "c", Nothing], [1, "c", "d", "ef"], [2, "gh", "ij", "u"]] expected_rows = [[0, "a", "c", Nothing], [1, "c", "d", "ef"], [2, "gh", "ij", "u"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "bar 2"] expected_rows expected = Table.from_rows ["foo", "bar 1", "bar 2", "bar 3"] expected_rows
t2 = t.split_to_columns "bar" "b" t2 = t.split_to_columns "bar" "b"
t2.should_equal expected t2.should_equal expected
@ -30,7 +30,7 @@ spec =
cols = [["foo", [0, 1, 2, 3]], ["bar", ["abc", "cbdbef", Nothing, "ghbijbu"]]] cols = [["foo", [0, 1, 2, 3]], ["bar", ["abc", "cbdbef", Nothing, "ghbijbu"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "a", "c", Nothing], [1, "c", "d", "ef"], [2, Nothing, Nothing, Nothing], [3, "gh", "ij", "u"]] expected_rows = [[0, "a", "c", Nothing], [1, "c", "d", "ef"], [2, Nothing, Nothing, Nothing], [3, "gh", "ij", "u"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "bar 2"] expected_rows expected = Table.from_rows ["foo", "bar 1", "bar 2", "bar 3"] expected_rows
t2 = t.split_to_columns "bar" "b" t2 = t.split_to_columns "bar" "b"
t2.should_equal expected t2.should_equal expected
@ -47,7 +47,7 @@ spec =
cols = [["foo", [0, 1, 2]], ["bar", ["a12b34r5", "23", "2r4r55"]]] cols = [["foo", [0, 1, 2]], ["bar", ["a12b34r5", "23", "2r4r55"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "12", "34", "5"], [1, "23", Nothing, Nothing], [2, "2", "4", "55"]] expected_rows = [[0, "12", "34", "5"], [1, "23", Nothing, Nothing], [2, "2", "4", "55"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "bar 2"] expected_rows expected = Table.from_rows ["foo", "bar 1", "bar 2", "bar 3"] expected_rows
t2 = t.tokenize_to_columns "bar" "\d+" t2 = t.tokenize_to_columns "bar" "\d+"
t2.should_equal expected t2.should_equal expected
@ -63,7 +63,7 @@ spec =
cols = [["foo", [0, 1, 2, 3]], ["bar", ["a12b34r5", Nothing, "23", "2r4r55"]]] cols = [["foo", [0, 1, 2, 3]], ["bar", ["a12b34r5", Nothing, "23", "2r4r55"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "12", "34", "5"], [1, Nothing, Nothing, Nothing], [2, "23", Nothing, Nothing], [3, "2", "4", "55"]] expected_rows = [[0, "12", "34", "5"], [1, Nothing, Nothing, Nothing], [2, "23", Nothing, Nothing], [3, "2", "4", "55"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "bar 2"] expected_rows expected = Table.from_rows ["foo", "bar 1", "bar 2", "bar 3"] expected_rows
t2 = t.tokenize_to_columns "bar" "\d+" t2 = t.tokenize_to_columns "bar" "\d+"
t2.should_equal expected t2.should_equal expected
@ -87,7 +87,7 @@ spec =
cols = [["foo", [0, 1]], ["bar", ["r a-1, b-12,qd-50", "ab-10:bc-20c"]]] cols = [["foo", [0, 1]], ["bar", ["r a-1, b-12,qd-50", "ab-10:bc-20c"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "a1", "b12", "d50"], [1, "b10", "c20", Nothing]] expected_rows = [[0, "a1", "b12", "d50"], [1, "b10", "c20", Nothing]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "bar 2"] expected_rows expected = Table.from_rows ["foo", "bar 1", "bar 2", "bar 3"] expected_rows
t2 = t.tokenize_to_columns "bar" "([a-z]).(\d+)" t2 = t.tokenize_to_columns "bar" "([a-z]).(\d+)"
t2.should_equal expected t2.should_equal expected
@ -103,7 +103,7 @@ spec =
cols = [["foo", [0, 1, 2]], ["bar", ["aBqcE", "qcBr", "cCb"]]] cols = [["foo", [0, 1, 2]], ["bar", ["aBqcE", "qcBr", "cCb"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "B", "c", Nothing], [1, "c", "B", Nothing], [2, "c", "C", "b"]] expected_rows = [[0, "B", "c", Nothing], [1, "c", "B", Nothing], [2, "c", "C", "b"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "bar 2"] expected_rows expected = Table.from_rows ["foo", "bar 1", "bar 2", "bar 3"] expected_rows
t2 = t.tokenize_to_columns "bar" "[bc]" case_sensitivity=Case_Sensitivity.Insensitive t2 = t.tokenize_to_columns "bar" "[bc]" case_sensitivity=Case_Sensitivity.Insensitive
t2.should_equal expected t2.should_equal expected
@ -132,7 +132,7 @@ spec =
cols = [["foo", [0, 1, 2]], ["bar", ["abc", "cbdbef", "ghbijbu"]]] cols = [["foo", [0, 1, 2]], ["bar", ["abc", "cbdbef", "ghbijbu"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "a", "c", Nothing, Nothing], [1, "c", "d", "ef", Nothing], [2, "gh", "ij", "u", Nothing]] expected_rows = [[0, "a", "c", Nothing, Nothing], [1, "c", "d", "ef", Nothing], [2, "gh", "ij", "u", Nothing]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "bar 2", "bar 3"] expected_rows expected = Table.from_rows ["foo", "bar 1", "bar 2", "bar 3", "bar 3"] expected_rows
t2 = t.split_to_columns "bar" "b" column_count=4 t2 = t.split_to_columns "bar" "b" column_count=4
t2.should_equal expected t2.should_equal expected
t2.at "bar 3" . value_type . is_text . should_be_true t2.at "bar 3" . value_type . is_text . should_be_true
@ -141,7 +141,7 @@ spec =
cols = [["foo", [0, 1, 2]], ["bar", ["abc", "cbdbef", "ghbijbu"]]] cols = [["foo", [0, 1, 2]], ["bar", ["abc", "cbdbef", "ghbijbu"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "a", "c"], [1, "c", "d"], [2, "gh", "ij"]] expected_rows = [[0, "a", "c"], [1, "c", "d"], [2, "gh", "ij"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1"] expected_rows expected = Table.from_rows ["foo", "bar 1", "bar 2"] expected_rows
action = t.split_to_columns "bar" "b" column_count=2 on_problems=_ action = t.split_to_columns "bar" "b" column_count=2 on_problems=_
tester = t-> t.should_equal expected tester = t-> t.should_equal expected
problems = [Column_Count_Exceeded.Error 2 3] problems = [Column_Count_Exceeded.Error 2 3]
@ -151,7 +151,7 @@ spec =
cols = [["foo", [0, 1]], ["bar", ["r a-1, b-12,qd-50", "ab-10:bc-20c"]]] cols = [["foo", [0, 1]], ["bar", ["r a-1, b-12,qd-50", "ab-10:bc-20c"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "a1", "b12", "d50"], [1, "b10", "c20", Nothing]] expected_rows = [[0, "a1", "b12", "d50"], [1, "b10", "c20", Nothing]]
expected = Table.from_rows ["foo", "bar 0", "bar 1"] expected_rows expected = Table.from_rows ["foo", "bar 1", "bar 2"] expected_rows
action = t.tokenize_to_columns "bar" "([a-z]).(\d+)" column_count=2 on_problems=_ action = t.tokenize_to_columns "bar" "([a-z]).(\d+)" column_count=2 on_problems=_
tester = t-> t.should_equal expected tester = t-> t.should_equal expected
problems = [Column_Count_Exceeded.Error 2 3] problems = [Column_Count_Exceeded.Error 2 3]
@ -161,7 +161,7 @@ spec =
cols = [["foo", [0, 1, 2]], ["bar", ["ghbijbu", "cbdbef", "abc"]]] cols = [["foo", [0, 1, 2]], ["bar", ["ghbijbu", "cbdbef", "abc"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "gh", "ij", "u", Nothing], [1, "c", "d", "ef", Nothing], [2, "a", "c", Nothing, Nothing]] expected_rows = [[0, "gh", "ij", "u", Nothing], [1, "c", "d", "ef", Nothing], [2, "a", "c", Nothing, Nothing]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "bar 2", "bar 3"] expected_rows expected = Table.from_rows ["foo", "bar 1", "bar 2", "bar 3", "bar 3"] expected_rows
t2 = t.split_to_columns "bar" "b" column_count=4 t2 = t.split_to_columns "bar" "b" column_count=4
t2.should_equal expected t2.should_equal expected
t2.at "bar 3" . value_type . is_text . should_be_true t2.at "bar 3" . value_type . is_text . should_be_true
@ -198,7 +198,7 @@ spec =
cols = [["foo", [0, 1, 2]], ["bar", ["abc", "cbdbef", "ghbijbu"]], ["bar 1", ["a", "b", "c"]]] cols = [["foo", [0, 1, 2]], ["bar", ["abc", "cbdbef", "ghbijbu"]], ["bar 1", ["a", "b", "c"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "a", "c", Nothing, "a"], [1, "c", "d", "ef", "b"], [2, "gh", "ij", "u", "c"]] expected_rows = [[0, "a", "c", Nothing, "a"], [1, "c", "d", "ef", "b"], [2, "gh", "ij", "u", "c"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1_1", "bar 2", "bar 1"] expected_rows expected = Table.from_rows ["foo", "bar 1 1", "bar 2", "bar 3", "bar 1"] expected_rows
action = t.split_to_columns "bar" "b" on_problems=_ action = t.split_to_columns "bar" "b" on_problems=_
tester = t-> t.should_equal expected tester = t-> t.should_equal expected
problems = [Duplicate_Output_Column_Names.Error ["bar 1"]] problems = [Duplicate_Output_Column_Names.Error ["bar 1"]]
@ -208,7 +208,7 @@ spec =
cols = [["foo", [0, 1, 2]], ["bar", ["a12b34r5", "23", "2r4r55"]], ["bar 1", ["a", "b", "c"]]] cols = [["foo", [0, 1, 2]], ["bar", ["a12b34r5", "23", "2r4r55"]], ["bar 1", ["a", "b", "c"]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "12", "34", "5", "a"], [1, "23", Nothing, Nothing, "b"], [2, "2", "4", "55", "c"]] expected_rows = [[0, "12", "34", "5", "a"], [1, "23", Nothing, Nothing, "b"], [2, "2", "4", "55", "c"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1_1", "bar 2", "bar 1"] expected_rows expected = Table.from_rows ["foo", "bar 1 1", "bar 2", "bar 3", "bar 1"] expected_rows
action = t.tokenize_to_columns "bar" "\d+" on_problems=_ action = t.tokenize_to_columns "bar" "\d+" on_problems=_
tester = t-> t.should_equal expected tester = t-> t.should_equal expected
problems = [Duplicate_Output_Column_Names.Error ["bar 1"]] problems = [Duplicate_Output_Column_Names.Error ["bar 1"]]
@ -219,14 +219,14 @@ spec =
cols = [["foo", [0, 1, 2]], ["bar", ["abc", "cbdbef", "ghbijbu"]], ["baz", [1, 2, 3]]] cols = [["foo", [0, 1, 2]], ["bar", ["abc", "cbdbef", "ghbijbu"]], ["baz", [1, 2, 3]]]
t = Table.new cols t = Table.new cols
expected_rows = [[0, "a", "c", Nothing, 1], [1, "c", "d", "ef", 2], [2, "gh", "ij", "u", 3]] expected_rows = [[0, "a", "c", Nothing, 1], [1, "c", "d", "ef", 2], [2, "gh", "ij", "u", 3]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "bar 2", "baz"] expected_rows expected = Table.from_rows ["foo", "bar 1", "bar 2", "bar 3", "baz"] expected_rows
t2 = t.split_to_columns "bar" "b" t2 = t.split_to_columns "bar" "b"
t2.should_equal expected t2.should_equal expected
Test.group "Table.parse_to_columns" <| Test.group "Table.parse_to_columns" <|
Test.specify "can parse to columns" <| Test.specify "can parse to columns" <|
t = Table.from_rows ["foo", "bar", "baz"] [["x", "12 34p q56", "y"], ["xx", "a48 59b", "yy"]] t = Table.from_rows ["foo", "bar", "baz"] [["x", "12 34p q56", "y"], ["xx", "a48 59b", "yy"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "baz"] [["x", 1, 2, "y"], ["x", 3, 4, "y"], ["x", 5, 6, "y"], ["xx", 4, 8, "yy"], ["xx", 5, 9, "yy"]] expected = Table.from_rows ["foo", "bar 1", "bar 2", "baz"] [["x", 1, 2, "y"], ["x", 3, 4, "y"], ["x", 5, 6, "y"], ["xx", 4, 8, "yy"], ["xx", 5, 9, "yy"]]
actual = t.parse_to_columns "bar" "(\d)(\d)" actual = t.parse_to_columns "bar" "(\d)(\d)"
actual.should_equal expected actual.should_equal expected
@ -244,31 +244,31 @@ spec =
Test.specify "non-participating groups" <| Test.specify "non-participating groups" <|
t = Table.from_rows ["foo", "bar", "baz"] [["x", "q1", "y"], ["xx", "qp", "yy"]] t = Table.from_rows ["foo", "bar", "baz"] [["x", "q1", "y"], ["xx", "qp", "yy"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "bar 2", "baz"] [["x", "1", 1, Nothing, "y"], ["xx", "p", Nothing, "p", "yy"]] expected = Table.from_rows ["foo", "bar 1", "bar 2", "bar 3", "baz"] [["x", "1", 1, Nothing, "y"], ["xx", "p", Nothing, "p", "yy"]]
actual = t.parse_to_columns "bar" "q((\d)|([a-z]))" actual = t.parse_to_columns "bar" "q((\d)|([a-z]))"
actual.should_equal expected actual.should_equal expected
Test.specify "case-insensitive" <| Test.specify "case-insensitive" <|
t = Table.from_rows ["foo", "bar", "baz"] [["x", "qq", "y"], ["xx", "qQ", "yy"]] t = Table.from_rows ["foo", "bar", "baz"] [["x", "qq", "y"], ["xx", "qQ", "yy"]]
expected = Table.from_rows ["foo", "bar 0", "baz"] [["x", "q", "y"], ["xx", "Q", "yy"]] expected = Table.from_rows ["foo", "bar 1", "baz"] [["x", "q", "y"], ["xx", "Q", "yy"]]
actual = t.parse_to_columns "bar" "q(q)" case_sensitivity=Case_Sensitivity.Insensitive actual = t.parse_to_columns "bar" "q(q)" case_sensitivity=Case_Sensitivity.Insensitive
actual.should_equal expected actual.should_equal expected
Test.specify "no post-parsing" <| Test.specify "no post-parsing" <|
t = Table.from_rows ["foo", "bar", "baz"] [["x", "12 34p q56", "y"], ["xx", "a48 59b", "yy"]] t = Table.from_rows ["foo", "bar", "baz"] [["x", "12 34p q56", "y"], ["xx", "a48 59b", "yy"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "baz"] [["x", "1", "2", "y"], ["x", "3", "4", "y"], ["x", "5", "6", "y"], ["xx", "4", "8", "yy"], ["xx", "5", "9", "yy"]] expected = Table.from_rows ["foo", "bar 1", "bar 2", "baz"] [["x", "1", "2", "y"], ["x", "3", "4", "y"], ["x", "5", "6", "y"], ["xx", "4", "8", "yy"], ["xx", "5", "9", "yy"]]
actual = t.parse_to_columns "bar" "(\d)(\d)" parse_values=False actual = t.parse_to_columns "bar" "(\d)(\d)" parse_values=False
actual.should_equal expected actual.should_equal expected
Test.specify "column name clash" <| Test.specify "column name clash" <|
t = Table.from_rows ["foo", "bar", "bar 1"] [["x", "12 34p q56", "y"], ["xx", "a48 59b", "yy"]] t = Table.from_rows ["foo", "bar", "bar 1"] [["x", "12 34p q56", "y"], ["xx", "a48 59b", "yy"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1_1", "bar 1"] [["x", 1, 2, "y"], ["x", 3, 4, "y"], ["x", 5, 6, "y"], ["xx", 4, 8, "yy"], ["xx", 5, 9, "yy"]] expected = Table.from_rows ["foo", "bar 1 1", "bar 2", "bar 1"] [["x", 1, 2, "y"], ["x", 3, 4, "y"], ["x", 5, 6, "y"], ["xx", 4, 8, "yy"], ["xx", 5, 9, "yy"]]
actual = t.parse_to_columns "bar" "(\d)(\d)" actual = t.parse_to_columns "bar" "(\d)(\d)"
actual.should_equal expected actual.should_equal expected
Test.specify "column and group name clash" <| Test.specify "column and group name clash" <|
t = Table.from_rows ["foo", "bar", "baz"] [["x", "123", "y"]] t = Table.from_rows ["foo", "bar", "baz"] [["x", "123", "y"]]
expected = Table.from_rows ["foo", "bar", "baz_1", "quux", "baz"] [["x", 1, 2, 3, "y"]] expected = Table.from_rows ["foo", "bar", "baz 1", "quux", "baz"] [["x", 1, 2, 3, "y"]]
actual = t.parse_to_columns "bar" "(?<bar>\d)(?<baz>\d)(?<quux>\d)" actual = t.parse_to_columns "bar" "(?<bar>\d)(?<baz>\d)(?<quux>\d)"
actual.should_equal expected actual.should_equal expected
@ -280,13 +280,13 @@ spec =
Test.specify "empty table, with regex groups" <| Test.specify "empty table, with regex groups" <|
t = Table.from_rows ["foo", "bar", "baz"] [["x", "a", "y"]] . take 0 t = Table.from_rows ["foo", "bar", "baz"] [["x", "a", "y"]] . take 0
expected = Table.from_rows ["foo", "bar 0", "bar 1", "baz"] [["x", "a", "a", "y"]] . take 0 expected = Table.from_rows ["foo", "bar 1", "bar 2", "baz"] [["x", "a", "a", "y"]] . take 0
actual = t.parse_to_columns "bar" "(\d)(\d)" actual = t.parse_to_columns "bar" "(\d)(\d)"
actual.should_equal expected actual.should_equal expected
Test.specify "empty table, with named and unnamed regex groups" <| Test.specify "empty table, with named and unnamed regex groups" <|
t = Table.from_rows ["foo", "bar", "baz"] [["x", "a", "y"]] . take 0 t = Table.from_rows ["foo", "bar", "baz"] [["x", "a", "y"]] . take 0
expected = Table.from_rows ["foo", "quux", "bar 0", "foo_1", "bar 1", "baz"] [["x", "a", "a", "a", "a", "y"]] . take 0 expected = Table.from_rows ["foo", "quux", "bar 1", "foo 1", "bar 2", "baz"] [["x", "a", "a", "a", "a", "y"]] . take 0
actual = t.parse_to_columns "bar" "(?<quux>)(\d)(?<foo>\d)(\d)" actual = t.parse_to_columns "bar" "(?<quux>)(\d)(?<foo>\d)(\d)"
actual.should_equal expected actual.should_equal expected
@ -298,13 +298,13 @@ spec =
Test.specify "input with no matches, with regex groups" <| Test.specify "input with no matches, with regex groups" <|
t = Table.from_rows ["foo", "bar", "baz"] [["x", "a", "y"]] t = Table.from_rows ["foo", "bar", "baz"] [["x", "a", "y"]]
expected = Table.from_rows ["foo", "bar 0", "bar 1", "baz"] [] expected = Table.from_rows ["foo", "bar 1", "bar 2", "baz"] []
actual = t.parse_to_columns "bar" "(\d)(\d)" actual = t.parse_to_columns "bar" "(\d)(\d)"
actual.should_equal expected actual.should_equal expected
Test.specify "input with no matches, with named and unnamed regex groups" <| Test.specify "input with no matches, with named and unnamed regex groups" <|
t = Table.from_rows ["foo", "bar", "baz"] [["x", "a", "y"]] t = Table.from_rows ["foo", "bar", "baz"] [["x", "a", "y"]]
expected = Table.from_rows ["foo", "quux", "bar 0", "foo_1", "bar 1", "baz"] [] expected = Table.from_rows ["foo", "quux", "bar 1", "foo 1", "bar 2", "baz"] []
actual = t.parse_to_columns "bar" "(?<quux>)(\d)(?<foo>\d)(\d)" actual = t.parse_to_columns "bar" "(?<quux>)(\d)(?<foo>\d)(\d)"
actual.should_equal expected actual.should_equal expected

View File

@ -541,7 +541,7 @@ spec =
c_4 = ['Z', [True, False, True]] c_4 = ['Z', [True, False, True]]
table = Table.new [c_0, c_1, c_2, c_3, c_4] table = Table.new [c_0, c_1, c_2, c_3, c_4]
action = table.use_first_row_as_names on_problems=_ action = table.use_first_row_as_names on_problems=_
tester = expect_column_names ["Column_1", "1980-01-01", "1", "5.3", "True"] tester = expect_column_names ["Column 1", "1980-01-01", "1", "5.3", "True"]
problems = [Invalid_Output_Column_Names.Error [""]] problems = [Invalid_Output_Column_Names.Error [""]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
@ -553,7 +553,7 @@ spec =
c_4 = ['Z', [True, False, True]] c_4 = ['Z', [True, False, True]]
table = Table.new [c_0, c_1, c_2, c_3, c_4] table = Table.new [c_0, c_1, c_2, c_3, c_4]
action = table.use_first_row_as_names on_problems=_ action = table.use_first_row_as_names on_problems=_
tester = expect_column_names ["A", "1980-01-01", "Column_1", "5.3", "True"] tester = expect_column_names ["A", "1980-01-01", "Column 1", "5.3", "True"]
problems = [Invalid_Output_Column_Names.Error [Nothing]] problems = [Invalid_Output_Column_Names.Error [Nothing]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
@ -565,7 +565,7 @@ spec =
c_4 = ['Z', [True, False, True]] c_4 = ['Z', [True, False, True]]
table = Table.new [c_0, c_1, c_2, c_3, c_4] table = Table.new [c_0, c_1, c_2, c_3, c_4]
action = table.use_first_row_as_names on_problems=_ action = table.use_first_row_as_names on_problems=_
tester = expect_column_names ["Column_1", "1980-01-01", "Column_2", "5.3", "True"] tester = expect_column_names ["Column 1", "1980-01-01", "Column 2", "5.3", "True"]
problems = [Invalid_Output_Column_Names.Error ["", Nothing]] problems = [Invalid_Output_Column_Names.Error ["", Nothing]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester
@ -576,7 +576,7 @@ spec =
c_3 = ['C', ["A", "B", "C"]] c_3 = ['C', ["A", "B", "C"]]
table = Table.new [c_0, c_1, c_2, c_3] table = Table.new [c_0, c_1, c_2, c_3]
action = table.use_first_row_as_names on_problems=_ action = table.use_first_row_as_names on_problems=_
tester = expect_column_names ["A", "A_1", "A_2", "A_3"] tester = expect_column_names ["A", "A 1", "A 2", "A 3"]
problems = [Duplicate_Output_Column_Names.Error ["A", "A", "A"]] problems = [Duplicate_Output_Column_Names.Error ["A", "A", "A"]]
Problems.test_problem_handling action problems tester Problems.test_problem_handling action problems tester

View File

@ -4,27 +4,36 @@ from Standard.Table import Table, Column
from Standard.Test import Test from Standard.Test import Test
import Standard.Test.Extensions import Standard.Test.Extensions
import Standard.Test.Test_Result.Test_Result
polyglot java import org.enso.base_test_helpers.FileSystemHelper polyglot java import org.enso.base_test_helpers.FileSystemHelper
Table.should_equal self expected = case expected of Table.should_equal : Any -> Integer -> Test_Result
_ : Table -> Table.should_equal self expected frames_to_skip=0 =
tables_equal t0 t1 = loc = Meta.get_source_location 1+frames_to_skip
same_headers = (t0.columns.map .name) == (t1.columns.map .name) case expected of
same_columns = (t0.columns.map .to_vector) == (t1.columns.map .to_vector) _ : Table ->
same_headers && same_columns tables_equal t0 t1 =
equal = tables_equal self expected same_headers = (t0.columns.map .name) == (t1.columns.map .name)
if equal.not then same_columns = (t0.columns.map .to_vector) == (t1.columns.map .to_vector)
msg = 'Tables differ.\nActual:\n' + self.display + '\nExpected:\n' + expected.display same_headers && same_columns
Test.fail msg equal = tables_equal self expected
_ -> Test.fail "Got a Table, but expected a "+expected.to_display_text if equal.not then
msg = 'Tables differ at '+loc+'.\nActual:\n' + self.display + '\nExpected:\n' + expected.display
Test.fail msg
_ -> Test.fail "Got a Table, but expected a "+expected.to_display_text+' (at '+loc+').'
Column.should_equal self expected = Column.should_equal : Any -> Integer -> Test_Result
if self.name != expected.name then Column.should_equal self expected frames_to_skip=0 =
Test.fail "Expected column name "+expected.name+", but got "+self.name+"." loc = Meta.get_source_location 1+frames_to_skip
if self.length != expected.length then case expected of
Test.fail "Expected column length "+expected.length.to_text+", but got "+self.length.to_text+"." _ : Column ->
self.to_vector.should_equal expected.to_vector if self.name != expected.name then
Test.fail "Expected column name "+expected.name+", but got "+self.name+" (at "+loc+")."
if self.length != expected.length then
Test.fail "Expected column length "+expected.length.to_text+", but got "+self.length.to_text+" (at "+loc+")."
self.to_vector.should_equal expected.to_vector
_ -> Test.fail "Got a Column, but expected a "+expected.to_display_text+' (at '+loc+').'
normalize_lines string line_separator=Line_Ending_Style.Unix.to_text newline_at_end=True = normalize_lines string line_separator=Line_Ending_Style.Unix.to_text newline_at_end=True =
case newline_at_end of case newline_at_end of

View File

@ -229,6 +229,22 @@ spec_with name create_new_date parse_date =
(create_new_date 2000 7 1).end_of Date_Period.Quarter . should_equal (Date.new 2000 9 30) (create_new_date 2000 7 1).end_of Date_Period.Quarter . should_equal (Date.new 2000 9 30)
(create_new_date 2000 6 30).end_of Date_Period.Quarter . should_equal (Date.new 2000 6 30) (create_new_date 2000 6 30).end_of Date_Period.Quarter . should_equal (Date.new 2000 6 30)
Test.specify "should allow to compute the number of days until a date" <|
create_new_date 2000 2 1 . days_until (create_new_date 2000 2 1) . should_equal 0
create_new_date 2000 2 1 . days_until (create_new_date 2000 2 2) . should_equal 1
create_new_date 2000 2 2 . days_until (create_new_date 2000 2 1) . should_equal -1
create_new_date 2001 3 1 . days_until (create_new_date 2001 4 1) . should_equal 31
create_new_date 2000 3 1 . days_until (create_new_date 2001 3 1) . should_equal 365
create_new_date 2001 3 1 . days_until (create_new_date 2000 3 1) . should_equal -365
Test.specify "should allow to compute the number of days until a date including the end date" <|
create_new_date 2000 2 1 . days_until (create_new_date 2000 2 1) include_end_date=True . should_equal 1
create_new_date 2000 2 1 . days_until (create_new_date 2000 2 2) include_end_date=True . should_equal 2
create_new_date 2000 2 2 . days_until (create_new_date 2000 2 1) include_end_date=True . should_equal -2
create_new_date 2001 3 1 . days_until (create_new_date 2001 4 1) include_end_date=True . should_equal 32
create_new_date 2000 3 1 . days_until (create_new_date 2001 3 1) include_end_date=True . should_equal 366
create_new_date 2001 3 1 . days_until (create_new_date 2000 3 1) include_end_date=True . should_equal -366
Test.specify "should allow to compute the number of working days until a later date" <| Test.specify "should allow to compute the number of working days until a later date" <|
# 2000-2-1 is a Tuesday # 2000-2-1 is a Tuesday
create_new_date 2000 2 1 . work_days_until (create_new_date 2000 2 1) . should_equal 0 create_new_date 2000 2 1 . work_days_until (create_new_date 2000 2 1) . should_equal 0

View File

@ -16,8 +16,8 @@ sample_table =
col1 = ["foo", [123456789,23456789,987654321]] col1 = ["foo", [123456789,23456789,987654321]]
col2 = ["bar", [4,5,6]] col2 = ["bar", [4,5,6]]
col3 = ["Baz", [7,8,9]] col3 = ["Baz", [7,8,9]]
col4 = ["foo_1", [10,11,12]] col4 = ["foo 1", [10,11,12]]
col5 = ["foo_2", [13,14,15]] col5 = ["foo 2", [13,14,15]]
col6 = ["ab.+123", [16,17,18]] col6 = ["ab.+123", [16,17,18]]
col7 = ["abcd123", ["19",20, t1]] col7 = ["abcd123", ["19",20, t1]]
Table.new [col1, col2, col3, col4, col5, col6, col7] Table.new [col1, col2, col3, col4, col5, col6, col7]