Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable SQLServer select columns #11270

Merged
merged 3 commits into from
Oct 8, 2024
Merged
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
123 changes: 59 additions & 64 deletions distribution/lib/Standard/Database/0.0.0-dev/src/DB_Table.enso
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,9 @@ type DB_Table
@selector Widget_Helpers.make_column_name_selector
at : Integer | Text -> DB_Column ! No_Such_Column | Index_Out_Of_Bounds
at self (selector:(Integer | Text)=0) =
Feature.Column_Operations.if_supported_else_throw self.connection.dialect "at" <|
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this check no longer neeeded for any backend?

Copy link
Member Author

Choose a reason for hiding this comment

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

Similar to the removal of set. All dialects should allow getting a column from a table. What you can do with that table is then limited by the operation flagging system.

case selector of
_ : Integer -> self.make_column (self.internal_columns.at selector)
_ -> self.get selector (Error.throw (No_Such_Column.Error selector))
case selector of
_ : Integer -> self.make_column (self.internal_columns.at selector)
_ -> self.get selector (Error.throw (No_Such_Column.Error selector))

## ICON select_column
Returns the column with the given name or index.
Expand All @@ -153,11 +152,10 @@ type DB_Table
@selector Widget_Helpers.make_column_name_selector
get : Integer | Text -> Any -> DB_Column | Any
get self (selector:(Integer | Text)=0) ~if_missing=Nothing =
Feature.Column_Operations.if_supported_else_throw self.connection.dialect "get" <|
internal_column = case selector of
_ : Integer -> self.internal_columns.get selector if_missing=Nothing
_ : Text -> self.internal_columns.find (p -> p.name == selector) if_missing=Nothing
if internal_column.is_nothing then if_missing else self.make_column internal_column
internal_column = case selector of
_ : Integer -> self.internal_columns.get selector if_missing=Nothing
_ : Text -> self.internal_columns.find (p -> p.name == selector) if_missing=Nothing
if internal_column.is_nothing then if_missing else self.make_column internal_column

## ALIAS cell value, get cell
GROUP Standard.Base.Selections
Expand Down Expand Up @@ -1010,46 +1008,45 @@ type DB_Table
@value Simple_Expression.default_widget
set : DB_Column | Text | Expression | Array | Vector | Range | Date_Range | Constant_Column | Simple_Expression -> Text -> Set_Mode -> Problem_Behavior -> DB_Table ! Existing_Column | Missing_Column | No_Such_Column | Expression_Error
set self value:(DB_Column | Text | Expression | Array | Vector | Range | Date_Range | Constant_Column | Simple_Expression) (as : Text = "") (set_mode : Set_Mode = ..Add_Or_Update) (on_problems : Problem_Behavior = ..Report_Warning) =
Feature.Set.if_supported_else_throw self.connection.dialect "set" <|
problem_builder = Problem_Builder.new
unique = self.column_naming_helper.create_unique_name_strategy
unique.mark_used self.column_names

resolved = case value of
_ : Text -> self.make_constant_column value
_ : Expression -> self.evaluate_expression value on_problems
_ : DB_Column ->
if Helpers.check_integrity self value then value else
Error.throw (Integrity_Error.Error "Column "+value.name)
_ : Constant_Column -> self.make_constant_column value
_ : Simple_Expression -> value.evaluate self (set_mode==Set_Mode.Update && as=="") on_problems
_ : Vector -> Error.throw (Unsupported_Database_Operation "`Vector` for `set`")
_ : Array -> Error.throw (Unsupported_Database_Operation.Error "`Array` for `set`")
_ : Range -> Error.throw (Unsupported_Database_Operation.Error "`Range` for `set`")
_ : Date_Range -> Error.throw (Unsupported_Database_Operation.Error "`Date_Range` for `set`")
_ -> Error.throw (Illegal_Argument.Error "Unsupported type for `DB_Table.set`.")

## If `as` was specified, use that. Otherwise, if `value` is a
`DB_Column`, use its name. In these two cases, do not make it unique.
Otherwise, make it unique. If set_mode is Update, however, do not
make it unique.
new_column_name = if as != "" then as else
if value.is_a DB_Column || set_mode==Set_Mode.Update || set_mode==Set_Mode.Add_Or_Update then resolved.name else unique.make_unique resolved.name
renamed = resolved.rename new_column_name
renamed.if_not_error <| self.column_naming_helper.check_ambiguity self.column_names renamed.name <|
index = self.internal_columns.index_of (c -> c.name == renamed.name)
check_add = case set_mode of
Set_Mode.Add_Or_Update -> True
Set_Mode.Add -> if index.is_nothing then True else Error.throw (Existing_Column.Error renamed.name)
Set_Mode.Update -> if index.is_nothing then Error.throw (Missing_Column.Error renamed.name) else True
new_table = check_add.if_not_error <|
new_col = renamed.as_internal
new_cols = if index.is_nothing then self.internal_columns + [new_col] else
Vector.new self.column_count i-> if i == index then new_col else self.internal_columns.at i
self.updated_columns new_cols

