From 0c39f8ec04888e7db627c1d0bcd225cc4d26db5f Mon Sep 17 00:00:00 2001 From: James Dunkerley Date: Wed, 7 Feb 2024 14:36:14 +0000 Subject: [PATCH] Allow Filter_Condition to be inverted. (#8861) - Various linting fixes (doc comments and type annotations etc.). - Add an action to determine if a `Filter_Condition` is keep or remove. https://github.com/enso-org/enso/assets/4699705/69ba2bd3-8893-4237-acc4-eb01f534a209 - Remove `Not_In`, `Not_Contains` and `Not_Like` from `Filter_Condition`. - Ability to use an `Expression` as a `Column_Ref`. https://github.com/enso-org/enso/assets/4699705/16a2e030-f8f9-4f59-beca-2646f56fcb90 --- CHANGELOG.md | 2 + .../AWS/0.0.0-dev/src/AWS_Credential.enso | 6 +- .../lib/Standard/Base/0.0.0-dev/src/Data.enso | 2 +- .../Base/0.0.0-dev/src/Data/Base_64.enso | 2 +- .../src/Data/Enso_Cloud/Enso_File.enso | 2 +- .../src/Data/Enso_Cloud/Enso_Secret.enso | 6 +- .../0.0.0-dev/src/Data/Enso_Cloud/Utils.enso | 3 +- .../0.0.0-dev/src/Data/Filter_Condition.enso | 234 +++++++----------- .../Base/0.0.0-dev/src/Data/Java_Json.enso | 9 +- .../Base/0.0.0-dev/src/Data/Json.enso | 2 +- .../Base/0.0.0-dev/src/Data/Locale.enso | 3 +- .../Base/0.0.0-dev/src/Data/Numbers.enso | 3 +- .../Base/0.0.0-dev/src/Data/Range.enso | 11 +- .../0.0.0-dev/src/Data/Time/Date_Time.enso | 2 +- .../Base/0.0.0-dev/src/Errors/File_Error.enso | 2 +- .../lib/Standard/Base/0.0.0-dev/src/Main.enso | 2 + .../0.0.0-dev/src/Network/HTTP/Header.enso | 12 +- .../0.0.0-dev/src/Network/HTTP/Response.enso | 4 +- .../src/Network/HTTP/Response_Body.enso | 6 +- .../Standard/Base/0.0.0-dev/src/Random.enso | 4 +- .../0.0.0-dev/src/System/File_By_Line.enso | 12 +- .../Base/0.0.0-dev/src/Widget_Helpers.enso | 4 +- .../0.0.0-dev/src/Connection/Connection.enso | 2 +- .../Database/0.0.0-dev/src/Data/Column.enso | 2 +- .../Table/0.0.0-dev/src/Data/Column.enso | 10 +- .../Table/0.0.0-dev/src/Data/Column_Ref.enso | 3 + .../Conversions/Convertible_To_Columns.enso | 2 +- .../Data/Conversions/Convertible_To_Rows.enso | 2 +- .../src/Delimited/Delimited_Format.enso | 4 +- .../0.0.0-dev/src/Excel/Excel_Workbook.enso | 2 +- .../0.0.0-dev/src/Extensions/Table_Ref.enso | 44 ++-- .../src/Internal/Expand_Objects_Helpers.enso | 2 +- .../Internal/Filter_Condition_Helpers.enso | 141 +++++------ .../src/Internal/Split_Tokenize.enso | 2 +- .../src/Internal/Widget_Helpers.enso | 13 +- .../Test_New/0.0.0-dev/src/Helpers.enso | 8 +- .../Standard/Test_New/0.0.0-dev/src/Main.enso | 5 +- .../Test_New/0.0.0-dev/src/Suite.enso | 6 +- .../Standard/Test_New/0.0.0-dev/src/Test.enso | 39 +-- .../Test_New/0.0.0-dev/src/Test_Reporter.enso | 6 +- .../Test_New/0.0.0-dev/src/Test_Result.enso | 12 +- .../data/column/storage/BoolStorage.java | 2 +- test/Base_Tests/src/Data/Json_Spec.enso | 6 +- test/Base_Tests/src/Data/List_Spec.enso | 34 ++- test/Base_Tests/src/Data/Range_Spec.enso | 80 ++++-- test/Base_Tests/src/Data/Vector_Spec.enso | 113 ++++++--- .../Column_Operations_Spec.enso | 12 + .../Derived_Columns_Spec.enso | 7 +- .../Common_Table_Operations/Filter_Spec.enso | 84 +++---- .../Missing_Values_Spec.enso | 4 +- .../src/Database/Codegen_Spec.enso | 14 +- .../src/Lazy_Table_Spec.enso | 1 - .../src/Lazy_Text_Spec.enso | 1 - .../benchmark-analysis/src/Main.enso | 2 +- 54 files changed, 531 insertions(+), 467 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a774a187a..12c504419c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -612,6 +612,7 @@ - [Added `File_By_Line` type allowing processing a file line by line. New faster JSON parser based off Jackson.][8719] - [Implemented `Table.replace` for the in-memory backend.][8935] +- [Allow removing rows using a Filter_Condition.][8861] [debug-shortcuts]: https://github.com/enso-org/enso/blob/develop/app/gui/docs/product/shortcuts.md#debug @@ -880,6 +881,7 @@ [8849]: https://github.com/enso-org/enso/pull/8849 [8865]: https://github.com/enso-org/enso/pull/8865 [8935]: https://github.com/enso-org/enso/pull/8935 +[8861]: https://github.com/enso-org/enso/pull/8861 #### Enso Compiler diff --git a/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS_Credential.enso b/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS_Credential.enso index 45ada97239..05d47537a9 100644 --- a/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS_Credential.enso +++ b/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS_Credential.enso @@ -1,9 +1,9 @@ from Standard.Base import all -from Standard.Base.Metadata import make_single_choice, Widget from Standard.Base.Data.Enso_Cloud.Enso_Secret import as_hideable_value +from Standard.Base.Metadata import make_single_choice, Widget -polyglot java import org.enso.aws.ProfileReader polyglot java import org.enso.aws.AwsCredential +polyglot java import org.enso.aws.ProfileReader type AWS_Credential ## Access using IAM via an AWS profile. @@ -32,7 +32,7 @@ type AWS_Credential make_single_choice [["default", "Nothing"], ["by profile", fqn + ".Profile"], ["by key", fqn + ".Key"]] ## PRIVATE - as_java : AWS_Credential|Nothing -> AwsCredential + as_java : AWS_Credential | Nothing -> AwsCredential as_java (credential : AWS_Credential | Nothing) = case credential of AWS_Credential.Profile profile -> AwsCredential.Profile.new profile AWS_Credential.Key access_key_id secret_access_key -> diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso index 1c7ed01b06..f8a0568674 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso @@ -146,7 +146,7 @@ read_text path (encoding=Encoding.utf_8) (on_problems=Problem_Behavior.Report_Wa example_list_files = Data.list_directory Examples.data_dir name_filter="**.md" recursive=True list_directory : File -> Text | Nothing -> Boolean -> Vector File -list_directory directory:File name_filter:Text|Nothing=Nothing recursive:Boolean=False = +list_directory directory:File (name_filter:(Text | Nothing)=Nothing) recursive:Boolean=False = directory . list name_filter=name_filter recursive=recursive ## ALIAS download, http get diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Base_64.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Base_64.enso index 407bb593ef..62a16690f5 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Base_64.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Base_64.enso @@ -1,5 +1,5 @@ -import project.Data.Text.Text import project.Data.Text.Encoding.Encoding +import project.Data.Text.Text import project.Errors.Encoding_Error.Encoding_Error from project.Data.Text.Extensions import all diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Enso_File.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Enso_File.enso index 535a00851f..38008153fc 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Enso_File.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Enso_File.enso @@ -255,7 +255,7 @@ type Enso_File ## UNSTABLE Resolves a file or directory within this directory. - / : Text -> Enso_File + / : Text -> Enso_File ! Not_Found / self (name : Text) -> Enso_File ! Not_Found = if self.is_directory.not then Error.throw (Illegal_Argument.Error "/ can only be used for directories") else if name.contains "/" then Error.throw (Illegal_Argument.Error "Resolving sub-paths (/) is not implemented. Temporary workaround: use the `/` operator multiple times.") else diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Enso_Secret.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Enso_Secret.enso index e6e55accc1..1a010f46fd 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Enso_Secret.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Enso_Secret.enso @@ -1,6 +1,6 @@ import project.Data.Base_64.Base_64 -import project.Data.Enso_Cloud.Enso_File.Enso_File import project.Data.Enso_Cloud.Enso_File.Enso_Asset_Type +import project.Data.Enso_Cloud.Enso_File.Enso_File import project.Data.Enso_Cloud.Utils import project.Data.Json.JS_Object import project.Data.Text.Text @@ -15,8 +15,8 @@ import project.Network.HTTP.Request_Body.Request_Body import project.Nothing.Nothing import project.Runtime.Context from project.Data.Boolean import Boolean, False, True -from project.Data.Text.Extensions import all from project.Data.Enso_Cloud.Enso_File import list_assets +from project.Data.Text.Extensions import all polyglot java import org.enso.base.enso_cloud.EnsoSecretHelper polyglot java import org.enso.base.enso_cloud.HideableValue @@ -165,7 +165,7 @@ Derived_Secret_Value.from (that : Text) = Derived_Secret_Value.Plain_Text that Derived_Secret_Value.from (that : Enso_Secret) = Derived_Secret_Value.Secret_Value that ## PRIVATE -as_hideable_value : Text | Enso_Secret | Nothing -> HideableValue +as_hideable_value : Text | Enso_Secret | Derived_Secret_Value -> HideableValue as_hideable_value (value : Text | Enso_Secret | Derived_Secret_Value) = case value of text : Text -> HideableValue.PlainValue.new text secret : Enso_Secret -> HideableValue.SecretValue.new secret.id diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Utils.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Utils.enso index dc5e4da916..c9547695c4 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Utils.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Enso_Cloud/Utils.enso @@ -1,6 +1,7 @@ private -import project.Data.Enso_Cloud.Enso_Secret.Enso_Secret + import project.Data.Enso_Cloud.Enso_Secret.Derived_Secret_Value +import project.Data.Enso_Cloud.Enso_Secret.Enso_Secret import project.Data.Enso_Cloud.Errors.Not_Logged_In import project.Data.Pair.Pair import project.Data.Text.Text diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Filter_Condition.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Filter_Condition.enso index 4e7bf07645..f0ff081207 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Filter_Condition.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Filter_Condition.enso @@ -21,25 +21,25 @@ polyglot java import org.enso.base.Regex_Utils type Filter_Condition ## Is less than a value (or another column, in case of Table operations)? - Less than:Any + Less than:Any action:Filter_Action=Filter_Action.Keep ## Is less than or equal to a value (or another column, in case of Table operations)? - Equal_Or_Less than:Any + Equal_Or_Less than:Any action:Filter_Action=Filter_Action.Keep ## Is equal to a value (or another column, in case of Table operations)? - Equal to:Any + Equal to:Any action:Filter_Action=Filter_Action.Keep ## Is greater than or equal to a value (or another column, in case of Table operations)? - Equal_Or_Greater than:Any + Equal_Or_Greater than:Any action:Filter_Action=Filter_Action.Keep ## Is greater than a value (or another column, in case of Table operations)? - Greater than:Any + Greater than:Any action:Filter_Action=Filter_Action.Keep ## Is not equal to a value (or another column, in case of Table operations)? - Not_Equal to:Any + Not_Equal to:Any action:Filter_Action=Filter_Action.Keep ## Is between (inclusive) two values (or columns, in case of Table operations)? - Between lower:Any upper:Any + Between lower:Any upper:Any action:Filter_Action=Filter_Action.Keep ## Is equal to another value, ignoring case (Text only)? @@ -54,7 +54,7 @@ type Filter_Condition This ensures that different ways of expressing the same character in the underlying binary representation are considered equal. @locale Locale.default_widget - Equal_Ignore_Case (to : Text | Any) (locale:Locale=Locale.default) + Equal_Ignore_Case (to : Text | Any) (locale:Locale=Locale.default) action:Filter_Action=Filter_Action.Keep ## Does the value start with a prefix (Text only)? @@ -62,7 +62,7 @@ type Filter_Condition It accepts a Text value to check if the value contains it. In case of Table operations, it can accept another column - then the corresponding values from the source column and the provided column are checked. - Starts_With (prefix : Text | Any) (case_sensitivity:Case_Sensitivity=Case_Sensitivity.Default) + Starts_With (prefix : Text | Any) (case_sensitivity:Case_Sensitivity=Case_Sensitivity.Default) action:Filter_Action=Filter_Action.Keep ## Does the value end with a suffix (Text only)? @@ -70,7 +70,7 @@ type Filter_Condition It accepts a Text value to check if the value contains it. In case of Table operations, it can accept another column - then the corresponding values from the source column and the provided column are checked. - Ends_With (suffix : Text | Any) (case_sensitivity:Case_Sensitivity=Case_Sensitivity.Default) + Ends_With (suffix : Text | Any) (case_sensitivity:Case_Sensitivity=Case_Sensitivity.Default) action:Filter_Action=Filter_Action.Keep ## Does the value contain the substring (Text only)? @@ -78,44 +78,36 @@ type Filter_Condition It accepts a Text value to check if the value contains it. In case of Table operations, it can accept another column - then the corresponding values from the source column and the provided column are checked. - Contains (substring : Text | Any) (case_sensitivity:Case_Sensitivity=Case_Sensitivity.Default) - - ## Is the substring not present in the value (Text only)? - - ? Table Operations - It accepts a Text value to check if the value contains it. In case of - Table operations, it can accept another column - then the corresponding - values from the source column and the provided column are checked. - Not_Contains (substring : Text | Any) (case_sensitivity:Case_Sensitivity=Case_Sensitivity.Default) + Contains (substring : Text | Any) (case_sensitivity:Case_Sensitivity=Case_Sensitivity.Default) action:Filter_Action=Filter_Action.Keep ## Is equal to Nothing? - Is_Nothing + Is_Nothing action:Filter_Action=Filter_Action.Keep ## Is not equal to Nothing? - Not_Nothing + Not_Nothing action:Filter_Action=Filter_Action.Keep ## Is the value a NaN (Number only)? - Is_Nan + Is_Nan action:Filter_Action=Filter_Action.Keep ## Is the value infinite (Number only)? - Is_Infinite + Is_Infinite action:Filter_Action=Filter_Action.Keep ## Is the value finite (Number only)? Finite numbers are ones that are not infinite nor NaN. - Is_Finite + Is_Finite action:Filter_Action=Filter_Action.Keep ## Is the value equal to True (Boolean only)? - Is_True + Is_True action:Filter_Action=Filter_Action.Keep ## Is the value equal to False (Boolean only)? - Is_False + Is_False action:Filter_Action=Filter_Action.Keep ## Is equal to "" or Nothing (Text only)? - Is_Empty + Is_Empty action:Filter_Action=Filter_Action.Keep ## Is not equal to "" and Nothing (Text only)? - Not_Empty + Not_Empty action:Filter_Action=Filter_Action.Keep ## Does the value match the SQL pattern (Text only)? @@ -134,26 +126,7 @@ type Filter_Condition Due to this limitation, Unicode normalization has been disabled for this function, so beware that some equivalent graphemes like 'ś' and 's\u0301' will not be matched. - Like (pattern : Text | Any) - - ## Does the value not match the SQL pattern (Text only)? - - The pattern is interpreted according to the standard SQL convention: - - the `%` character matches any sequence of characters, - - the `_` character matches any single character, - - any other character is matched literally. - - ? Table Operations - It accepts a Text value to check if the value contains it. In case of - Table operations, it can accept another column - then the corresponding - values from the source column and the provided column are checked. - - ! Known Limitations. - The Truffle regex engine does not transparently handle normalization. - Due to this limitation, Unicode normalization has been disabled for - this function, so beware that some equivalent graphemes like 'ś' and - 's\u0301' will not be matched. - Not_Like pattern:Text|Any + Like (pattern : Text | Any) action:Filter_Action=Filter_Action.Keep ## Is the value contained in `values`? @@ -167,21 +140,7 @@ type Filter_Condition Using Columns can be particularly useful for Database operations, as uploading a temporary table and using its column for an `Is_In` check will likely be faster than using the vector directly. - Is_In values:Vector|Any - - ## Is the value not contained in `values`? - - ? Table Operations - It accepts a `Vector` of values. In case of Table operations, it can - also accept another column - then it acts as if `column.to_vector` was - passed - i.e. every element of the original table's column is checked - if it is contained in the provided column. The columns can have - different lengths. - - Using Columns can be particularly useful for Database operations, as - uploading a temporary table and using its column for an `Not_In` check - will likely be faster than using the vector directly. - Not_In values:(Vector | Any) + Is_In values:Vector|Any action:Filter_Action=Filter_Action.Keep ## Converts a `Filter_Condition` condition into a predicate taking an element and returning a value indicating whether the element should be @@ -190,57 +149,45 @@ type Filter_Condition The predicate can handle `Nothing` values in all cases. However, the predicate will raise an error if the value is not of the expected type. to_predicate : (Any -> Boolean) - to_predicate self = case self of - # == does not need special handling for Nothing - Equal value -> ==value - Not_Equal value -> !=value - Less value -> handle_nothing ( handle_nothing (<=value) - Equal_Or_Greater value -> handle_nothing (>=value) - Greater value -> handle_nothing (>value) - Between lower upper -> handle_nothing <| elem-> - (lower <= elem) && (elem <= upper) - Equal_Ignore_Case value locale -> - handle_nothing <| txt-> (txt : Text).equals_ignore_case value locale - Starts_With prefix case_sensitivity -> - handle_nothing <| txt-> (txt : Text).starts_with prefix case_sensitivity - Ends_With suffix case_sensitivity -> - handle_nothing <| txt-> (txt : Text).ends_with suffix case_sensitivity - Contains substring case_sensitivity -> - handle_nothing <| txt-> (txt : Text).contains substring case_sensitivity - Not_Contains substring case_sensitivity -> - handle_nothing <| txt-> (txt : Text).contains substring case_sensitivity . not - Is_Nothing -> elem -> case elem of - Nothing -> True - _ -> False - Not_Nothing -> elem -> case elem of - Nothing -> False - _ -> True - Is_Nan -> handle_nothing x-> (x:Number).is_nan - Is_Infinite -> handle_nothing x-> (x:Number).is_infinite - Is_Finite -> handle_nothing x-> (x:Number).is_finite - Is_True -> ==True - Is_False -> ==False - Is_Empty -> elem -> case elem of - Nothing -> True - "" -> True - _ -> False - Not_Empty -> elem -> case elem of - Nothing -> False - "" -> False - _ -> True - Like sql_pattern -> - regex = sql_like_to_regex sql_pattern - handle_nothing <| regex.matches - Not_Like sql_pattern -> - regex = sql_like_to_regex sql_pattern - handle_nothing <| elem-> regex.matches elem . not - Is_In values -> - set = Set.from_vector values - set.contains - Not_In values -> - set = Set.from_vector values - elem-> set.contains elem . not + to_predicate self = + base = case self of + # == does not need special handling for Nothing + Equal value _ -> ==value + Not_Equal value _ -> !=value + Less value _ -> handle_nothing ( handle_nothing (<=value) + Equal_Or_Greater value _ -> handle_nothing (>=value) + Greater value _ -> handle_nothing (>value) + Between lower upper _ -> handle_nothing <| elem-> + (lower <= elem) && (elem <= upper) + Equal_Ignore_Case value locale _ -> + handle_nothing <| txt-> (txt : Text).equals_ignore_case value locale + Starts_With prefix case_sensitivity _ -> + handle_nothing <| txt-> (txt : Text).starts_with prefix case_sensitivity + Ends_With suffix case_sensitivity _ -> + handle_nothing <| txt-> (txt : Text).ends_with suffix case_sensitivity + Contains substring case_sensitivity _ -> + handle_nothing <| txt-> (txt : Text).contains substring case_sensitivity + Is_Nothing _ -> elem -> case elem of + Nothing -> True + _ -> False + Not_Nothing _ -> elem -> case elem of + Nothing -> False + _ -> True + Is_Nan _ -> handle_nothing x-> (x:Number).is_nan + Is_Infinite _ -> handle_nothing x-> (x:Number).is_infinite + Is_Finite _ -> handle_nothing x-> (x:Number).is_finite + Is_True _ -> handle_nothing b-> (b:Boolean)==True + Is_False _ -> handle_nothing b-> (b:Boolean)==False + Is_Empty _ -> elem-> elem.is_nothing || (elem : Text)=="" + Not_Empty _ -> handle_nothing elem-> (elem : Text)!="" + Like sql_pattern _ -> + regex = sql_like_to_regex sql_pattern + handle_nothing <| regex.matches + Is_In values _ -> + set = Set.from_vector values + set.contains + if self.action == Filter_Action.Keep then base else v -> (base v).not ## PRIVATE Convert to a display representation of this Filter_Condition. @@ -250,34 +197,31 @@ type Filter_Condition if case_sensitivity == Case_Sensitivity.Default then "" else " Case " + case_sensitivity.to_display_text condition = case self of - Less value -> "<" + value.to_display_text - Equal_Or_Less value -> "<=" + value.to_display_text - Equal value -> "==" + value.to_display_text - Equal_Or_Greater value -> ">=" + value.to_display_text - Greater value -> ">" + value.to_display_text - Not_Equal value -> "!=" + value.to_display_text - Between lower upper -> "Between " + lower.to_display_text + " And " + upper.to_display_text - Equal_Ignore_Case value locale -> + Less value _ -> "<" + value.to_display_text + Equal_Or_Less value _ -> "<=" + value.to_display_text + Equal value _ -> "==" + value.to_display_text + Equal_Or_Greater value _ -> ">=" + value.to_display_text + Greater value _ -> ">" + value.to_display_text + Not_Equal value _ -> "!=" + value.to_display_text + Between lower upper _ -> "Between " + lower.to_display_text + " And " + upper.to_display_text + Equal_Ignore_Case value locale _ -> suffix = if locale == Locale.default then "" else " (within locale " + locale.to_display_text + ")" "Equal Ignore Case " + value.to_display_text + suffix - Starts_With prefix case_sensitivity -> "Starts With " + prefix.to_display_text + (render_case case_sensitivity) - Ends_With suffix case_sensitivity -> "Ends With " + suffix.to_display_text + (render_case case_sensitivity) - Contains substring case_sensitivity -> "Contains " + substring.to_display_text + (render_case case_sensitivity) - Not_Contains substring case_sensitivity -> "not Contains " + substring.to_display_text + (render_case case_sensitivity) - Is_Nothing -> "is Nothing" - Not_Nothing -> "is not Nothing" - Is_Nan -> "is NaN" - Is_Infinite -> "is Infinite" - Is_Finite -> "is Finite" - Is_True -> "is True" - Is_False -> "is False" - Is_Empty -> "is Empty" - Not_Empty -> "is not Empty" - Like sql_pattern -> "Like " + sql_pattern.to_display_text - Not_Like sql_pattern -> "not Like " + sql_pattern.to_display_text - Is_In values -> "is in " + values.to_display_text - Not_In values -> "is not in " + values.to_display_text - "Filter Condition: " + condition + Starts_With prefix case_sensitivity _ -> "Starts With " + prefix.to_display_text + (render_case case_sensitivity) + Ends_With suffix case_sensitivity _ -> "Ends With " + suffix.to_display_text + (render_case case_sensitivity) + Contains substring case_sensitivity _ -> "Contains " + substring.to_display_text + (render_case case_sensitivity) + Is_Nothing _ -> "is Nothing" + Not_Nothing _ -> "is not Nothing" + Is_Nan _ -> "is NaN" + Is_Infinite _ -> "is Infinite" + Is_Finite _ -> "is Finite" + Is_True _ -> "is True" + Is_False _ -> "is False" + Is_Empty _ -> "is Empty" + Not_Empty _ -> "is not Empty" + Like sql_pattern _ -> "Like " + sql_pattern.to_display_text + Is_In values _ -> "is in " + values.to_display_text + "Filter Condition: " + condition + (if self.action == Filter_Action.Keep then "" else " (Remove)") ## PRIVATE Creates a Single_Choice Widget for delimiters. @@ -309,11 +253,8 @@ type Filter_Condition options_builder.append "Starts_With" options_builder.append "Ends_With" options_builder.append "Contains" - options_builder.append "Not_Contains" options_builder.append "Like" - options_builder.append "Not_Like" options_builder.append "Is_In" - options_builder.append "Not_In" options = options_builder.to_vector.map constructor_name-> name = constructor_name.replace "_" " " @@ -321,6 +262,13 @@ type Filter_Condition [name, code] make_single_choice options +## Specifies the action of a Filter_Condition. +type Filter_Action + ## Items matching the filter are kept. + Keep + + ## Items matching the filter are removed. + Remove ## PRIVATE sql_like_to_regex sql_pattern = diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Java_Json.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Java_Json.enso index 116084074a..9d5609edad 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Java_Json.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Java_Json.enso @@ -22,14 +22,19 @@ from project.Metadata.Widget import Single_Choice polyglot java import com.fasterxml.jackson.core.JsonProcessingException polyglot java import com.fasterxml.jackson.databind.JsonNode -polyglot java import com.fasterxml.jackson.databind.ObjectMapper polyglot java import com.fasterxml.jackson.databind.node.ArrayNode polyglot java import com.fasterxml.jackson.databind.node.JsonNodeType polyglot java import com.fasterxml.jackson.databind.node.ObjectNode +polyglot java import com.fasterxml.jackson.databind.ObjectMapper ## PRIVATE Jackson-based JSON Parser type Java_Json + ## ALIAS from text + GROUP Conversions + + Parse a Text value into a `Jackson_Object` or an Enso primitive value + (like `Text`, `Number`, `Boolean`, `Nothing`), or a `Vector` of values. parse : Text -> Nothing | Boolean | Number | Text | Vector | Jackson_Object parse text:Text = error_handler js_exception = @@ -60,6 +65,8 @@ read_json_array node = ## PRIVATE type Jackson_Object + ## PRIVATE + Creates a new `Jackson_Object` from an `ObjectNode`. new : ObjectNode -> Jackson_Object new object_node = make_field_names object = diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso index 1de2fd1c42..38551df0fb 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso @@ -279,7 +279,7 @@ type JS_Object obj.set_value "foo" "asdf" # => {"foo":"asdf","baz":"quux"} set_value : Text -> Any -> JS_Object - set_value self:JS_Object key:Text value = JS_Object.Value (set_value self.js_object key value.to_js_object) + set_value self key:Text value = JS_Object.Value (set_value self.js_object key value.to_js_object) ## PRIVATE type JS_Object_Comparator diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Locale.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Locale.enso index b8035c7746..b35394fe63 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Locale.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Locale.enso @@ -1,4 +1,5 @@ import project.Any.Any +import project.Data.Filter_Condition.Filter_Action import project.Data.Filter_Condition.Filter_Condition import project.Data.Text.Case.Case import project.Data.Text.Text @@ -438,7 +439,7 @@ type Locale predefined_locale_fields = locale_meta = Meta.meta Locale remove_us = locale_meta.methods + ["Value", "new", "default", "from_language_tag", "from_java", "predefined_locale_fields", "default_widget", "widget_options"] - Meta.Type.Value (Meta.type_of locale_meta.value) . methods . filter (Filter_Condition.Not_In remove_us) . sort + Meta.Type.Value (Meta.type_of locale_meta.value) . methods . filter (Filter_Condition.Is_In remove_us Filter_Action.Remove) . sort ## PRIVATE widget_options : Vector Option diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso index 5ba64f7529..b8d87a7988 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso @@ -8,11 +8,10 @@ import project.Errors.Common.Incomparable_Values import project.Errors.Common.Unsupported_Argument_Types import project.Errors.Illegal_Argument.Illegal_Argument import project.Function.Function +import project.Internal.Rounding_Helpers import project.Nothing.Nothing import project.Panic.Panic from project.Data.Boolean import Boolean, False, True - -import project.Internal.Rounding_Helpers from project.Internal.Number_Builtins import all polyglot java import java.lang.Double diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso index 732c6b3ccf..7f2373b97a 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso @@ -184,12 +184,11 @@ type Range (0.up_to 7).filter (Filter_Condition.Greater than=3) @filter range_default_filter_condition_widget filter : (Filter_Condition | (Integer -> Boolean)) -> Vector Integer - filter self filter = case filter of - _ : Filter_Condition -> self.filter filter.to_predicate - predicate : Function -> - builder = self.fold Vector.new_builder builder-> elem-> - if predicate elem then builder.append elem else builder - builder.to_vector + filter self filter = + predicate = unify_condition_or_predicate filter + builder = self.fold Vector.new_builder builder-> elem-> + if predicate elem then builder.append elem else builder + builder.to_vector ## GROUP Selections Partitions the range into `Vector`s of elements which satisfy a given diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Time/Date_Time.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Time/Date_Time.enso index ca5ab7b677..27979fb12e 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Time/Date_Time.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Time/Date_Time.enso @@ -308,7 +308,7 @@ type Date_Time from Standard.Base import Date_Time example_from_unix_epoch = Date_Time.from_unix_epoch_milliseconds 1601587200000 - from_unix_epoch_milliseconds : Integer -> Time_Zone -> Date_Time + from_unix_epoch_milliseconds : Integer -> Date_Time from_unix_epoch_milliseconds milliseconds:Integer = unix_epoch_start + Duration.new milliseconds=milliseconds diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Errors/File_Error.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Errors/File_Error.enso index 507a52f0b6..b15384406b 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Errors/File_Error.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Errors/File_Error.enso @@ -5,8 +5,8 @@ import project.Meta import project.Nothing.Nothing import project.Panic.Panic import project.System.File.File -import project.System.File_Format_Metadata.File_Format_Metadata import project.System.File_Format.File_Format +import project.System.File_Format_Metadata.File_Format_Metadata polyglot java import java.io.FileNotFoundException polyglot java import java.io.IOException diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso index b24a890c2d..44abe8ed10 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso @@ -5,6 +5,7 @@ import project.Data.Boolean import project.Data.Enso_Cloud.Enso_File.Enso_File import project.Data.Enso_Cloud.Enso_Secret.Enso_Secret import project.Data.Enso_Cloud.Enso_User.Enso_User +import project.Data.Filter_Condition.Filter_Action import project.Data.Filter_Condition.Filter_Condition import project.Data.Index_Sub_Range.Index_Sub_Range import project.Data.Interval.Bound @@ -102,6 +103,7 @@ export project.Data.Array.Array export project.Data.Enso_Cloud.Enso_File.Enso_File export project.Data.Enso_Cloud.Enso_Secret.Enso_Secret export project.Data.Enso_Cloud.Enso_User.Enso_User +export project.Data.Filter_Condition.Filter_Action export project.Data.Filter_Condition.Filter_Condition export project.Data.Index_Sub_Range.Index_Sub_Range export project.Data.Interval.Bound diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Header.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Header.enso index a3ec10362c..f9772d14ec 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Header.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Header.enso @@ -1,13 +1,13 @@ -import project.Data.Enso_Cloud.Enso_Secret.Enso_Secret import project.Data.Enso_Cloud.Enso_Secret.Derived_Secret_Value +import project.Data.Enso_Cloud.Enso_Secret.Enso_Secret import project.Data.Enso_Cloud.Utils as Cloud_Utils import project.Data.Numbers.Integer import project.Data.Text.Encoding.Encoding import project.Data.Text.Text import project.Nothing.Nothing from project.Data.Boolean import Boolean, False, True -from project.Data.Ordering import all from project.Data.Enso_Cloud.Enso_Secret import as_hideable_value +from project.Data.Ordering import all from project.Data.Text.Extensions import all polyglot java import org.graalvm.collections.Pair as Java_Pair @@ -22,7 +22,7 @@ type Header - value: The header value. Value name:Text value:(Text|Enso_Secret|Derived_Secret_Value) - ## ALIAS Build a Header + ## ALIAS build a header Create a new Header. @@ -36,7 +36,7 @@ type Header import Standard.Base.Network.HTTP.Header.Header example_new = Header.new "My_Header" "my header's value" - new : Text -> Text | Enso_Secret -> Header + new : Text -> Text | Enso_Secret | Derived_Secret_Value -> Header new name:Text value:(Text | Enso_Secret | Derived_Secret_Value) = Header.Value name value ## Create an "Accept" header. @@ -64,7 +64,7 @@ type Header accept_all : Header accept_all = Header.accept "*/*" - ## ALIAS Build an Auth Header + ## ALIAS build an auth header Create an "Authorization" header. @@ -102,7 +102,7 @@ type Header Arguments: - token: The token. - authorization_bearer : Text -> Header + authorization_bearer : Text | Enso_Secret | Derived_Secret_Value -> Header authorization_bearer (token : Text | Enso_Secret | Derived_Secret_Value) = value = ((Derived_Secret_Value.from "Bearer ") + (Derived_Secret_Value.from token)) Header.authorization value.simplify diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response.enso index 9f1bbd16a2..0c2659e899 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response.enso @@ -134,7 +134,7 @@ type Response inferred from response headers. If that fails, UTF-8 is used as the fallback. @encoding Encoding.default_widget - decode_as_text : Encoding|Infer -> Text + decode_as_text : Encoding | Infer -> Text decode_as_text self (encoding : Encoding | Infer = Infer) = self.body.decode_as_text encoding @@ -154,7 +154,7 @@ type Response example_to_text = Examples.get_geo_data.decode_as_json @encoding Encoding.default_widget - decode_as_json : Encoding|Infer -> JS_Object | Boolean | Number | Nothing | Text | Vector + decode_as_json : Encoding | Infer -> JS_Object | Boolean | Number | Nothing | Text | Vector decode_as_json self (encoding : Encoding | Infer = Infer) = self.body.decode_as_json encoding diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response_Body.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response_Body.enso index 81b76d8414..a4c7c48bd3 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response_Body.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response_Body.enso @@ -49,7 +49,7 @@ type Response_Body - stream: The body of the response as an InputStream. - metadata: File format metadata associated with the response. - uri: The URI of the response. - new : InputStream -> Text -> URI -> Response_Body + new : InputStream -> File_Format_Metadata -> URI -> Response_Body new stream (metadata : File_Format_Metadata) (uri : URI) = input_stream = Input_Stream.new stream (HTTP_Error.handle_java_exceptions uri) Response_Body.Raw_Stream input_stream metadata uri @@ -142,7 +142,7 @@ type Response_Body inferred from response headers. If that fails, UTF-8 is used as the fallback. @encoding Encoding.default_widget - decode_as_text : Encoding|Infer -> Text + decode_as_text : Encoding | Infer -> Text decode_as_text self (encoding : Encoding | Infer = Infer) = self.decode (Plain_Text_Format.Plain_Text encoding) ## ALIAS parse as json, parse json @@ -161,7 +161,7 @@ type Response_Body example_to_text = Examples.get_geo_data.decode_as_json @encoding Encoding.default_widget - decode_as_json : Encoding|Infer -> JS_Object | Boolean | Number | Nothing | Text | Vector + decode_as_json : Encoding | Infer -> JS_Object | Boolean | Number | Nothing | Text | Vector decode_as_json self (encoding : Encoding | Infer = Infer) = self.decode_as_text encoding . parse_json diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso index 41660e9f1d..739b06a950 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso @@ -155,7 +155,7 @@ type Random import Standard.Base.Random.Random d = Random.date (Date.new 2023 03 01) (Date.new 2023 10 15) - date : Date -> Date -> Boolean -> Date + date : Date -> Date -> Date date min:Date max:Date = Random_Generator.global_random_generator.date min max ## GROUP Random @@ -297,7 +297,7 @@ type Random_Generator Vector.from_polyglot_array array ## PRIVATE - date : Date -> Date -> Boolean -> Date + date : Date -> Date -> Date date self start_date:Date end_date:Date = date_range = start_date.up_to end_date include_end=True date_range.at (self.integer 0 (date_range.length - 1)) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File_By_Line.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File_By_Line.enso index c9e38fa7b2..8d1768dba6 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File_By_Line.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File_By_Line.enso @@ -14,11 +14,11 @@ from project.Data.Range.Extensions import all from project.Data.Text.Extensions import all from project.Logging import all +polyglot java import java.io.File as Java_File +polyglot java import java.nio.charset.Charset polyglot java import org.enso.base.Array_Utils polyglot java import org.enso.base.arrays.LongArrayList polyglot java import org.enso.base.FileLineReader -polyglot java import java.io.File as Java_File -polyglot java import java.nio.charset.Charset type File_By_Line ## Creates a new File_By_Line object. @@ -27,7 +27,7 @@ type File_By_Line - file: The file to read. - encoding: The encoding to use when reading the file (defaults to UTF 8). - offset: The position within the file to read from (defaults to first byte). - new : File->Encoding->File_By_Line + new : File -> Encoding -> Integer -> File_By_Line new file:File encoding:Encoding=Encoding.utf_8 offset:Integer=0 = create_row_map = row_map = LongArrayList.new @@ -52,7 +52,7 @@ type File_By_Line Arguments - line: The line to read (0 indexed). - get : Integer->Text + get : Integer -> Text get self line:Integer = if self.limit_lines.is_nothing.not && line>self.limit_lines then Error.throw (Index_Out_Of_Bounds.Error line self.limit_lines) else read_line self line @@ -201,13 +201,13 @@ type File_By_Line ## PRIVATE Reads a specific line from the file. -read_line : File_By_Line->Integer->Any->Any +read_line : File_By_Line -> Integer -> Any -> Any read_line file:File_By_Line line:Integer=0 ~default=Nothing = File_Error.handle_java_exceptions file.file <| FileLineReader.readSingleLine file.java_file file.file_end file.row_map line file.charset file.filter_func . if_nothing default ## PRIVATE Performs an action on each line in the file. -for_each_lines : File_By_Line->Integer->(Integer|Nothing)->Any->Any +for_each_lines : File_By_Line -> Integer -> (Integer|Nothing) -> Any -> Any for_each_lines file:File_By_Line start_at:Integer end_at:(Integer|Nothing) action = File_Error.handle_java_exceptions file.file <| java_file = file.java_file row_map = file.row_map diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Widget_Helpers.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Widget_Helpers.enso index 18c2b320f9..d86e7aabb5 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Widget_Helpers.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Widget_Helpers.enso @@ -19,8 +19,8 @@ make_delimiter_selector : Widget make_delimiter_selector = make_single_choice [',', ';', '|', ['{tab}', "'\t'"], ['{space}', "' '"], ['{newline}', "['\n', '\r\n', '\r']"], '_', ['Custom', "'?'"]] - ## PRIVATE - Creates a Single_Choice Widget for file read delimiters. +## PRIVATE + Creates a Single_Choice Widget for file read delimiters. make_file_read_delimiter_selector : Widget make_file_read_delimiter_selector = make_single_choice [',', ';', '|', ['{tab}', "'\t'"], ['{space}', "' '"], ['{none}', "''"], '_', ['Custom', "'?'"]] diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso index 79b66c9114..a6d9315633 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso @@ -180,7 +180,7 @@ type Connection True -> result False -> hidden_tables = self.hidden_table_registry.list_hidden_tables - result.filter "Name" (Filter_Condition.Not_In hidden_tables) + result.filter "Name" (Filter_Condition.Is_In hidden_tables Filter_Action.Remove) ## PRIVATE Checks if the table with the given name exists in the database. diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso index 82e87ffe02..9d27f1393a 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso @@ -147,7 +147,7 @@ type Column import Standard.Examples example_at = Examples.integer_column.get 0 -1 - get : Integer -> (Any | Nothing) + get : Integer -> Any -> Any | Nothing get self (index : Integer) (~default=Nothing) = self.read index+1 . get index default diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index 370799de87..638b70470b 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -32,9 +32,9 @@ from project.Internal.Column_Format import all from project.Internal.Java_Exports import make_date_builder_adapter, make_string_builder polyglot java import org.enso.base.Time_Utils -polyglot java import org.enso.table.data.mask.OrderMask polyglot java import org.enso.table.data.column.operation.cast.CastProblemAggregator polyglot java import org.enso.table.data.column.storage.Storage as Java_Storage +polyglot java import org.enso.table.data.mask.OrderMask polyglot java import org.enso.table.data.table.Column as Java_Column polyglot java import org.enso.table.error.ValueTypeMismatchException polyglot java import org.enso.table.operations.OrderBuilder @@ -1063,7 +1063,11 @@ type Column internal_is_empty : Column internal_is_empty self = new_name = naming_helper.concat [naming_helper.to_expression_text self, "is empty"] - run_vectorized_unary_op self Java_Storage.Maps.IS_EMPTY new_name fallback_fn=Filter_Condition.Is_Empty.to_predicate expected_result_type=Value_Type.Boolean skip_nulls=False + fallback x = case x of + _ : Text -> x == "" + Nothing -> True + _ -> False + run_vectorized_unary_op self Java_Storage.Maps.IS_EMPTY new_name fallback_fn=fallback expected_result_type=Value_Type.Boolean skip_nulls=False ## GROUP Standard.Base.Logical Returns a column of booleans, with `True` items at the positions where @@ -2072,7 +2076,7 @@ type Column import Standard.Examples example_at = Examples.integer_column.get 0 -1 - get : Integer -> (Any | Nothing) + get : Integer -> Any -> Any | Nothing get self (index : Integer) (~default=Nothing) = valid_index = (index >= 0) && (index < self.length) if valid_index.not then default else diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column_Ref.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column_Ref.enso index 4749ba6b73..094dc46b49 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column_Ref.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column_Ref.enso @@ -7,3 +7,6 @@ type Column_Ref ## Reference to a column by index in a table. Index index:Integer + + ## Representation of an expression derived in a table. + Expression expression:Text diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Conversions/Convertible_To_Columns.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Conversions/Convertible_To_Columns.enso index e5489aa8ae..9648271c4f 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Conversions/Convertible_To_Columns.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Conversions/Convertible_To_Columns.enso @@ -1,6 +1,6 @@ from Standard.Base import all -import Standard.Base.Errors.Illegal_Argument.Illegal_Argument import Standard.Base.Data.Java_Json.Jackson_Object +import Standard.Base.Errors.Illegal_Argument.Illegal_Argument ## PRIVATE A special type describing how to convert an object into a set of table diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Conversions/Convertible_To_Rows.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Conversions/Convertible_To_Rows.enso index 85ffe4d41d..bbba208d98 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Conversions/Convertible_To_Rows.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Conversions/Convertible_To_Rows.enso @@ -91,4 +91,4 @@ type Key_Value ## PRIVATE Convertible_To_Columns.from (that:Key_Value) = - Convertible_To_Columns.Value ["Key", "Value"] (k-> if k == "Key" then that.key else that.value) \ No newline at end of file + Convertible_To_Columns.Value ["Key", "Value"] (k-> if k == "Key" then that.key else that.value) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Format.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Format.enso index bc457b137c..25df57910f 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Format.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Format.enso @@ -140,8 +140,8 @@ type Delimited_Format self.clone value_formatter=Nothing ## Creates a clone of this with a changed line ending style. - with_line_endings : Line_Ending_Style|Infer -> Delimited_Format - with_line_endings self (line_endings : Line_Ending_Style | Infer)=Infer = + with_line_endings : Line_Ending_Style | Infer -> Delimited_Format + with_line_endings self (line_endings : Line_Ending_Style | Infer = Infer) = self.clone line_endings=line_endings ## Creates a clone of this with comment parsing enabled. diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Excel/Excel_Workbook.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Excel/Excel_Workbook.enso index 3301079456..5465abf2e8 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Excel/Excel_Workbook.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Excel/Excel_Workbook.enso @@ -34,7 +34,7 @@ type Excel_Workbook - xls_format: Whether to use the old XLS format (default is XLSX). - headers: Whether to use the first row as headers (default is to infer). new : File | Temporary_File -> Boolean -> Boolean | Infer -> Excel_Workbook - new file:(File|Temporary_File) xls_format=False headers=Infer = + new file:(File | Temporary_File) xls_format=False headers=Infer = file_for_errors = if file.is_a Temporary_File then Nothing else file continuation raw_file = diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Extensions/Table_Ref.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Extensions/Table_Ref.enso index 4367878dd5..8ac458467a 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Extensions/Table_Ref.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Extensions/Table_Ref.enso @@ -7,7 +7,7 @@ import project.Data.Column_Ref.Column_Ref import project.Data.Expression.Expression_Error import project.Data.Set_Mode.Set_Mode import project.Data.Table.Table -from project.Errors import Existing_Column, Missing_Column, No_Such_Column +from project.Errors import Existing_Column, Invalid_Value_Type, Missing_Column, No_Such_Column ## PRIVATE A helper type allowing to resolve column references in a context of an underlying table. @@ -23,12 +23,24 @@ type Table_Ref at : Text | Integer -> Any ! No_Such_Column | Index_Out_Of_Bounds at self selector=0 = self.underlying.at selector + ## PRIVATE + Given an expression, create a derived column where each value is the + result of evaluating the expression for the row. + + Arguments: + - expression: The expression to evaluate. + - on_problems: Specifies how to handle non-fatal problems, attaching a + warning by default. + evaluate_expression : Text -> Problem_Behavior -> Any ! No_Such_Column | Invalid_Value_Type | Expression_Error + evaluate_expression self expression on_problems=Report_Warning = self.underlying.evaluate_expression expression on_problems=on_problems + ## PRIVATE Resolve a Column_Ref to a Column, keeping any other values as-is. resolve : Any -> Any ! No_Such_Column | Index_Out_Of_Bounds resolve self value = case value of Column_Ref.Name name -> self.at name Column_Ref.Index index -> self.at index + Column_Ref.Expression expression -> self.evaluate_expression expression _ -> value ## PRIVATE @@ -38,28 +50,26 @@ type Table_Ref resolve_as_column self value = case value of Column_Ref.Name name -> self.at name Column_Ref.Index index -> self.at index + Column_Ref.Expression expression -> self.evaluate_expression expression _ -> self.underlying.make_constant_column value ## PRIVATE Transforms a condition, changing any Column_Ref instances into Column instances resolved in this table. resolve_condition : Filter_Condition -> Filter_Condition resolve_condition self condition = case condition of - Filter_Condition.Equal value -> Filter_Condition.Equal (self.resolve value) - Filter_Condition.Not_Equal value -> Filter_Condition.Not_Equal (self.resolve value) - Filter_Condition.Less value -> Filter_Condition.Less (self.resolve value) - Filter_Condition.Equal_Or_Less value -> Filter_Condition.Equal_Or_Less (self.resolve value) - Filter_Condition.Greater value -> Filter_Condition.Greater (self.resolve value) - Filter_Condition.Equal_Or_Greater value -> Filter_Condition.Equal_Or_Greater (self.resolve value) - Filter_Condition.Between lower upper -> Filter_Condition.Between (self.resolve lower) (self.resolve upper) - Filter_Condition.Equal_Ignore_Case value locale -> Filter_Condition.Equal_Ignore_Case (self.resolve value) locale - Filter_Condition.Starts_With prefix case_sensitivity -> Filter_Condition.Starts_With (self.resolve prefix) case_sensitivity - Filter_Condition.Ends_With prefix case_sensitivity -> Filter_Condition.Ends_With (self.resolve prefix) case_sensitivity - Filter_Condition.Contains prefix case_sensitivity -> Filter_Condition.Contains (self.resolve prefix) case_sensitivity - Filter_Condition.Not_Contains prefix case_sensitivity -> Filter_Condition.Not_Contains (self.resolve prefix) case_sensitivity - Filter_Condition.Like pattern -> Filter_Condition.Like (self.resolve pattern) - Filter_Condition.Not_Like pattern -> Filter_Condition.Not_Like (self.resolve pattern) - Filter_Condition.Is_In values -> Filter_Condition.Is_In (check_is_in_values "Is_In" values) - Filter_Condition.Not_In values -> Filter_Condition.Not_In (check_is_in_values "Not_In" values) + Filter_Condition.Equal value action -> Filter_Condition.Equal (self.resolve value) action + Filter_Condition.Not_Equal value action -> Filter_Condition.Not_Equal (self.resolve value) action + Filter_Condition.Less value action -> Filter_Condition.Less (self.resolve value) action + Filter_Condition.Equal_Or_Less value action -> Filter_Condition.Equal_Or_Less (self.resolve value) action + Filter_Condition.Greater value action -> Filter_Condition.Greater (self.resolve value) action + Filter_Condition.Equal_Or_Greater value action -> Filter_Condition.Equal_Or_Greater (self.resolve value) action + Filter_Condition.Between lower upper action -> Filter_Condition.Between (self.resolve lower) (self.resolve upper) action + Filter_Condition.Equal_Ignore_Case value locale action -> Filter_Condition.Equal_Ignore_Case (self.resolve value) locale action + Filter_Condition.Starts_With prefix case_sensitivity action -> Filter_Condition.Starts_With (self.resolve prefix) case_sensitivity action + Filter_Condition.Ends_With prefix case_sensitivity action -> Filter_Condition.Ends_With (self.resolve prefix) case_sensitivity action + Filter_Condition.Contains prefix case_sensitivity action -> Filter_Condition.Contains (self.resolve prefix) case_sensitivity action + Filter_Condition.Like pattern action -> Filter_Condition.Like (self.resolve pattern) action + Filter_Condition.Is_In values action -> Filter_Condition.Is_In (check_is_in_values "Is_In" values) action _ -> condition ## PRIVATE diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Expand_Objects_Helpers.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Expand_Objects_Helpers.enso index 95611fc928..23a4fb3647 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Expand_Objects_Helpers.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Expand_Objects_Helpers.enso @@ -78,7 +78,7 @@ expand_column (table : Table) (column : Text | Integer) (fields : (Vector Text) # => Table.new [["aaa", [1, 1, 2, 2]], ["bbb", [30, 31, 40, 41]]] @column Widget_Helpers.make_column_name_selector expand_to_rows : Table -> Text | Integer -> Boolean -> Table ! Type_Error | No_Such_Column | Index_Out_Of_Bounds -expand_to_rows table column:(Text|Integer) at_least_one_row=False = if column.is_a Integer then expand_to_rows table (table.at column).name at_least_one_row else +expand_to_rows table column:(Text | Integer) at_least_one_row=False = if column.is_a Integer then expand_to_rows table (table.at column).name at_least_one_row else row_expander : Any -> Vector row_expander value:Convertible_To_Rows = value.to_vector diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Filter_Condition_Helpers.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Filter_Condition_Helpers.enso index 11e77bcefc..f5262c84c1 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Filter_Condition_Helpers.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Filter_Condition_Helpers.enso @@ -13,80 +13,73 @@ from project.Errors import Nothing_Value_In_Filter_Condition It also performs validation and will throw errors if unexpected column types are encountered. -make_filter_column source_column filter_condition on_problems = case filter_condition of - # Equality - Equal value -> - warn_on_nothing_in_comparison filter_condition value <| - Warning.with_suspended source_column source_column-> - Warning.with_suspended value value-> - on_problems.escalate_warnings <| - source_column == value - Not_Equal value -> - warn_on_nothing_in_comparison filter_condition value <| - Warning.with_suspended source_column source_column-> - Warning.with_suspended value value-> - on_problems.escalate_warnings <| - source_column != value - # Nothing - Is_Nothing -> source_column.is_nothing - Not_Nothing -> source_column.is_nothing.not - # Boolean - Is_True -> - Value_Type.expect_boolean source_column <| source_column - Is_False -> source_column.not - # Comparisons - Less value -> - warn_on_nothing_in_comparison filter_condition value <| - source_column < value - Equal_Or_Less value -> - warn_on_nothing_in_comparison filter_condition value <| - source_column <= value - Equal_Or_Greater value -> - warn_on_nothing_in_comparison filter_condition value <| - source_column >= value - Greater value -> - warn_on_nothing_in_comparison filter_condition value <| - source_column > value - Between lower upper -> - warn_on_nothing_in_comparison filter_condition lower <| - warn_on_nothing_in_comparison filter_condition upper <| - source_column.between lower upper - # Text - Equal_Ignore_Case value locale -> - source_column.equals_ignore_case value locale - Starts_With prefix case_sensitivity -> - source_column.starts_with prefix case_sensitivity - Ends_With suffix case_sensitivity -> - source_column.ends_with suffix case_sensitivity - Contains substring case_sensitivity -> - source_column.contains substring case_sensitivity - Not_Contains substring case_sensitivity -> - source_column.contains substring case_sensitivity . not - Is_Empty -> - source_column.is_empty - Not_Empty -> - source_column.is_empty.not - Like pattern -> - source_column.like pattern - Not_Like pattern -> - source_column.like pattern . not - # Numeric - Is_Nan -> source_column.is_nan - Is_Infinite -> source_column.is_infinite - Is_Finite -> - is_infinite_column = source_column.is_infinite - is_nan_column = source_column.is_nan - ## We check is_nan_column for error, since some Database backends may - actually not support it and throw Unsupported_Database_Operation here. - if is_nan_column.is_error then is_infinite_column.not else - (is_infinite_column || is_nan_column).not - # Vector - Is_In values -> - warn_on_nothing_in_comparison_vector filter_condition values <| - source_column.is_in values - Not_In values -> - warn_on_nothing_in_comparison_vector filter_condition values <| - source_column.is_in values . not +make_filter_column source_column filter_condition on_problems = + base_column = case filter_condition of + # Equality + Equal value _ -> + warn_on_nothing_in_comparison filter_condition value <| + Warning.with_suspended source_column source_column-> + Warning.with_suspended value value-> + on_problems.escalate_warnings <| + source_column == value + Not_Equal value _ -> + warn_on_nothing_in_comparison filter_condition value <| + Warning.with_suspended source_column source_column-> + Warning.with_suspended value value-> + on_problems.escalate_warnings <| + source_column != value + # Nothing + Is_Nothing _ -> source_column.is_nothing + Not_Nothing _ -> source_column.is_nothing.not + # Boolean + Is_True _ -> Value_Type.expect_boolean source_column <| source_column + Is_False _ -> Value_Type.expect_boolean source_column <| source_column.not + # Comparisons + Less value _ -> + warn_on_nothing_in_comparison filter_condition value <| + source_column < value + Equal_Or_Less value _ -> + warn_on_nothing_in_comparison filter_condition value <| + source_column <= value + Equal_Or_Greater value _ -> + warn_on_nothing_in_comparison filter_condition value <| + source_column >= value + Greater value _ -> + warn_on_nothing_in_comparison filter_condition value <| + source_column > value + Between lower upper _ -> + warn_on_nothing_in_comparison filter_condition lower <| + warn_on_nothing_in_comparison filter_condition upper <| + source_column.between lower upper + # Text + Equal_Ignore_Case value locale _ -> + source_column.equals_ignore_case value locale + Starts_With prefix case_sensitivity _ -> + source_column.starts_with prefix case_sensitivity + Ends_With suffix case_sensitivity _ -> + source_column.ends_with suffix case_sensitivity + Contains substring case_sensitivity _ -> + source_column.contains substring case_sensitivity + Is_Empty _ -> source_column.is_empty + Not_Empty _ -> source_column.is_empty.not + Like pattern _ -> source_column.like pattern + # Numeric + Is_Nan _ -> source_column.is_nan + Is_Infinite _ -> source_column.is_infinite + Is_Finite _ -> + is_infinite_column = source_column.is_infinite + is_nan_column = source_column.is_nan + ## We check is_nan_column for error, since some Database backends may + actually not support it and throw Unsupported_Database_Operation here. + if is_nan_column.is_error then is_infinite_column.not else + (is_infinite_column || is_nan_column).not + # Vector + Is_In values _ -> + warn_on_nothing_in_comparison_vector filter_condition values <| + source_column.is_in values + if filter_condition.action == Filter_Action.Keep then base_column else + ## We need to fill in the Nothing values and then negate the result. + (base_column.fill_nothing False).not ## Attach a warning if the provided value is `Nothing`. warn_on_nothing_in_comparison : Filter_Condition -> Any -> Any -> Any diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Split_Tokenize.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Split_Tokenize.enso index 71dcd2ef21..77badcd57c 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Split_Tokenize.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Split_Tokenize.enso @@ -17,7 +17,7 @@ split_to_columns table input_column_id delimiter="," column_count=Nothing on_pro Splits a column of text into a set of new rows. See `Table.split_to_rows`. split_to_rows : Table -> Text | Integer -> Text -> Table -split_to_rows table input_column_id:(Text|Integer) delimiter="," = +split_to_rows table input_column_id:(Text | Integer) delimiter="," = column = table.at input_column_id Value_Type.expect_text column <| fan_out_to_rows table column.name (handle_nothing (_.split delimiter)) at_least_one_row=True diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Widget_Helpers.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Widget_Helpers.enso index cde1df60d6..9bf79419ad 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Widget_Helpers.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Widget_Helpers.enso @@ -85,7 +85,8 @@ make_column_name_vector_selector table display=Display.Always = make_column_ref_by_name_selector : Table -> Display -> Widget make_column_ref_by_name_selector table display=Display.Always = col_names_options = table.column_names.map (name -> Option name "(Column_Ref.Name "+name.pretty+")") - Single_Choice values=col_names_options display=display + expression_option = Option "" "(Column_Ref.Expression '["+table.column_names.first+"]')" + Single_Choice values=(col_names_options+[expression_option]) display=display ## PRIVATE Same as `make_column_ref_by_name_selector` but also highlights an option for @@ -94,7 +95,8 @@ make_column_ref_or_text_value_selector : Table -> Display -> Widget make_column_ref_or_text_value_selector table display=Display.Always = col_names_options = table.column_names.map (name -> Option name "(Column_Ref.Name "+name.pretty+")") custom_text_option = Option "'custom text'" "''" - Single_Choice values=(col_names_options+[custom_text_option]) display=display + expression_option = Option "" "(Column_Ref.Expression '["+table.column_names.first+"]')" + Single_Choice values=(col_names_options+[custom_text_option, expression_option]) display=display ## PRIVATE If `column_source` is Nothing, `Column_Ref` options will not be added. @@ -104,7 +106,9 @@ make_fill_default_value_selector column_source=Nothing include_custom_text=False column_source.column_names.map (name -> Option name "(Column_Ref.Name "+name.pretty+")") custom_text_option = if include_custom_text then [Option "'custom text'" "''"] else [] previous_value_option = [Option 'Previous Value' 'Previous_Value'] - Single_Choice values=(previous_value_option+col_names_options+custom_text_option) display=display + default_column = if column_source.is_nothing then '""' else column_source.name.pretty + expression_option = Option "" '(Column_Ref.Expression \''+default_column+'\')' + Single_Choice values=(previous_value_option+col_names_options+custom_text_option+expression_option) display=display ## PRIVATE Make a filter condition selector. @@ -124,7 +128,6 @@ make_filter_condition_selector table display=Display.Always = builder.append (Option "Starts With" fqn+".Starts_With" [["prefix", col_names]]) builder.append (Option "Ends With" fqn+".Ends_With" [["suffix", col_names]]) builder.append (Option "Contains" fqn+".Contains" [["substring", col_names]]) - builder.append (Option "Not Contains" fqn+".Not_Contains" [["substring", col_names]]) builder.append (Option "Is Nothing" fqn+".Is_Nothing") builder.append (Option "Is Not Nothing" fqn+".Not_Nothing") builder.append (Option "Is Finite" fqn+".Is_Finite") @@ -135,9 +138,7 @@ make_filter_condition_selector table display=Display.Always = builder.append (Option "Is Empty" fqn+".Is_Empty") builder.append (Option "Is Not Empty" fqn+".Not_Empty") builder.append (Option "Like" fqn+".Like" [["pattern", col_names]]) - builder.append (Option "Not Like" fqn+".Not_Like" [["pattern", col_names]]) builder.append (Option "Is In" fqn+".Is_In") - builder.append (Option "Not In" fqn+".Not_In") Single_Choice builder.to_vector display=display ## PRIVATE diff --git a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Helpers.enso b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Helpers.enso index ad61cac17d..1541295bc5 100644 --- a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Helpers.enso +++ b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Helpers.enso @@ -5,13 +5,13 @@ from Standard.Base.Runtime import State import project.Clue.Clue import project.Group.Group -import project.Spec_Result.Spec_Result import project.Spec.Spec +import project.Spec_Result.Spec_Result import project.Suite.Suite import project.Suite_Config.Suite_Config -import project.Test_Result.Test_Result -import project.Test_Reporter import project.Test.Test +import project.Test_Reporter +import project.Test_Result.Test_Result run_group_with_filter : Group -> (Regex|Text|Nothing) -> Vector Test_Result run_group_with_filter (group : Group) (spec_filter : (Regex|Text|Nothing)) = @@ -28,7 +28,7 @@ run_group (group : Group) = run_specs_from_group group.specs group -run_specs_from_group : Vector Spec -> Text -> Vector Test_Result +run_specs_from_group : Vector Spec -> Group -> Vector Test_Result run_specs_from_group (specs : Vector Spec) (group : Group) = case specs.is_empty of True -> [] diff --git a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Main.enso b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Main.enso index d5ebf1f293..48d4b805c5 100644 --- a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Main.enso +++ b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Main.enso @@ -1,9 +1,10 @@ +import project.Problems import project.Suite.Suite import project.Test.Test -import project.Problems from project.Extensions import all +export project.Problems export project.Suite.Suite export project.Test.Test -export project.Problems from project.Extensions export all + diff --git a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Suite.enso b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Suite.enso index 6f204313b2..39dafe7354 100644 --- a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Suite.enso +++ b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Suite.enso @@ -28,7 +28,7 @@ type Suite_Builder `specify` method on group builder. See its docs. - pending: Contains a reason for why the test group should be ignored. If Nothing, the test is not ignored. - group : Text -> (Group_Builder -> Any) -> Nothing + group : Text -> (Group_Builder -> Any) -> (Text | Nothing) -> Nothing group self (name:Text) (fn : (Group_Builder -> Any)) (pending : (Text | Nothing) = Nothing) = group_builder = Group_Builder.Impl case pending of @@ -62,7 +62,7 @@ type Suite - group_filter: Filter for group names. - spec_filter: Filter for spec names. - should_exit: If true, executes `System.exit` at the end. - run_with_filter : (Regex | Text | Nothing) -> (Regex | Text | Nothing) -> Nothing + run_with_filter : (Regex | Text | Nothing) -> (Regex | Text | Nothing) -> Boolean -> Nothing run_with_filter self group_filter=Nothing spec_filter=Nothing should_exit=True = config = Suite_Config.from_environment @@ -99,9 +99,11 @@ type Suite False -> failed_tests == 0 + ## Gets the names of all the groups in this suite. group_names self = self.groups.map (_.name) + ## Print the structure of the suite to the console. print_all self = IO.println "Test Suite:" self.groups.each group-> diff --git a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test.enso b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test.enso index 87302034c8..3bc2bec86c 100644 --- a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test.enso +++ b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test.enso @@ -1,14 +1,14 @@ from Standard.Base import all from Standard.Base.Errors.Common import Uninitialized_State from Standard.Base.Runtime import State -import project.Test_Result.Test_Result + import project.Clue.Clue import project.Group.Group -import project.Suite.Suite -import project.Suite.Suite_Builder import project.Spec.Spec import project.Spec_Result.Spec_Result - +import project.Suite.Suite +import project.Suite.Suite_Builder +import project.Test_Result.Test_Result ## Contains only static methods type Test @@ -46,26 +46,27 @@ type Test if err.is_a matcher then Nothing else Test.fail ("Expected a " + matcher.to_text + ", but " + err.to_text + " was thrown instead.") - ## Expect a function to fail with the provided panic. + ## Expect a function to fail with the provided panic. - An alternative API to `expect_panic_with` where the order of arguments is - more natural - as it allows blocks without reordering the arguments. + An alternative API to `expect_panic_with` where the order of arguments is + more natural - as it allows blocks without reordering the arguments. - Arguments: - - matcher: The expected type of the panic thrown by `action`. - - action: The action to evaluate that is expected to fail with a panic. + Arguments: + - matcher: The expected type of the panic thrown by `action`. + - action: The action to evaluate that is expected to fail with a panic. - > Example - Expect that a computation should panic as part of a test. + > Example + Expect that a computation should panic as part of a test. - import Standard.Examples - from Standard.Test import Test + import Standard.Examples + from Standard.Test import Test - example_expect_panic_with = - Test.expect_panic_with Examples.My_Error <| - IO.println 'hello' - Examples.throw_panic - IO.println 'this is not reached' + example_expect_panic_with = + Test.expect_panic_with Examples.My_Error <| + IO.println 'hello' + Examples.throw_panic + + IO.println 'this is not reached' expect_panic : Any -> Any -> Test_Result expect_panic matcher ~action = Test.expect_panic_with action matcher diff --git a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test_Reporter.enso b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test_Reporter.enso index fd9cc93210..44d3fc5a8b 100644 --- a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test_Reporter.enso +++ b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test_Reporter.enso @@ -1,11 +1,11 @@ private from Standard.Base import all -from Standard.Base.Runtime import assert import Standard.Base.Runtime.Context +from Standard.Base.Runtime import assert -import project.Suite_Config.Suite_Config import project.Spec_Result.Spec_Result +import project.Suite_Config.Suite_Config import project.Test.Test import project.Test_Result.Test_Result @@ -74,7 +74,7 @@ print_single_result (test_result : Test_Result) (config : Suite_Config) = groups. - builder: StringBuilder or Nothing. If StringBuilder, then a jUnit XML format is appended to that StringBuilder. -print_report : Vector Test_Result -> Suite_Config -> (StringBuilder|Nothing) -> Nothing +print_report : Vector Test_Result -> Suite_Config -> (StringBuilder | Nothing) -> Nothing print_report (test_results : Vector Test_Result) (config : Suite_Config) (builder : (StringBuilder | Nothing)) = distinct_group_names = test_results.map (_.group_name) . distinct results_per_group = distinct_group_names.fold Map.empty acc-> group_name-> diff --git a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test_Result.enso b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test_Result.enso index dc2d69be97..95a7bb698e 100644 --- a/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test_Result.enso +++ b/distribution/lib/Standard/Test_New/0.0.0-dev/src/Test_Result.enso @@ -5,17 +5,23 @@ import project.Spec_Result.Spec_Result ## A wrapper for `Spec_Result` that contains also name of the group and name of the spec. type Test_Result + ## PRIVATE Impl (group_name : Text) (spec_name : Text) (spec_result : Spec_Result) (time_taken : Duration) + ## PRIVATE + Render as Test_Result as Text. to_text self = "'" + self.group_name + "' '" + self.spec_name + "': " + self.spec_result.to_text - + + ## Was the test pending? is_pending self = self.spec_result.is_pending - + + ## Was the test successful? is_success self = self.spec_result.is_success - + + ## Was the test a failure? is_fail self = self.spec_result.is_fail diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/BoolStorage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/BoolStorage.java index 2ae0b75af6..c01ac1d080 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/BoolStorage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/BoolStorage.java @@ -124,7 +124,7 @@ public final class BoolStorage extends Storage { */ private Storage fillMissingBoolean(boolean arg) { final var newValues = (BitSet) values.clone(); - if (arg) { + if (arg != negated) { newValues.or(isMissing); } else { newValues.andNot(isMissing); diff --git a/test/Base_Tests/src/Data/Json_Spec.enso b/test/Base_Tests/src/Data/Json_Spec.enso index 2eed33769b..0f99328484 100644 --- a/test/Base_Tests/src/Data/Json_Spec.enso +++ b/test/Base_Tests/src/Data/Json_Spec.enso @@ -77,9 +77,9 @@ add_specs suite_builder = Json.parse '{"start": 15, "end": 20, "step": 3}' . into Range . should_equal (Range.Between 15 20 3) group_builder.specify "should be able to deserialize using into for multiple constructors" <| - Json.parse '{"than": 2}' . into Filter_Condition . should_fail_with Illegal_Argument - Json.parse '{"constructor": "Less", "than": 2}' . into Filter_Condition . should_equal (Filter_Condition.Less 2) - Json.parse '{"constructor": "NotARealOne", "than": 2}' . into Filter_Condition . should_fail_with Illegal_Argument + Json.parse '{"than": 2}' . into Statistic . should_fail_with Illegal_Argument + Json.parse '{"constructor": "Skew", "population": true}' . into Statistic . should_equal (Statistic.Skew True) + Json.parse '{"constructor": "NotARealOne", "population": true}' . into Statistic . should_fail_with Illegal_Argument group_builder.specify "should be able to convert a JS_Object into a Map using into" <| Json.parse '{"a": 15, "b": 20, "c": "X", "d": null}' . into Map . should_equal (Map.from_vector [["a", 15], ["b", 20], ["c", "X"], ["d", Nothing]]) diff --git a/test/Base_Tests/src/Data/List_Spec.enso b/test/Base_Tests/src/Data/List_Spec.enso index 99cbf1cfd9..03622e5f33 100644 --- a/test/Base_Tests/src/Data/List_Spec.enso +++ b/test/Base_Tests/src/Data/List_Spec.enso @@ -36,6 +36,7 @@ add_specs suite_builder = suite_builder.group "List" group_builder-> l.any (Filter_Condition.Greater 1) . should_be_true l.any (Filter_Condition.Less 0) . should_be_false + l.any (Filter_Condition.Equal_Or_Greater 1 Filter_Action.Remove) . should_be_false Test.expect_panic_with (l.any "invalid arg") Type_Error @@ -47,6 +48,7 @@ add_specs suite_builder = suite_builder.group "List" group_builder-> l.all (Filter_Condition.Greater 0) . should_be_true l.all (Filter_Condition.Less 3) . should_be_false + l.any (Filter_Condition.Less 0 Filter_Action.Remove) . should_be_true Test.expect_panic_with (l.all "invalid arg") Type_Error @@ -70,6 +72,7 @@ add_specs suite_builder = suite_builder.group "List" group_builder-> empty.find (==1) if_missing=Nothing . should_equal Nothing l.find (Filter_Condition.Greater 1) . should_equal 2 + l.find (Filter_Condition.Less 2 Filter_Action.Remove) . should_equal 2 Test.expect_panic_with (l.find "invalid arg") Type_Error @@ -90,6 +93,7 @@ add_specs suite_builder = suite_builder.group "List" group_builder-> l.index_of 2 start=-4 . should_fail_with Index_Out_Of_Bounds l.index_of (Filter_Condition.Greater 1) . should_equal 1 + l.index_of (Filter_Condition.Less 3 Filter_Action.Remove) . should_equal 2 l.index_of "invalid arg" . should_equal Nothing group_builder.specify "should allow finding the last index of an element in the list with `.last_index_of`" <| @@ -110,6 +114,7 @@ add_specs suite_builder = suite_builder.group "List" group_builder-> ll.last_index_of (Filter_Condition.Greater 1) . should_equal 5 ll.last_index_of (Filter_Condition.Less 3) . should_equal 4 + ll.last_index_of (Filter_Condition.Greater 2 Filter_Action.Remove) . should_equal 4 ll.last_index_of "invalid arg" . should_equal Nothing group_builder.specify "should allow checking if the list is empty with `.is_empty`" <| @@ -129,6 +134,7 @@ add_specs suite_builder = suite_builder.group "List" group_builder-> group_builder.specify "should filter elements by Filter_Condition" <| list = [1, 2, 3, 4, 5].to_list list.filter (Filter_Condition.Greater than=3) . should_equal [4, 5].to_list + list.filter (Filter_Condition.Greater than=3 action=Filter_Action.Remove) . should_equal [1, 2, 3].to_list list.filter (Filter_Condition.Less than=3.5) . should_equal [1, 2, 3].to_list list.filter (Filter_Condition.Equal to=3) . should_equal (List.Cons 3 List.Nil) list.filter (Filter_Condition.Not_Equal to=3) . should_equal [1, 2, 4, 5].to_list @@ -136,14 +142,23 @@ add_specs suite_builder = suite_builder.group "List" group_builder-> list.filter (Filter_Condition.Equal_Or_Less than=(-1)) . should_equal List.Nil list.filter (Filter_Condition.Between 2 4) . should_equal [2, 3, 4].to_list list.filter (Filter_Condition.Is_In [7, 3, 2]) . should_equal [2, 3].to_list - list.filter (Filter_Condition.Not_In [7, 3, 2]) . should_equal [1, 4, 5].to_list - Test.expect_panic Type_Error (list.filter (Filter_Condition.Starts_With "a")) - list.filter Filter_Condition.Is_True . should_equal List.Nil - list.filter Filter_Condition.Is_False . should_equal List.Nil list.filter Filter_Condition.Is_Nothing . should_equal List.Nil list.filter Filter_Condition.Not_Nothing . should_equal list + ## Boolean based filters should fail with type error + Test.expect_panic Type_Error (list.filter Filter_Condition.Is_True) + Test.expect_panic Type_Error (list.filter Filter_Condition.Is_False) + + ## Text based filters should fail with type error + Test.expect_panic Type_Error (list.filter (Filter_Condition.Starts_With "a")) + Test.expect_panic Type_Error (list.filter (Filter_Condition.Ends_With "a")) + Test.expect_panic Type_Error (list.filter (Filter_Condition.Contains "a")) + Test.expect_panic Type_Error (list.filter (Filter_Condition.Equal_Ignore_Case "a")) + Test.expect_panic Type_Error (list.filter (Filter_Condition.Like "a%")) + Test.expect_panic Type_Error (list.filter Filter_Condition.Is_Empty) + Test.expect_panic Type_Error (list.filter Filter_Condition.Not_Empty) + txt = ["aaa", "bbb", "abab", "cccc", "baaa", "ś"].to_list txt.filter (Filter_Condition.Contains "a") . should_equal ["aaa", "abab", "baaa"].to_list txt.filter (Filter_Condition.Contains 'A' Case_Sensitivity.Sensitive) . should_equal [].to_list @@ -151,12 +166,6 @@ add_specs suite_builder = suite_builder.group "List" group_builder-> txt.filter (Filter_Condition.Contains 's\u0301') . should_equal ["ś"].to_list txt.filter (Filter_Condition.Contains 'S\u0301' Case_Sensitivity.Sensitive) . should_equal [].to_list txt.filter (Filter_Condition.Contains 'S\u0301' Case_Sensitivity.Insensitive) . should_equal ["ś"].to_list - txt.filter (Filter_Condition.Not_Contains "a") . should_equal ["bbb", "cccc", "ś"].to_list - txt.filter (Filter_Condition.Not_Contains "A" Case_Sensitivity.Sensitive) . should_equal ["aaa", "bbb", "abab", "cccc", "baaa", "ś"].to_list - txt.filter (Filter_Condition.Not_Contains "A" Case_Sensitivity.Insensitive) . should_equal ["bbb", "cccc", "ś"].to_list - txt.filter (Filter_Condition.Not_Contains 's\u0301') . should_equal ["aaa", "bbb", "abab", "cccc", "baaa"].to_list - txt.filter (Filter_Condition.Not_Contains 'S\u0301' Case_Sensitivity.Sensitive) . should_equal ["aaa", "bbb", "abab", "cccc", "baaa", "ś"].to_list - txt.filter (Filter_Condition.Not_Contains 'S\u0301' Case_Sensitivity.Insensitive) . should_equal ["aaa", "bbb", "abab", "cccc", "baaa"].to_list txt.filter (Filter_Condition.Starts_With "a") . should_equal ["aaa", "abab"].to_list txt.filter (Filter_Condition.Starts_With "A" Case_Sensitivity.Sensitive) . should_equal [].to_list txt.filter (Filter_Condition.Starts_With "A" Case_Sensitivity.Insensitive) . should_equal ["aaa", "abab"].to_list @@ -173,7 +182,6 @@ add_specs suite_builder = suite_builder.group "List" group_builder-> ["abab", "aaabaaaa", "ba"].to_list.filter (Filter_Condition.Like "ba") . should_equal (List.Cons "ba" List.Nil) ["abab", "aaabaaaa"].to_list.filter (Filter_Condition.Like "_ba_") . should_equal ["abab"].to_list ["abab", "aaabaaaa"].to_list.filter (Filter_Condition.Like "%ba__%") . should_equal ["aaabaaaa"].to_list - ["abab", "aaabaaaa"].to_list.filter (Filter_Condition.Not_Like "%ba%") . should_equal List.Nil mixed = [1, Nothing, "b"].to_list mixed.filter Filter_Condition.Is_Nothing . should_equal (List.Cons Nothing List.Nil) @@ -192,6 +200,10 @@ add_specs suite_builder = suite_builder.group "List" group_builder-> r2.first . should_equal (List.Cons 2 (List.Cons 3 List.Nil)) r2.second . should_equal (List.Cons 1 List.Nil) + r2r = l.partition (Filter_Condition.Greater than=1 action=Filter_Action.Remove) + r2r.second . should_equal (List.Cons 2 (List.Cons 3 List.Nil)) + r2r.first . should_equal (List.Cons 1 List.Nil) + r3 = l.partition (Filter_Condition.Equal_Or_Greater than=10) r3.first . should_equal List.Nil r3.second . should_equal l diff --git a/test/Base_Tests/src/Data/Range_Spec.enso b/test/Base_Tests/src/Data/Range_Spec.enso index 331a74da90..657bd768a7 100644 --- a/test/Base_Tests/src/Data/Range_Spec.enso +++ b/test/Base_Tests/src/Data/Range_Spec.enso @@ -152,30 +152,48 @@ add_specs suite_builder = suite_builder.group "Range" group_builder-> group_builder.specify "should filter elements by Filter_Condition" <| range = 1.up_to 6 - range.filter (Filter_Condition.Greater than=3) . should_equal [4, 5] - range.filter (Filter_Condition.Less than=3.5) . should_equal [1, 2, 3] - range.filter (Filter_Condition.Equal to=3) . should_equal [3] - range.filter (Filter_Condition.Not_Equal to=3) . should_equal [1, 2, 4, 5] - range.filter (Filter_Condition.Equal_Or_Greater than=3) . should_equal [3, 4, 5] - range.filter (Filter_Condition.Equal_Or_Less than=(-1)) . should_equal [] + range.filter (Filter_Condition.Greater 3) . should_equal [4, 5] + range.filter (Filter_Condition.Greater 3 Filter_Action.Remove) . should_equal [1, 2, 3] + range.filter (Filter_Condition.Less 3.5) . should_equal [1, 2, 3] + range.filter (Filter_Condition.Less 3.5 Filter_Action.Remove) . should_equal [4, 5] + range.filter (Filter_Condition.Equal 3) . should_equal [3] + range.filter (Filter_Condition.Equal 3 Filter_Action.Remove) . should_equal [1, 2, 4, 5] + range.filter (Filter_Condition.Not_Equal 3) . should_equal [1, 2, 4, 5] + range.filter (Filter_Condition.Not_Equal 3 Filter_Action.Remove) . should_equal [3] + range.filter (Filter_Condition.Equal_Or_Greater 3) . should_equal [3, 4, 5] + range.filter (Filter_Condition.Equal_Or_Greater 3 Filter_Action.Remove) . should_equal [1, 2] + range.filter (Filter_Condition.Equal_Or_Less (-1)) . should_equal [] + range.filter (Filter_Condition.Equal_Or_Less (-1) Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5] range.filter (Filter_Condition.Between 2 4) . should_equal [2, 3, 4] range.filter (Filter_Condition.Between 2.1 4.5) . should_equal [3, 4] + range.filter (Filter_Condition.Between 2 4 Filter_Action.Remove) . should_equal [1, 5] range.filter (Filter_Condition.Is_In [7, 3, 2]) . should_equal [2, 3] - range.filter (Filter_Condition.Not_In [7, 3, 2]) . should_equal [1, 4, 5] + range.filter (Filter_Condition.Is_In [7, 3, 2] Filter_Action.Remove) . should_equal [1, 4, 5] - Test.expect_panic Type_Error (range.filter (Filter_Condition.Starts_With "a")) - Test.expect_panic Type_Error (range.filter (Filter_Condition.Equal_Ignore_Case "a")) - range.filter (Filter_Condition.Like "a%") . should_fail_with Type_Error - range.filter (Filter_Condition.Not_Like "a_") . should_fail_with Type_Error range.filter Filter_Condition.Is_Nan . should_equal [] + range.filter (Filter_Condition.Is_Nan Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5] range.filter Filter_Condition.Is_Infinite . should_equal [] + range.filter (Filter_Condition.Is_Infinite Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5] range.filter Filter_Condition.Is_Finite . should_equal [1, 2, 3, 4, 5] - range.filter Filter_Condition.Is_True . should_equal [] - range.filter Filter_Condition.Is_False . should_equal [] + range.filter (Filter_Condition.Is_Finite Filter_Action.Remove) . should_equal [] + range.filter Filter_Condition.Is_Nothing . should_equal [] + range.filter (Filter_Condition.Is_Nothing Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5] range.filter Filter_Condition.Not_Nothing . should_equal [1, 2, 3, 4, 5] - range.filter Filter_Condition.Is_Empty . should_equal [] - range.filter Filter_Condition.Not_Empty . should_equal [1, 2, 3, 4, 5] + range.filter (Filter_Condition.Not_Nothing Filter_Action.Remove) . should_equal [] + + ## Text based filters should fail with type error + Test.expect_panic Type_Error (range.filter (Filter_Condition.Starts_With "a")) + Test.expect_panic Type_Error (range.filter (Filter_Condition.Ends_With "a")) + Test.expect_panic Type_Error (range.filter (Filter_Condition.Contains "a")) + Test.expect_panic Type_Error (range.filter (Filter_Condition.Equal_Ignore_Case "a")) + Test.expect_panic Type_Error (range.filter (Filter_Condition.Like "a%")) + Test.expect_panic Type_Error (range.filter Filter_Condition.Is_Empty) + Test.expect_panic Type_Error (range.filter Filter_Condition.Not_Empty) + + ## Boolean based filters should fail with type error + Test.expect_panic Type_Error (range.filter Filter_Condition.Is_True) + Test.expect_panic Type_Error (range.filter Filter_Condition.Is_False) group_builder.specify "should allow to partition its elements" <| elements = 0.up_to 10 @@ -183,14 +201,19 @@ add_specs suite_builder = suite_builder.group "Range" group_builder-> r1.first . should_equal [0, 2, 4, 6, 8] r1.second . should_equal [1, 3, 5, 7, 9] - r2 = elements.partition (Filter_Condition.Greater than=3) + r2 = elements.partition (Filter_Condition.Greater 3) r2.first . should_equal [4, 5, 6, 7, 8, 9] r2.second . should_equal [0, 1, 2, 3] + r2r = elements.partition (Filter_Condition.Greater 3 Filter_Action.Remove) + r2r.first . should_equal [0, 1, 2, 3] + r2r.second . should_equal [4, 5, 6, 7, 8, 9] + group_builder.specify "should allow iteration" <| vec_mut = Vector.new_builder 1.up_to 6 . each (i -> vec_mut.append i) vec_mut.to_vector . should_equal [1, 2, 3, 4, 5] + group_builder.specify "should allow iteration, with error propagation and early exit" <| vec_mut = Vector.new_builder result = 1.up_to 6 . each_propagate i-> @@ -198,6 +221,7 @@ add_specs suite_builder = suite_builder.group "Range" group_builder-> vec_mut.append i result . should_fail_with Illegal_Argument vec_mut.to_vector . should_equal [1, 2] + group_builder.specify "should allow iteration with index" <| vec_mut = Vector.new_builder 5.up_to 8 . each_with_index ix-> elem-> @@ -208,36 +232,46 @@ add_specs suite_builder = suite_builder.group "Range" group_builder-> 5.up_to 10 . with_step 2 . each_with_index ix-> elem-> vec_mut_2.append (Pair.new ix elem) vec_mut_2.to_vector . should_equal [Pair.new 0 5, Pair.new 1 7, Pair.new 2 9] + group_builder.specify "should be able to be folded" <| 1.up_to 6 . fold 0 (+) . should_equal 15 1.up_to 1 . fold 123 (+) . should_equal 123 + group_builder.specify "should be able to perform a running fold" <| 1.up_to 6 . running_fold 0 (+) . should_equal [1, 3, 6, 10, 15] 1.up_to 1 . running_fold 123 (+) . should_equal [] + group_builder.specify "should be able to be reduced" <| 1.up_to 6 . reduce (+) . should_equal 15 1.up_to 6 . with_step 2 . reduce (+) . should_equal 9 1.up_to 1 . reduce (+) . should_fail_with Empty_Error 1.up_to 1 . reduce (+) 0 . should_equal 0 + group_builder.specify "should check all" <| 1.up_to 10 . all (> 0) . should_be_true 1.up_to 10 . all (< 0) . should_be_false 1.up_to 10 . all (Filter_Condition.Greater 10) . should_be_false + 1.up_to 10 . all (Filter_Condition.Greater 10 Filter_Action.Remove) . should_be_true Test.expect_panic_with (1.up_to 10 . all "invalid arg") Type_Error + group_builder.specify "should check any" <| 1.up_to 10 . any (> 5) . should_be_true 1.up_to 10 . any (> 10) . should_be_false 1.up_to 10 . any (Filter_Condition.Greater 5) . should_be_true + 1.up_to 10 . any (Filter_Condition.Equal_Or_Greater 1 Filter_Action.Remove) . should_be_false Test.expect_panic_with (1.up_to 10 . any "invalid arg") Type_Error + group_builder.specify "should find elements" <| 1.up_to 10 . find (> 5) . should_equal 6 - 1.up_to 10 . find (Filter_Condition.Greater than=5) . should_equal 6 + 1.up_to 10 . find (Filter_Condition.Greater 5) . should_equal 6 + 1.up_to 10 . find (Filter_Condition.Equal_Or_Less 3 Filter_Action.Remove) . should_equal 4 1.up_to 10 . find (> 10) . should_be_a Nothing 1.up_to 10 . find (v-> v%4 == 0) start=6 . should_equal 8 1.up_to 10 . find (< 5) start=6 . should_be_a Nothing 1.up_to 10 . find (< 5) start=10 . should_fail_with Index_Out_Of_Bounds 1.up_to 10 . find (< 5) start=10 . catch . should_equal (Index_Out_Of_Bounds.Error 10 10) Test.expect_panic_with (1.up_to 10 . find "invalid arg") Type_Error + group_builder.specify "should find index of elements" <| 1.up_to 10 . index_of (> 5) . should_equal 5 1.up_to 10 . index_of 7 . should_equal 6 @@ -253,9 +287,11 @@ add_specs suite_builder = suite_builder.group "Range" group_builder-> 1.up_to 10 . index_of (< 5) start=10 . catch . should_equal (Index_Out_Of_Bounds.Error 10 10) 1.up_to 10 . index_of (< 5) start=-1 . should_equal Nothing 1.up_to 10 . index_of (< 5) start=-9 . should_equal 0 - 1.up_to 10 . index_of (Filter_Condition.Greater than=5) . should_equal 5 + 1.up_to 10 . index_of (Filter_Condition.Greater 5) . should_equal 5 + 1.up_to 10 . index_of (Filter_Condition.Less 5 Filter_Action.Remove) . should_equal 4 1.up_to 10 . index_of "invalid arg" . should_fail_with Illegal_Argument 1.up_to 10 . index_of 2.5 . should_fail_with Illegal_Argument + group_builder.specify "should find last index of elements" <| 1.up_to 10 . last_index_of (> 5) . should_equal 8 1.up_to 10 . last_index_of 7 . should_equal 6 @@ -271,11 +307,14 @@ add_specs suite_builder = suite_builder.group "Range" group_builder-> 1.up_to 10 . last_index_of (< 5) start=9 . should_fail_with Index_Out_Of_Bounds 1.up_to 10 . last_index_of (< 5) start=10 . catch . should_equal (Index_Out_Of_Bounds.Error 10 9) 1.up_to 10 . last_index_of (< 5) start=-10 . should_fail_with Index_Out_Of_Bounds - 1.up_to 10 . last_index_of (Filter_Condition.Greater than=5) . should_equal 8 + 1.up_to 10 . last_index_of (Filter_Condition.Greater 5) . should_equal 8 + 1.up_to 10 . last_index_of (Filter_Condition.Greater 5 Filter_Action.Remove) . should_equal 4 1.up_to 10 . last_index_of "invalid arg" . should_fail_with Illegal_Argument 1.up_to 10 . last_index_of 2.5 . should_fail_with Illegal_Argument + group_builder.specify "should allow conversion to vector" <| 1.up_to 6 . to_vector . should_equal [1, 2, 3, 4, 5] + group_builder.specify "should allow reversing" <| 1.up_to 6 . reverse . should_equal (5.down_to 0) 5.down_to 0 . reverse . should_equal (1.up_to 6) @@ -297,7 +336,6 @@ add_specs suite_builder = suite_builder.group "Range" group_builder-> 5.down_to 0 . contains 2.5 . should_fail_with Illegal_Argument 5.down_to 0 . contains 3.0 . should_fail_with Illegal_Argument - verify_contains range expected unexpected = expected.each x-> if range.contains x . not then @@ -305,10 +343,12 @@ add_specs suite_builder = suite_builder.group "Range" group_builder-> unexpected.each x-> if range.contains x then Test.fail "Range "+range.to_text+" unexpectedly contained "+x.to_text+"." + build_with_each range = builder = Vector.new_builder range.each builder.append builder.to_vector + group_builder.specify "should behave correctly if it is empty" <| check_empty_range r = r.is_empty . should_be_true diff --git a/test/Base_Tests/src/Data/Vector_Spec.enso b/test/Base_Tests/src/Data/Vector_Spec.enso index 61b7bef0b0..9e5515c971 100644 --- a/test/Base_Tests/src/Data/Vector_Spec.enso +++ b/test/Base_Tests/src/Data/Vector_Spec.enso @@ -164,6 +164,7 @@ type_spec suite_builder name alter = suite_builder.group name group_builder-> vec.any (ix -> ix < 0) . should_be_false vec.any (Filter_Condition.Greater 0) . should_be_true + vec.any (Filter_Condition.Greater 0 Filter_Action.Remove) . should_be_false vec.any (Filter_Condition.Less 3) . should_be_true vec.any (Filter_Condition.Less 0) . should_be_false @@ -175,6 +176,7 @@ type_spec suite_builder name alter = suite_builder.group name group_builder-> vec.all (ix -> ix < 5) . should_be_false vec.all (Filter_Condition.Greater 0) . should_be_true + vec.all (Filter_Condition.Greater 0 Filter_Action.Remove) . should_be_false vec.all (Filter_Condition.Less 3) . should_be_false Test.expect_panic_with matcher=Type_Error (vec.all "invalid argument") @@ -203,55 +205,84 @@ type_spec suite_builder name alter = suite_builder.group name group_builder-> vec.filter (x -> x < 0) . should_equal [] vec.filter (x -> if x == 2 then Error.throw <| My_Error.Error "foo" else True) . should_fail_with My_Error - group_builder.specify "should filter elements by Filter_Condition" <| + group_builder.specify "should filter numerical elements by Filter_Condition" <| vec = alter [1, 2, 3, 4, 5] - vec.filter (Filter_Condition.Greater than=3) . should_equal [4, 5] - vec.filter (Filter_Condition.Less than=3.5) . should_equal [1, 2, 3] - vec.filter (Filter_Condition.Equal to=3) . should_equal [3] - vec.filter (Filter_Condition.Equal to=3.0) . should_equal [3] - vec.filter (Filter_Condition.Equal to=3.1) . should_equal [] - vec.filter (Filter_Condition.Not_Equal to=3) . should_equal [1, 2, 4, 5] - vec.filter (Filter_Condition.Equal_Or_Greater than=3) . should_equal [3, 4, 5] - vec.filter (Filter_Condition.Equal_Or_Less than=(-1)) . should_equal [] + vec.filter (Filter_Condition.Greater 3) . should_equal [4, 5] + vec.filter (Filter_Condition.Greater 3 Filter_Action.Remove) . should_equal [1, 2, 3] + vec.filter (Filter_Condition.Less 3.5) . should_equal [1, 2, 3] + vec.filter (Filter_Condition.Less 3.5 Filter_Action.Remove) . should_equal [4, 5] + vec.filter (Filter_Condition.Equal 3) . should_equal [3] + vec.filter (Filter_Condition.Equal 3 Filter_Action.Remove) . should_equal [1, 2, 4, 5] + vec.filter (Filter_Condition.Not_Equal 3) . should_equal [1, 2, 4, 5] + vec.filter (Filter_Condition.Not_Equal 3 Filter_Action.Remove) . should_equal [3] + vec.filter (Filter_Condition.Equal_Or_Greater 3) . should_equal [3, 4, 5] + vec.filter (Filter_Condition.Equal_Or_Greater 3 Filter_Action.Remove) . should_equal [1, 2] + vec.filter (Filter_Condition.Equal_Or_Less (-1)) . should_equal [] + vec.filter (Filter_Condition.Equal_Or_Less (-1) Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5] vec.filter (Filter_Condition.Between 2 4) . should_equal [2, 3, 4] vec.filter (Filter_Condition.Between 2.1 4.5) . should_equal [3, 4] + vec.filter (Filter_Condition.Between 2 4 Filter_Action.Remove) . should_equal [1, 5] vec.filter (Filter_Condition.Is_In [7, 3, 2, 2, 2]) . should_equal [2, 3] - vec.filter (Filter_Condition.Is_In []) . should_equal [] - vec.filter (Filter_Condition.Not_In [7, 3, 2, 2]) . should_equal [1, 4, 5] + vec.filter (Filter_Condition.Is_In [7, 3, 2] Filter_Action.Remove) . should_equal [1, 4, 5] - Test.expect_panic_with (vec.filter (Filter_Condition.Starts_With "a")) Type_Error - vec.filter Filter_Condition.Is_True . should_equal [] - vec.filter Filter_Condition.Is_False . should_equal [] vec.filter Filter_Condition.Is_Nothing . should_equal [] - vec.filter Filter_Condition.Not_Nothing . should_equal vec + vec.filter (Filter_Condition.Is_Nothing Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5] + vec.filter Filter_Condition.Not_Nothing . should_equal [1, 2, 3, 4, 5] + vec.filter (Filter_Condition.Not_Nothing Filter_Action.Remove) . should_equal [] - txtvec = ["aaa", "bbb", "abab", "cccc", "baaa", "ś"] + numvec = alter [1, 2.5, Number.nan, Number.positive_infinity, Number.negative_infinity, 0] + # We need to use to_text because NaN!=NaN + numvec.filter Filter_Condition.Is_Nan . map .to_text . should_equal ["NaN"] + numvec.filter (Filter_Condition.Is_Nan Filter_Action.Remove) . should_equal [1, 2.5, Number.positive_infinity, Number.negative_infinity, 0] + numvec.filter Filter_Condition.Is_Infinite . should_equal [Number.positive_infinity, Number.negative_infinity] + numvec.filter (Filter_Condition.Is_Infinite Filter_Action.Remove) . length . should_equal 4 + numvec.filter Filter_Condition.Is_Finite . should_equal [1, 2.5, 0] + numvec.filter (Filter_Condition.Is_Finite Filter_Action.Remove) . length . should_equal 3 + + ## Text based filters should fail with type error + Test.expect_panic Type_Error (vec.filter (Filter_Condition.Starts_With "a")) + Test.expect_panic Type_Error (vec.filter (Filter_Condition.Ends_With "a")) + Test.expect_panic Type_Error (vec.filter (Filter_Condition.Contains "a")) + Test.expect_panic Type_Error (vec.filter (Filter_Condition.Equal_Ignore_Case "a")) + Test.expect_panic Type_Error (vec.filter (Filter_Condition.Like "a%")) + Test.expect_panic Type_Error (vec.filter Filter_Condition.Is_Empty) + Test.expect_panic Type_Error (vec.filter Filter_Condition.Not_Empty) + + ## Boolean based filters should fail with type error + Test.expect_panic Type_Error (vec.filter Filter_Condition.Is_True) + Test.expect_panic Type_Error (vec.filter Filter_Condition.Is_False) + + group_builder.specify "should filter text elements by Filter_Condition" <| + txtvec = alter ["aaa", "bbb", "abab", "cccc", "baaa", "ś"] txtvec.filter (Filter_Condition.Contains "a") . should_equal ["aaa", "abab", "baaa"] + txtvec.filter (Filter_Condition.Contains "a" action=Filter_Action.Remove) . should_equal ["bbb", "cccc", "ś"] txtvec.filter (Filter_Condition.Contains 'A' Case_Sensitivity.Sensitive) . should_equal [] txtvec.filter (Filter_Condition.Contains 'A' Case_Sensitivity.Insensitive) . should_equal ["aaa", "abab", "baaa"] txtvec.filter (Filter_Condition.Contains 's\u0301') . should_equal ["ś"] txtvec.filter (Filter_Condition.Contains 'S\u0301' Case_Sensitivity.Sensitive) . should_equal [] txtvec.filter (Filter_Condition.Contains 'S\u0301' Case_Sensitivity.Insensitive) . should_equal ["ś"] - txtvec.filter (Filter_Condition.Not_Contains "a") . should_equal ["bbb", "cccc", "ś"] - txtvec.filter (Filter_Condition.Not_Contains "A" Case_Sensitivity.Sensitive) . should_equal ["aaa", "bbb", "abab", "cccc", "baaa", "ś"] - txtvec.filter (Filter_Condition.Not_Contains "A" Case_Sensitivity.Insensitive) . should_equal ["bbb", "cccc", "ś"] - txtvec.filter (Filter_Condition.Not_Contains 's\u0301') . should_equal ["aaa", "bbb", "abab", "cccc", "baaa"] - txtvec.filter (Filter_Condition.Not_Contains 'S\u0301' Case_Sensitivity.Sensitive) . should_equal ["aaa", "bbb", "abab", "cccc", "baaa", "ś"] - txtvec.filter (Filter_Condition.Not_Contains 'S\u0301' Case_Sensitivity.Insensitive) . should_equal ["aaa", "bbb", "abab", "cccc", "baaa"] + Test.expect_panic_with (txtvec.filter (Filter_Condition.Contains 42)) Unsupported_Argument_Types txtvec.filter (Filter_Condition.Starts_With "a") . should_equal ["aaa", "abab"] + txtvec.filter (Filter_Condition.Starts_With "a" action=Filter_Action.Remove) . should_equal ["bbb", "cccc", "baaa", "ś"] txtvec.filter (Filter_Condition.Starts_With "A" Case_Sensitivity.Sensitive) . should_equal [] txtvec.filter (Filter_Condition.Starts_With "A" Case_Sensitivity.Insensitive) . should_equal ["aaa", "abab"] + Test.expect_panic_with (txtvec.filter (Filter_Condition.Starts_With 42)) Unsupported_Argument_Types txtvec.filter (Filter_Condition.Ends_With "a") . should_equal ["aaa", "baaa"] + txtvec.filter (Filter_Condition.Ends_With "a" action=Filter_Action.Remove) . should_equal ["bbb", "abab", "cccc", "ś"] txtvec.filter (Filter_Condition.Ends_With "A" Case_Sensitivity.Sensitive) . should_equal [] txtvec.filter (Filter_Condition.Ends_With "A" Case_Sensitivity.Insensitive) . should_equal ["aaa", "baaa"] + Test.expect_panic_with (txtvec.filter (Filter_Condition.Ends_With 42)) Unsupported_Argument_Types + txtvec.filter (Filter_Condition.Less than="a") . should_equal [] txtvec.filter (Filter_Condition.Greater than="b") . should_equal ["bbb", "cccc", "baaa", "ś"] txtvec.filter (Filter_Condition.Between "b" "c") . should_equal ["bbb", "baaa"] - Test.expect_panic_with (txtvec.filter (Filter_Condition.Starts_With 42)) Unsupported_Argument_Types - txtvec.filter Filter_Condition.Is_True . should_equal [] txtvec.filter (Filter_Condition.Is_In [1, 2]) . should_equal [] txtvec.filter (Filter_Condition.Is_In ["bbb", 's\u0301', "bbb", "FOOBAR"]) . should_equal ["bbb", "ś"] + ## Boolean based filters should fail with type error + Test.expect_panic Type_Error (txtvec.filter Filter_Condition.Is_True) + Test.expect_panic Type_Error (txtvec.filter Filter_Condition.Is_False) + alter ["", Nothing, " ", "a"] . filter (Filter_Condition.Is_Empty) . should_equal ["", Nothing] alter ["", Nothing, " ", "a"] . filter (Filter_Condition.Not_Empty) . should_equal [" ", "a"] alter ["abab", "aaabaaaa", "ba"] . filter (Filter_Condition.Like "ba") . should_equal ["ba"] @@ -259,18 +290,23 @@ type_spec suite_builder name alter = suite_builder.group name group_builder-> alter ["abab", "aaabaaaa"] . filter (Filter_Condition.Like "%ba__%") . should_equal ["aaabaaaa"] alter ["aaaa", "bbbbb", "[ab]aaaa"] . filter (Filter_Condition.Like "[ab]%") . should_equal ["[ab]aaaa"] alter ["f.txt", "abc.*"] . filter (Filter_Condition.Like "%.*") . should_equal ["abc.*"] - alter ["f.txt", "abc.*"] . filter (Filter_Condition.Not_Like "%.*") . should_equal ["f.txt"] txt2 = alter ['a\n\n\n', 'a\n', 'a\n\n\nb', 'a\nb', 'caa\nbb'] txt2.filter (Filter_Condition.Like 'a_') . should_equal ['a\n'] + txt2.filter (Filter_Condition.Like 'a_' Filter_Action.Remove) . should_equal ['a\n\n\n', 'a\n\n\nb', 'a\nb', 'caa\nbb'] txt2.filter (Filter_Condition.Like 'a%') . should_equal ['a\n\n\n', 'a\n', 'a\n\n\nb', 'a\nb'] txt2.filter (Filter_Condition.Like 'a_b') . should_equal ['a\nb'] txt2.filter (Filter_Condition.Like '%\nb') . should_equal ['a\n\n\nb', 'a\nb'] + ## NUmber based filters should fail with type error + Test.expect_panic Type_Error (txtvec.filter Filter_Condition.Is_Nan) + Test.expect_panic Type_Error (txtvec.filter Filter_Condition.Is_Infinite) + Test.expect_panic Type_Error (txtvec.filter Filter_Condition.Is_Finite) + + group_builder.specify "should filter unicode text elements by Filter_Condition" <| txt3 = alter ['śnieg', 's\u0301nieg', 'X', 'połać', 'połac\u0301'] txt3.filter (Filter_Condition.Starts_With 'ś') . should_equal ['śnieg', 's\u0301nieg'] txt3.filter (Filter_Condition.Contains 'ś') . should_equal ['śnieg', 's\u0301nieg'] - txt3.filter (Filter_Condition.Not_Contains 'ś') . should_equal ['X', 'połać', 'połac\u0301'] txt3.filter (Filter_Condition.Ends_With 'ś') . should_equal [] txt3.filter (Filter_Condition.Ends_With 'ć') . should_equal ['połać', 'połac\u0301'] ## There is a bug with Java Regex in Unicode normalized mode (CANON_EQ) with quoting. @@ -284,19 +320,12 @@ type_spec suite_builder name alter = suite_builder.group name group_builder-> txt4.filter (Filter_Condition.Equal_Ignore_Case 's\u0301') . should_equal ['ś', 'Ś'] txt4.filter (Filter_Condition.Equal_Ignore_Case 'FFI') . should_equal ['ffi'] + group_builder.specify "should filter mixed elements by Filter_Condition" <| mixed = alter [1, Nothing, "b"] mixed.filter Filter_Condition.Is_Nothing . should_equal [Nothing] mixed.filter Filter_Condition.Not_Nothing . should_equal [1, "b"] - mixed.filter Filter_Condition.Is_Empty . should_equal [Nothing] - mixed.filter Filter_Condition.Not_Empty . should_equal [1, "b"] - - numvec = alter [1, 2.5, Number.nan, Number.positive_infinity, Number.negative_infinity, 0] - # We need to use to_text because NaN!=NaN - numvec.filter Filter_Condition.Is_Nan . map .to_text . should_equal ["NaN"] - numvec.filter Filter_Condition.Is_Infinite . should_equal [Number.positive_infinity, Number.negative_infinity] - numvec.filter Filter_Condition.Is_Finite . should_equal [1, 2.5, 0] - - Test.expect_panic Type_Error (txtvec.filter Filter_Condition.Is_Finite) + Test.expect_panic Type_Error (mixed.filter Filter_Condition.Is_Empty) + Test.expect_panic Type_Error (mixed.filter Filter_Condition.Not_Empty) (alter [2, "a"]).filter (Filter_Condition.Greater 1) . should_fail_with Incomparable_Values @@ -320,8 +349,6 @@ type_spec suite_builder name alter = suite_builder.group name group_builder-> txtvec.filter (Filter_Condition.Starts_With "a") . should_equal ["abab"] txtvec.filter (Filter_Condition.Ends_With "a") . should_equal ["baaa"] txtvec.filter (Filter_Condition.Like "b%a") . should_equal ["baaa"] - # Nothing is not included in the negation either - txtvec.filter (Filter_Condition.Not_Like "b%a") . should_equal ["abab", "cccc", "BAAA"] (alter ["a", 2, Nothing, 3]).filter (Filter_Condition.Is_In [Nothing, 2]) . should_equal [2, Nothing] @@ -340,11 +367,12 @@ type_spec suite_builder name alter = suite_builder.group name group_builder-> (alter [1, 2, 3, 4] . filter_with_index ix-> _-> if ix == 1 then Error.throw <| My_Error.Error "foo" else True) . should_fail_with My_Error group_builder.specify "should partition elements" <| - vec = alter [1, 2, 3, 4, 5] - vec.partition (x -> x % 2 == 0) . should_equal <| Pair.new [2, 4] [1, 3, 5] + vec = alter [1, 2, 3, 4, 5, Nothing] + vec.partition (x -> x.is_nothing.not && x%2==0) . should_equal <| Pair.new [2, 4] [1, 3, 5, Nothing] (vec . partition x-> if x == 1 then Error.throw <| My_Error.Error "foo" else True) . should_fail_with My_Error - vec.partition (Filter_Condition.Between 2 4) . should_equal <| Pair.new [2, 3, 4] [1, 5] + vec.partition (Filter_Condition.Between 2 4) . should_equal <| Pair.new [2, 3, 4] [1, 5, Nothing] + vec.partition (Filter_Condition.Between 2 4 Filter_Action.Remove) . should_equal <| Pair.new [1, 5, Nothing] [2, 3, 4] Test.expect_panic_with matcher=Type_Error (vec.partition "invalid arg") @@ -462,6 +490,7 @@ type_spec suite_builder name alter = suite_builder.group name group_builder-> input.find (x -> x%3 == 3) if_missing=Nothing . should_equal Nothing input.find (Filter_Condition.Greater 5) . should_equal 6 + input.find (Filter_Condition.Less 5 Filter_Action.Remove) . should_equal 5 Test.expect_panic_with matcher=Type_Error (input.find "invalid arg") alter ["b", "A", "c"] . find (Filter_Condition.Equal_Ignore_Case "a") . should_equal "A" @@ -480,6 +509,7 @@ type_spec suite_builder name alter = suite_builder.group name group_builder-> input.index_of 2 start=-11 . should_fail_with Index_Out_Of_Bounds input.index_of (Filter_Condition.Equal_Or_Greater 2) . should_equal 1 + input.index_of (Filter_Condition.Less 3 Filter_Action.Remove) . should_equal 2 input.index_of "text" . should_equal Nothing group_builder.specify "should allow finding the last index of a value" <| @@ -494,6 +524,7 @@ type_spec suite_builder name alter = suite_builder.group name group_builder-> input.last_index_of 2 start=-11 . should_fail_with Index_Out_Of_Bounds input.last_index_of (Filter_Condition.Equal_Or_Greater 2) . should_equal input.length-2 + input.last_index_of (Filter_Condition.Less 3 Filter_Action.Remove) . should_equal 6 input.last_index_of "text" . should_equal Nothing group_builder.specify "should be convertible to a list" <| diff --git a/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso index 0a4d62fc7c..2d91126f82 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso @@ -596,6 +596,18 @@ add_specs suite_builder setup = actual.at "col1" . to_vector . should_equal [1000, 200, 1000, 400, 500, 1000] actual.column_names . should_equal ["col0", "col_between", "col1", "def"] + group_builder.specify "fill_nothing should cope with notted boolean columns" <| + t = table_builder [["col0", [True, False, Nothing, True]], ["colTrue", [True, True, True, True]], ["colFalse", [False, False, False, False]]] + s = t.set (t.at "col0" . not) "col1" + s_false = s.fill_nothing ["col1"] False + s_false.at "col1" . to_vector . should_equal [False, True, False, False] + s_false_2 = s.fill_nothing ["col1"] (s.at "colFalse") + s_false_2.at "col1" . to_vector . should_equal [False, True, False, False] + s_true = s.fill_nothing ["col1"] True + s_true.at "col1" . to_vector . should_equal [False, True, True, False] + s_true_2 = s.fill_nothing ["col1"] (s.at "colTrue") + s_true_2.at "col1" . to_vector . should_equal [False, True, True, False] + suite_builder.group prefix+"Table.text_replace" group_builder-> data = Data.setup create_connection_fn diff --git a/test/Table_Tests/src/Common_Table_Operations/Derived_Columns_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Derived_Columns_Spec.enso index 78501361fa..5d97b74401 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Derived_Columns_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Derived_Columns_Spec.enso @@ -136,6 +136,7 @@ add_specs suite_builder setup = group_builder.specify "if" <| t = table_builder [["A", [1, 100]], ["B", [10, 40]], ["C", [23, 55]]] t.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Greater than=(Column_Ref.Name "B"))) "Z" . at "Z" . to_vector . should_equal [False, True] + t.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Greater than=(Column_Ref.Name "B") Filter_Action.Remove)) "Z" . at "Z" . to_vector . should_equal [True, False] t.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Greater than=20) "T" "F") "Z" . at "Z" . to_vector . should_equal ["F", "T"] t.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Less than=20) (Column_Ref.Name "B") (Column_Ref.Name "C")) "Z" . at "Z" . to_vector . should_equal [10, 55] @@ -148,19 +149,15 @@ add_specs suite_builder setup = t2.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Equal_Ignore_Case "C") "==" "!=") "Z" . at "Z" . to_vector . should_equal ["!=", "=="] t2.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Is_In ["x", "a", "dd"]) "TT" "FF") "Z" . at "Z" . to_vector . should_equal ["TT", "FF"] - t2.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Not_In ["x", "a", "dd"]) "TT" "FF") "Z" . at "Z" . to_vector . should_equal ["FF", "TT"] t2.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Is_In []) "TT" "FF") "Z" . at "Z" . to_vector . should_equal ["FF", "FF"] - t2.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Not_In []) "TT" "FF") "Z" . at "Z" . to_vector . should_equal ["TT", "TT"] # Passing a column does not work row-by-row, but looks at whole column contents. t2.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Is_In (t2.at "B")) "TT" "FF") "Z" . at "Z" . to_vector . should_equal ["FF", "TT"] t3 = table_builder [["x", ["e", "e", "a"]]] t2.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Is_In (t3.at "x")) "TT" "FF") "Z" . at "Z" . to_vector . should_equal ["TT", "FF"] - # Thus, passing a Column_Ref into Is_In/Not_In is not allowed as it would be confusing. + # Thus, passing a Column_Ref into Is_In is not allowed as it would be confusing. t2.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Is_In (Column_Ref.Name "B")) "TT" "FF") . should_fail_with Illegal_Argument - t2.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Not_In (Column_Ref.Name "B")) "TT" "FF") . should_fail_with Illegal_Argument - t2.set (Column_Operation.If (Column_Ref.Name "A") (Filter_Condition.Not_In [Column_Ref.Name "B", "X"]) "TT" "FF") . should_fail_with Illegal_Argument group_builder.specify "text" <| t = table_builder [["A", [" a ", "b"]], ["B", ["c", " d "]]] diff --git a/test/Table_Tests/src/Common_Table_Operations/Filter_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Filter_Spec.enso index 90e699ff96..1bfc4e6c99 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Filter_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Filter_Spec.enso @@ -49,19 +49,29 @@ add_specs suite_builder setup = group_builder.specify "by integer comparisons" <| t = table_builder [["ix", [1, 2, 3, 4, 5]], ["X", [100, 3, Nothing, 4, 12]], ["Y", [100, 4, 2, Nothing, 11]]] - t1 = t.filter "X" (Filter_Condition.Less than=10) - t1.at "ix" . to_vector . should_equal [2, 4] - t1.at "X" . to_vector . should_equal [3, 4] + t.filter "X" (Filter_Condition.Less than=10) . at "X" . to_vector . should_equal [3, 4] t.filter "X" (Filter_Condition.Less than=4) . at "X" . to_vector . should_equal [3] + t.filter "X" (Filter_Condition.Less than=4 action=Filter_Action.Remove) . at "X" . to_vector . should_equal [100, Nothing, 4, 12] t.filter "X" (Filter_Condition.Equal_Or_Less than=4) . at "X" . to_vector . should_equal [3, 4] + t.filter "X" (Filter_Condition.Equal_Or_Less than=4 action=Filter_Action.Remove) . at "X" . to_vector . should_equal [100, Nothing, 12] t.filter "X" (Filter_Condition.Greater than=4) . at "X" . to_vector . should_equal [100, 12] + t.filter "X" (Filter_Condition.Greater than=4 action=Filter_Action.Remove) . at "X" . to_vector . should_equal [3, Nothing, 4] t.filter "X" (Filter_Condition.Equal_Or_Greater than=4) . at "X" . to_vector . should_equal [100, 4, 12] + t.filter "X" (Filter_Condition.Equal_Or_Greater than=4 action=Filter_Action.Remove) . at "X" . to_vector . should_equal [3, Nothing] t.filter "X" (Filter_Condition.Between 4 100) . at "X" . to_vector . should_equal [100, 4, 12] - t2 = t.filter "X" (Filter_Condition.Equal to=100) - t2 . at "X" . to_vector . should_equal [100] - t2 . at "ix" . to_vector . should_equal [1] - + t.filter "X" (Filter_Condition.Between 4 100 action=Filter_Action.Remove) . at "X" . to_vector . should_equal [3, Nothing] + t.filter "X" (Filter_Condition.Equal to=100) . at "X" . to_vector . should_equal [100] t.filter "X" (Filter_Condition.Equal to=123) . at "X" . to_vector . should_equal [] + t.filter "X" (Filter_Condition.Equal to=3 action=Filter_Action.Remove) . at "X" . to_vector . should_equal [100, Nothing, 4, 12] + + t.filter "X" (Filter_Condition.Is_Finite) . at "ix" . to_vector . should_equal [1, 2, 4, 5] + t.filter "X" (Filter_Condition.Is_Finite action=Filter_Action.Remove) . at "ix" . to_vector . should_equal [3] + t.filter "X" (Filter_Condition.Is_Infinite) . at "ix" . to_vector . should_equal [] + t.filter "X" (Filter_Condition.Is_Infinite action=Filter_Action.Remove) . at "ix" . to_vector . should_equal [1, 2, 3, 4, 5] + if test_selection.is_nan_and_nothing_distinct then + t.filter "X" (Filter_Condition.Is_Nan) . at "ix" . to_vector . should_equal [] + t.filter "X" (Filter_Condition.Is_Nan action=Filter_Action.Remove) . at "ix" . to_vector . should_equal [1, 2, 3, 4, 5] + v = t.filter "X" (Filter_Condition.Equal to="SOME TEXT :)") . at "X" . to_vector ## We do not do typechecking at Enso level here, as it is DB-dependent if such mixing is allowed, so we will rely on an SQL @@ -71,25 +81,26 @@ add_specs suite_builder setup = False -> v.should_fail_with SQL_Error t.filter "X" (Filter_Condition.Equal to=(t.at "Y")) . at "X" . to_vector . should_equal [100] + t.filter "X" (Filter_Condition.Equal to=(t.at "Y") action=Filter_Action.Remove) . at "X" . to_vector . should_equal [3, Nothing, 4, 12] t.filter "X" (Filter_Condition.Less than=(t.at "Y")) . at "X" . to_vector . should_equal [3] + t.filter "X" (Filter_Condition.Less than=(t.at "Y") action=Filter_Action.Remove) . at "X" . to_vector . should_equal [100, Nothing, 4, 12] t.filter "X" (Filter_Condition.Equal_Or_Less than=(t.at "Y")) . at "X" . to_vector . should_equal [100, 3] + t.filter "X" (Filter_Condition.Equal_Or_Less than=(t.at "Y") action=Filter_Action.Remove) . at "X" . to_vector . should_equal [Nothing, 4, 12] t.filter "X" (Filter_Condition.Equal_Or_Greater than=(t.at "Y")) . at "X" . to_vector . should_equal [100, 12] + t.filter "X" (Filter_Condition.Equal_Or_Greater than=(t.at "Y") action=Filter_Action.Remove) . at "X" . to_vector . should_equal [3, Nothing, 4] t.filter "X" (Filter_Condition.Greater than=(t.at "Y")) . at "X" . to_vector . should_equal [12] + t.filter "X" (Filter_Condition.Greater than=(t.at "Y") action=Filter_Action.Remove) . at "X" . to_vector . should_equal [100, 3, Nothing, 4] t.filter "Y" (Filter_Condition.Between (t.at "ix") 100) . at "Y" . to_vector . should_equal [100, 4, 11] + t.filter "Y" (Filter_Condition.Between (t.at "ix") 100 action=Filter_Action.Remove) . at "Y" . to_vector . should_equal [2, Nothing] t.filter "X" (Filter_Condition.Equal to=(Column_Ref.Name "Y")) . at "X" . to_vector . should_equal [100] + t.filter "X" (Filter_Condition.Equal to=(Column_Ref.Expression "[Y]-1")) . at "X" . to_vector . should_equal [3] t.filter "X" (Filter_Condition.Less than=(Column_Ref.Name "Y")) . at "X" . to_vector . should_equal [3] t.filter "X" (Filter_Condition.Equal_Or_Less than=(Column_Ref.Name "Y")) . at "X" . to_vector . should_equal [100, 3] t.filter "X" (Filter_Condition.Equal_Or_Greater than=(Column_Ref.Name "Y")) . at "X" . to_vector . should_equal [100, 12] t.filter "X" (Filter_Condition.Greater than=(Column_Ref.Name "Y")) . at "X" . to_vector . should_equal [12] t.filter "Y" (Filter_Condition.Between (Column_Ref.Name "ix") 100) . at "Y" . to_vector . should_equal [100, 4, 11] - t.filter "X" (Filter_Condition.Is_Finite) . at "ix" . to_vector . should_equal [1, 2, 4, 5] - t.filter "X" (Filter_Condition.Is_Infinite) . at "ix" . to_vector . should_equal [] - - if test_selection.is_nan_and_nothing_distinct then - t.filter "X" (Filter_Condition.Is_Nan) . at "ix" . to_vector . should_equal [] - group_builder.specify "by float operations" <| t = table_builder [["ix", [1, 2, 3, 4, 5, 6]], ["X", [100.0, 2.5, Nothing, Number.nan, Number.positive_infinity, Number.negative_infinity]]] @@ -109,13 +120,14 @@ add_specs suite_builder setup = if test_selection.is_nan_and_nothing_distinct then t.filter "X" Filter_Condition.Is_Nan . at "ix" . to_vector . should_equal [4] - group_builder.specify "Not_Equal test cases" pending="Specification needs clarifying, see: https://github.com/enso-org/enso/issues/5241#issuecomment-1480167927" <| + group_builder.specify "Not_Equal test cases" <| t = table_builder [["ix", [1, 2, 3, 4, 5]], ["X", [100, 3, Nothing, 4, 12]], ["Y", [100, 4, 2, Nothing, 11]]] t3 = t.filter "X" (Filter_Condition.Not_Equal to=100) - t3 . at "X" . to_vector . should_equal [3, Nothing, 4, 12] - t3 . at "ix" . to_vector . should_equal [2, 3, 4, 5] - t.filter "X" (Filter_Condition.Not_Equal to=(t.at "Y")) . at "X" . to_vector . should_equal [3, Nothing, 4, 12] - t.filter "X" (Filter_Condition.Not_Equal to=(Column_Ref.Name "Y")) . at "X" . to_vector . should_equal [3, Nothing, 4, 12] + t3 . at "X" . to_vector . should_equal [3, 4, 12] + t3 . at "ix" . to_vector . should_equal [2, 4, 5] + t.filter "X" (Filter_Condition.Not_Equal to=(t.at "Y")) . at "X" . to_vector . should_equal [3, 12] + t.filter "X" (Filter_Condition.Not_Equal to=(Column_Ref.Name "Y")) . at "X" . to_vector . should_equal [3, 12] + t.filter "X" (Filter_Condition.Not_Equal to=(Column_Ref.Expression "[Y]")) . at "X" . to_vector . should_equal [3, 12] group_builder.specify "by text comparisons" <| t = table_builder [["ix", [1, 2, 3, 4, 5]], ["X", ["abb", "baca", "b", Nothing, "c"]], ["Y", ["a", "b", "b", "c", "c"]]] @@ -155,19 +167,20 @@ add_specs suite_builder setup = t = table_builder [["ix", [1, 2, 3, 4, 5]], ["X", ["abb", "bacb", "banana", Nothing, "nana"]], ["Y", ["a", "B", "d", "c", "a"]], ["Z", ["aaaaa", "bbbbb", "[ab]", "[ab]aaaa", "[ab]ccc"]]] t.filter "X" (Filter_Condition.Starts_With "ba") . at "X" . to_vector . should_equal ["bacb", "banana"] + t.filter "X" (Filter_Condition.Starts_With "ba" action=Filter_Action.Remove) . at "X" . to_vector . should_equal ["abb", Nothing, "nana"] t.filter "X" (Filter_Condition.Starts_With "BA" Case_Sensitivity.Sensitive) . at "X" . to_vector . should_equal [] t.filter "X" (Filter_Condition.Starts_With "BA" Case_Sensitivity.Insensitive) . at "X" . to_vector . should_equal ["bacb", "banana"] t.filter "X" (Filter_Condition.Ends_With "na") . at "X" . to_vector . should_equal ["banana", "nana"] + t.filter "X" (Filter_Condition.Ends_With "na" action=Filter_Action.Remove) . at "X" . to_vector . should_equal ["abb", "bacb", Nothing] t.filter "X" (Filter_Condition.Ends_With "NA" Case_Sensitivity.Sensitive) . at "X" . to_vector . should_equal [] t.filter "X" (Filter_Condition.Ends_With "NA" Case_Sensitivity.Insensitive) . at "X" . to_vector . should_equal ["banana", "nana"] t.filter "X" (Filter_Condition.Contains "ac") . at "X" . to_vector . should_equal ["bacb"] + t.filter "X" (Filter_Condition.Contains "ac" action=Filter_Action.Remove) . at "X" . to_vector . should_equal ["abb", "banana", Nothing, "nana"] t.filter "X" (Filter_Condition.Contains "AC" Case_Sensitivity.Sensitive) . at "X" . to_vector . should_equal [] t.filter "X" (Filter_Condition.Contains "AC" Case_Sensitivity.Insensitive) . at "X" . to_vector . should_equal ["bacb"] - t.filter "X" (Filter_Condition.Not_Contains "ac") . at "X" . to_vector . should_equal ["abb", "banana", "nana"] - t.filter "X" (Filter_Condition.Not_Contains "AC" Case_Sensitivity.Sensitive) . at "X" . to_vector . should_equal ["abb", "bacb", "banana", "nana"] - t.filter "X" (Filter_Condition.Not_Contains "AC" Case_Sensitivity.Insensitive) . at "X" . to_vector . should_equal ["abb", "banana", "nana"] t.filter "X" (Filter_Condition.Starts_With (t.at "Y")) . at "X" . to_vector . should_equal ["abb"] + t.filter "X" (Filter_Condition.Starts_With (t.at "Y") action=Filter_Action.Remove) . at "X" . to_vector . should_equal ["bacb", "banana", Nothing, "nana"] t.filter "X" (Filter_Condition.Starts_With (t.at "Y") Case_Sensitivity.Sensitive) . at "X" . to_vector . should_equal ["abb"] t.filter "X" (Filter_Condition.Starts_With (t.at "Y") Case_Sensitivity.Insensitive) . at "X" . to_vector . should_equal ["abb", "bacb"] t.filter "X" (Filter_Condition.Ends_With (t.at "Y")) . at "X" . to_vector . should_equal ["nana"] @@ -176,27 +189,21 @@ add_specs suite_builder setup = t.filter "X" (Filter_Condition.Contains (t.at "Y")) . at "X" . to_vector . should_equal ["abb", "nana"] t.filter "X" (Filter_Condition.Contains (t.at "Y") Case_Sensitivity.Sensitive) . at "X" . to_vector . should_equal ["abb", "nana"] t.filter "X" (Filter_Condition.Contains (t.at "Y") Case_Sensitivity.Insensitive) . at "X" . to_vector . should_equal ["abb", "bacb", "nana"] - t.filter "X" (Filter_Condition.Not_Contains (t.at "Y")) . at "X" . to_vector . should_equal ["bacb", "banana"] - t.filter "X" (Filter_Condition.Not_Contains (t.at "Y") Case_Sensitivity.Sensitive) . at "X" . to_vector . should_equal ["bacb", "banana"] - t.filter "X" (Filter_Condition.Not_Contains (t.at "Y") Case_Sensitivity.Insensitive) . at "X" . to_vector . should_equal ["banana"] t.filter "X" (Filter_Condition.Starts_With (Column_Ref.Name "Y")) . at "X" . to_vector . should_equal ["abb"] t.filter "X" (Filter_Condition.Ends_With (Column_Ref.Name "Y") Case_Sensitivity.Insensitive) . at "X" . to_vector . should_equal ["bacb", "nana"] t.filter "X" (Filter_Condition.Contains (Column_Ref.Name "Y") Case_Sensitivity.Insensitive) . at "X" . to_vector . should_equal ["abb", "bacb", "nana"] - t.filter "X" (Filter_Condition.Not_Contains (Column_Ref.Name "Y") Case_Sensitivity.Insensitive) . at "X" . to_vector . should_equal ["banana"] group_builder.specify "by text search (like, not_like)" <| t = table_builder [["ix", [1, 2, 3, 4, 5]], ["X", ["abb", "bacb", "banana", Nothing, "nana"]], ["Y", ["a", "B", "d", "c", "a"]], ["Z", ["aaaaa", "bbbbb", "[ab]", "[ab]aaaa", "[ab]ccc"]]] t.filter "X" (Filter_Condition.Like "%an%") . at "X" . to_vector . should_equal ["banana", "nana"] + t.filter "X" (Filter_Condition.Like "%an%" action=Filter_Action.Remove) . at "X" . to_vector . should_equal ["abb", "bacb", Nothing] t.filter "X" (Filter_Condition.Like "_a%") . at "X" . to_vector . should_equal ["bacb", "banana", "nana"] t.filter "X" (Filter_Condition.Like "%b") . at "X" . to_vector . should_equal ["abb", "bacb"] t.filter "X" (Filter_Condition.Like "nana") . at "X" . to_vector . should_equal ["nana"] t.filter "Z" (Filter_Condition.Like "[ab]_%") . at "Z" . to_vector . should_equal ["[ab]aaaa", "[ab]ccc"] - t.filter "X" (Filter_Condition.Not_Like "%b") . at "X" . to_vector . should_equal ["banana", "nana"] - t.filter "Z" (Filter_Condition.Not_Like "[ab]%") . at "Z" . to_vector . should_equal ["aaaaa", "bbbbb"] - group_builder.specify "text operations should also match newlines" <| t = table_builder [["X", ['a\n\n\n', 'a\n', 'a\n\n\nb', 'a\nb', 'caa\nbb']]] t.filter "X" (Filter_Condition.Like 'a_') . at "X" . to_vector . should_equal ['a\n'] @@ -208,7 +215,6 @@ add_specs suite_builder setup = t.filter "X" (Filter_Condition.Ends_With '\nb') . at "X" . to_vector . should_equal ['a\n\n\nb', 'a\nb'] t.filter "X" (Filter_Condition.Ends_With '\n') . at "X" . to_vector . should_equal ['a\n\n\n', 'a\n'] t.filter "X" (Filter_Condition.Starts_With 'c') . at "X" . to_vector . should_equal ['caa\nbb'] - t.filter "X" (Filter_Condition.Not_Contains '\nb') . at "X" . to_vector . should_equal ['a\n\n\n', 'a\n'] if test_selection.supports_unicode_normalization then t = table_builder [["X", ['śnieg', 's\u0301nieg', 'X', Nothing, 'połać', 'połac\u0301']]] @@ -217,7 +223,6 @@ add_specs suite_builder setup = t.filter "X" (Filter_Condition.Contains 'ś') . at "X" . to_vector . should_equal ['śnieg', 's\u0301nieg'] t.filter "X" (Filter_Condition.Ends_With 'ś') . at "X" . to_vector . should_equal [] t.filter "X" (Filter_Condition.Ends_With 'ć') . at "X" . to_vector . should_equal ['połać', 'połac\u0301'] - t.filter "X" (Filter_Condition.Not_Contains 'ś') . at "X" . to_vector . should_equal ['X', 'połać', 'połac\u0301'] # This should be replaced with the disabled test below, once the related bug is fixed. t.filter "X" (Filter_Condition.Like 'ś%') . at "X" . to_vector . should_equal ['śnieg'] @@ -242,24 +247,18 @@ add_specs suite_builder setup = check_problem (t.filter "X" (Filter_Condition.Ends_With (t.at "ix"))) check_problem (t.filter "X" (Filter_Condition.Contains (t.at "ix"))) check_problem (t.filter "X" (Filter_Condition.Like (t.at "ix"))) - check_problem (t.filter "X" (Filter_Condition.Not_Like (t.at "ix"))) - check_problem (t.filter "X" (Filter_Condition.Not_Contains (t.at "ix"))) check_problem (t.filter "X" (Filter_Condition.Equal_Ignore_Case (Column_Ref.Name "ix"))) check_problem (t.filter "X" (Filter_Condition.Starts_With (Column_Ref.Name "ix"))) check_problem (t.filter "X" (Filter_Condition.Ends_With (Column_Ref.Name "ix"))) check_problem (t.filter "X" (Filter_Condition.Contains (Column_Ref.Name "ix"))) check_problem (t.filter "X" (Filter_Condition.Like (Column_Ref.Name "ix"))) - check_problem (t.filter "X" (Filter_Condition.Not_Like (Column_Ref.Name "ix"))) - check_problem (t.filter "X" (Filter_Condition.Not_Contains (Column_Ref.Name "ix"))) check_problem (t.filter "ix" (Filter_Condition.Equal_Ignore_Case "A")) check_problem (t.filter "ix" (Filter_Condition.Starts_With "A")) check_problem (t.filter "ix" (Filter_Condition.Ends_With "A")) check_problem (t.filter "ix" (Filter_Condition.Contains "A")) check_problem (t.filter "ix" (Filter_Condition.Like "A")) - check_problem (t.filter "ix" (Filter_Condition.Not_Like "A")) - check_problem (t.filter "ix" (Filter_Condition.Not_Contains "A")) check_problem (t.filter "ix" Filter_Condition.Is_Empty) check_problem (t.filter "ix" Filter_Condition.Not_Empty) @@ -271,8 +270,6 @@ add_specs suite_builder setup = check_scalar_type_error_handling (t.filter "X" (Filter_Condition.Ends_With 42)) check_scalar_type_error_handling (t.filter "X" (Filter_Condition.Contains 42)) check_scalar_type_error_handling (t.filter "X" (Filter_Condition.Like 42)) - check_scalar_type_error_handling (t.filter "X" (Filter_Condition.Not_Like 42)) - check_scalar_type_error_handling (t.filter "X" (Filter_Condition.Not_Contains 42)) group_builder.specify "by nulls" <| t = table_builder [["ix", [1, 2, 3, 4]], ["X", [Nothing, 1, Nothing, 4]]] @@ -287,17 +284,11 @@ add_specs suite_builder setup = group_builder.specify "by an Is_In check" <| t = table_builder [["ix", [1, 2, 3, Nothing, 5, 6]], ["X", ["a", "b", "ccc", "X", "f", "2"]]] t1 = table_builder [["txt", ["X", "a", "c", Nothing]], ["int", [Nothing, 2, 5, 4]], ["bool", [True, Nothing, Nothing, True]]] - t2 = table_builder [["txt", ["X", "a", "c", "q"]], ["int", [123, 2, 5, 4]], ["bool", [True, True, True, True]]] t.filter "X" (Filter_Condition.Is_In (t1.at "txt")) . at "X" . to_vector . should_equal ["a", "X"] t.filter "X" (Filter_Condition.Is_In (t1.at "txt" . to_vector)) . at "X" . to_vector . should_equal ["a", "X"] - t.filter "X" (Filter_Condition.Not_In (t1.at "txt")) . at "X" . to_vector . should_equal [] - t.filter "X" (Filter_Condition.Not_In (t2.at "txt")) . at "X" . to_vector . should_equal ["b", "ccc", "f", "2"] - t.filter "X" (Filter_Condition.Not_In (t1.at "txt" . to_vector)) . at "X" . to_vector . should_equal [] - t.filter "X" (Filter_Condition.Not_In (t2.at "txt" . to_vector)) . at "X" . to_vector . should_equal ["b", "ccc", "f", "2"] t.filter "X" (Filter_Condition.Is_In ["ccc"]) . at "X" . to_vector . should_equal ["ccc"] t.filter "X" (Filter_Condition.Is_In []) . at "X" . to_vector . should_equal [] - t.filter "X" (Filter_Condition.Not_In []) . at "X" . to_vector . should_equal ["a", "b", "ccc", "X", "f", "2"] if test_selection.allows_mixed_type_comparisons then mixed = t.filter "X" (Filter_Condition.Is_In (t1.at "int")) . at "X" . to_vector @@ -308,8 +299,6 @@ add_specs suite_builder setup = t.filter "ix" (Filter_Condition.Is_In (t1.at "int" . to_vector)) . at "ix" . to_vector . should_equal [2, 5] t.filter "ix" (Filter_Condition.Is_In [2, 5, 4]) . at "ix" . to_vector . should_equal [2, 5] t.filter "ix" (Filter_Condition.Is_In [Nothing]) . at "ix" . to_vector . should_equal [] - t.filter "ix" (Filter_Condition.Not_In [Nothing]) . at "ix" . to_vector . should_equal [] - t.filter "ix" (Filter_Condition.Not_In [1, 3]) . at "ix" . to_vector . should_equal [2, 5, 6] v1 = t.filter "X" (Filter_Condition.Is_In ["c", "f", "b", "b", "b", 15, Nothing]) . at "X" . to_vector case test_selection.allows_mixed_type_comparisons of @@ -329,7 +318,7 @@ add_specs suite_builder setup = t3.filter "B" (Filter_Condition.Is_In [False]) . at "B" . to_vector . should_equal [False, False, False] t3.filter "C" (Filter_Condition.Is_In [False, False]) . at "C" . to_vector . should_equal [False] - group_builder.specify "does not allow Column_Ref in Is_In/Not_In because that would be confusing" <| + group_builder.specify "does not allow Column_Ref in Is_In because that would be confusing" <| ## Is In and Not In check if a value is contained anywhere in a provided collection (e.g. column), NOT on a row-by-row basis like all other operations. Column_Ref is used with row-by-row ops, so this would only cause confusion. Very rarely someone wants to filter a column by Is_In @@ -459,7 +448,6 @@ add_specs suite_builder setup = + [Filter_Condition.Less Nothing, Filter_Condition.Equal_Or_Less Nothing] + [Filter_Condition.Equal_Or_Greater Nothing, Filter_Condition.Greater Nothing] + [Filter_Condition.Between Nothing Nothing , Filter_Condition.Is_In [Nothing]] - + [Filter_Condition.Not_In [Nothing]] + [Filter_Condition.Is_In [1, Nothing, 2]] fcs.map fc-> Test.with_clue fc.to_text <| diff --git a/test/Table_Tests/src/Common_Table_Operations/Missing_Values_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Missing_Values_Spec.enso index 92fe66b0c8..167dc6df33 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Missing_Values_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Missing_Values_Spec.enso @@ -75,7 +75,7 @@ add_specs suite_builder setup = ## TODO currently our builder does not allow all-null tables, so we create one with a 0 and remove it by filter. See #6159. t0 = table_builder [["X", [0, Nothing, Nothing, Nothing]]] - t1 = t0.filter "X" (Filter_Condition.Is_Nothing) + t1 = t0.filter "X" Filter_Condition.Is_Nothing t1.row_count . should_equal 3 t1.at "X" . to_vector . should_equal [Nothing, Nothing, Nothing] @@ -171,7 +171,7 @@ add_specs suite_builder setup = group_builder.specify "select_blank_columns and remove_blank_columns should deal with edge cases" <| t = table_builder [["X", [1, 2, 3, 4]]] - no_rows = t.filter "X" (Filter_Condition.Equal to=0) + no_rows = t.filter "X" Filter_Condition.Is_Nothing no_rows.row_count . should_equal 0 no_rows.at "X" . to_vector . should_equal [] diff --git a/test/Table_Tests/src/Database/Codegen_Spec.enso b/test/Table_Tests/src/Database/Codegen_Spec.enso index 62d76c8bb8..7cc610121e 100644 --- a/test/Table_Tests/src/Database/Codegen_Spec.enso +++ b/test/Table_Tests/src/Database/Codegen_Spec.enso @@ -42,14 +42,17 @@ add_specs suite_builder = group_builder.teardown <| data.teardown - group_builder.specify "should serialize Tables and Columns to their SQL representation" pending="ToDo: decide on how we handle ==, see https://github.com/enso-org/enso/issues/5241" <| + group_builder.specify "should serialize Tables and Columns to their SQL representation" <| q1 = data.t1.filter (data.t1.at "A" == 42) . to_json - part1 = JS_Object.from_pairs [["sql_code", 'SELECT "T1"."A" AS "A", "T1"."B" AS "B", "T1"."C" AS "C" FROM "T1" AS "T1" WHERE ("T1"."A" = ']] + part1 = JS_Object.from_pairs [["sql_code", 'SELECT "T1"."A" AS "A", "T1"."B" AS "B", "T1"."C" AS "C" FROM "T1" AS "T1" WHERE (("T1"."A") = (']] part2_sub = JS_Object.from_pairs [["value", 42]] part2 = JS_Object.from_pairs [["sql_interpolation", part2_sub]] - part3 = JS_Object.from_pairs [["sql_code", ")"]] - expected = JS_Object.from_pairs [["query", [part1, part2, part3]]] . to_text + part3 = JS_Object.from_pairs [["sql_code", ")) = ("]] + part4_sub = JS_Object.from_pairs [["value", True]] + part4 = JS_Object.from_pairs [["sql_interpolation", part4_sub]] + part5 = JS_Object.from_pairs [["sql_code", ")"]] + expected = JS_Object.from_pairs [["query", [part1, part2, part3, part4, part5]]] . to_text q1.should_equal expected q2 = data.t1.at "A" . to_json @@ -90,6 +93,9 @@ add_specs suite_builder = t2 = data.t1.filter "A" (Filter_Condition.Between 10 20) t2.to_sql.prepare . should_equal ['SELECT "T1"."A" AS "A", "T1"."B" AS "B", "T1"."C" AS "C" FROM "T1" AS "T1" WHERE ("T1"."A" BETWEEN ? AND ?)', [10, 20]] + t2r = data.t1.filter "A" (Filter_Condition.Between 10 20 Filter_Action.Remove) + t2r.to_sql.prepare . should_equal ['SELECT "T1"."A" AS "A", "T1"."B" AS "B", "T1"."C" AS "C" FROM "T1" AS "T1" WHERE (NOT CAST(COALESCE(("T1"."A" BETWEEN ? AND ?), ?) AS BOOLEAN))', [10, 20, False]] + group_builder.specify "should generate an IN expression" <| t2 = data.t1.filter "A" (Filter_Condition.Is_In [1, 2, 'foo']) t2.to_sql.prepare . should_equal ['SELECT "T1"."A" AS "A", "T1"."B" AS "B", "T1"."C" AS "C" FROM "T1" AS "T1" WHERE "T1"."A" IN (?, ?, ?)', [1, 2, "foo"]] diff --git a/test/Visualization_Tests/src/Lazy_Table_Spec.enso b/test/Visualization_Tests/src/Lazy_Table_Spec.enso index 851809631d..91b9e5bb3a 100644 --- a/test/Visualization_Tests/src/Lazy_Table_Spec.enso +++ b/test/Visualization_Tests/src/Lazy_Table_Spec.enso @@ -4,7 +4,6 @@ from Standard.Table import Table import Standard.Examples import Standard.Visualization.Table as Table_Visualization -import Standard.Visualization.Preprocessor as Preprocessor from Standard.Test_New import all diff --git a/test/Visualization_Tests/src/Lazy_Text_Spec.enso b/test/Visualization_Tests/src/Lazy_Text_Spec.enso index 7b7db965d4..3b0f5e373d 100644 --- a/test/Visualization_Tests/src/Lazy_Text_Spec.enso +++ b/test/Visualization_Tests/src/Lazy_Text_Spec.enso @@ -3,7 +3,6 @@ from Standard.Visualization import all import Standard.Examples import Standard.Visualization.Text as TextVis -import Standard.Visualization.Preprocessor as Preprocessor from Standard.Test_New import all diff --git a/tools/performance/benchmark-analysis/src/Main.enso b/tools/performance/benchmark-analysis/src/Main.enso index 894247bd27..67d28739ab 100644 --- a/tools/performance/benchmark-analysis/src/Main.enso +++ b/tools/performance/benchmark-analysis/src/Main.enso @@ -10,7 +10,7 @@ main = operator14 = var1.to_column "Color" operator16 = operator14.to_table operator40 = enso_project.data/'benchmarks-vectorized-3-2023-07-17.txt' . read (Delimited_Format.Delimited) - operator1 = operator40.filter 'Column 1' (Filter_Condition.Not_Contains "average") + operator1 = operator40.filter 'Column 1' (Filter_Condition.Contains "average" Filter_Action.Remove) operator3 = operator1.parse_to_columns 'Column 1' text1 operator4 = operator3.select_columns ['Operation'] operator5 = operator4.distinct