e6data-python-connector 2.3.13__tar.gz → 2.3.14__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. {e6data_python_connector-2.3.13/e6data_python_connector.egg-info → e6data_python_connector-2.3.14}/PKG-INFO +44 -2
  2. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/README.md +43 -1
  3. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/dialect.py +16 -4
  4. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14/e6data_python_connector.egg-info}/PKG-INFO +44 -2
  5. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector.egg-info/SOURCES.txt +1 -0
  6. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/setup.py +1 -1
  7. e6data_python_connector-2.3.14/test/test_dialect_columns.py +86 -0
  8. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/LICENSE +0 -0
  9. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/MANIFEST.in +0 -0
  10. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/__init__.py +0 -0
  11. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/cluster_manager.py +0 -0
  12. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/cluster_server/__init__.py +0 -0
  13. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/cluster_server/cluster_pb2.py +0 -0
  14. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/cluster_server/cluster_pb2_grpc.py +0 -0
  15. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/common.py +0 -0
  16. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/connection_pool.py +0 -0
  17. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/constants.py +0 -0
  18. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/datainputstream.py +0 -0
  19. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/date_time_utils.py +0 -0
  20. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/e6data_grpc.py +0 -0
  21. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/e6x_vector/__init__.py +0 -0
  22. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/e6x_vector/constants.py +0 -0
  23. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/e6x_vector/ttypes.py +0 -0
  24. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/exceptions.py +0 -0
  25. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/server/QueryEngineService.py +0 -0
  26. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/server/__init__.py +0 -0
  27. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/server/constants.py +0 -0
  28. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/server/e6x_engine_pb2.py +0 -0
  29. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/server/e6x_engine_pb2.pyi +0 -0
  30. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/server/e6x_engine_pb2_grpc.py +0 -0
  31. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/server/ttypes.py +0 -0
  32. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/strategy.py +0 -0
  33. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector/typeId.py +0 -0
  34. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector.egg-info/dependency_links.txt +0 -0
  35. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector.egg-info/entry_points.txt +0 -0
  36. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector.egg-info/requires.txt +0 -0
  37. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/e6data_python_connector.egg-info/top_level.txt +0 -0
  38. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/gen-py/__init__.py +0 -0
  39. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/gen-py/e6x_vector/__init__.py +0 -0
  40. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/gen-py/e6x_vector/constants.py +0 -0
  41. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/gen-py/e6x_vector/ttypes.py +0 -0
  42. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/pyproject.toml +0 -0
  43. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/setup.cfg +0 -0
  44. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/__init__.py +0 -0
  45. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/analyze_38_nines.py +0 -0
  46. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/analyze_all_cases.py +0 -0
  47. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/analyze_binary.py +0 -0
  48. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/analyze_correct_value.py +0 -0
  49. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/analyze_fields.py +0 -0
  50. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/check_decimal_errors.py +0 -0
  51. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/cleanup_test_files.py +0 -0
  52. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/debug_38_nines.py +0 -0
  53. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/debug_binary.py +0 -0
  54. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/final_test.py +0 -0
  55. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/move_tests.py +0 -0
  56. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/quick_test.py +0 -0
  57. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_38_nines.py +0 -0
  58. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_all_decimal128_cases.py +0 -0
  59. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_cluster_manager_efficiency.py +0 -0
  60. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_cluster_manager_none_strategy.py +0 -0
  61. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_cluster_manager_strategy.py +0 -0
  62. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_code_optimizations.py +0 -0
  63. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_comprehensive.py +0 -0
  64. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_connection_pool.py +0 -0
  65. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_connection_pool_e2e.py +0 -0
  66. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_current_implementation.py +0 -0
  67. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_decimal128_binary_parsing.py +0 -0
  68. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_decimal128_parsing.py +0 -0
  69. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_fix.py +0 -0
  70. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_improved_parsing.py +0 -0
  71. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_known_case.py +0 -0
  72. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_manual_analysis.py +0 -0
  73. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_mock_server.py +0 -0
  74. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_multiprocessing_fix.py +0 -0
  75. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_new_implementation.py +0 -0
  76. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_pool_concurrency_simple.py +0 -0
  77. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_pool_threading_multiprocessing.py +0 -0
  78. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_simple_connection_pool.py +0 -0
  79. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_specific_binary.py +0 -0
  80. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_strategy.py +0 -0
  81. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_strategy_logic.py +0 -0
  82. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_strategy_persistence_fix.py +0 -0
  83. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_strategy_sharing_fix.py +0 -0
  84. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/test_user_binary_value.py +0 -0
  85. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/tests.py +0 -0
  86. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/tests_grpc.py +0 -0
  87. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/validate_decimal128.py +0 -0
  88. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/validate_implementation.py +0 -0
  89. {e6data_python_connector-2.3.13 → e6data_python_connector-2.3.14}/test/verify_decimal_fix.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: e6data-python-connector
