|
7 | 7 | from unittest.mock import MagicMock |
8 | 8 |
|
9 | 9 | import pytest |
| 10 | +from gooddata_api_client.model.declarative_column import DeclarativeColumn |
10 | 11 | from gooddata_api_client.model.json_api_data_source_in_attributes import JsonApiDataSourceInAttributes |
| 12 | +from gooddata_api_client.model.sql_column import SqlColumn as ApiSqlColumn |
11 | 13 | from gooddata_sdk import ( |
12 | 14 | BasicCredentials, |
13 | 15 | CatalogDataSource, |
|
20 | 22 | CatalogDataSourceRedshift, |
21 | 23 | CatalogDataSourceSnowflake, |
22 | 24 | CatalogDataSourceVertica, |
| 25 | + CatalogDeclarativeColumn, |
23 | 26 | CatalogDeclarativeDataSources, |
24 | 27 | CatalogDeclarativeModel, |
25 | 28 | CatalogGenerateLdmRequest, |
@@ -892,3 +895,192 @@ def test_jdbc_urls_creation( |
892 | 895 | ), |
893 | 896 | ) |
894 | 897 | assert data_source.url == url |
| 898 | + |
| 899 | + |
| 900 | +# CQ-1665: Tests for column description field |
| 901 | +class TestColumnDescription: |
| 902 | + """Tests for column description field support (CQ-1665). |
| 903 | +
|
| 904 | + This feature exposes database column comments/descriptions through the scan model API |
| 905 | + and uses them when generating LDM (Logical Data Model). |
| 906 | + """ |
| 907 | + |
| 908 | + def test_sql_column_with_description(self): |
| 909 | + """Test that SqlColumn can be created with a description field.""" |
| 910 | + column = SqlColumn( |
| 911 | + name="customer_id", |
| 912 | + data_type="INT", |
| 913 | + description="Unique identifier for the customer", |
| 914 | + ) |
| 915 | + assert column.name == "customer_id" |
| 916 | + assert column.data_type == "INT" |
| 917 | + assert column.description == "Unique identifier for the customer" |
| 918 | + |
| 919 | + def test_sql_column_without_description(self): |
| 920 | + """Test that SqlColumn works without description (backward compatibility).""" |
| 921 | + column = SqlColumn(name="order_id", data_type="STRING") |
| 922 | + assert column.name == "order_id" |
| 923 | + assert column.data_type == "STRING" |
| 924 | + assert column.description is None |
| 925 | + |
| 926 | + def test_sql_column_with_none_description(self): |
| 927 | + """Test that SqlColumn accepts explicit None description.""" |
| 928 | + column = SqlColumn(name="product_id", data_type="INT", description=None) |
| 929 | + assert column.name == "product_id" |
| 930 | + assert column.data_type == "INT" |
| 931 | + assert column.description is None |
| 932 | + |
| 933 | + def test_sql_column_with_empty_description(self): |
| 934 | + """Test that SqlColumn accepts empty string description.""" |
| 935 | + column = SqlColumn(name="price", data_type="NUMERIC", description="") |
| 936 | + assert column.name == "price" |
| 937 | + assert column.data_type == "NUMERIC" |
| 938 | + assert column.description == "" |
| 939 | + |
| 940 | + def test_sql_column_to_api_conversion(self): |
| 941 | + """Test that SqlColumn with description converts to API client correctly.""" |
| 942 | + column = SqlColumn( |
| 943 | + name="amount", |
| 944 | + data_type="NUMERIC", |
| 945 | + description="Total transaction amount in USD", |
| 946 | + ) |
| 947 | + api_column = column.to_api() |
| 948 | + assert api_column.name == "amount" |
| 949 | + assert api_column.data_type == "NUMERIC" |
| 950 | + assert api_column.description == "Total transaction amount in USD" |
| 951 | + |
| 952 | + def test_sql_column_from_api_conversion(self): |
| 953 | + """Test that SqlColumn with description can be created from API client.""" |
| 954 | + api_column = ApiSqlColumn( |
| 955 | + name="quantity", |
| 956 | + data_type="INT", |
| 957 | + description="Number of items purchased", |
| 958 | + ) |
| 959 | + column = SqlColumn.from_api(api_column) |
| 960 | + assert column.name == "quantity" |
| 961 | + assert column.data_type == "INT" |
| 962 | + assert column.description == "Number of items purchased" |
| 963 | + |
| 964 | + def test_sql_column_equality_with_description(self): |
| 965 | + """Test that SqlColumn equality includes description field.""" |
| 966 | + column1 = SqlColumn(name="id", data_type="INT", description="Primary key") |
| 967 | + column2 = SqlColumn(name="id", data_type="INT", description="Primary key") |
| 968 | + column3 = SqlColumn(name="id", data_type="INT", description="Different description") |
| 969 | + column4 = SqlColumn(name="id", data_type="INT") |
| 970 | + |
| 971 | + assert column1 == column2 |
| 972 | + assert column1 != column3 |
| 973 | + assert column1 != column4 |
| 974 | + |
| 975 | + def test_catalog_pdm_sql_with_column_descriptions(self): |
| 976 | + """Test that CatalogPdmSql works with columns that have descriptions.""" |
| 977 | + pdm_sql = CatalogPdmSql( |
| 978 | + statement="SELECT * FROM customers", |
| 979 | + title="Customers with descriptions", |
| 980 | + columns=[ |
| 981 | + SqlColumn( |
| 982 | + name="customer_id", |
| 983 | + data_type="INT", |
| 984 | + description="Unique customer identifier", |
| 985 | + ), |
| 986 | + SqlColumn( |
| 987 | + name="customer_name", |
| 988 | + data_type="STRING", |
| 989 | + description="Full name of the customer", |
| 990 | + ), |
| 991 | + SqlColumn( |
| 992 | + name="email", |
| 993 | + data_type="STRING", |
| 994 | + # No description - backward compatibility |
| 995 | + ), |
| 996 | + ], |
| 997 | + ) |
| 998 | + assert len(pdm_sql.columns) == 3 |
| 999 | + assert pdm_sql.columns[0].description == "Unique customer identifier" |
| 1000 | + assert pdm_sql.columns[1].description == "Full name of the customer" |
| 1001 | + assert pdm_sql.columns[2].description is None |
| 1002 | + |
| 1003 | + |
| 1004 | +class TestCatalogDeclarativeColumnDescription: |
| 1005 | + """Tests for CatalogDeclarativeColumn description field support (CQ-1665). |
| 1006 | +
|
| 1007 | + CatalogDeclarativeColumn represents a column in the Physical Data Model (PDM). |
| 1008 | + The description field stores the column comment/description from the database. |
| 1009 | + """ |
| 1010 | + |
| 1011 | + def test_declarative_column_with_description(self): |
| 1012 | + """Test that CatalogDeclarativeColumn can be created with a description.""" |
| 1013 | + column = CatalogDeclarativeColumn( |
| 1014 | + name="customer_id", |
| 1015 | + data_type="INT", |
| 1016 | + description="Unique customer identifier", |
| 1017 | + is_primary_key=True, |
| 1018 | + ) |
| 1019 | + assert column.name == "customer_id" |
| 1020 | + assert column.data_type == "INT" |
| 1021 | + assert column.description == "Unique customer identifier" |
| 1022 | + assert column.is_primary_key is True |
| 1023 | + |
| 1024 | + def test_declarative_column_without_description(self): |
| 1025 | + """Test that CatalogDeclarativeColumn works without description (backward compatibility).""" |
| 1026 | + column = CatalogDeclarativeColumn( |
| 1027 | + name="order_id", |
| 1028 | + data_type="STRING", |
| 1029 | + is_primary_key=False, |
| 1030 | + ) |
| 1031 | + assert column.name == "order_id" |
| 1032 | + assert column.data_type == "STRING" |
| 1033 | + assert column.description is None |
| 1034 | + assert column.is_primary_key is False |
| 1035 | + |
| 1036 | + def test_declarative_column_with_all_fields(self): |
| 1037 | + """Test CatalogDeclarativeColumn with all fields including description.""" |
| 1038 | + column = CatalogDeclarativeColumn( |
| 1039 | + name="foreign_key_id", |
| 1040 | + data_type="INT", |
| 1041 | + description="Reference to parent table", |
| 1042 | + is_primary_key=False, |
| 1043 | + referenced_table_id="parent_table", |
| 1044 | + referenced_table_column="id", |
| 1045 | + ) |
| 1046 | + assert column.name == "foreign_key_id" |
| 1047 | + assert column.data_type == "INT" |
| 1048 | + assert column.description == "Reference to parent table" |
| 1049 | + assert column.is_primary_key is False |
| 1050 | + assert column.referenced_table_id == "parent_table" |
| 1051 | + assert column.referenced_table_column == "id" |
| 1052 | + |
| 1053 | + def test_declarative_column_to_api_conversion(self): |
| 1054 | + """Test that CatalogDeclarativeColumn with description converts to API client correctly.""" |
| 1055 | + column = CatalogDeclarativeColumn( |
| 1056 | + name="amount", |
| 1057 | + data_type="NUMERIC", |
| 1058 | + description="Transaction amount in base currency", |
| 1059 | + ) |
| 1060 | + api_column = column.to_api() |
| 1061 | + assert api_column.name == "amount" |
| 1062 | + assert api_column.data_type == "NUMERIC" |
| 1063 | + assert api_column.description == "Transaction amount in base currency" |
| 1064 | + |
| 1065 | + def test_declarative_column_from_api_conversion(self): |
| 1066 | + """Test that CatalogDeclarativeColumn with description can be created from API client.""" |
| 1067 | + api_column = DeclarativeColumn( |
| 1068 | + name="quantity", |
| 1069 | + data_type="INT", |
| 1070 | + description="Number of items in the order", |
| 1071 | + ) |
| 1072 | + column = CatalogDeclarativeColumn.from_api(api_column) |
| 1073 | + assert column.name == "quantity" |
| 1074 | + assert column.data_type == "INT" |
| 1075 | + assert column.description == "Number of items in the order" |
| 1076 | + |
| 1077 | + def test_declarative_column_equality_with_description(self): |
| 1078 | + """Test that CatalogDeclarativeColumn equality includes description field.""" |
| 1079 | + column1 = CatalogDeclarativeColumn(name="id", data_type="INT", description="Primary key") |
| 1080 | + column2 = CatalogDeclarativeColumn(name="id", data_type="INT", description="Primary key") |
| 1081 | + column3 = CatalogDeclarativeColumn(name="id", data_type="INT", description="Different") |
| 1082 | + column4 = CatalogDeclarativeColumn(name="id", data_type="INT") |
| 1083 | + |
| 1084 | + assert column1 == column2 |
| 1085 | + assert column1 != column3 |
| 1086 | + assert column1 != column4 |
0 commit comments