problem_builder.report_unique_name_strategy unique
problem_builder.attach_problems_after on_problems new_table
problem_builder = Problem_Builder.new
unique = self.column_naming_helper.create_unique_name_strategy
unique.mark_used self.column_names

resolved = case value of
_ : Text -> self.make_constant_column value
_ : Expression -> self.evaluate_expression value on_problems
_ : DB_Column ->
if Helpers.check_integrity self value then value else
Error.throw (Integrity_Error.Error "Column "+value.name)
_ : Constant_Column -> self.make_constant_column value
_ : Simple_Expression -> value.evaluate self (set_mode==Set_Mode.Update && as=="") on_problems
_ : Vector -> Error.throw (Unsupported_Database_Operation "`Vector` for `set`")
_ : Array -> Error.throw (Unsupported_Database_Operation.Error "`Array` for `set`")
_ : Range -> Error.throw (Unsupported_Database_Operation.Error "`Range` for `set`")
_ : Date_Range -> Error.throw (Unsupported_Database_Operation.Error "`Date_Range` for `set`")
_ -> Error.throw (Illegal_Argument.Error "Unsupported type for `DB_Table.set`.")

## If `as` was specified, use that. Otherwise, if `value` is a
`DB_Column`, use its name. In these two cases, do not make it unique.
Otherwise, make it unique. If set_mode is Update, however, do not
make it unique.
new_column_name = if as != "" then as else
if value.is_a DB_Column || set_mode==Set_Mode.Update || set_mode==Set_Mode.Add_Or_Update then resolved.name else unique.make_unique resolved.name
renamed = resolved.rename new_column_name
renamed.if_not_error <| self.column_naming_helper.check_ambiguity self.column_names renamed.name <|
index = self.internal_columns.index_of (c -> c.name == renamed.name)
check_add = case set_mode of
Set_Mode.Add_Or_Update -> True
Set_Mode.Add -> if index.is_nothing then True else Error.throw (Existing_Column.Error renamed.name)
Set_Mode.Update -> if index.is_nothing then Error.throw (Missing_Column.Error renamed.name) else True
new_table = check_add.if_not_error <|
new_col = renamed.as_internal
new_cols = if index.is_nothing then self.internal_columns + [new_col] else
Vector.new self.column_count i-> if i == index then new_col else self.internal_columns.at i
self.updated_columns new_cols

problem_builder.report_unique_name_strategy unique
problem_builder.attach_problems_after on_problems new_table

## PRIVATE
Given an expression, create a derived column where each value is the
Expand All @@ -1076,17 +1073,16 @@ type DB_Table
an `Additional_Warnings`.
evaluate_expression : Text | Expression -> Problem_Behavior -> DB_Column ! No_Such_Column | Invalid_Value_Type | Expression_Error
evaluate_expression self expression:(Text | Expression) on_problems:Problem_Behavior=..Report_Warning =
Feature.Set.if_supported_else_throw self.connection.dialect "evaluate_expression" <|
if expression.is_a Text then self.evaluate_expression (Expression.Value expression) on_problems else
get_column name = self.at name
make_constant_column value = case value of
_ : DB_Column -> value
_ -> self.make_constant_column value
new_column = Expression.evaluate expression get_column make_constant_column "Standard.Database.DB_Column" "DB_Column" DB_Column.var_args_functions
problems = Warning.get_all new_column . map .value
result = new_column.rename (self.connection.base_connection.column_naming_helper.sanitize_name expression.expression)
on_problems.attach_problems_before problems <|
Warning.set result []
if expression.is_a Text then self.evaluate_expression (Expression.Value expression) on_problems else
get_column name = self.at name
make_constant_column value = case value of
_ : DB_Column -> value
_ -> self.make_constant_column value
new_column = Expression.evaluate expression get_column make_constant_column "Standard.Database.DB_Column" "DB_Column" DB_Column.var_args_functions
problems = Warning.get_all new_column . map .value
result = new_column.rename (self.connection.base_connection.column_naming_helper.sanitize_name expression.expression)
on_problems.attach_problems_before problems <|
Warning.set result []

## PRIVATE
A helper that creates a two-column table from a Dictionary.
Expand Down Expand Up @@ -1176,10 +1172,9 @@ type DB_Table
Returns the vector of columns contained in this table.
columns : Vector DB_Column
columns self =
Feature.Column_Operations.if_supported_else_throw self.connection.dialect "columns" <|
Vector.from_polyglot_array <|
Array_Proxy.new self.internal_columns.length i->
self.make_column (self.internal_columns.at i)
Vector.from_polyglot_array <|
Array_Proxy.new self.internal_columns.length i->
self.make_column (self.internal_columns.at i)