3
- Version: 2.3.13
3
+ Version: 2.3.14
4
4
  Summary: Client for the e6data distributed SQL Engine.
5
5
  Home-page: https://github.com/e6x-labs/e6data-python-connector
6
6
  Author: e6data, Inc.
@@ -39,7 +39,7 @@ Dynamic: summary
39
39
 
40
40
  # e6data Python Connector
41
41
 
42
- ![version](https://img.shields.io/badge/version-2.3.13-blue.svg)
42
+ ![version](https://img.shields.io/badge/version-2.3.14-blue.svg)
43
43
 
44
44
  ## Introduction
45
45
 
@@ -324,6 +324,48 @@ query_id = '<query_id>' # query id from execute function response.
324
324
  cursor.cancel(query_id)
325
325
  ```
326
326
 
327
+ To get the status of a running or completed query:
328
+ ```python
329
+ query_id = '<query_id>' # query id from execute function response.
330
+ status_response = cursor.status(query_id)
331
+
332
+ # Check if query execution is complete
333
+ is_complete = status_response.status # Returns True when query is done, False if still running
334
+
335
+ # Get the total row count
336
+ row_count = status_response.rowCount # Total number of rows in the result set
337
+
338
+ print(f"Query complete: {is_complete}")
339
+ print(f"Row count: {row_count}")
340
+ ```
341
+
342
+ The `status()` method is useful for:
343
+ - **Monitoring long-running queries**: Poll the status periodically to check if execution is complete
344
+ - **Checking row counts**: Get the total number of rows without fetching all results
345
+ - **Query progress tracking**: Integrate with monitoring systems or progress bars
346
+ - **Conditional fetching**: Decide whether to fetch results based on completion status
347
+
348
+ Example - Polling for query completion:
349
+ ```python
350
+ import time
351
+
352
+ cursor = conn.cursor(catalog_name=catalog_name)
353
+ query_id = cursor.execute("SELECT * FROM large_table")
354
+
355
+ # Poll until query is complete
356
+ while True:
357
+ status_response = cursor.status(query_id)
358
+ if status_response.status:
359
+ print(f"Query complete! Total rows: {status_response.rowCount}")
360
+ break
361
+ else:
362
+ print("Query still running...")
363
+ time.sleep(1) # Wait 1 second before checking again
364
+
365
+ # Now fetch the results
366
+ results = cursor.fetchall()
367
+ ```
368
+
327
369
  Switch database in an existing connection:
328
370
  ```python
329
371
  database = '<new_database_name>' # Replace with the new database.
@@ -1,6 +1,6 @@
1
1
  # e6data Python Connector
2
2
 
3
- ![version](https://img.shields.io/badge/version-2.3.13-blue.svg)
3
+ ![version](https://img.shields.io/badge/version-2.3.14-blue.svg)
4
4
 
5
5
  ## Introduction
6
6
 
@@ -285,6 +285,48 @@ query_id = '<query_id>' # query id from execute function response.
285
285
  cursor.cancel(query_id)
286
286
  ```
287
287
 
288
+ To get the status of a running or completed query:
289
+ ```python
290
+ query_id = '<query_id>' # query id from execute function response.
291
+ status_response = cursor.status(query_id)
292
+
293
+ # Check if query execution is complete
294
+ is_complete = status_response.status # Returns True when query is done, False if still running
295
+
296
+ # Get the total row count
297
+ row_count = status_response.rowCount # Total number of rows in the result set
298
+
299
+ print(f"Query complete: {is_complete}")
300
+ print(f"Row count: {row_count}")
301
+ ```
302
+
303
+ The `status()` method is useful for:
304
+ - **Monitoring long-running queries**: Poll the status periodically to check if execution is complete
305
+ - **Checking row counts**: Get the total number of rows without fetching all results
306
+ - **Query progress tracking**: Integrate with monitoring systems or progress bars
307
+ - **Conditional fetching**: Decide whether to fetch results based on completion status
308
+
309
+ Example - Polling for query completion:
310
+ ```python
311
+ import time
312
+
313
+ cursor = conn.cursor(catalog_name=catalog_name)
314
+ query_id = cursor.execute("SELECT * FROM large_table")
315
+
316
+ # Poll until query is complete
317
+ while True:
318
+ status_response = cursor.status(query_id)
319
+ if status_response.status:
320
+ print(f"Query complete! Total rows: {status_response.rowCount}")
321
+ break
322
+ else:
323
+ print("Query still running...")
324
+ time.sleep(1) # Wait 1 second before checking again
325
+
326
+ # Now fetch the results
327
+ results = cursor.fetchall()
328
+ ```
329
+
288
330
  Switch database in an existing connection:
289
331
  ```python
290
332
  database = '<new_database_name>' # Replace with the new database.
@@ -14,9 +14,15 @@ from decimal import Decimal
14
14
 
15
15
  from dateutil.parser import parse
16
16
  from sqlalchemy import exc
17
- from sqlalchemy import processors
18
17
  from sqlalchemy import types
19
- from sqlalchemy.databases import mysql
18
+ try:
19
+ from sqlalchemy import processors
20
+ except ImportError:
21
+ from sqlalchemy.engine import processors
22
+ try:
23
+ from sqlalchemy.databases import mysql
24
+ except ImportError:
25
+ from sqlalchemy.dialects import mysql
20
26
  from sqlalchemy.engine import default, Engine, Connection
21
27
  from sqlalchemy.sql import compiler
22
28
  from sqlalchemy.sql.compiler import SQLCompiler
@@ -27,6 +33,11 @@ from e6data_python_connector.exceptions import *
27
33
 
28
34
  _logger = logging.getLogger(__name__)
29
35
 
36
+ _MYSQL_TINY_INTEGER = (
37
+ getattr(mysql, "MSTinyInteger", None) or
38
+ getattr(mysql, "TINYINT", types.SmallInteger)
39
+ )
40
+
30
41
 
31
42
  class E6dataStringTypeBase(types.TypeDecorator):
32
43
  """Translates strings returned by Thrift into something else"""
@@ -120,7 +131,7 @@ class E6dataIdentifierPreparer(compiler.IdentifierPreparer):
120
131
 
121
132
  _type_map = {
122
133
  'boolean': types.Boolean,
123
- 'tinyint': mysql.MSTinyInteger,
134
+ 'tinyint': _MYSQL_TINY_INTEGER,
124
135
  'smallint': types.SmallInteger,
125
136
  'integer': types.Integer,
126
137
  'bigint': types.BigInteger,
@@ -316,7 +327,8 @@ class E6dataDialect(default.DefaultDialect):
316
327
  for column in columns:
317
328
  row = dict()
318
329
  row["name"] = column.get('fieldName')
319
- row["type"] = lambda: column.get('fieldType')
330
+ field_type = str(column.get('fieldType')).lower()
331
+ row["type"] = _type_map.get(field_type, types.String)
320
332
  rows.append(row)
321
333
  return rows
322
334
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: e6data-python-connector
3
- Version: 2.3.13
3
+ Version: 2.3.14
4
4
  Summary: Client for the e6data distributed SQL Engine.
5
5
  Home-page: https://github.com/e6x-labs/e6data-python-connector
6
6
  Author: e6data, Inc.
@@ -39,7 +39,7 @@ Dynamic: summary
39
39
 
40
40
  # e6data Python Connector
41
41
 
42
- ![version](https://img.shields.io/badge/version-2.3.13-blue.svg)
42
+ ![version](https://img.shields.io/badge/version-2.3.14-blue.svg)
43
43
 
44
44
  ## Introduction
45
45
 
@@ -324,6 +324,48 @@ query_id = '<query_id>' # query id from execute function response.
324
324
  cursor.cancel(query_id)
325
325
  ```
326
326
 
327
+ To get the status of a running or completed query:
328
+ ```python
329
+ query_id = '<query_id>' # query id from execute function response.
330
+ status_response = cursor.status(query_id)
331
+
332
+ # Check if query execution is complete
333
+ is_complete = status_response.status # Returns True when query is done, False if still running
334
+
335
+ # Get the total row count
336
+ row_count = status_response.rowCount # Total number of rows in the result set
337
+
338
+ print(f"Query complete: {is_complete}")
339
+ print(f"Row count: {row_count}")
340
+ ```
341
+
342
+ The `status()` method is useful for:
343
+ - **Monitoring long-running queries**: Poll the status periodically to check if execution is complete
344
+ - **Checking row counts**: Get the total number of rows without fetching all results
345
+ - **Query progress tracking**: Integrate with monitoring systems or progress bars
346
+ - **Conditional fetching**: Decide whether to fetch results based on completion status
347
+
348
+ Example - Polling for query completion:
349
+ ```python
350
+ import time
351
+
352
+ cursor = conn.cursor(catalog_name=catalog_name)
353
+ query_id = cursor.execute("SELECT * FROM large_table")
354
+
355
+ # Poll until query is complete
356
+ while True:
357
+ status_response = cursor.status(query_id)
358
+ if status_response.status:
359
+ print(f"Query complete! Total rows: {status_response.rowCount}")
360
+ break
361
+ else:
362
+ print("Query still running...")
363
+ time.sleep(1) # Wait 1 second before checking again
364
+
365
+ # Now fetch the results
366
+ results = cursor.fetchall()
367
+ ```
368
+
327
369
  Switch database in an existing connection:
328
370
  ```python
329
371
  database = '<new_database_name>' # Replace with the new database.
@@ -64,6 +64,7 @@ test/test_connection_pool_e2e.py
64
64
  test/test_current_implementation.py
65
65
  test/test_decimal128_binary_parsing.py
66
66
  test/test_decimal128_parsing.py
67
+ test/test_dialect_columns.py
67
68
  test/test_fix.py
68
69
  test/test_improved_parsing.py
69
70
  test/test_known_case.py
@@ -12,7 +12,7 @@
12
12
 
13
13
  import setuptools
14
14
 
15
- VERSION = (2, 3, 13,)
15
+ VERSION = (2, 3, 14,)
16
16
 
17
17
 
18
18
  def get_long_desc():
@@ -0,0 +1,86 @@
1
+ import unittest
2
+ from unittest.mock import patch
3
+
4
+ from sqlalchemy import types
5
+
6
+ from e6data_python_connector import dialect as dialect_module
7
+ from e6data_python_connector.dialect import (
8
+ E6dataDate,
9
+ E6dataDecimal,
10
+ E6dataDialect,
11
+ E6dataTimestamp,
12
+ )
13
+
14
+
15
+ class FakeClient(object):
16
+ def __init__(self, columns):
17
+ self.columns = columns
18
+ self.calls = []
19
+
20
+ def get_columns(self, catalog, schema, table_name):
21
+ self.calls.append((catalog, schema, table_name))
22
+ return self.columns
23
+
24
+
25
+ class FakeCursorOwner(object):
26
+ def __init__(self, client):
27
+ self.client = client
28
+
29
+ def cursor(self, catalog_name=None):
30
+ return FakeCursor(self.client)
31
+
32
+
33
+ class FakeCursor(object):
34
+ def __init__(self, client):
35
+ self.connection = client
36
+
37
+
38
+ class FakeSQLAlchemyConnection(object):
39
+ def __init__(self, client):
40
+ self.connection = FakeCursorOwner(client)
41
+
42
+
43
+ class TestDialectGetColumns(unittest.TestCase):
44
+ def test_get_columns_maps_each_reflected_column_to_its_own_sqlalchemy_type(self):
45
+ client = FakeClient([
46
+ {"fieldName": "id", "fieldType": "integer"},
47
+ {"fieldName": "customer_name", "fieldType": "varchar"},
48
+ {"fieldName": "amount", "fieldType": "decimal"},
49
+ {"fieldName": "created_on", "fieldType": "date"},
50
+ {"fieldName": "created_at", "fieldType": "timestamp"},
51
+ ])
52
+ connection = FakeSQLAlchemyConnection(client)
53
+ dialect = E6dataDialect()
54
+ dialect.catalog_name = "lakehouse"
55
+
56
+ with patch.object(dialect_module, "Connection", FakeSQLAlchemyConnection):
57
+ columns = dialect.get_columns(connection, "orders", "sales")
58
+
59
+ self.assertEqual(
60
+ ["id", "customer_name", "amount", "created_on", "created_at"],
61
+ [column["name"] for column in columns],
62
+ )
63
+ self.assertEqual([("lakehouse", "sales", "orders")], client.calls)
64
+ self.assertIs(columns[0]["type"], types.Integer)
65
+ self.assertIs(columns[1]["type"], types.String)
66
+ self.assertIs(columns[2]["type"], E6dataDecimal)
67
+ self.assertIs(columns[3]["type"], E6dataDate)
68
+ self.assertIs(columns[4]["type"], E6dataTimestamp)
69
+
70
+ def test_get_columns_defaults_unknown_e6data_type_to_string(self):
71
+ client = FakeClient([
72
+ {"fieldName": "payload", "fieldType": "variant"},
73
+ ])
74
+ connection = FakeSQLAlchemyConnection(client)
75
+ dialect = E6dataDialect()
76
+ dialect.catalog_name = "lakehouse"
77
+
78
+ with patch.object(dialect_module, "Connection", FakeSQLAlchemyConnection):
79
+ columns = dialect.get_columns(connection, "events", "sales")
80
+
81
+ self.assertEqual("payload", columns[0]["name"])
82
+ self.assertIs(columns[0]["type"], types.String)
83
+
84
+
85
+ if __name__ == "__main__":
86
+ unittest.main()