Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
- [Hiding `Prim_Text_Helper` from the API][14979]
- [Add reverse][14931]
- [Support for Spatial aggregates and making lines and polygons.][14973]
- [Add text trim methods][14982]

[14522]: https://github.com/enso-org/enso/pull/14522
[14476]: https://github.com/enso-org/enso/pull/14476
Expand All @@ -102,6 +103,7 @@
[14931]: https://github.com/enso-org/enso/pull/14931
[14979]: https://github.com/enso-org/enso/pull/14979
[14973]: https://github.com/enso-org/enso/pull/14973
[14982]: https://github.com/enso-org/enso/pull/14982

#### Enso Language & Runtime

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Standard.Base.Errors.Unimplemented.Unimplemented
import Standard.Table.Column.Column
import Standard.Table.Column.Rest_Of_String
import Standard.Table.Internal.Value_Type_Checks
from Standard.Table import Value_Type

import project.DB_Column.DB_Column
import project.Internal.Helpers
Expand Down Expand Up @@ -188,6 +189,28 @@ type DB_Text_Column_Implementation
new_name = (naming_helper column).function_name "pad_right" [column, length, with_pad]
make_op column "PAD_RIGHT" [length, with_pad] new_name

trim (column : Column & DB_Column) (what : Column | Text | Any) (where : Location) =
Value_Type_Checks.is_text column
parsed_what = if what.is_a Column && what.value_type == Value_Type.Null then Nothing else what
new_name = (naming_helper column).function_name "trim" [column, what, where]
operation_name = case where of
Location.Left -> "LTRIM"
Location.Right -> "RTRIM"
Location.Both -> "TRIM"
make_op column operation_name [parsed_what] new_name

trim_left (column : Column & DB_Column) (what : Column | Text | Any) =
Value_Type_Checks.is_text column
parsed_what = if what.is_a Column && what.value_type == Value_Type.Null then Nothing else what
new_name = (naming_helper column).function_name "trim_left" [column, what]
make_op column "LTRIM" [parsed_what] new_name

trim_right (column : Column & DB_Column) (what : Column | Text | Any) =
Value_Type_Checks.is_text column
parsed_what = if what.is_a Column && what.value_type == Value_Type.Null then Nothing else what
new_name = (naming_helper column).function_name "trim_right" [column, what]
make_op column "RTRIM" [parsed_what] new_name

parse_json column on_problems =
_ = [column, on_problems]
Unimplemented.throw "parse_json is not implemented for database backends."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@
- reverse self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Text_Column.Text_Column)
- right self n:(Standard.Table.Column.Column|Standard.Base.Data.Numbers.Integer|Standard.Base.Nothing.Nothing)= -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Text_Column.Text_Column)
- to_case self case_option:Standard.Base.Data.Text.Case.Case= locale:Standard.Base.Data.Locale.Locale= -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Text_Column.Text_Column)
- trim self what:(Standard.Table.Column.Column|Standard.Base.Data.Text.Text|Standard.Base.Any.Any)= where:Standard.Base.Data.Text.Location.Location= -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Text_Column.Text_Column)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • why do we create three methods here?
  • Can't we follow the signature of Text.trim
  • e.g. have just a single method
  • and where:Standard.Base.Data.Text.Location.Location argument defaulted to Both?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is really to make it easier in the expression language. We don't have autocomplete for Location at the moment so typing it as an expression requires you to know the names of the options.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Ááá, expression language...
  • it might be a good moment for the Enso API and expression language to diverge then
  • expression language would hardcode trim_left to mean trim with location=..Left
  • just an opinion, feel free to proceed without such "complications"

- trim_left self what:(Standard.Table.Column.Column|Standard.Base.Data.Text.Text|Standard.Base.Any.Any)= -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Text_Column.Text_Column)
- trim_right self what:(Standard.Table.Column.Column|Standard.Base.Data.Text.Text|Standard.Base.Any.Any)= -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Text_Column.Text_Column)
- upper self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Text_Column.Text_Column)
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,24 @@ type In_Memory_Text_Column_Implementation
new_name = naming_helper.function_name "pad_right" [this_column, length, with_pad]
_apply_pad this_column length with_pad Location.Right new_name

