77 pyarrow = None
88
99from tests .e2e .test_driver import PySQLPytestTestCase
10+ from tests .e2e .common .predicates import pysql_supports_arrow
1011
1112class TestVariantTypes (PySQLPytestTestCase ):
1213 """Tests for the proper detection and handling of VARIANT type columns"""
1314
1415 @pytest .fixture (scope = "class" )
15- def variant_table_fixture (self , connection_details ):
16+ def variant_table (self , connection_details ):
17+ """A pytest fixture that creates a test table and cleans up after tests"""
1618 self .arguments = connection_details .copy ()
17- """A pytest fixture that creates a table with variant columns, inserts records, yields, and then drops the table"" "
18-
19+ table_name = "pysql_test_variant_types_table "
20+
1921 with self .cursor () as cursor :
20- # Check if VARIANT type is supported
2122 try :
22- # delete the table if it exists
23- cursor .execute ("DROP TABLE IF EXISTS pysql_test_variant_types_table" )
24-
2523 # Create the table with variant columns
2624 cursor .execute (
2725 """
@@ -42,133 +40,41 @@ def variant_table_fixture(self, connection_details):
4240 (2, PARSE_JSON('[1, 2, 3, 4]'), 'another string')
4341 """
4442 )
45-
46- variant_supported = True
47- except Exception as e :
48- # VARIANT type not supported in this environment
49- print (f"VARIANT type not supported: { e } " )
50- variant_supported = False
51-
52- yield variant_supported
53-
54- # Clean up if table was created
55- if variant_supported :
56- cursor .execute ("DROP TABLE IF EXISTS pysql_test_variant_types_table" )
43+ yield table_name
44+ finally :
45+ cursor .execute (f"DROP TABLE IF EXISTS { table_name } " )
5746
58- def test_variant_type_detection (self , variant_table_fixture ):
59- """Test that VARIANT type columns are properly detected"""
60- if not variant_table_fixture :
61- pytest .skip ("VARIANT type not supported in this environment" )
62-
47+ @pytest .mark .skipif (not pysql_supports_arrow (), reason = "Requires arrow support" )
48+ def test_variant_type_detection (self , variant_table ):
49+ """Test that VARIANT type columns are properly detected in schema"""
6350 with self .cursor () as cursor :
64- cursor .execute ("SELECT * FROM pysql_test_variant_types_table LIMIT 1 " )
51+ cursor .execute (f "SELECT * FROM { variant_table } LIMIT 0 " )
6552
66- # Check that the column type is properly detected as 'variant'
53+ # Verify column types in description
54+ assert cursor .description [0 ][1 ] == 'int' , "Integer column type not correctly identified"
6755 assert cursor .description [1 ][1 ] == 'variant' , "VARIANT column type not correctly identified"
68-
69- # Regular string column should still be reported as string
70- assert cursor .description [2 ][1 ] == 'string' , "Regular string column type not correctly identified"
56+ assert cursor .description [2 ][1 ] == 'string' , "String column type not correctly identified"
7157
72- def test_variant_data_retrieval (self , variant_table_fixture ):
58+ @pytest .mark .skipif (not pysql_supports_arrow (), reason = "Requires arrow support" )
59+ def test_variant_data_retrieval (self , variant_table ):
7360 """Test that VARIANT data is properly retrieved and can be accessed as JSON"""
74- if not variant_table_fixture :
75- pytest .skip ("VARIANT type not supported in this environment" )
76-
7761 with self .cursor () as cursor :
78- cursor .execute ("SELECT * FROM pysql_test_variant_types_table ORDER BY id" )
62+ cursor .execute (f "SELECT * FROM { variant_table } ORDER BY id" )
7963 rows = cursor .fetchall ()
8064
8165 # First row should have a JSON object
8266 json_obj = rows [0 ][1 ]
8367 assert isinstance (json_obj , str ), "VARIANT column should be returned as string"
84-
85- # Parsing to verify it's valid JSON
68+
8669 parsed = json .loads (json_obj )
8770 assert parsed .get ('name' ) == 'John'
8871 assert parsed .get ('age' ) == 30
89-
72+
9073 # Second row should have a JSON array
9174 json_array = rows [1 ][1 ]
9275 assert isinstance (json_array , str ), "VARIANT array should be returned as string"
9376
9477 # Parsing to verify it's valid JSON array
9578 parsed_array = json .loads (json_array )
9679 assert isinstance (parsed_array , list )
97- assert parsed_array == [1 , 2 , 3 , 4 ]
98-
99- @pytest .mark .parametrize (
100- "test_id, json_value, expected_result, description" ,
101- [
102- # Primitive types
103- (1 , '"string value"' , "string value" , "String value" ),
104- (2 , '42' , 42 , "Integer value" ),
105- (3 , '3.14159' , 3.14159 , "Float value" ),
106- (4 , 'true' , True , "Boolean true" ),
107- (5 , 'false' , False , "Boolean false" ),
108- (6 , 'null' , None , "Null value" ),
109-
110- # Complex types
111- (7 , '["a", "b", "c"]' , ["a" , "b" , "c" ], "String array" ),
112- (8 , '[1, 2, 3]' , [1 , 2 , 3 ], "Integer array" ),
113- (9 , '{"key1": "value1", "key2": "value2"}' , {"key1" : "value1" , "key2" : "value2" }, "Simple object" ),
114-
115- # Nested structures
116- (10 , '{"nested": {"a": 1, "b": 2}}' , {"nested" : {"a" : 1 , "b" : 2 }}, "Nested object" ),
117- (11 , '[["nested"], ["arrays"]]' , [["nested" ], ["arrays" ]], "Nested arrays" ),
118- (12 , '{"array": [1, 2, 3], "object": {"a": "b"}}' , {"array" : [1 , 2 , 3 ], "object" : {"a" : "b" }}, "Mixed nested structures" ),
119-
120- # Mixed types
121- (13 , '[1, "string", true, null, {"key": "value"}]' , [1 , "string" , True , None , {"key" : "value" }], "Array with mixed types" ),
122-
123- # Special cases
124- (14 , '{}' , {}, "Empty object" ),
125- (15 , '[]' , [], "Empty array" ),
126- (16 , '{"unicode": "✓ öäü 😀"}' , {"unicode" : "✓ öäü 😀" }, "Unicode characters" ),
127- (17 , '{"large_number": 9223372036854775807}' , {"large_number" : 9223372036854775807 }, "Large integer" ),
128-
129- # Deeply nested structure
130- (18 , '{"level1": {"level2": {"level3": {"level4": {"level5": "deep value"}}}}}' ,
131- {"level1" : {"level2" : {"level3" : {"level4" : {"level5" : "deep value" }}}}}, "Deeply nested structure" ),
132-
133- # Date and time types
134- (19 , '"2023-01-01"' , "2023-01-01" , "Date as string (ISO format)" ),
135- (20 , '"12:34:56"' , "12:34:56" , "Time as string (ISO format)" ),
136- (21 , '"2023-01-01T12:34:56"' , "2023-01-01T12:34:56" , "Datetime as string (ISO format)" ),
137- (22 , '"2023-01-01T12:34:56Z"' , "2023-01-01T12:34:56Z" , "Datetime with Z timezone (UTC)" ),
138- (23 , '"2023-01-01T12:34:56+02:00"' , "2023-01-01T12:34:56+02:00" , "Datetime with timezone offset" ),
139- (24 , '{"date": "2023-01-01", "time": "12:34:56"}' , {"date" : "2023-01-01" , "time" : "12:34:56" }, "Object with date and time fields" ),
140- (25 , '["2023-01-01", "2023-02-02", "2023-03-03"]' , ["2023-01-01" , "2023-02-02" , "2023-03-03" ], "Array of dates" ),
141- (26 , '{"events": [{"timestamp": "2023-01-01T12:34:56Z", "name": "event1"}, {"timestamp": "2023-02-02T12:34:56Z", "name": "event2"}]}' ,
142- {"events" : [{"timestamp" : "2023-01-01T12:34:56Z" , "name" : "event1" }, {"timestamp" : "2023-02-02T12:34:56Z" , "name" : "event2" }]},
143- "Complex object with timestamps" ),
144- ]
145- )
146- def test_variant_data_types (self , test_id , json_value , expected_result , description ):
147- """Test that different data types can be stored and retrieved from VARIANT columns"""
148- # Use a unique table name for each test case to avoid conflicts in parallel execution
149- table_name = f"pysql_test_variant_type_{ test_id } "
150-
151- with self .cursor () as cursor :
152- try :
153- # Drop the table if it exists
154- cursor .execute (f"DROP TABLE IF EXISTS { table_name } " )
155-
156- # Create a new table with a variant column
157- cursor .execute (f"CREATE TABLE { table_name } (id INTEGER, variant_col VARIANT)" )
158-
159- # Insert the test value
160- cursor .execute (f"INSERT INTO { table_name } VALUES (1, PARSE_JSON('{ json_value } '))" )
161-
162- # Query the data
163- cursor .execute (f"SELECT variant_col FROM { table_name } " )
164- result = cursor .fetchone ()
165-
166- # Parse the JSON result
167- parsed_json = json .loads (result [0 ])
168-
169- # Verify the result matches the expected value
170- assert parsed_json == expected_result , f"Failed for test case { description } "
171-
172- finally :
173- # Clean up
174- cursor .execute (f"DROP TABLE IF EXISTS { table_name } " )
80+ assert parsed_array == [1 , 2 , 3 , 4 ]
0 commit comments