## GROUP Standard.Base.Metadata
ICON metadata
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ type Feature
## PRIVATE
currently blocks getting a DB_Column from a DB_Table, but will soon refine to operations on DB_Column.
Column_Operations
## PRIVATE
set operations on tables.
Set
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this flag no longer needed?

Copy link
Member Author

Choose a reason for hiding this comment

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

Set is a fairly basic operation that all dbs should be able to support from day 1. The only hard bit comes from all of the operations and we have a separate flagging system for these. is_operation_supported

## PRIVATE
get_row, take, drop, limit
Sample
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ type SQLServer_Dialect
Checks if a feature is supported by the dialect.
is_feature_supported self feature:Feature -> Boolean =
case feature of
Feature.Select_Columns -> True
_ -> False

## PRIVATE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ type SQLServer_Type_Mapping
should_warn_on_materialize (db_type : Value_Type) (in_memory_type : Value_Type) -> Boolean =
SQL_Type_Mapping.default_should_warn_on_materialize db_type in_memory_type

## PRIVATE
is_integer_type (value_type : Value_Type) -> Boolean = value_type.is_integer

## PRIVATE
is_same_type (value_type1 : Value_Type) (value_type2 : Value_Type) -> Boolean =
value_type1.is_same_type value_type2

## PRIVATE
on_unknown_type sql_type =
Value_Type.Unsupported_Data_Type sql_type.name sql_type
Expand Down
2 changes: 1 addition & 1 deletion test/Microsoft_Tests/src/SQLServer_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ add_sqlserver_specs suite_builder create_connection_fn =

materialize = .read

common_selection = Common_Table_Operations.Main.Test_Selection.Config supports_case_sensitive_columns=True order_by_unicode_normalization_by_default=True allows_mixed_type_comparisons=False text_length_limited_columns=True fixed_length_text_columns=True removes_trailing_whitespace_casting_from_char_to_varchar=True char_max_size_after_substring=..Reset supports_decimal_type=True supported_replace_params=supported_replace_params run_advanced_edge_case_tests_by_default=True supports_date_time_without_timezone=False date_time=False is_nan_comparable=True
common_selection = Common_Table_Operations.Main.Test_Selection.Config supports_case_sensitive_columns=False order_by_unicode_normalization_by_default=True allows_mixed_type_comparisons=False text_length_limited_columns=True fixed_length_text_columns=True removes_trailing_whitespace_casting_from_char_to_varchar=True char_max_size_after_substring=..Reset supports_decimal_type=True supported_replace_params=supported_replace_params run_advanced_edge_case_tests_by_default=True supports_date_time_without_timezone=False date_time=False is_nan_comparable=True
aggregate_selection = Common_Table_Operations.Aggregate_Spec.Test_Selection.Config first_last_row_order=False aggregation_problems=False
agg_in_memory_table = (enso_project.data / "data.csv") . read

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,18 +146,7 @@ type Connection_Data
self.connection.close

add_specs suite_builder setup =
if setup.is_feature_supported Feature.Filter then (add_column_operation_specs suite_builder setup) else
suite_builder.group setup.prefix+"(Column_Operations_Spec)" group_builder->
group_builder.specify "at should report unsupported" <|
table_builder = setup.light_table_builder
t = table_builder [["ix", [1, 2, 3, 4, 5]], ["X", [100, 3, Nothing, 4, 12]], ["Y", [100, 4, 2, Nothing, 11]]]
t2 = t.at "X"
t2.should_fail_with (Unsupported_Database_Operation.Error "at")
group_builder.specify "get should report unsupported" <|
table_builder = setup.light_table_builder
t = table_builder [["ix", [1, 2, 3, 4, 5]], ["X", [100, 3, Nothing, 4, 12]], ["Y", [100, 4, 2, Nothing, 11]]]
t2 = t.get "X"
t2.should_fail_with (Unsupported_Database_Operation.Error "get")
if setup.is_feature_supported Feature.Column_Operations then (add_column_operation_specs suite_builder setup)

add_column_operation_specs suite_builder setup =
prefix = setup.prefix
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@ from project.Common_Table_Operations.Util import all
main filter=Nothing = run_default_backend add_specs filter

add_specs suite_builder setup =
if setup.is_feature_supported Feature.Set then (add_derived_columns_specs suite_builder setup) else
suite_builder.group setup.prefix+"(Derived_Columns_Spec) Table.set" group_builder->
group_builder.specify "set should report unsupported" <|
table_builder = setup.light_table_builder
t1 = table_builder [["X", [1, 2, 3]], ["Y", [4, 5, 6]]]
t2 = t1.set (Simple_Expression.Simple_Expr (Column_Ref.Name "A") Simple_Calculation.Copy) "C"
t2.should_fail_with (Unsupported_Database_Operation.Error "set")
if setup.is_feature_supported Feature.Column_Operations then (add_derived_columns_specs suite_builder setup)

add_derived_columns_specs suite_builder setup =
prefix = setup.prefix
Expand Down
Loading