sql-testing-library 0.19.0__tar.gz → 0.20.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.19.0 → sql_testing_library-0.20.0}/CHANGELOG.md +6 -0
  2. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/PKG-INFO +102 -5
  3. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/README.md +101 -4
  4. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/pyproject.toml +1 -1
  5. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/__init__.py +3 -2
  6. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_mock_table.py +91 -0
  7. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/LICENSE +0 -0
  8. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_adapters/__init__.py +0 -0
  9. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_adapters/athena.py +0 -0
  10. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_adapters/base.py +0 -0
  11. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_adapters/bigquery.py +0 -0
  12. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_adapters/duckdb.py +0 -0
  13. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_adapters/presto.py +0 -0
  14. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_adapters/redshift.py +0 -0
  15. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_adapters/snowflake.py +0 -0
  16. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_adapters/trino.py +0 -0
  17. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_core.py +0 -0
  18. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_exceptions.py +0 -0
  19. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_pytest_plugin.py +0 -0
  20. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_sql_logger.py +0 -0
  21. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_sql_utils.py +0 -0
  22. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/_types.py +0 -0
  23. {sql_testing_library-0.19.0 → sql_testing_library-0.20.0}/src/sql_testing_library/py.typed +0 -0
@@ -5,6 +5,12 @@ 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.20.0 (2025-12-07)
9
+
10
+ ### Feat
11
+
12
+ - add BigQueryMockTable class for explicit three-part naming (#134)
13
+
8
14
  ## 0.19.0 (2025-12-07)
9
15
 
10
16
  ### Feat
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sql-testing-library
3
- Version: 0.19.0
3
+ Version: 0.20.0
4
4
  Summary: SQL Testing Framework for Python: Unit test SQL queries with mock data injection for BigQuery, Snowflake, Redshift, Athena, Trino, and DuckDB. Simplify data engineering ETL testing and analytics validation.
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -570,8 +570,16 @@ TestCase(
570
570
  #### Example Mock Table Implementations:
571
571
 
572
572
  ```python
573
- # BigQuery Mock Table
574
- class UsersMockTable(BaseMockTable):
573
+ # BigQuery Mock Table (Recommended: Use BigQueryMockTable for clearer three-part naming)
574
+ from sql_testing_library import BigQueryMockTable
575
+
576
+ class UsersMockTable(BigQueryMockTable):
577
+ project_name = "test-project"
578
+ dataset_name = "test_dataset"
579
+ table_name = "users"
580
+
581
+ # BigQuery Mock Table (Alternative: Use BaseMockTable with combined project.dataset)
582
+ class UsersMockTableAlternative(BaseMockTable):
575
583
  def get_database_name(self) -> str:
576
584
  return "test-project.test_dataset" # project.dataset format
577
585
 
@@ -1047,6 +1055,7 @@ The adapter_type parameter will use the configuration from the corresponding sec
1047
1055
  - Supports Google Cloud BigQuery service
1048
1056
  - Uses UNION ALL pattern for CTE creation with complex data types
1049
1057
  - Handles authentication via service account or application default credentials
1058
+ - **Special Feature**: `BigQueryMockTable` class for explicit three-part naming (project.dataset.table)
1050
1059
 
1051
1060
  #### Athena Adapter
1052
1061
  - Supports Amazon Athena service for querying data in S3
@@ -1085,6 +1094,94 @@ The adapter_type parameter will use the configuration from the corresponding sec
1085
1094
  - No authentication required - perfect for local development and testing
1086
1095
  - Excellent performance for analytical workloads
1087
1096
 
1097
+ ### BigQuery-Specific: BigQueryMockTable
1098
+
1099
+ BigQuery uses a three-part naming scheme (`project.dataset.table`) which doesn't fit naturally into the two-part `database.table` model used by most databases. The `BigQueryMockTable` class provides explicit support for BigQuery's naming convention.
1100
+
1101
+ #### The Problem with BaseMockTable
1102
+
1103
+ Using `BaseMockTable` for BigQuery requires awkwardly cramming the project and dataset together:
1104
+
1105
+ ```python
1106
+ # Awkward: Combines project.dataset into database_name
1107
+ class UsersMockTable(BaseMockTable):
1108
+ def get_database_name(self) -> str:
1109
+ return "test-project.test_dataset" # Confusing!
1110
+
1111
+ def get_table_name(self) -> str:
1112
+ return "users"
1113
+ ```
1114
+
1115
+ #### The Solution: BigQueryMockTable
1116
+
1117
+ `BigQueryMockTable` makes BigQuery's three-part naming explicit and clear:
1118
+
1119
+ ```python
1120
+ from sql_testing_library import BigQueryMockTable
1121
+
1122
+ class UsersMockTable(BigQueryMockTable):
1123
+ project_name = "test-project"
1124
+ dataset_name = "test_dataset"
1125
+ table_name = "users"
1126
+ ```
1127
+
1128
+ #### Usage Examples
1129
+
1130
+ **Basic Usage:**
1131
+ ```python
1132
+ from sql_testing_library import BigQueryMockTable
1133
+
1134
+ class UsersMockTable(BigQueryMockTable):
1135
+ project_name = "my-project"
1136
+ dataset_name = "analytics"
1137
+ table_name = "users"
1138
+
1139
+ class OrdersMockTable(BigQueryMockTable):
1140
+ project_name = "my-project"
1141
+ dataset_name = "analytics"
1142
+ table_name = "orders"
1143
+ ```
1144
+
1145
+ **Avoid Repetition with Inheritance:**
1146
+ ```python
1147
+ # Base class for all tables in the same project
1148
+ class MyProjectTable(BigQueryMockTable):
1149
+ project_name = "my-project"
1150
+
1151
+ # Subclasses only specify dataset and table
1152
+ class UsersTable(MyProjectTable):
1153
+ dataset_name = "analytics"
1154
+ table_name = "users"
1155
+
1156
+ class OrdersTable(MyProjectTable):
1157
+ dataset_name = "analytics"
1158
+ table_name = "orders"
1159
+ ```
1160
+
1161
+ **Available Methods:**
1162
+ ```python
1163
+ table = UsersMockTable([...])
1164
+
1165
+ # BigQuery-specific methods
1166
+ table.get_project_name() # "my-project"
1167
+ table.get_dataset_name() # "analytics"
1168
+ table.get_fully_qualified_name() # "my-project.analytics.users"
1169
+
1170
+ # Backwards compatible methods (from BaseMockTable)
1171
+ table.get_database_name() # "my-project.analytics"
1172
+ table.get_table_name() # "users"
1173
+ table.get_qualified_name() # "my-project.analytics.users"
1174
+ table.get_cte_alias() # "my_project_analytics__users"
1175
+ ```
1176
+
1177
+ **Benefits:**
1178
+ - ✅ **Clear Semantics**: Each BigQuery component is explicit
1179
+ - ✅ **No Confusion**: No more cramming project.dataset together
1180
+ - ✅ **Type Safe**: Full type hints and IDE autocomplete
1181
+ - ✅ **Backwards Compatible**: Still implements all `BaseMockTable` methods
1182
+ - ✅ **Simple**: Just 3 class variables to set
1183
+ - ✅ **Flexible**: Use inheritance to share common properties
1184
+
1088
1185
  **Default Behavior:**
1089
1186
  - If adapter_type is not specified in the TestCase or decorator, the library will use the adapter specified in the `[sql_testing]` section's `adapter` setting.
1090
1187
  - If no adapter is specified in the `[sql_testing]` section, it defaults to "bigquery".
@@ -1291,7 +1388,7 @@ The library automatically:
1291
1388
  - Injects mock data via CTEs or temp tables
1292
1389
  - Deserializes results to typed Python objects
1293
1390
 
1294
- For detailed usage and configuration options, see the example files included.
1391
+ For detailed usage and configuration options, see the [documentation](https://gurmeetsaran.github.io/sqltesting/).
1295
1392
 
1296
1393
  ## Integration with Mocksmith
1297
1394
 
@@ -1326,7 +1423,7 @@ class Customer:
1326
1423
  customers = [Customer.mock() for _ in range(100)]
1327
1424
  ```
1328
1425
 
1329
- See the [Mocksmith Integration Guide](docs/mocksmith_integration.md) and [examples](examples/mocksmith_integration_example.py) for detailed usage patterns.
1426
+ See the [Mocksmith Integration Guide](docs/mocksmith_integration.md) for detailed usage patterns.
1330
1427
 
1331
1428
  ## Known Limitations and TODOs
1332
1429
 
@@ -510,8 +510,16 @@ TestCase(
510
510
  #### Example Mock Table Implementations:
511
511
 
512
512
  ```python
513
- # BigQuery Mock Table
514
- class UsersMockTable(BaseMockTable):
513
+ # BigQuery Mock Table (Recommended: Use BigQueryMockTable for clearer three-part naming)
514
+ from sql_testing_library import BigQueryMockTable
515
+
516
+ class UsersMockTable(BigQueryMockTable):
517
+ project_name = "test-project"
518
+ dataset_name = "test_dataset"
519
+ table_name = "users"
520
+
521
+ # BigQuery Mock Table (Alternative: Use BaseMockTable with combined project.dataset)
522
+ class UsersMockTableAlternative(BaseMockTable):
515
523
  def get_database_name(self) -> str:
516
524
  return "test-project.test_dataset" # project.dataset format
517
525
 
@@ -987,6 +995,7 @@ The adapter_type parameter will use the configuration from the corresponding sec
987
995
  - Supports Google Cloud BigQuery service
988
996
  - Uses UNION ALL pattern for CTE creation with complex data types
989
997
  - Handles authentication via service account or application default credentials
998
+ - **Special Feature**: `BigQueryMockTable` class for explicit three-part naming (project.dataset.table)
990
999
 
991
1000
  #### Athena Adapter
992
1001
  - Supports Amazon Athena service for querying data in S3
@@ -1025,6 +1034,94 @@ The adapter_type parameter will use the configuration from the corresponding sec
1025
1034
  - No authentication required - perfect for local development and testing
1026
1035
  - Excellent performance for analytical workloads
1027
1036
 
1037
+ ### BigQuery-Specific: BigQueryMockTable
1038
+
1039
+ BigQuery uses a three-part naming scheme (`project.dataset.table`) which doesn't fit naturally into the two-part `database.table` model used by most databases. The `BigQueryMockTable` class provides explicit support for BigQuery's naming convention.
1040
+
1041
+ #### The Problem with BaseMockTable
1042
+
1043
+ Using `BaseMockTable` for BigQuery requires awkwardly cramming the project and dataset together:
1044
+
1045
+ ```python
1046
+ # Awkward: Combines project.dataset into database_name
1047
+ class UsersMockTable(BaseMockTable):
1048
+ def get_database_name(self) -> str:
1049
+ return "test-project.test_dataset" # Confusing!
1050
+
1051
+ def get_table_name(self) -> str:
1052
+ return "users"
1053
+ ```
1054
+
1055
+ #### The Solution: BigQueryMockTable
1056
+
1057
+ `BigQueryMockTable` makes BigQuery's three-part naming explicit and clear:
1058
+
1059
+ ```python
1060
+ from sql_testing_library import BigQueryMockTable
1061
+
1062
+ class UsersMockTable(BigQueryMockTable):
1063
+ project_name = "test-project"
1064
+ dataset_name = "test_dataset"
1065
+ table_name = "users"
1066
+ ```
1067
+
1068
+ #### Usage Examples
1069
+
1070
+ **Basic Usage:**
1071
+ ```python
1072
+ from sql_testing_library import BigQueryMockTable
1073
+
1074
+ class UsersMockTable(BigQueryMockTable):
1075
+ project_name = "my-project"
1076
+ dataset_name = "analytics"
1077
+ table_name = "users"
1078
+
1079
+ class OrdersMockTable(BigQueryMockTable):
1080
+ project_name = "my-project"
1081
+ dataset_name = "analytics"
1082
+ table_name = "orders"
1083
+ ```
1084
+
1085
+ **Avoid Repetition with Inheritance:**
1086
+ ```python
1087
+ # Base class for all tables in the same project
1088
+ class MyProjectTable(BigQueryMockTable):
1089
+ project_name = "my-project"
1090
+
1091
+ # Subclasses only specify dataset and table
1092
+ class UsersTable(MyProjectTable):
1093
+ dataset_name = "analytics"
1094
+ table_name = "users"
1095
+
1096
+ class OrdersTable(MyProjectTable):
1097
+ dataset_name = "analytics"
1098
+ table_name = "orders"
1099
+ ```
1100
+
1101
+ **Available Methods:**
1102
+ ```python
1103
+ table = UsersMockTable([...])
1104
+
1105
+ # BigQuery-specific methods
1106
+ table.get_project_name() # "my-project"
1107
+ table.get_dataset_name() # "analytics"
1108
+ table.get_fully_qualified_name() # "my-project.analytics.users"
1109
+
1110
+ # Backwards compatible methods (from BaseMockTable)
1111
+ table.get_database_name() # "my-project.analytics"
1112
+ table.get_table_name() # "users"
1113
+ table.get_qualified_name() # "my-project.analytics.users"
1114
+ table.get_cte_alias() # "my_project_analytics__users"
1115
+ ```
1116
+
1117
+ **Benefits:**
1118
+ - ✅ **Clear Semantics**: Each BigQuery component is explicit
1119
+ - ✅ **No Confusion**: No more cramming project.dataset together
1120
+ - ✅ **Type Safe**: Full type hints and IDE autocomplete
1121
+ - ✅ **Backwards Compatible**: Still implements all `BaseMockTable` methods
1122
+ - ✅ **Simple**: Just 3 class variables to set
1123
+ - ✅ **Flexible**: Use inheritance to share common properties
1124
+
1028
1125
  **Default Behavior:**
1029
1126
  - If adapter_type is not specified in the TestCase or decorator, the library will use the adapter specified in the `[sql_testing]` section's `adapter` setting.
1030
1127
  - If no adapter is specified in the `[sql_testing]` section, it defaults to "bigquery".
@@ -1231,7 +1328,7 @@ The library automatically:
1231
1328
  - Injects mock data via CTEs or temp tables
1232
1329
  - Deserializes results to typed Python objects
1233
1330
 
1234
- For detailed usage and configuration options, see the example files included.
1331
+ For detailed usage and configuration options, see the [documentation](https://gurmeetsaran.github.io/sqltesting/).
1235
1332
 
1236
1333
  ## Integration with Mocksmith
1237
1334
 
@@ -1266,7 +1363,7 @@ class Customer:
1266
1363
  customers = [Customer.mock() for _ in range(100)]
1267
1364
  ```
1268
1365
 
1269
- See the [Mocksmith Integration Guide](docs/mocksmith_integration.md) and [examples](examples/mocksmith_integration_example.py) for detailed usage patterns.
1366
+ See the [Mocksmith Integration Guide](docs/mocksmith_integration.md) for detailed usage patterns.
1270
1367
 
1271
1368
  ## Known Limitations and TODOs
1272
1369
 
@@ -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.19.0"
7
+ version = "0.20.0"
8
8
  description = "SQL Testing Framework for Python: Unit test SQL queries with mock data injection for BigQuery, Snowflake, Redshift, Athena, Trino, and DuckDB. Simplify data engineering ETL testing and analytics validation."
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>"]
@@ -10,7 +10,7 @@ from ._exceptions import (
10
10
  SQLTestingError, # noqa: F401
11
11
  TypeConversionError, # noqa: F401
12
12
  )
13
- from ._mock_table import BaseMockTable # noqa: F401
13
+ from ._mock_table import BaseMockTable, BigQueryMockTable # noqa: F401
14
14
  from ._pytest_plugin import sql_test # noqa: F401
15
15
 
16
16
 
@@ -27,12 +27,13 @@ try:
27
27
  except ImportError:
28
28
  __all__ = []
29
29
 
30
- __version__ = "0.19.0"
30
+ __version__ = "0.20.0"
31
31
  __all__.extend(
32
32
  [
33
33
  "SQLTestFramework",
34
34
  "TestCase",
35
35
  "BaseMockTable",
36
+ "BigQueryMockTable",
36
37
  "DatabaseAdapter",
37
38
  "sql_test",
38
39
  "SQLTestingError",
@@ -204,3 +204,94 @@ class BaseMockTable(ABC):
204
204
  db_name = self.get_database_name().replace("-", "_").replace(".", "_")
205
205
  table_name = self.get_table_name().replace("-", "_").replace(".", "_")
206
206
  return f"{db_name}__{table_name}"
207
+
208
+
209
+ class BigQueryMockTable(BaseMockTable):
210
+ """Mock table specifically for BigQuery with three-part naming support.
211
+
212
+ BigQuery uses a three-part naming scheme: project.dataset.table
213
+ This class makes it explicit and provides better semantics than cramming
214
+ project and dataset into the generic database_name field.
215
+
216
+ Two usage patterns are supported:
217
+
218
+ Usage - Class variables for table definition:
219
+ >>> class UsersMockTable(BigQueryMockTable):
220
+ ... project_name = "my-project"
221
+ ... dataset_name = "analytics"
222
+ ... table_name = "users"
223
+ """
224
+
225
+ # Class variables that subclasses must set (mandatory)
226
+ project_name: str
227
+ dataset_name: str
228
+ table_name: str
229
+
230
+ def get_bigquery_project(self) -> str:
231
+ """Return the BigQuery project name from class variable.
232
+
233
+ Returns:
234
+ BigQuery project ID
235
+
236
+ Raises:
237
+ AttributeError: If project_name class variable not set
238
+ """
239
+ return self.project_name
240
+
241
+ def get_bigquery_dataset(self) -> str:
242
+ """Return the BigQuery dataset name from class variable.
243
+
244
+ Returns:
245
+ BigQuery dataset name
246
+
247
+ Raises:
248
+ AttributeError: If dataset_name class variable not set
249
+ """
250
+ return self.dataset_name
251
+
252
+ def get_bigquery_table(self) -> str:
253
+ """Return the BigQuery table name from class variable.
254
+
255
+ Returns:
256
+ BigQuery table name
257
+
258
+ Raises:
259
+ AttributeError: If table_name class variable not set
260
+ """
261
+ return self.table_name
262
+
263
+ def get_project_name(self) -> str:
264
+ """Return the BigQuery project name (alias for get_bigquery_project)."""
265
+ return self.get_bigquery_project()
266
+
267
+ def get_dataset_name(self) -> str:
268
+ """Return the BigQuery dataset name (alias for get_bigquery_dataset)."""
269
+ return self.get_bigquery_dataset()
270
+
271
+ def get_database_name(self) -> str:
272
+ """Return database name (for BigQuery, this is project.dataset).
273
+
274
+ This implements the BaseMockTable abstract method by combining
275
+ project and dataset to maintain backwards compatibility with
276
+ the two-part naming assumption in the base class.
277
+ """
278
+ return f"{self.get_bigquery_project()}.{self.get_bigquery_dataset()}"
279
+
280
+ def get_table_name(self) -> str:
281
+ """Return the table name (alias for get_bigquery_table)."""
282
+ return self.get_bigquery_table()
283
+
284
+ def get_fully_qualified_name(self) -> str:
285
+ """Return the three-part BigQuery table reference.
286
+
287
+ Returns:
288
+ Fully qualified table name in format: project.dataset.table
289
+
290
+ Example:
291
+ >>> table.get_fully_qualified_name()
292
+ 'my-project.analytics.users'
293
+ """
294
+ project = self.get_bigquery_project()
295
+ dataset = self.get_bigquery_dataset()
296
+ table = self.get_bigquery_table()
297
+ return f"{project}.{dataset}.{table}"