trim (this_column : Column & In_Memory_Column) (what : Column | Text | Any) (where : Location) =
Value_Type_Checks.is_text this_column
parsed_what = if what.is_a Column && what.value_type == Value_Type.Null then "" else what
new_name = naming_helper.function_name "trim" [this_column, what, where]
_apply_trim this_column parsed_what where new_name

trim_left (this_column : Column & In_Memory_Column) (what : Column | Text | Any) =
Value_Type_Checks.is_text this_column
parsed_what = if what.is_a Column && what.value_type == Value_Type.Null then "" else what
new_name = naming_helper.function_name "trim_left" [this_column, what]
_apply_trim this_column parsed_what Location.Left new_name

trim_right (this_column : Column & In_Memory_Column) (what : Column | Text | Any) =
Value_Type_Checks.is_text this_column
parsed_what = if what.is_a Column && what.value_type == Value_Type.Null then "" else what
new_name = naming_helper.function_name "trim_right" [this_column, what]
_apply_trim this_column parsed_what Location.Right new_name

parse_json (column : Column & In_Memory_Column) (on_problems:Problem_Behavior) =
Value_Type_Checks.is_text column
new_name = naming_helper.function_name "parse_json" [column]
Expand Down Expand Up @@ -298,3 +316,19 @@ private _apply_pad (this_column : Column & In_Memory_Column) (length : Column |
_apply_binary_map this_column (text -> pad-> do_pad text length pad) with_pad new_name skip_nulls=False expected_result_type=Value_Type.Char
else
apply_unary_map this_column new_name (text -> do_pad text length with_pad) expected_result_type=Value_Type.Char nothing_unchanged=False

private _apply_trim (this_column : Column & In_Memory_Column) (what : Column | Text | Any) location:Location new_name:Text =
do_trim text chars =
if text.is_nothing then Nothing else
if chars.is_nothing || chars.is_empty then text.trim location else text.trim location chars

case what of
_ : Text ->
trim_fn = if what.is_empty then t-> t.trim location else
t-> t.trim location what
apply_unary_map this_column new_name trim_fn expected_result_type=Value_Type.Char
_ : Column ->
Value_Type_Checks.is_text what
_apply_binary_map this_column do_trim what new_name skip_nulls=False expected_result_type=Value_Type.Char
_ ->
what : Text
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,91 @@ type Text_Column
pad_right self (length : Column | Integer | Nothing) (with_pad : Column | Text | Any = " ") -> Column & Text_Column =
self.operations_implementation.pad_right self.column length with_pad

## ---
group: Standard.Base.Text
icon: text
---
Trims whitespace or specified characters from both ends of each element in the column.

Arguments:
- what: The text to trim. Defaults to whitespace.
- where: The location to trim from (Left, Right, or Both). Defaults to Both.

## Examples
### Trim whitespace from both ends of values in a column.

```
import Standard.Examples

example_trim = Examples.text_column_1.trim
```

### Trim a specific character from the left side only.

```
import Standard.Examples

example_trim_custom = Examples.text_column_1.trim "x" ..Left
```
trim self (what : Column | Text | Any = '') (where : Location = ..Both) -> Column & Text_Column =
self.operations_implementation.trim self.column what where

## ---
group: Standard.Base.Text
icon: text
---
Trims whitespace or specified characters from the start of each element in the column.

Arguments:
- what: The text to trim. Defaults to whitespace.

## Examples
### Trim whitespace from the start of values in a column.

```
import Standard.Examples

example_trim_left = Examples.text_column_1.trim_left
```

### Trim a specific character from the start.

```
import Standard.Examples

example_trim_left_custom = Examples.text_column_1.trim_left "x"
```
trim_left self (what : Column | Text | Any = '') -> Column & Text_Column =
self.operations_implementation.trim_left self.column what

## ---
group: Standard.Base.Text
icon: text
---
Trims whitespace or specified characters from the end of each element in the column.

Arguments:
- what: The text to trim. Defaults to whitespace.

## Examples
### Trim whitespace from the end of values in a column.

```
import Standard.Examples

example_trim_right = Examples.text_column_1.trim_right
```

### Trim a specific character from the end.

```
import Standard.Examples

example_trim_right_custom = Examples.text_column_1.trim_right "x"
```
trim_right self (what : Column | Text | Any = '') -> Column & Text_Column =
self.operations_implementation.trim_right self.column what

## ---
group: Standard.Base.Conversions
icon: convert
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1800,6 +1800,54 @@ add_column_operation_specs suite_builder setup =
Test.expect_panic Type_Error <| data.a.trim what=1
data.a.trim what=data.c . should_fail_with Invalid_Value_Type

group_builder.specify "trim_left should trim whitespace from the start by default" <|
with_mixed_columns_if_supported [["A", [" A ", ' \t\n\rA\r\n\t ', "xxxAxx"]]] t->
a = t.at "A"
a.trim_left . to_vector . should_equal ["A ", 'A\r\n\t ', "xxxAxx"]

group_builder.specify "trim_left should trim custom characters from the start" <|
data.a.trim_left what='x' . to_vector . should_equal [" A ", ' \t\n\rA\r\n\t ', "Axx"]
data.a.trim_left what=' ' . to_vector . should_equal ["A ", '\t\n\rA\r\n\t ', "xxxAxx"]
data.a.trim_left what=' \t' . to_vector . should_equal ["A ", '\n\rA\r\n\t ', "xxxAxx"]
data.a.trim_left what=data.b . to_vector . should_equal ["A ", '\n\rA\r\n\t ', "Axx"]

group_builder.specify "trim_right should trim whitespace from the end by default" <|
with_mixed_columns_if_supported [["A", [" A ", ' \t\n\rA\r\n\t ', "xxxAxx"]]] t->
a = t.at "A"
a.trim_right . to_vector . should_equal [" A", ' \t\n\rA', "xxxAxx"]

group_builder.specify "trim_right should trim custom characters from the end" <|
data.a.trim_right what='x' . to_vector . should_equal [" A ", ' \t\n\rA\r\n\t ', "xxxA"]
data.a.trim_right what=' ' . to_vector . should_equal [" A", ' \t\n\rA\r\n\t', "xxxAxx"]
data.a.trim_right what=' \t' . to_vector . should_equal [" A", ' \t\n\rA\r\n', "xxxAxx"]
data.a.trim_right what=data.b . to_vector . should_equal [" A", ' \t\n\rA\r\n', "xxxA"]

group_builder.specify "trim_left and trim_right should only allow Text columns as arguments" <|
Test.expect_panic Type_Error <| data.a.trim_left what=1
Test.expect_panic Type_Error <| data.a.trim_right what=1
data.a.trim_left what=data.c . should_fail_with Invalid_Value_Type
data.a.trim_right what=data.c . should_fail_with Invalid_Value_Type

group_builder.specify "should handle Nothing values in trim operations" <|
with_mixed_columns_if_supported [["A", [" A ", Nothing, "xxxAxx"]]] t->
a = t.at "A"
a.trim . to_vector . should_equal ["A", Nothing, "xxxAxx"]
a.trim_left . to_vector . should_equal ["A ", Nothing, "xxxAxx"]
a.trim_right . to_vector . should_equal [" A", Nothing, "xxxAxx"]
a.trim what='x' . to_vector . should_equal [" A ", Nothing, "A"]
a.trim_left what='x' . to_vector . should_equal [" A ", Nothing, "Axx"]
a.trim_right what='x' . to_vector . should_equal [" A ", Nothing, "xxxA"]

group_builder.specify "should handle empty strings in trim operations" <|
with_mixed_columns_if_supported [["A", [" ", " ", ""]]] t->
a = t.at "A"
a.trim . to_vector . should_equal ["", "", ""]
a.trim_left . to_vector . should_equal ["", "", ""]
a.trim_right . to_vector . should_equal ["", "", ""]
a.trim what='x' . to_vector . should_equal [" ", " ", ""]
a.trim_left what='x' . to_vector . should_equal [" ", " ", ""]
a.trim_right what='x' . to_vector . should_equal [" ", " ", ""]

suite_builder.group prefix+"(Column_Operations_Spec) Other Column Operations" group_builder->
table_builder = build_sorted_table table_builder=setup.light_table_builder
group_builder.specify "is_in" <|
Expand Down
Loading