sql-testing-library 0.13.0__tar.gz → 0.14.0__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 (23) hide show
  1. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/CHANGELOG.md +13 -0
  2. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/PKG-INFO +87 -7
  3. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/README.md +86 -6
  4. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/pyproject.toml +1 -1
  5. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_adapters/base.py +16 -0
  6. sql_testing_library-0.14.0/src/sql_testing_library/_adapters/bigquery.py +479 -0
  7. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_adapters/presto.py +2 -5
  8. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_adapters/redshift.py +18 -25
  9. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_adapters/snowflake.py +47 -50
  10. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_core.py +183 -6
  11. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_pytest_plugin.py +18 -0
  12. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_sql_utils.py +86 -4
  13. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_types.py +23 -4
  14. sql_testing_library-0.13.0/src/sql_testing_library/_adapters/bigquery.py +0 -270
  15. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/LICENSE +0 -0
  16. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/__init__.py +0 -0
  17. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_adapters/__init__.py +0 -0
  18. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_adapters/athena.py +0 -0
  19. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_adapters/trino.py +0 -0
  20. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_exceptions.py +0 -0
  21. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_mock_table.py +0 -0
  22. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/_sql_logger.py +0 -0
  23. {sql_testing_library-0.13.0 → sql_testing_library-0.14.0}/src/sql_testing_library/py.typed +0 -0
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## 0.14.0 (2025-06-30)
9
+
10
+ ### Feat
11
+
12
+ - **bigquery**: add struct support with list fields (#109)
13
+ - **bigquery**: add struct support for big query (#108)
14
+ - add parallel table cleanup for improved performance (#107)
15
+ - add parallel table creation for physical tables mode (#106)
16
+
17
+ ### Fix
18
+
19
+ - **athena**: handle mixed format structs with lists and maps (#111)
20
+
8
21
  ## 0.13.0 (2025-06-27)
9
22
 
10
23
  ### Feat
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sql-testing-library
3
- Version: 0.13.0
3
+ Version: 0.14.0
4
4
  Summary: A powerful Python framework for unit testing SQL queries across BigQuery, Snowflake, Redshift, Athena, and Trino with mock data
5
5
  License: MIT
6
6
  Keywords: sql,testing,unit-testing,mock-data,database-testing,bigquery,snowflake,redshift,athena,trino,data-engineering,etl-testing,sql-validation,query-testing
@@ -137,12 +137,12 @@ The library supports different data types across database engines. All checkmark
137
137
  | **Decimal Array** | `List[Decimal]` | ✅ | ✅ | ✅ | ✅ | ✅ |
138
138
  | **Optional Array** | `Optional[List[T]]` | ✅ | ✅ | ✅ | ✅ | ✅ |
139
139
  | **Map/Dict** | `Dict[K, V]` | ✅ | ✅ | ✅ | ✅ | ✅ |
140
- | **Struct/Record** | `dataclass` | | ✅ | ❌ | ✅ | ❌ |
140
+ | **Struct/Record** | `dataclass` | | ✅ | ❌ | ✅ | ❌ |
141
141
  | **Nested Arrays** | `List[List[T]]` | ❌ | ❌ | ❌ | ❌ | ❌ |
142
142
 
143
143
  ### Database-Specific Notes
144
144
 
145
- - **BigQuery**: NULL arrays become empty arrays `[]`; uses scientific notation for large decimals; dict/map types stored as JSON strings; struct types not yet supported
145
+ - **BigQuery**: NULL arrays become empty arrays `[]`; uses scientific notation for large decimals; dict/map types stored as JSON strings; struct types supported using `STRUCT` syntax with named fields (dataclasses and Pydantic models)
146
146
  - **Athena**: 256KB query size limit; supports arrays and maps using `ARRAY[]` and `MAP(ARRAY[], ARRAY[])` syntax; supports struct types using `ROW` with named fields (dataclasses and Pydantic models)
147
147
  - **Redshift**: Arrays and maps implemented via SUPER type (JSON parsing); 16MB query size limit; struct types not yet supported
148
148
  - **Trino**: Memory catalog for testing; excellent decimal precision; supports arrays, maps, and struct types using `ROW` with named fields (dataclasses and Pydantic models)
@@ -301,13 +301,85 @@ def test_physical_tables():
301
301
  query="SELECT * FROM table",
302
302
  use_physical_tables=True # Force physical tables
303
303
  )
304
+
305
+ # Physical Tables with Custom Parallel Settings
306
+ @sql_test(
307
+ mock_tables=[...],
308
+ result_class=ResultClass,
309
+ use_physical_tables=True,
310
+ max_workers=4 # Customize parallel execution
311
+ )
312
+ def test_with_custom_parallelism():
313
+ return TestCase(query="SELECT * FROM table")
304
314
  ```
305
315
 
306
316
  **Notes:**
307
317
  - **CTE Mode**: Default mode, works with all database engines, suitable for most use cases
308
318
  - **Physical Tables**: Used automatically when CTE queries exceed database size limits or when explicitly requested
319
+ - **Parallel Table Creation**: When using physical tables with multiple mock tables, they are created in parallel by default for better performance
309
320
  - **Snowflake**: Full support for both CTE and physical table modes
310
321
 
322
+ ### Performance Optimization: Parallel Table Operations
323
+
324
+ When using `use_physical_tables=True` with multiple mock tables, the library can create and cleanup tables in parallel for better performance.
325
+
326
+ #### Parallel Table Creation
327
+
328
+ **Default Behavior:**
329
+ - Parallel creation is **enabled by default** when using physical tables
330
+ - Smart worker allocation based on table count:
331
+ - 1-2 tables: Same number of workers as tables
332
+ - 3-5 tables: 3 workers
333
+ - 6-10 tables: 5 workers
334
+ - 11+ tables: 8 workers (capped)
335
+
336
+ **Customization:**
337
+ ```python
338
+ # Disable parallel creation
339
+ @sql_test(use_physical_tables=True, parallel_table_creation=False)
340
+
341
+ # Custom worker count
342
+ @sql_test(use_physical_tables=True, max_workers=2)
343
+
344
+ # In SQLTestCase directly
345
+ TestCase(
346
+ query="...",
347
+ use_physical_tables=True,
348
+ parallel_table_creation=True, # Default
349
+ max_workers=4 # Custom worker limit
350
+ )
351
+ ```
352
+
353
+ #### Parallel Table Cleanup
354
+
355
+ **Default Behavior:**
356
+ - Parallel cleanup is **enabled by default** when using physical tables
357
+ - Uses the same smart worker allocation as table creation
358
+ - Cleanup errors are logged as warnings (best-effort cleanup)
359
+
360
+ **Customization:**
361
+ ```python
362
+ # Disable parallel cleanup
363
+ @sql_test(use_physical_tables=True, parallel_table_cleanup=False)
364
+
365
+ # Custom worker count for both creation and cleanup
366
+ @sql_test(use_physical_tables=True, max_workers=2)
367
+
368
+ # In SQLTestCase directly
369
+ TestCase(
370
+ query="...",
371
+ use_physical_tables=True,
372
+ parallel_table_creation=True, # Default
373
+ parallel_table_cleanup=True, # Default
374
+ max_workers=4 # Custom worker limit for both operations
375
+ )
376
+ ```
377
+
378
+ **Performance Benefits:**
379
+ - Both table creation and cleanup operations are parallelized when multiple tables are involved
380
+ - Significantly reduces test execution time for tests with many mock tables
381
+ - Particularly beneficial for cloud databases where network latency is a factor
382
+
311
383
  ## Installation
312
384
 
313
385
  ### For End Users (pip)
@@ -572,9 +644,9 @@ def test_pattern_3():
572
644
  )
573
645
  ```
574
646
 
575
- ### Working with Struct Types (Athena and Trino)
647
+ ### Working with Struct Types (Athena, Trino, and BigQuery)
576
648
 
577
- The library supports struct/record types using Python dataclasses or Pydantic models for Athena and Trino:
649
+ The library supports struct/record types using Python dataclasses or Pydantic models for Athena, Trino, and BigQuery:
578
650
 
579
651
  ```python
580
652
  from dataclasses import dataclass
@@ -621,7 +693,7 @@ class EmployeesMockTable(BaseMockTable):
621
693
 
622
694
  # Test with struct types
623
695
  @sql_test(
624
- adapter_type="athena", # or "trino"
696
+ adapter_type="athena", # or "trino" or "bigquery"
625
697
  mock_tables=[
626
698
  EmployeesMockTable([
627
699
  Employee(
@@ -667,7 +739,7 @@ def test_struct_with_dot_notation():
667
739
 
668
740
  # You can also query entire structs
669
741
  @sql_test(
670
- adapter_type="trino",
742
+ adapter_type="trino", # or "athena" or "bigquery"
671
743
  mock_tables=[EmployeesMockTable([...])],
672
744
  result_class=dict # Returns full struct as dict
673
745
  )
@@ -1172,6 +1244,14 @@ For detailed usage and configuration options, see the example files included.
1172
1244
 
1173
1245
  The library has a few known limitations that are planned to be addressed in future updates:
1174
1246
 
1247
+ ### Struct Type Support
1248
+ - **Redshift**: Struct types are not supported due to lack of native struct/record types (uses SUPER type for JSON)
1249
+ - **Snowflake**: Struct types are not supported due to lack of native struct/record types (uses VARIANT type for JSON)
1250
+
1251
+
1252
+ ### Database-Specific Limitations
1253
+ - **BigQuery**: Does not support nested arrays (arrays of arrays). This is a BigQuery database limitation, not a library limitation. (See TODO in `test_struct_types_integration.py:test_nested_lists`)
1254
+
1175
1255
  ### General Improvements
1176
1256
  - Add support for more SQL dialects
1177
1257
  - Improve error handling for malformed SQL
@@ -80,12 +80,12 @@ The library supports different data types across database engines. All checkmark
80
80
  | **Decimal Array** | `List[Decimal]` | ✅ | ✅ | ✅ | ✅ | ✅ |
81
81
  | **Optional Array** | `Optional[List[T]]` | ✅ | ✅ | ✅ | ✅ | ✅ |
82
82
  | **Map/Dict** | `Dict[K, V]` | ✅ | ✅ | ✅ | ✅ | ✅ |
83
- | **Struct/Record** | `dataclass` | | ✅ | ❌ | ✅ | ❌ |
83
+ | **Struct/Record** | `dataclass` | | ✅ | ❌ | ✅ | ❌ |
84
84
  | **Nested Arrays** | `List[List[T]]` | ❌ | ❌ | ❌ | ❌ | ❌ |
85
85
 
86
86
  ### Database-Specific Notes
87
87
 
88
- - **BigQuery**: NULL arrays become empty arrays `[]`; uses scientific notation for large decimals; dict/map types stored as JSON strings; struct types not yet supported
88
+ - **BigQuery**: NULL arrays become empty arrays `[]`; uses scientific notation for large decimals; dict/map types stored as JSON strings; struct types supported using `STRUCT` syntax with named fields (dataclasses and Pydantic models)
89
89
  - **Athena**: 256KB query size limit; supports arrays and maps using `ARRAY[]` and `MAP(ARRAY[], ARRAY[])` syntax; supports struct types using `ROW` with named fields (dataclasses and Pydantic models)
90
90
  - **Redshift**: Arrays and maps implemented via SUPER type (JSON parsing); 16MB query size limit; struct types not yet supported
91
91
  - **Trino**: Memory catalog for testing; excellent decimal precision; supports arrays, maps, and struct types using `ROW` with named fields (dataclasses and Pydantic models)
@@ -244,13 +244,85 @@ def test_physical_tables():
244
244
  query="SELECT * FROM table",
245
245
  use_physical_tables=True # Force physical tables
246
246
  )
247
+
248
+ # Physical Tables with Custom Parallel Settings
249
+ @sql_test(
250
+ mock_tables=[...],
251
+ result_class=ResultClass,
252
+ use_physical_tables=True,
253
+ max_workers=4 # Customize parallel execution
254
+ )
255
+ def test_with_custom_parallelism():
256
+ return TestCase(query="SELECT * FROM table")
247
257
  ```
248
258
 
249
259
  **Notes:**
250
260
  - **CTE Mode**: Default mode, works with all database engines, suitable for most use cases
251
261
  - **Physical Tables**: Used automatically when CTE queries exceed database size limits or when explicitly requested
262
+ - **Parallel Table Creation**: When using physical tables with multiple mock tables, they are created in parallel by default for better performance
252
263
  - **Snowflake**: Full support for both CTE and physical table modes
253
264
 
265
+ ### Performance Optimization: Parallel Table Operations
266
+
267
+ When using `use_physical_tables=True` with multiple mock tables, the library can create and cleanup tables in parallel for better performance.
268
+
269
+ #### Parallel Table Creation
270
+
271
+ **Default Behavior:**
272
+ - Parallel creation is **enabled by default** when using physical tables
273
+ - Smart worker allocation based on table count:
274
+ - 1-2 tables: Same number of workers as tables
275
+ - 3-5 tables: 3 workers
276
+ - 6-10 tables: 5 workers
277
+ - 11+ tables: 8 workers (capped)
278
+
279
+ **Customization:**
280
+ ```python
281
+ # Disable parallel creation
282
+ @sql_test(use_physical_tables=True, parallel_table_creation=False)
283
+
284
+ # Custom worker count
285
+ @sql_test(use_physical_tables=True, max_workers=2)
286
+
287
+ # In SQLTestCase directly
288
+ TestCase(
289
+ query="...",
290
+ use_physical_tables=True,
291
+ parallel_table_creation=True, # Default
292
+ max_workers=4 # Custom worker limit
293
+ )
294
+ ```
295
+
296
+ #### Parallel Table Cleanup
297
+
298
+ **Default Behavior:**
299
+ - Parallel cleanup is **enabled by default** when using physical tables
300
+ - Uses the same smart worker allocation as table creation
301
+ - Cleanup errors are logged as warnings (best-effort cleanup)
302
+
303
+ **Customization:**
304
+ ```python
305
+ # Disable parallel cleanup
306
+ @sql_test(use_physical_tables=True, parallel_table_cleanup=False)
307
+
308
+ # Custom worker count for both creation and cleanup
309
+ @sql_test(use_physical_tables=True, max_workers=2)
310
+
311
+ # In SQLTestCase directly
312
+ TestCase(
313
+ query="...",
314
+ use_physical_tables=True,
315
+ parallel_table_creation=True, # Default
316
+ parallel_table_cleanup=True, # Default
317
+ max_workers=4 # Custom worker limit for both operations
318
+ )
319
+ ```
320
+
321
+ **Performance Benefits:**
322
+ - Both table creation and cleanup operations are parallelized when multiple tables are involved
323
+ - Significantly reduces test execution time for tests with many mock tables
324
+ - Particularly beneficial for cloud databases where network latency is a factor
325
+
254
326
  ## Installation
255
327
 
256
328
  ### For End Users (pip)
@@ -515,9 +587,9 @@ def test_pattern_3():
515
587
  )
516
588
  ```
517
589
 
518
- ### Working with Struct Types (Athena and Trino)
590
+ ### Working with Struct Types (Athena, Trino, and BigQuery)
519
591
 
520
- The library supports struct/record types using Python dataclasses or Pydantic models for Athena and Trino:
592
+ The library supports struct/record types using Python dataclasses or Pydantic models for Athena, Trino, and BigQuery:
521
593
 
522
594
  ```python
523
595
  from dataclasses import dataclass
@@ -564,7 +636,7 @@ class EmployeesMockTable(BaseMockTable):
564
636
 
565
637
  # Test with struct types
566
638
  @sql_test(
567
- adapter_type="athena", # or "trino"
639
+ adapter_type="athena", # or "trino" or "bigquery"
568
640
  mock_tables=[
569
641
  EmployeesMockTable([
570
642
  Employee(
@@ -610,7 +682,7 @@ def test_struct_with_dot_notation():
610
682
 
611
683
  # You can also query entire structs
612
684
  @sql_test(
613
- adapter_type="trino",
685
+ adapter_type="trino", # or "athena" or "bigquery"
614
686
  mock_tables=[EmployeesMockTable([...])],
615
687
  result_class=dict # Returns full struct as dict
616
688
  )
@@ -1115,6 +1187,14 @@ For detailed usage and configuration options, see the example files included.
1115
1187
 
1116
1188
  The library has a few known limitations that are planned to be addressed in future updates:
1117
1189
 
1190
+ ### Struct Type Support
1191
+ - **Redshift**: Struct types are not supported due to lack of native struct/record types (uses SUPER type for JSON)
1192
+ - **Snowflake**: Struct types are not supported due to lack of native struct/record types (uses VARIANT type for JSON)
1193
+
1194
+
1195
+ ### Database-Specific Limitations
1196
+ - **BigQuery**: Does not support nested arrays (arrays of arrays). This is a BigQuery database limitation, not a library limitation. (See TODO in `test_struct_types_integration.py:test_nested_lists`)
1197
+
1118
1198
  ### General Improvements
1119
1199
  - Add support for more SQL dialects
1120
1200
  - Improve error handling for malformed SQL
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "sql-testing-library"
7
- version = "0.13.0"
7
+ version = "0.14.0"
8
8
  description = "A powerful Python framework for unit testing SQL queries across BigQuery, Snowflake, Redshift, Athena, and Trino with mock data"
9
9
  authors = ["Gurmeet Saran <gurmeetx@gmail.com>", "Kushal Thakkar <kushal.thakkar@gmail.com>"]
10
10
  maintainers = ["Gurmeet Saran <gurmeetx@gmail.com>", "Kushal Thakkar <kushal.thakkar@gmail.com>"]
@@ -1,5 +1,7 @@
1
1
  """Base database adapter interface."""
2
2
 
3
+ import time
4
+ import uuid
3
5
  from abc import ABC, abstractmethod
4
6
  from typing import TYPE_CHECKING, Any, List, Optional, Tuple
5
7
 
@@ -56,3 +58,17 @@ class DatabaseAdapter(ABC):
56
58
  def get_query_size_limit(self) -> Optional[int]:
57
59
  """Return query size limit in bytes, or None if no limit."""
58
60
  return None
61
+
62
+ def get_temp_table_name(self, mock_table: BaseMockTable, prefix: str = "temp") -> str:
63
+ """Generate a unique temporary table name.
64
+
65
+ Args:
66
+ mock_table: The mock table to generate a name for
67
+ prefix: The prefix to use (default "temp", Snowflake uses "TEMP")
68
+
69
+ Returns:
70
+ A unique table name with timestamp and UUID
71
+ """
72
+ timestamp = int(time.time() * 1000)
73
+ unique_id = str(uuid.uuid4()).replace("-", "")[:8]
74
+ return f"{prefix}_{mock_table.get_table_name()}_{timestamp}_{unique_id}"