google-pso-data-validator 7.6.1__tar.gz → 7.7.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.
- {google_pso_data_validator-7.6.1/google_pso_data_validator.egg-info → google_pso_data_validator-7.7.0}/PKG-INFO +10 -3
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/README.md +9 -2
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/cli_tools.py +9 -2
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/clients.py +27 -7
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/consts.py +1 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/result_handlers/bigquery.py +1 -1
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0/google_pso_data_validator.egg-info}/PKG-INFO +10 -3
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/google_pso_data_validator.egg-info/SOURCES.txt +2 -2
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/setup.py +1 -1
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_addon/operations.py +25 -62
- google_pso_data_validator-7.7.0/third_party/ibis/ibis_bigquery/__init__.py +142 -0
- google_pso_data_validator-7.7.0/third_party/ibis/ibis_bigquery/api.py +35 -0
- google_pso_data_validator-7.7.0/third_party/ibis/ibis_postgres/registry.py +86 -0
- google_pso_data_validator-7.6.1/third_party/ibis/ibis_biquery/api.py +0 -15
- google_pso_data_validator-7.6.1/third_party/ibis/ibis_postgres/registry.py +0 -43
- google_pso_data_validator-7.6.1/third_party/ibis/ibis_snowflake/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/LICENSE +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/__main__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/app.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/client_info.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/combiner.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/config_manager.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/data_validation.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/exceptions.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/find_tables.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/gcs_helper.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/jellyfish_distance.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/metadata.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/partition_builder.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/query_builder/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/query_builder/partition_row_builder.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/query_builder/query_builder.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/query_builder/random_row_builder.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/raw_query.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/result_handlers/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/result_handlers/base_backend.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/result_handlers/factory.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/result_handlers/postgres.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/result_handlers/text.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/schema_validation.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/secret_manager.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/state_manager.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/util.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/validation_builder.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/google_pso_data_validator.egg-info/dependency_links.txt +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/google_pso_data_validator.egg-info/entry_points.txt +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/google_pso_data_validator.egg-info/requires.txt +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/google_pso_data_validator.egg-info/top_level.txt +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/setup.cfg +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_addon/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_addon/api.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_cloud_spanner/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_cloud_spanner/api.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_cloud_spanner/client.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_cloud_spanner/compiler.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_cloud_spanner/datatypes.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_cloud_spanner/registry.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_cloud_spanner/tests/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_cloud_spanner/tests/conftest.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_cloud_spanner/to_pandas.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_db2/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_db2/api.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_db2/compiler.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_db2/datatypes.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_db2/registry.py +0 -0
- {google_pso_data_validator-7.6.1/third_party/ibis/ibis_biquery → google_pso_data_validator-7.7.0/third_party/ibis/ibis_impala}/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_impala/api.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_mssql/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_mssql/api.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_mssql/datatypes.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_mssql/registry.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_mysql/__init__.py +0 -0
- {google_pso_data_validator-7.6.1/third_party/ibis/ibis_impala → google_pso_data_validator-7.7.0/third_party/ibis/ibis_mysql/base_sql_compiler}/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_mysql/base_sql_compiler/select_builder.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_mysql/compiler.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_oracle/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_oracle/api.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_oracle/compiler.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_oracle/datatypes.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_oracle/registry.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_postgres/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_postgres/client.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_postgres/datatypes.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_redshift/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_redshift/api.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_redshift/compiler.py +0 -0
- {google_pso_data_validator-7.6.1/third_party/ibis/ibis_mysql/base_sql_compiler → google_pso_data_validator-7.7.0/third_party/ibis/ibis_snowflake}/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_snowflake/api.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_snowflake/datatypes.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_teradata/__init__.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_teradata/api.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_teradata/compiler.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_teradata/datatypes.py +0 -0
- {google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_teradata/registry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-pso-data-validator
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.7.0
|
|
4
4
|
Summary: A package to enable easy data validation
|
|
5
5
|
Author: PSO DVT Engineering team
|
|
6
6
|
Author-email: data-validator-eng@google.com
|
|
@@ -125,8 +125,10 @@ please review the [Connections](https://github.com/GoogleCloudPlatform/professio
|
|
|
125
125
|
### Running Validations
|
|
126
126
|
|
|
127
127
|
The CLI is the main interface to use this tool and it has several different
|
|
128
|
-
commands which can be used to create and run validations.
|
|
129
|
-
|
|
128
|
+
commands which can be used to create and run validations. DVT is designed to run in
|
|
129
|
+
an environment connected to GCP services, specifically, BigQuery, GCS and Secret manager.
|
|
130
|
+
If DVT is being run on-premises or in an environment with restricted access to GCP services, see
|
|
131
|
+
[running DVT at on-prem](#running-dvt-at-on-prem). Below are the command syntax and options for running validations.
|
|
130
132
|
|
|
131
133
|
Alternatives to running DVT in the CLI include deploying DVT to Cloud Run, Cloud Functions, or Airflow
|
|
132
134
|
([Examples Here](https://github.com/GoogleCloudPlatform/professional-services-data-validator/tree/develop/samples)). See the [Validation Logic](https://github.com/GoogleCloudPlatform/professional-services-data-validator#validation-logic) section
|
|
@@ -584,6 +586,11 @@ For example, this flag can be used as follows:
|
|
|
584
586
|
"target_query": "SELECT `hash__all`, `station_id`\nFROM ..."
|
|
585
587
|
}
|
|
586
588
|
```
|
|
589
|
+
#### Running DVT at on-prem
|
|
590
|
+
On-premises environments can have limited access to GCP services. DVT supports using BigQuery for storing validation results, GCS for storage and
|
|
591
|
+
the Secret Manager for secrets. You may also use BigQuery and Spanner as a source or target for validation. Service
|
|
592
|
+
APIs (i.e. bigquery.googleapis.com) may not always be accessible due to firewall restrictions. Work with your network
|
|
593
|
+
adminstrator to identify the way to access these services. They may set up a [Private Service Connect Endpoint](https://cloud.google.com/vpc/docs/about-accessing-google-apis-endpoints). DVT supports accessing source and target tables in Spanner and BigQuery via endpoints set up in your network. Connection Parameters for [Spanner](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#google-spanner) and [BigQuery](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#google-bigquery) outline regarding how to specify endpoints.
|
|
587
594
|
|
|
588
595
|
### Running DVT with YAML Configuration Files
|
|
589
596
|
|
|
@@ -66,8 +66,10 @@ please review the [Connections](https://github.com/GoogleCloudPlatform/professio
|
|
|
66
66
|
### Running Validations
|
|
67
67
|
|
|
68
68
|
The CLI is the main interface to use this tool and it has several different
|
|
69
|
-
commands which can be used to create and run validations.
|
|
70
|
-
|
|
69
|
+
commands which can be used to create and run validations. DVT is designed to run in
|
|
70
|
+
an environment connected to GCP services, specifically, BigQuery, GCS and Secret manager.
|
|
71
|
+
If DVT is being run on-premises or in an environment with restricted access to GCP services, see
|
|
72
|
+
[running DVT at on-prem](#running-dvt-at-on-prem). Below are the command syntax and options for running validations.
|
|
71
73
|
|
|
72
74
|
Alternatives to running DVT in the CLI include deploying DVT to Cloud Run, Cloud Functions, or Airflow
|
|
73
75
|
([Examples Here](https://github.com/GoogleCloudPlatform/professional-services-data-validator/tree/develop/samples)). See the [Validation Logic](https://github.com/GoogleCloudPlatform/professional-services-data-validator#validation-logic) section
|
|
@@ -525,6 +527,11 @@ For example, this flag can be used as follows:
|
|
|
525
527
|
"target_query": "SELECT `hash__all`, `station_id`\nFROM ..."
|
|
526
528
|
}
|
|
527
529
|
```
|
|
530
|
+
#### Running DVT at on-prem
|
|
531
|
+
On-premises environments can have limited access to GCP services. DVT supports using BigQuery for storing validation results, GCS for storage and
|
|
532
|
+
the Secret Manager for secrets. You may also use BigQuery and Spanner as a source or target for validation. Service
|
|
533
|
+
APIs (i.e. bigquery.googleapis.com) may not always be accessible due to firewall restrictions. Work with your network
|
|
534
|
+
adminstrator to identify the way to access these services. They may set up a [Private Service Connect Endpoint](https://cloud.google.com/vpc/docs/about-accessing-google-apis-endpoints). DVT supports accessing source and target tables in Spanner and BigQuery via endpoints set up in your network. Connection Parameters for [Spanner](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#google-spanner) and [BigQuery](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#google-bigquery) outline regarding how to specify endpoints.
|
|
528
535
|
|
|
529
536
|
### Running DVT with YAML Configuration Files
|
|
530
537
|
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/cli_tools.py
RENAMED
|
@@ -76,7 +76,11 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
76
76
|
["google_service_account_key_path", "(Optional) GCP SA Key Path"],
|
|
77
77
|
[
|
|
78
78
|
"api_endpoint",
|
|
79
|
-
'(Optional) GCP BigQuery API endpoint (e.g. "https://
|
|
79
|
+
'(Optional) GCP BigQuery API endpoint (e.g. "https://bigquery-mypsc.p.googleapis.com")',
|
|
80
|
+
],
|
|
81
|
+
[
|
|
82
|
+
"storage_api_endpoint",
|
|
83
|
+
'(Optional) GCP BigQuery Storage API endpoint (e.g. "https://bigquerystorage-mypsc.p.googleapis.com")',
|
|
80
84
|
],
|
|
81
85
|
],
|
|
82
86
|
consts.SOURCE_TYPE_TERADATA: [
|
|
@@ -140,7 +144,7 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
140
144
|
["google_service_account_key_path", "(Optional) GCP SA Key Path"],
|
|
141
145
|
[
|
|
142
146
|
"api_endpoint",
|
|
143
|
-
'(Optional) GCP Spanner API endpoint (e.g. "https://
|
|
147
|
+
'(Optional) GCP Spanner API endpoint (e.g. "https://spanner-mypsc.p.googleapis.com")',
|
|
144
148
|
],
|
|
145
149
|
],
|
|
146
150
|
consts.SOURCE_TYPE_FILESYSTEM: [
|
|
@@ -1284,6 +1288,9 @@ def _get_result_handler(rc_value: str, sa_file=None) -> dict:
|
|
|
1284
1288
|
consts.PROJECT_ID: conn_from_file["project_id"],
|
|
1285
1289
|
consts.TABLE_ID: config[1],
|
|
1286
1290
|
consts.API_ENDPOINT: conn_from_file.get("api_endpoint", None),
|
|
1291
|
+
consts.STORAGE_API_ENDPOINT: conn_from_file.get(
|
|
1292
|
+
"storage_api_endpoint", None
|
|
1293
|
+
),
|
|
1287
1294
|
}
|
|
1288
1295
|
elif conn_from_file[consts.SOURCE_TYPE] == consts.SOURCE_TYPE_POSTGRES:
|
|
1289
1296
|
result_handler = {
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/clients.py
RENAMED
|
@@ -27,6 +27,8 @@ import pandas
|
|
|
27
27
|
|
|
28
28
|
from data_validation import client_info, consts, exceptions
|
|
29
29
|
from data_validation.secret_manager import SecretManagerBuilder
|
|
30
|
+
|
|
31
|
+
from third_party.ibis.ibis_bigquery.api import bigquery_connect
|
|
30
32
|
from third_party.ibis.ibis_cloud_spanner.api import spanner_connect
|
|
31
33
|
from third_party.ibis.ibis_impala.api import impala_connect
|
|
32
34
|
from third_party.ibis.ibis_mssql.api import mssql_connect
|
|
@@ -111,24 +113,42 @@ def get_google_bigquery_client(
|
|
|
111
113
|
)
|
|
112
114
|
|
|
113
115
|
|
|
116
|
+
def _get_google_bqstorage_client(credentials=None, api_endpoint: str = None):
|
|
117
|
+
options = None
|
|
118
|
+
if api_endpoint:
|
|
119
|
+
options = client_options.ClientOptions(api_endpoint=api_endpoint)
|
|
120
|
+
from google.cloud import bigquery_storage_v1 as bigquery_storage
|
|
121
|
+
|
|
122
|
+
return bigquery_storage.BigQueryReadClient(
|
|
123
|
+
credentials=credentials,
|
|
124
|
+
client_options=options,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
114
128
|
def get_bigquery_client(
|
|
115
|
-
project_id: str,
|
|
129
|
+
project_id: str,
|
|
130
|
+
dataset_id: str = "",
|
|
131
|
+
credentials=None,
|
|
132
|
+
api_endpoint: str = None,
|
|
133
|
+
storage_api_endpoint: str = None,
|
|
116
134
|
):
|
|
117
135
|
google_client = get_google_bigquery_client(
|
|
118
136
|
project_id, credentials=credentials, api_endpoint=api_endpoint
|
|
119
137
|
)
|
|
138
|
+
bqstorage_client = None
|
|
139
|
+
if storage_api_endpoint:
|
|
140
|
+
bqstorage_client = _get_google_bqstorage_client(
|
|
141
|
+
credentials=credentials, api_endpoint=storage_api_endpoint
|
|
142
|
+
)
|
|
120
143
|
|
|
121
|
-
|
|
144
|
+
return bigquery_connect(
|
|
122
145
|
project_id=project_id,
|
|
123
146
|
dataset_id=dataset_id,
|
|
124
147
|
credentials=credentials,
|
|
148
|
+
bigquery_client=google_client,
|
|
149
|
+
bqstorage_client=bqstorage_client,
|
|
125
150
|
)
|
|
126
151
|
|
|
127
|
-
# Override the BigQuery client object to ensure the correct user agent is
|
|
128
|
-
# included and any api_endpoint is used.
|
|
129
|
-
ibis_client.client = google_client
|
|
130
|
-
return ibis_client
|
|
131
|
-
|
|
132
152
|
|
|
133
153
|
def get_pandas_client(table_name, file_path, file_type):
|
|
134
154
|
"""Return pandas client and env with file loaded into DataFrame
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/consts.py
RENAMED
|
@@ -143,6 +143,7 @@ PROJECT_ID = "project_id"
|
|
|
143
143
|
TABLE_ID = "table_id"
|
|
144
144
|
GOOGLE_SERVICE_ACCOUNT_KEY_PATH = "google_service_account_key_path"
|
|
145
145
|
API_ENDPOINT = "api_endpoint"
|
|
146
|
+
STORAGE_API_ENDPOINT = "storage_api_endpoint"
|
|
146
147
|
|
|
147
148
|
# Result Handler Output Table Fields
|
|
148
149
|
VALIDATION_TYPE = "validation_type"
|
|
@@ -65,7 +65,7 @@ class BigQueryResultHandler(BaseBackendResultHandler):
|
|
|
65
65
|
Explicit credentials to use in case default credentials
|
|
66
66
|
aren't working properly.
|
|
67
67
|
status_list (list): provided status to filter the results with
|
|
68
|
-
api_endpoint (str): BigQuery API endpoint (e.g. https://
|
|
68
|
+
api_endpoint (str): BigQuery API endpoint (e.g. https://bigquery-mypsc.p.googleapis.com)
|
|
69
69
|
text_format (str, optional):
|
|
70
70
|
This allows the user to influence the text results written via logger.debug.
|
|
71
71
|
See: https://github.com/GoogleCloudPlatform/professional-services-data-validator/issues/871
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-pso-data-validator
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.7.0
|
|
4
4
|
Summary: A package to enable easy data validation
|
|
5
5
|
Author: PSO DVT Engineering team
|
|
6
6
|
Author-email: data-validator-eng@google.com
|
|
@@ -125,8 +125,10 @@ please review the [Connections](https://github.com/GoogleCloudPlatform/professio
|
|
|
125
125
|
### Running Validations
|
|
126
126
|
|
|
127
127
|
The CLI is the main interface to use this tool and it has several different
|
|
128
|
-
commands which can be used to create and run validations.
|
|
129
|
-
|
|
128
|
+
commands which can be used to create and run validations. DVT is designed to run in
|
|
129
|
+
an environment connected to GCP services, specifically, BigQuery, GCS and Secret manager.
|
|
130
|
+
If DVT is being run on-premises or in an environment with restricted access to GCP services, see
|
|
131
|
+
[running DVT at on-prem](#running-dvt-at-on-prem). Below are the command syntax and options for running validations.
|
|
130
132
|
|
|
131
133
|
Alternatives to running DVT in the CLI include deploying DVT to Cloud Run, Cloud Functions, or Airflow
|
|
132
134
|
([Examples Here](https://github.com/GoogleCloudPlatform/professional-services-data-validator/tree/develop/samples)). See the [Validation Logic](https://github.com/GoogleCloudPlatform/professional-services-data-validator#validation-logic) section
|
|
@@ -584,6 +586,11 @@ For example, this flag can be used as follows:
|
|
|
584
586
|
"target_query": "SELECT `hash__all`, `station_id`\nFROM ..."
|
|
585
587
|
}
|
|
586
588
|
```
|
|
589
|
+
#### Running DVT at on-prem
|
|
590
|
+
On-premises environments can have limited access to GCP services. DVT supports using BigQuery for storing validation results, GCS for storage and
|
|
591
|
+
the Secret Manager for secrets. You may also use BigQuery and Spanner as a source or target for validation. Service
|
|
592
|
+
APIs (i.e. bigquery.googleapis.com) may not always be accessible due to firewall restrictions. Work with your network
|
|
593
|
+
adminstrator to identify the way to access these services. They may set up a [Private Service Connect Endpoint](https://cloud.google.com/vpc/docs/about-accessing-google-apis-endpoints). DVT supports accessing source and target tables in Spanner and BigQuery via endpoints set up in your network. Connection Parameters for [Spanner](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#google-spanner) and [BigQuery](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#google-bigquery) outline regarding how to specify endpoints.
|
|
587
594
|
|
|
588
595
|
### Running DVT with YAML Configuration Files
|
|
589
596
|
|
|
@@ -43,8 +43,8 @@ google_pso_data_validator.egg-info/top_level.txt
|
|
|
43
43
|
third_party/ibis/ibis_addon/__init__.py
|
|
44
44
|
third_party/ibis/ibis_addon/api.py
|
|
45
45
|
third_party/ibis/ibis_addon/operations.py
|
|
46
|
-
third_party/ibis/
|
|
47
|
-
third_party/ibis/
|
|
46
|
+
third_party/ibis/ibis_bigquery/__init__.py
|
|
47
|
+
third_party/ibis/ibis_bigquery/api.py
|
|
48
48
|
third_party/ibis/ibis_cloud_spanner/__init__.py
|
|
49
49
|
third_party/ibis/ibis_cloud_spanner/api.py
|
|
50
50
|
third_party/ibis/ibis_cloud_spanner/client.py
|
|
@@ -61,7 +61,7 @@ from ibis.backends.postgres.compiler import PostgreSQLExprTranslator
|
|
|
61
61
|
from ibis.expr.types import BinaryValue, NumericValue, StringValue, TemporalValue
|
|
62
62
|
|
|
63
63
|
# Do not remove these lines, they trigger patching of Ibis code.
|
|
64
|
-
import third_party.ibis.
|
|
64
|
+
import third_party.ibis.ibis_bigquery.api # noqa
|
|
65
65
|
import third_party.ibis.ibis_mysql.compiler # noqa
|
|
66
66
|
from third_party.ibis.ibis_mssql import registry as mssql_registry
|
|
67
67
|
from third_party.ibis.ibis_postgres import registry as postgres_registry
|
|
@@ -329,40 +329,6 @@ def sa_format_binary_length_oracle(translator, op):
|
|
|
329
329
|
return sa.func.dbms_lob.getlength(arg)
|
|
330
330
|
|
|
331
331
|
|
|
332
|
-
def sa_cast_decimal_when_scale_padded_fmt_fm(t, op):
|
|
333
|
-
"""Caters for engines that fully pad scale with 0s when casting decimal to string and support FM format."""
|
|
334
|
-
# Add cast from numeric to string
|
|
335
|
-
arg = op.arg
|
|
336
|
-
typ = op.to
|
|
337
|
-
arg_dtype = arg.output_dtype
|
|
338
|
-
|
|
339
|
-
# Specialize going from numeric(p,s>0) to string
|
|
340
|
-
if (
|
|
341
|
-
arg_dtype.is_decimal()
|
|
342
|
-
and arg_dtype.scale
|
|
343
|
-
and arg_dtype.scale > 0
|
|
344
|
-
and typ.is_string()
|
|
345
|
-
):
|
|
346
|
-
sa_arg = t.translate(arg)
|
|
347
|
-
# When casting a number to string PostgreSQL and Snowflake include the full scale, e.g.:
|
|
348
|
-
# SELECT CAST(CAST(100 AS DECIMAL(5,2)) AS VARCHAR(10));
|
|
349
|
-
# 100.00
|
|
350
|
-
# This doesn't match most engines which would return "100".
|
|
351
|
-
# Using to_char() function instead of cast to return a more typical value.
|
|
352
|
-
# We've wrapped to_char in rtrim(".") due to whole numbers having a trailing ".".
|
|
353
|
-
# Would have liked to use trim_scale but this is only available in PostgreSQL 13+
|
|
354
|
-
# return (sa.cast(sa.func.trim_scale(arg), typ))
|
|
355
|
-
precision = arg_dtype.precision or 38
|
|
356
|
-
fmt = (
|
|
357
|
-
"FM"
|
|
358
|
-
+ ("9" * (precision - arg_dtype.scale - 1))
|
|
359
|
-
+ "0."
|
|
360
|
-
+ ("9" * arg_dtype.scale)
|
|
361
|
-
)
|
|
362
|
-
return sa.func.rtrim(sa.func.to_char(sa_arg, fmt), ".")
|
|
363
|
-
return None
|
|
364
|
-
|
|
365
|
-
|
|
366
332
|
def sa_cast_hive(t, op):
|
|
367
333
|
arg = op.arg
|
|
368
334
|
typ = op.to
|
|
@@ -387,27 +353,6 @@ def sa_cast_hive(t, op):
|
|
|
387
353
|
return cast_expr
|
|
388
354
|
|
|
389
355
|
|
|
390
|
-
def sa_cast_postgres(t, op):
|
|
391
|
-
custom_cast = sa_cast_decimal_when_scale_padded_fmt_fm(t, op)
|
|
392
|
-
if custom_cast is not None:
|
|
393
|
-
return custom_cast
|
|
394
|
-
|
|
395
|
-
arg = op.arg
|
|
396
|
-
typ = op.to
|
|
397
|
-
arg_dtype = arg.output_dtype
|
|
398
|
-
|
|
399
|
-
sa_arg = t.translate(arg)
|
|
400
|
-
if arg_dtype.is_binary() and typ.is_string():
|
|
401
|
-
# Binary to string cast is a "to hex" conversion for DVT.
|
|
402
|
-
return sa.func.encode(sa_arg, sa.literal("hex"))
|
|
403
|
-
elif arg_dtype.is_string() and typ.is_binary():
|
|
404
|
-
# Binary from string cast is a "from hex" conversion for DVT.
|
|
405
|
-
return sa.func.decode(sa_arg, sa.literal("hex"))
|
|
406
|
-
|
|
407
|
-
# Follow the original Ibis code path.
|
|
408
|
-
return sa_fixed_cast(t, op)
|
|
409
|
-
|
|
410
|
-
|
|
411
356
|
def sa_cast_mssql(t, op):
|
|
412
357
|
arg = op.arg
|
|
413
358
|
typ = op.to
|
|
@@ -477,15 +422,33 @@ def sa_cast_mysql(t, op):
|
|
|
477
422
|
|
|
478
423
|
|
|
479
424
|
def sa_cast_snowflake(t, op):
|
|
480
|
-
custom_cast = sa_cast_decimal_when_scale_padded_fmt_fm(t, op)
|
|
481
|
-
if custom_cast is not None:
|
|
482
|
-
return custom_cast
|
|
483
|
-
|
|
484
425
|
arg = op.arg
|
|
485
426
|
typ = op.to
|
|
486
427
|
arg_dtype = arg.output_dtype
|
|
487
|
-
|
|
488
428
|
sa_arg = t.translate(arg)
|
|
429
|
+
|
|
430
|
+
# Specialize going from numeric(p,s>0) to string
|
|
431
|
+
if (
|
|
432
|
+
arg_dtype.is_decimal()
|
|
433
|
+
and arg_dtype.scale
|
|
434
|
+
and arg_dtype.scale > 0
|
|
435
|
+
and typ.is_string()
|
|
436
|
+
):
|
|
437
|
+
# When casting a number to string Snowflake includes the full scale, e.g.:
|
|
438
|
+
# SELECT CAST(CAST(100 AS DECIMAL(5,2)) AS VARCHAR(10));
|
|
439
|
+
# 100.00
|
|
440
|
+
# This doesn't match most engines which would return "100".
|
|
441
|
+
# Using to_char() function instead of cast to return a more typical value.
|
|
442
|
+
# We've wrapped to_char in rtrim(".") due to whole numbers having a trailing ".".
|
|
443
|
+
precision = arg_dtype.precision or 38
|
|
444
|
+
fmt = (
|
|
445
|
+
"FM"
|
|
446
|
+
+ ("9" * (precision - arg_dtype.scale - 1))
|
|
447
|
+
+ "0."
|
|
448
|
+
+ ("9" * arg_dtype.scale)
|
|
449
|
+
)
|
|
450
|
+
return sa.func.rtrim(sa.func.to_char(sa_arg, fmt), ".")
|
|
451
|
+
|
|
489
452
|
if arg_dtype.is_binary() and typ.is_string():
|
|
490
453
|
# Binary to string cast is a "to hex" conversion for DVT.
|
|
491
454
|
return sa.func.hex_encode(sa_arg, sa.literal(0))
|
|
@@ -648,7 +611,7 @@ PostgreSQLExprTranslator._registry[
|
|
|
648
611
|
] = postgres_registry.sa_format_hashbytes
|
|
649
612
|
PostgreSQLExprTranslator._registry[RawSQL] = sa_format_raw_sql
|
|
650
613
|
PostgreSQLExprTranslator._registry[ToChar] = sa_format_to_char
|
|
651
|
-
PostgreSQLExprTranslator._registry[ops.Cast] = sa_cast_postgres
|
|
614
|
+
PostgreSQLExprTranslator._registry[ops.Cast] = postgres_registry.sa_cast_postgres
|
|
652
615
|
PostgreSQLExprTranslator._registry[BinaryLength] = sa_format_binary_length
|
|
653
616
|
PostgreSQLExprTranslator._registry[
|
|
654
617
|
ops.ExtractEpochSeconds
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Copyright 2024 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
import google.auth.credentials
|
|
18
|
+
import google.cloud.bigquery as bq
|
|
19
|
+
import pydata_google_auth
|
|
20
|
+
from pydata_google_auth import cache
|
|
21
|
+
|
|
22
|
+
from ibis.backends.bigquery import (
|
|
23
|
+
Backend as BigQueryBackend,
|
|
24
|
+
_create_client_info,
|
|
25
|
+
parse_project_and_dataset,
|
|
26
|
+
CLIENT_ID,
|
|
27
|
+
CLIENT_SECRET,
|
|
28
|
+
EXTERNAL_DATA_SCOPES,
|
|
29
|
+
SCOPES,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
import google.cloud.bigquery_storage_v1
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Backend(BigQueryBackend):
|
|
37
|
+
def __init__(self):
|
|
38
|
+
super().__init__()
|
|
39
|
+
self.storage_client = None
|
|
40
|
+
|
|
41
|
+
def do_connect(
|
|
42
|
+
self,
|
|
43
|
+
project_id: str = None,
|
|
44
|
+
dataset_id: str = "",
|
|
45
|
+
credentials: google.auth.credentials.Credentials = None,
|
|
46
|
+
application_name: str = None,
|
|
47
|
+
auth_local_webserver: bool = True,
|
|
48
|
+
auth_external_data: bool = False,
|
|
49
|
+
auth_cache: str = "default",
|
|
50
|
+
partition_column: str = "PARTITIONTIME",
|
|
51
|
+
# Custom DVT arguments:
|
|
52
|
+
bigquery_client: bq.Client = None,
|
|
53
|
+
bqstorage_client: "google.cloud.bigquery_storage_v1.BigQueryReadClient" = None,
|
|
54
|
+
):
|
|
55
|
+
"""Copy of Ibis v5 BigQuery do_connect() customized for DVT, see original method for docs."""
|
|
56
|
+
default_project_id = ""
|
|
57
|
+
|
|
58
|
+
if credentials is None:
|
|
59
|
+
scopes = SCOPES
|
|
60
|
+
if auth_external_data:
|
|
61
|
+
scopes = EXTERNAL_DATA_SCOPES
|
|
62
|
+
|
|
63
|
+
if auth_cache == "default":
|
|
64
|
+
credentials_cache = cache.ReadWriteCredentialsCache(
|
|
65
|
+
filename="ibis.json"
|
|
66
|
+
)
|
|
67
|
+
elif auth_cache == "reauth":
|
|
68
|
+
credentials_cache = cache.WriteOnlyCredentialsCache(
|
|
69
|
+
filename="ibis.json"
|
|
70
|
+
)
|
|
71
|
+
elif auth_cache == "none":
|
|
72
|
+
credentials_cache = cache.NOOP
|
|
73
|
+
else:
|
|
74
|
+
raise ValueError(
|
|
75
|
+
f"Got unexpected value for auth_cache = '{auth_cache}'. "
|
|
76
|
+
"Expected one of 'default', 'reauth', or 'none'."
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
credentials, default_project_id = pydata_google_auth.default(
|
|
80
|
+
scopes,
|
|
81
|
+
client_id=CLIENT_ID,
|
|
82
|
+
client_secret=CLIENT_SECRET,
|
|
83
|
+
credentials_cache=credentials_cache,
|
|
84
|
+
use_local_webserver=auth_local_webserver,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
project_id = project_id or default_project_id
|
|
88
|
+
|
|
89
|
+
(
|
|
90
|
+
self.data_project,
|
|
91
|
+
self.billing_project,
|
|
92
|
+
self.dataset,
|
|
93
|
+
) = parse_project_and_dataset(project_id, dataset_id)
|
|
94
|
+
|
|
95
|
+
if bigquery_client is None:
|
|
96
|
+
self.client = bq.Client(
|
|
97
|
+
project=self.billing_project,
|
|
98
|
+
credentials=credentials,
|
|
99
|
+
client_info=_create_client_info(application_name),
|
|
100
|
+
)
|
|
101
|
+
else:
|
|
102
|
+
self.client = bigquery_client
|
|
103
|
+
self.partition_column = partition_column
|
|
104
|
+
self.storage_client = bqstorage_client
|
|
105
|
+
|
|
106
|
+
def _cursor_to_arrow(
|
|
107
|
+
self,
|
|
108
|
+
cursor,
|
|
109
|
+
*,
|
|
110
|
+
method=None,
|
|
111
|
+
chunk_size: int = None,
|
|
112
|
+
):
|
|
113
|
+
"""Copy of Ibis v5 BigQuery _cursor_to_arrow() except can use custom DVT storage client"""
|
|
114
|
+
if method is None:
|
|
115
|
+
|
|
116
|
+
def method(result, storage_client=self.storage_client):
|
|
117
|
+
return result.to_arrow(
|
|
118
|
+
progress_bar_type=None,
|
|
119
|
+
# Include DVT specific storage client.
|
|
120
|
+
bqstorage_client=storage_client,
|
|
121
|
+
create_bqstorage_client=bool(not self.storage_client),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
query = cursor.query
|
|
125
|
+
query_result = query.result(page_size=chunk_size)
|
|
126
|
+
# workaround potentially not having the ability to create read sessions
|
|
127
|
+
# in the dataset project
|
|
128
|
+
orig_project = query_result._project
|
|
129
|
+
query_result._project = self.billing_project
|
|
130
|
+
try:
|
|
131
|
+
arrow_obj = method(query_result)
|
|
132
|
+
finally:
|
|
133
|
+
query_result._project = orig_project
|
|
134
|
+
return arrow_obj
|
|
135
|
+
|
|
136
|
+
def list_primary_key_columns(self, database: str, table: str) -> list:
|
|
137
|
+
"""Return a list of primary key column names."""
|
|
138
|
+
# TODO: Related to issue-1253, it's not clear if this is possible, we should revisit if it becomes a requirement.
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
def dvt_list_tables(self, like=None, database=None):
|
|
142
|
+
return self.list_tables(like=like, database=database)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Copyright 2024 Google Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
from third_party.ibis.ibis_bigquery import Backend as BigQueryBackend
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def bigquery_connect(
|
|
20
|
+
project_id: str = None,
|
|
21
|
+
dataset_id: str = "",
|
|
22
|
+
credentials=None,
|
|
23
|
+
bigquery_client=None,
|
|
24
|
+
bqstorage_client=None,
|
|
25
|
+
):
|
|
26
|
+
"""Create a BigQuery Backend for use with Ibis."""
|
|
27
|
+
backend = BigQueryBackend()
|
|
28
|
+
backend.do_connect(
|
|
29
|
+
project_id=project_id,
|
|
30
|
+
dataset_id=dataset_id,
|
|
31
|
+
credentials=credentials,
|
|
32
|
+
bigquery_client=bigquery_client,
|
|
33
|
+
bqstorage_client=bqstorage_client,
|
|
34
|
+
)
|
|
35
|
+
return backend
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Copyright 2024 Google Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import sqlalchemy as sa
|
|
16
|
+
from ibis.backends.base.sql.alchemy.registry import _cast as sa_fixed_cast
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def sa_format_hashbytes(translator, op):
|
|
20
|
+
arg = translator.translate(op.arg)
|
|
21
|
+
convert = sa.func.convert_to(arg, sa.sql.literal_column("'UTF8'"))
|
|
22
|
+
hash_func = sa.func.sha256(convert)
|
|
23
|
+
return sa.func.encode(hash_func, sa.sql.literal_column("'hex'"))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def sa_epoch_seconds(translator, op):
|
|
27
|
+
"""Override for standard ExtractEpochSeconds but catering for larger second values.
|
|
28
|
+
|
|
29
|
+
This expression also truncates fractional seconds from the incoming datetime.
|
|
30
|
+
This matches behaviour on other SQL engines' epoch seconds expressions."""
|
|
31
|
+
arg = translator.translate(op.arg)
|
|
32
|
+
return sa.cast(
|
|
33
|
+
sa.extract("epoch", sa.func.date_trunc(sa.sql.literal_column("'second'"), arg)),
|
|
34
|
+
sa.BIGINT,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def sa_cast_postgres(t, op):
|
|
39
|
+
arg = op.arg
|
|
40
|
+
typ = op.to
|
|
41
|
+
arg_dtype = arg.output_dtype
|
|
42
|
+
sa_arg = t.translate(arg)
|
|
43
|
+
|
|
44
|
+
if arg_dtype.is_decimal() and typ.is_string():
|
|
45
|
+
if arg_dtype.scale is None:
|
|
46
|
+
# trim_scale() is only available in PostgreSQL 13+ but solves a lot of problems
|
|
47
|
+
# when trying to get consistently formatted numerics.
|
|
48
|
+
# We've documented a workaround for PostgreSQL 12 and prior versions.
|
|
49
|
+
return sa.cast(sa.func.trim_scale(sa_arg), t.get_sqla_type(typ))
|
|
50
|
+
elif arg_dtype.scale > 0:
|
|
51
|
+
# When casting a number to string PostgreSQL includes the full scale, e.g.:
|
|
52
|
+
# SELECT CAST(CAST(100 AS DECIMAL(5,2)) AS VARCHAR(10));
|
|
53
|
+
# 100.00
|
|
54
|
+
# This doesn't match most engines which would return "100".
|
|
55
|
+
# Using to_char() function instead of cast to return a more typical value.
|
|
56
|
+
# We've wrapped to_char in rtrim(".") due to whole numbers having a trailing ".".
|
|
57
|
+
#
|
|
58
|
+
# Potentially we could use trim_scale() here like when scale is None but this is
|
|
59
|
+
# a much more common scenario than decimal(scale=None) so I'm trying to minimize
|
|
60
|
+
# risk of needing a UDF.
|
|
61
|
+
precision = arg_dtype.precision or 38
|
|
62
|
+
fmt = (
|
|
63
|
+
"FM"
|
|
64
|
+
+ ("9" * (precision - arg_dtype.scale - 1))
|
|
65
|
+
+ "0."
|
|
66
|
+
+ ("9" * arg_dtype.scale)
|
|
67
|
+
)
|
|
68
|
+
return sa.func.rtrim(sa.func.to_char(sa_arg, fmt), ".")
|
|
69
|
+
elif arg_dtype.is_binary() and typ.is_string():
|
|
70
|
+
# Binary to string cast is a "to hex" conversion for DVT.
|
|
71
|
+
return sa.func.encode(sa_arg, sa.literal("hex"))
|
|
72
|
+
elif arg_dtype.is_string() and typ.is_binary():
|
|
73
|
+
# Binary from string cast is a "from hex" conversion for DVT.
|
|
74
|
+
return sa.func.decode(sa_arg, sa.literal("hex"))
|
|
75
|
+
|
|
76
|
+
# Follow the original Ibis code path.
|
|
77
|
+
return sa_fixed_cast(t, op)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def sa_format_postgres_padded_char_length(translator, op):
|
|
81
|
+
"""Inject concat of empty string into length(bpchar) to protect trailing spaces.
|
|
82
|
+
|
|
83
|
+
Without this workaround the bpchar value is implicitly cast to varchar and loses trailing spaces.
|
|
84
|
+
"""
|
|
85
|
+
arg = translator.translate(op.arg)
|
|
86
|
+
return sa.func.char_length(sa.func.concat(arg, sa.text("''")))
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
from ibis.backends.bigquery import Backend as BigQueryBackend
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def _list_primary_key_columns(self, database: str, table: str) -> list:
|
|
5
|
-
"""Return a list of primary key column names."""
|
|
6
|
-
# TODO: Related to issue-1253, it's not clear if this is possible, we should revisit if it becomes a requirement.
|
|
7
|
-
return None
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def _dvt_list_tables(self, like=None, database=None):
|
|
11
|
-
return self.list_tables(like=like, database=database)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
BigQueryBackend.list_primary_key_columns = _list_primary_key_columns
|
|
15
|
-
BigQueryBackend.dvt_list_tables = _dvt_list_tables
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# Copyright 2024 Google Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
import sqlalchemy as sa
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def sa_format_hashbytes(translator, op):
|
|
19
|
-
arg = translator.translate(op.arg)
|
|
20
|
-
convert = sa.func.convert_to(arg, sa.sql.literal_column("'UTF8'"))
|
|
21
|
-
hash_func = sa.func.sha256(convert)
|
|
22
|
-
return sa.func.encode(hash_func, sa.sql.literal_column("'hex'"))
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def sa_epoch_seconds(translator, op):
|
|
26
|
-
"""Override for standard ExtractEpochSeconds but catering for larger second values.
|
|
27
|
-
|
|
28
|
-
This expression also truncates fractional seconds from the incoming datetime.
|
|
29
|
-
This matches behaviour on other SQL engines' epoch seconds expressions."""
|
|
30
|
-
arg = translator.translate(op.arg)
|
|
31
|
-
return sa.cast(
|
|
32
|
-
sa.extract("epoch", sa.func.date_trunc(sa.sql.literal_column("'second'"), arg)),
|
|
33
|
-
sa.BIGINT,
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def sa_format_postgres_padded_char_length(translator, op):
|
|
38
|
-
"""Inject concat of empty string into length(bpchar) to protect trailing spaces.
|
|
39
|
-
|
|
40
|
-
Without this workaround the bpchar value is implicitly cast to varchar and loses trailing spaces.
|
|
41
|
-
"""
|
|
42
|
-
arg = translator.translate(op.arg)
|
|
43
|
-
return sa.func.char_length(sa.func.concat(arg, sa.text("''")))
|
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/__init__.py
RENAMED
|
File without changes
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/client_info.py
RENAMED
|
File without changes
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/combiner.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/exceptions.py
RENAMED
|
File without changes
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/find_tables.py
RENAMED
|
File without changes
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/gcs_helper.py
RENAMED
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/raw_query.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/data_validation/state_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.6.1 → google_pso_data_validator-7.7.0}/third_party/ibis/ibis_db2/api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|