dataops-testgen 2.2.0__py3-none-any.whl
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.
- dataops_testgen-2.2.0.dist-info/LICENSE +203 -0
- dataops_testgen-2.2.0.dist-info/METADATA +287 -0
- dataops_testgen-2.2.0.dist-info/NOTICE +5 -0
- dataops_testgen-2.2.0.dist-info/RECORD +270 -0
- dataops_testgen-2.2.0.dist-info/WHEEL +5 -0
- dataops_testgen-2.2.0.dist-info/entry_points.txt +2 -0
- dataops_testgen-2.2.0.dist-info/top_level.txt +1 -0
- testgen/__init__.py +0 -0
- testgen/__main__.py +770 -0
- testgen/commands/__init__.py +0 -0
- testgen/commands/queries/__init__.py +0 -0
- testgen/commands/queries/execute_cat_tests_query.py +95 -0
- testgen/commands/queries/execute_tests_query.py +160 -0
- testgen/commands/queries/generate_tests_query.py +94 -0
- testgen/commands/queries/profiling_query.py +366 -0
- testgen/commands/queries/test_parameter_validation_query.py +88 -0
- testgen/commands/run_execute_cat_tests.py +162 -0
- testgen/commands/run_execute_tests.py +168 -0
- testgen/commands/run_generate_tests.py +107 -0
- testgen/commands/run_get_entities.py +122 -0
- testgen/commands/run_launch_db_config.py +84 -0
- testgen/commands/run_observability_exporter.py +330 -0
- testgen/commands/run_profiling_bridge.py +495 -0
- testgen/commands/run_quick_start.py +168 -0
- testgen/commands/run_setup_profiling_tools.py +96 -0
- testgen/commands/run_test_definition.py +146 -0
- testgen/commands/run_test_parameter_validation.py +135 -0
- testgen/commands/run_upgrade_db_config.py +156 -0
- testgen/common/__init__.py +8 -0
- testgen/common/clean_sql.py +53 -0
- testgen/common/credentials.py +25 -0
- testgen/common/database/__init__.py +0 -0
- testgen/common/database/database_service.py +629 -0
- testgen/common/database/flavor/__init__.py +0 -0
- testgen/common/database/flavor/flavor_service.py +75 -0
- testgen/common/database/flavor/mssql_flavor_service.py +34 -0
- testgen/common/database/flavor/postgresql_flavor_service.py +5 -0
- testgen/common/database/flavor/redshift_flavor_service.py +22 -0
- testgen/common/database/flavor/snowflake_flavor_service.py +69 -0
- testgen/common/database/flavor/trino_flavor_service.py +21 -0
- testgen/common/date_service.py +68 -0
- testgen/common/display_service.py +85 -0
- testgen/common/docker_service.py +76 -0
- testgen/common/encrypt.py +55 -0
- testgen/common/get_pipeline_parms.py +57 -0
- testgen/common/logs.py +79 -0
- testgen/common/process_service.py +62 -0
- testgen/common/read_file.py +69 -0
- testgen/settings.py +440 -0
- testgen/template/dbsetup/010_create_base_schema.sql +2 -0
- testgen/template/dbsetup/020_create_standard_functions_sprocs.sql +179 -0
- testgen/template/dbsetup/030_initialize_new_schema_structure.sql +735 -0
- testgen/template/dbsetup/040_populate_new_schema_project.sql +59 -0
- testgen/template/dbsetup/050_populate_new_schema_metadata.sql +1517 -0
- testgen/template/dbsetup/060_create_standard_views.sql +248 -0
- testgen/template/dbsetup/070_create_default_users.sql +17 -0
- testgen/template/dbsetup/075_grant_role_rights.sql +43 -0
- testgen/template/dbsetup/080_set_current_revision.sql +5 -0
- testgen/template/dbupgrade/0100_incremental_upgrade.sql +5 -0
- testgen/template/dbupgrade/0101_incremental_upgrade.sql +15 -0
- testgen/template/dbupgrade/0102_incremental_upgrade.sql +4 -0
- testgen/template/dbupgrade/0103_incremental_upgrade.sql +22 -0
- testgen/template/dbupgrade/0104_incremental_upgrade.sql +44 -0
- testgen/template/dbupgrade/0105_incremental_upgrade.sql +1 -0
- testgen/template/dbupgrade/0106_incremental_upgrade.sql +5 -0
- testgen/template/dbupgrade/0107_incremental_upgrade.sql +3 -0
- testgen/template/dbupgrade_helpers/get_tg_revision.sql +2 -0
- testgen/template/exec_cat_tests/ex_cat_build_agg_table_tests.sql +116 -0
- testgen/template/exec_cat_tests/ex_cat_get_distinct_tables.sql +11 -0
- testgen/template/exec_cat_tests/ex_cat_results_parse.sql +69 -0
- testgen/template/exec_cat_tests/ex_cat_retrieve_agg_test_parms.sql +6 -0
- testgen/template/exec_cat_tests/ex_cat_test_query.sql +8 -0
- testgen/template/execution/ex_finalize_test_run_results.sql +37 -0
- testgen/template/execution/ex_get_tests_non_cat.sql +47 -0
- testgen/template/execution/ex_update_test_record_in_testrun_table.sql +27 -0
- testgen/template/execution/ex_write_test_record_to_testrun_table.sql +6 -0
- testgen/template/flavors/generic/exec_query_tests/ex_aggregate_match_no_drops_generic.sql +48 -0
- testgen/template/flavors/generic/exec_query_tests/ex_aggregate_match_num_incr_generic.sql +34 -0
- testgen/template/flavors/generic/exec_query_tests/ex_aggregate_match_percent_above_generic.sql +49 -0
- testgen/template/flavors/generic/exec_query_tests/ex_aggregate_match_percent_within_generic.sql +49 -0
- testgen/template/flavors/generic/exec_query_tests/ex_aggregate_match_same_generic.sql +49 -0
- testgen/template/flavors/generic/exec_query_tests/ex_custom_query_generic.sql +39 -0
- testgen/template/flavors/generic/exec_query_tests/ex_data_match_2way_generic.sql +58 -0
- testgen/template/flavors/generic/exec_query_tests/ex_data_match_generic.sql +44 -0
- testgen/template/flavors/generic/exec_query_tests/ex_prior_match_generic.sql +37 -0
- testgen/template/flavors/generic/exec_query_tests/ex_relative_entropy_generic.sql +53 -0
- testgen/template/flavors/generic/exec_query_tests/ex_window_match_no_drops_generic.sql +46 -0
- testgen/template/flavors/generic/exec_query_tests/ex_window_match_same_generic.sql +59 -0
- testgen/template/flavors/generic/profiling/contingency_counts.sql +3 -0
- testgen/template/flavors/generic/validate_tests/ex_get_project_column_list_generic.sql +3 -0
- testgen/template/flavors/mssql/exec_query_tests/ex_relative_entropy_mssql.sql +53 -0
- testgen/template/flavors/mssql/profiling/project_ddf_query_mssql.sql +35 -0
- testgen/template/flavors/mssql/profiling/project_profiling_query_mssql.yaml +246 -0
- testgen/template/flavors/mssql/profiling/project_secondary_profiling_query_mssql.sql +36 -0
- testgen/template/flavors/mssql/setup_profiling_tools/00_drop_existing_functions_mssql.sql +8 -0
- testgen/template/flavors/mssql/setup_profiling_tools/01_create_functions_mssql.sql +12 -0
- testgen/template/flavors/mssql/setup_profiling_tools/02_create_functions_mssql.sql +54 -0
- testgen/template/flavors/mssql/setup_profiling_tools/create_qc_schema_mssql.sql +4 -0
- testgen/template/flavors/mssql/setup_profiling_tools/grant_execute_privileges_mssql.sql +1 -0
- testgen/template/flavors/postgresql/exec_query_tests/ex_window_match_no_drops_postgresql.sql +46 -0
- testgen/template/flavors/postgresql/exec_query_tests/ex_window_match_same_postgresql.sql +59 -0
- testgen/template/flavors/postgresql/profiling/project_ddf_query_postgresql.sql +42 -0
- testgen/template/flavors/postgresql/profiling/project_profiling_query_postgresql.yaml +225 -0
- testgen/template/flavors/postgresql/profiling/project_secondary_profiling_query_postgresql.sql +28 -0
- testgen/template/flavors/postgresql/setup_profiling_tools/create_functions_postgresql.sql +157 -0
- testgen/template/flavors/postgresql/setup_profiling_tools/create_qc_schema_postgresql.sql +1 -0
- testgen/template/flavors/postgresql/setup_profiling_tools/grant_execute_privileges_postgresql.sql +2 -0
- testgen/template/flavors/redshift/profiling/project_ddf_query_redshift.sql +38 -0
- testgen/template/flavors/redshift/profiling/project_profiling_query_redshift.yaml +221 -0
- testgen/template/flavors/redshift/profiling/project_secondary_profiling_query_redshift.sql +29 -0
- testgen/template/flavors/redshift/setup_profiling_tools/create_functions_redshift.sql +115 -0
- testgen/template/flavors/redshift/setup_profiling_tools/create_qc_schema_redshift.sql +1 -0
- testgen/template/flavors/redshift/setup_profiling_tools/grant_execute_privileges_redshift.sql +2 -0
- testgen/template/flavors/snowflake/profiling/project_ddf_query_snowflake.sql +38 -0
- testgen/template/flavors/snowflake/profiling/project_profiling_query_snowflake.yaml +220 -0
- testgen/template/flavors/snowflake/profiling/project_secondary_profiling_query_snowflake.sql +29 -0
- testgen/template/flavors/snowflake/setup_profiling_tools/create_functions_snowflake.sql +69 -0
- testgen/template/flavors/snowflake/setup_profiling_tools/create_qc_schema_snowflake.sql +1 -0
- testgen/template/flavors/snowflake/setup_profiling_tools/grant_execute_privileges_snowflake.sql +6 -0
- testgen/template/flavors/trino/profiling/project_profiling_query_trino.yaml +219 -0
- testgen/template/flavors/trino/setup_profiling_tools/create_functions_trino.sql +92 -0
- testgen/template/flavors/trino/setup_profiling_tools/create_qc_schema_trino.sql +1 -0
- testgen/template/gen_funny_cat_tests/gen_test_constant.sql +104 -0
- testgen/template/gen_funny_cat_tests/gen_test_distinct_value_ct.sql +98 -0
- testgen/template/gen_funny_cat_tests/gen_test_row_ct.sql +57 -0
- testgen/template/gen_funny_cat_tests/gen_test_row_ct_pct.sql +59 -0
- testgen/template/generation/gen_delete_old_tests.sql +5 -0
- testgen/template/generation/gen_insert_test_suite.sql +5 -0
- testgen/template/generation/gen_retrieve_or_insert_test_suite.sql +58 -0
- testgen/template/generation/gen_standard_test_type_list.sql +13 -0
- testgen/template/generation/gen_standard_tests.sql +48 -0
- testgen/template/get_entities/get_connection.sql +21 -0
- testgen/template/get_entities/get_connections_list.sql +9 -0
- testgen/template/get_entities/get_latest.sql +4 -0
- testgen/template/get_entities/get_profile.sql +12 -0
- testgen/template/get_entities/get_profile_info.sql +17 -0
- testgen/template/get_entities/get_profile_list.sql +17 -0
- testgen/template/get_entities/get_profile_screen.sql +275 -0
- testgen/template/get_entities/get_project_list.sql +6 -0
- testgen/template/get_entities/get_table_group_list.sql +10 -0
- testgen/template/get_entities/get_test_generation_list.sql +18 -0
- testgen/template/get_entities/get_test_info.sql +41 -0
- testgen/template/get_entities/get_test_results_for_run_cli.sql +16 -0
- testgen/template/get_entities/get_test_run_list.sql +24 -0
- testgen/template/get_entities/get_test_suite.sql +13 -0
- testgen/template/get_entities/get_test_suite_list.sql +18 -0
- testgen/template/get_entities/list_test_types.sql +4 -0
- testgen/template/observability/get_event_data.sql +23 -0
- testgen/template/observability/get_test_results.sql +41 -0
- testgen/template/observability/update_test_results_exported_to_observability.sql +12 -0
- testgen/template/parms/parms_profiling.sql +34 -0
- testgen/template/parms/parms_test_execution.sql +13 -0
- testgen/template/parms/parms_test_gen.sql +23 -0
- testgen/template/profiling/contingency_columns.sql +7 -0
- testgen/template/profiling/datatype_suggestions.sql +56 -0
- testgen/template/profiling/functional_datatype.sql +523 -0
- testgen/template/profiling/functional_tabletype_stage.sql +48 -0
- testgen/template/profiling/functional_tabletype_update.sql +8 -0
- testgen/template/profiling/pii_flag.sql +133 -0
- testgen/template/profiling/profile_anomalies_screen_column.sql +22 -0
- testgen/template/profiling/profile_anomalies_screen_multi_column.sql +58 -0
- testgen/template/profiling/profile_anomalies_screen_table.sql +22 -0
- testgen/template/profiling/profile_anomalies_screen_table_dates.sql +30 -0
- testgen/template/profiling/profile_anomalies_screen_variants.sql +40 -0
- testgen/template/profiling/profile_anomaly_types_get.sql +3 -0
- testgen/template/profiling/project_get_table_sample_count.sql +22 -0
- testgen/template/profiling/project_profile_run_record_insert.sql +8 -0
- testgen/template/profiling/project_profile_run_record_update.sql +5 -0
- testgen/template/profiling/project_profile_run_record_update_status.sql +5 -0
- testgen/template/profiling/project_update_profile_results_to_estimates.sql +32 -0
- testgen/template/profiling/refresh_anomalies.sql +33 -0
- testgen/template/profiling/refresh_data_chars_from_profiling.sql +156 -0
- testgen/template/profiling/secondary_profiling_columns.sql +12 -0
- testgen/template/profiling/secondary_profiling_delete.sql +4 -0
- testgen/template/profiling/secondary_profiling_update.sql +18 -0
- testgen/template/quick_start/populate_target_data.sql +1077 -0
- testgen/template/quick_start/recreate_target_data_schema.sql +167 -0
- testgen/template/quick_start/update_target_data.sql +100 -0
- testgen/template/updates/create_tmp_test_definition.sql +19 -0
- testgen/template/updates/get_test_def_parms.sql +38 -0
- testgen/template/updates/populate_stg_test_definitions.sql +184 -0
- testgen/template/validate_tests/ex_disable_tests_test_definitions.sql +5 -0
- testgen/template/validate_tests/ex_flag_tests_test_definitions.sql +64 -0
- testgen/template/validate_tests/ex_get_project_column_list_generic.sql +3 -0
- testgen/template/validate_tests/ex_get_test_column_list_tg.sql +65 -0
- testgen/template/validate_tests/ex_write_test_val_errors.sql +22 -0
- testgen/ui/__init__.py +0 -0
- testgen/ui/app.py +98 -0
- testgen/ui/assets/dk_logo.svg +46 -0
- testgen/ui/assets/question_mark.png +0 -0
- testgen/ui/assets/scripts.js +68 -0
- testgen/ui/assets/style.css +140 -0
- testgen/ui/bootstrap.py +109 -0
- testgen/ui/components/__init__.py +0 -0
- testgen/ui/components/frontend/css/KFOlCnqEu92Fr1MmEU9fBBc4.woff2 +0 -0
- testgen/ui/components/frontend/css/KFOlCnqEu92Fr1MmEU9fChc4EsA.woff2 +0 -0
- testgen/ui/components/frontend/css/KFOmCnqEu92Fr1Mu4mxK.woff2 +0 -0
- testgen/ui/components/frontend/css/KFOmCnqEu92Fr1Mu7GxKOzY.woff2 +0 -0
- testgen/ui/components/frontend/css/material-symbols-rounded.css +24 -0
- testgen/ui/components/frontend/css/material-symbols-rounded.woff2 +0 -0
- testgen/ui/components/frontend/css/roboto-font-faces.css +35 -0
- testgen/ui/components/frontend/css/shared.css +36 -0
- testgen/ui/components/frontend/img/dk_logo.svg +46 -0
- testgen/ui/components/frontend/index.html +17 -0
- testgen/ui/components/frontend/js/components/breadcrumbs.js +86 -0
- testgen/ui/components/frontend/js/components/button.js +66 -0
- testgen/ui/components/frontend/js/components/location.js +62 -0
- testgen/ui/components/frontend/js/components/select.js +75 -0
- testgen/ui/components/frontend/js/components/sidebar.js +358 -0
- testgen/ui/components/frontend/js/main.js +99 -0
- testgen/ui/components/frontend/js/streamlit.js +19 -0
- testgen/ui/components/frontend/js/van.min.js +1 -0
- testgen/ui/components/utils/__init__.py +0 -0
- testgen/ui/components/utils/callbacks.py +51 -0
- testgen/ui/components/utils/component.py +13 -0
- testgen/ui/components/widgets/__init__.py +6 -0
- testgen/ui/components/widgets/breadcrumbs.py +32 -0
- testgen/ui/components/widgets/location.py +65 -0
- testgen/ui/components/widgets/modal.py +97 -0
- testgen/ui/components/widgets/sidebar.py +69 -0
- testgen/ui/navigation/__init__.py +0 -0
- testgen/ui/navigation/menu.py +42 -0
- testgen/ui/navigation/page.py +20 -0
- testgen/ui/navigation/router.py +63 -0
- testgen/ui/queries/__init__.py +0 -0
- testgen/ui/queries/authentication_queries.py +47 -0
- testgen/ui/queries/connection_queries.py +121 -0
- testgen/ui/queries/profiling_queries.py +148 -0
- testgen/ui/queries/project_queries.py +9 -0
- testgen/ui/queries/table_group_queries.py +186 -0
- testgen/ui/queries/test_definition_queries.py +270 -0
- testgen/ui/queries/test_run_queries.py +32 -0
- testgen/ui/queries/test_suite_queries.py +145 -0
- testgen/ui/scripts/__init__.py +0 -0
- testgen/ui/scripts/patch_streamlit.py +111 -0
- testgen/ui/services/__init__.py +0 -0
- testgen/ui/services/authentication_service.py +119 -0
- testgen/ui/services/connection_service.py +220 -0
- testgen/ui/services/database_service.py +282 -0
- testgen/ui/services/form_service.py +1008 -0
- testgen/ui/services/javascript_service.py +44 -0
- testgen/ui/services/query_service.py +316 -0
- testgen/ui/services/string_service.py +12 -0
- testgen/ui/services/table_group_service.py +130 -0
- testgen/ui/services/test_definition_service.py +117 -0
- testgen/ui/services/test_run_service.py +13 -0
- testgen/ui/services/test_suite_service.py +76 -0
- testgen/ui/services/toolbar_service.py +77 -0
- testgen/ui/session.py +46 -0
- testgen/ui/views/__init__.py +0 -0
- testgen/ui/views/app_log_modal.py +92 -0
- testgen/ui/views/connections.py +72 -0
- testgen/ui/views/connections_base.py +367 -0
- testgen/ui/views/login.py +40 -0
- testgen/ui/views/not_found.py +16 -0
- testgen/ui/views/overview.py +34 -0
- testgen/ui/views/profiling_anomalies.py +501 -0
- testgen/ui/views/profiling_details.py +335 -0
- testgen/ui/views/profiling_modal.py +40 -0
- testgen/ui/views/profiling_results.py +206 -0
- testgen/ui/views/profiling_summary.py +177 -0
- testgen/ui/views/project_settings.py +74 -0
- testgen/ui/views/table_groups.py +530 -0
- testgen/ui/views/test_definitions.py +1020 -0
- testgen/ui/views/test_results.py +908 -0
- testgen/ui/views/test_runs.py +195 -0
- testgen/ui/views/test_suites.py +545 -0
- testgen/utils/__init__.py +0 -0
- testgen/utils/plugins.py +17 -0
- testgen/utils/singleton.py +14 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
__all__ = ["get_template_files", "read_template_sql_file", "read_template_yaml_file"]
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import re
|
|
5
|
+
from collections.abc import Generator
|
|
6
|
+
from functools import cache
|
|
7
|
+
from importlib.abc import Traversable
|
|
8
|
+
from importlib.resources import as_file, files
|
|
9
|
+
|
|
10
|
+
import yaml
|
|
11
|
+
|
|
12
|
+
LOG = logging.getLogger("testgen")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _get_template_package_resource(
|
|
16
|
+
template_file_name: str | None = None,
|
|
17
|
+
sub_directory: str | None = None,
|
|
18
|
+
path: str | None = None,
|
|
19
|
+
) -> Traversable:
|
|
20
|
+
if path is None:
|
|
21
|
+
path = "testgen.template"
|
|
22
|
+
if sub_directory:
|
|
23
|
+
path = f"{path}.{sub_directory.replace('/', '.')}"
|
|
24
|
+
if template_file_name:
|
|
25
|
+
return files(path).joinpath(template_file_name)
|
|
26
|
+
else:
|
|
27
|
+
return files(path)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@cache
|
|
31
|
+
def read_template_sql_file(template_file_name: str, sub_directory: str | None = None) -> str:
|
|
32
|
+
file = _get_template_package_resource(template_file_name, sub_directory)
|
|
33
|
+
LOG.debug("Reading SQL resource: %s", str(file))
|
|
34
|
+
try:
|
|
35
|
+
contents = file.read_text(encoding="utf-8").strip()
|
|
36
|
+
except FileNotFoundError as e:
|
|
37
|
+
raise ValueError(f"template.{sub_directory}.{template_file_name}: File not found") from e
|
|
38
|
+
|
|
39
|
+
if not contents.strip():
|
|
40
|
+
raise ValueError(f"template.{sub_directory}.{template_file_name}: file is empty")
|
|
41
|
+
|
|
42
|
+
return contents
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_template_files(mask: str, sub_directory: str | None = None, path: str | None = None) -> Generator[Traversable, None, None]:
|
|
46
|
+
folder = _get_template_package_resource(template_file_name=None, sub_directory=sub_directory, path=path)
|
|
47
|
+
LOG.debug("Reading SQL folder resource: %s", str(folder))
|
|
48
|
+
for entry in folder.iterdir():
|
|
49
|
+
if entry.is_file() and re.search(mask, str(entry)):
|
|
50
|
+
yield entry
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@cache
|
|
54
|
+
def read_template_yaml_file(template_file_name: str, sub_directory: str | None = None) -> dict:
|
|
55
|
+
if not template_file_name.endswith(("yaml", "yml")):
|
|
56
|
+
raise ValueError(f"{template_file_name}: does not have a yaml/yml suffix; is it yaml?")
|
|
57
|
+
resource_file = _get_template_package_resource(template_file_name=template_file_name, sub_directory=sub_directory)
|
|
58
|
+
LOG.debug("Reading Yaml resource: %s", str(resource_file))
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
with as_file(resource_file) as f:
|
|
62
|
+
with f.open("r") as file:
|
|
63
|
+
template = yaml.safe_load(file)
|
|
64
|
+
except FileNotFoundError as e:
|
|
65
|
+
raise ValueError(f"{template_file_name}: File not found") from e
|
|
66
|
+
if not template:
|
|
67
|
+
raise ValueError(f"{template_file_name}: File is empty")
|
|
68
|
+
|
|
69
|
+
return template
|
testgen/settings.py
ADDED
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
IS_DEBUG_LOG_LEVEL: bool = os.getenv("TESTGEN_DEBUG_LOG_LEVEL", "no").lower() == "yes"
|
|
4
|
+
"""
|
|
5
|
+
When set, logs will be at debug level.
|
|
6
|
+
defaults to: `no`
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
IS_DEBUG: bool = os.getenv("TESTGEN_DEBUG", "no").lower() == "yes"
|
|
10
|
+
"""
|
|
11
|
+
When True invalidates the cache with the bootstrapped application
|
|
12
|
+
causing the changes to the routing and plugins to take effect on every
|
|
13
|
+
render.
|
|
14
|
+
|
|
15
|
+
from env variable: `TESTGEN_DEBUG`
|
|
16
|
+
defaults to: `True`
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
LOG_TO_FILE: bool = os.getenv("TESTGEN_LOG_TO_FILE", "yes").lower() == "yes"
|
|
20
|
+
"""
|
|
21
|
+
When set, rotating file logs will be generated.
|
|
22
|
+
defaults to: `True`
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
LOG_FILE_PATH: str = os.getenv("TESTGEN_LOG_FILE_PATH", "/var/lib/testgen/log")
|
|
26
|
+
"""
|
|
27
|
+
When set, rotating file logs will be generated under this path.
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
LOG_FILE_MAX_QTY: str = os.getenv("TESTGEN_LOG_FILE_MAX_QTY", "90")
|
|
32
|
+
"""
|
|
33
|
+
Maximum log files to keep, defaults to 90 days (one file per day).
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
APP_ENCRYPTION_SALT: str = os.getenv("TG_DECRYPT_SALT")
|
|
37
|
+
"""
|
|
38
|
+
Salt used to encrypt and decrypt user secrets. Only allows ascii
|
|
39
|
+
characters.
|
|
40
|
+
|
|
41
|
+
A minimun length of 16 characters is recommended.
|
|
42
|
+
|
|
43
|
+
from env variable: `TG_DECRYPT_SALT`
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
APP_ENCRYPTION_SECRET: str = os.getenv("TG_DECRYPT_PASSWORD")
|
|
47
|
+
"""
|
|
48
|
+
Secret passcode used in combination with `APP_ENCRYPTION_SALT` to
|
|
49
|
+
encrypt and decrypt user secrets. Only allows ascii characters.
|
|
50
|
+
|
|
51
|
+
from env variable: `TG_DECRYPT_PASSWORD`
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
USERNAME: str = os.getenv("TESTGEN_USERNAME")
|
|
55
|
+
"""
|
|
56
|
+
Username to log into the web application
|
|
57
|
+
|
|
58
|
+
from env variable: `TESTGEN_USERNAME`
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
PASSWORD: str = os.getenv("TESTGEN_PASSWORD")
|
|
62
|
+
"""
|
|
63
|
+
Password to log into the web application
|
|
64
|
+
|
|
65
|
+
from env variable: `TESTGEN_PASSWORD`
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
DATABASE_USER: str = os.getenv("TG_METADATA_DB_USER", USERNAME)
|
|
69
|
+
"""
|
|
70
|
+
User to connect to the testgen application postgres database.
|
|
71
|
+
|
|
72
|
+
from env variable: `TG_METADATA_DB_USER`
|
|
73
|
+
defaults to: `environ[USERNAME]`
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
DATABASE_PASSWORD: str = os.getenv("TG_METADATA_DB_PASSWORD", PASSWORD)
|
|
77
|
+
"""
|
|
78
|
+
Password to connect to the testgen application postgres database.
|
|
79
|
+
|
|
80
|
+
from env variable: `TG_METADATA_DB_PASSWORD`
|
|
81
|
+
defaults to: `environ[PASSWORD]`
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
DATABASE_ADMIN_USER: str = os.getenv("DATABASE_ADMIN_USER", DATABASE_USER)
|
|
85
|
+
"""
|
|
86
|
+
User with admin privileges in the testgen application postgres database
|
|
87
|
+
used to create roles, users, database and schema. Required if the user
|
|
88
|
+
in `TG_METADATA_DB_USER` does not have the required privileges.
|
|
89
|
+
|
|
90
|
+
from env variable: `DATABASE_ADMIN_USER`
|
|
91
|
+
defaults to: `environ[DATABASE_USER]`
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
DATABASE_ADMIN_PASSWORD: str = os.getenv("DATABASE_ADMIN_PASSWORD", DATABASE_PASSWORD)
|
|
95
|
+
"""
|
|
96
|
+
Password for the admin user to connect to the testgen application
|
|
97
|
+
postgres database.
|
|
98
|
+
|
|
99
|
+
from env variable: `DATABASE_ADMIN_PASSWORD`
|
|
100
|
+
defaults to: `environ[DATABASE_PASSWORD]`
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
DATABASE_EXECUTE_USER: str = os.getenv("DATABASE_EXECUTE_USER", "testgen_execute")
|
|
104
|
+
"""
|
|
105
|
+
User to be created into the testgen application postgres database. Will
|
|
106
|
+
be granted:
|
|
107
|
+
|
|
108
|
+
_ read/write to tables `test_results`, `test_suites` and `test_definitions`
|
|
109
|
+
_ read_only to all other tables
|
|
110
|
+
|
|
111
|
+
from env variable: `DATABASE_EXECUTE_USER`
|
|
112
|
+
defaults to: `testgen_execute`
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
DATABASE_REPORT_USER: str = os.getenv("DATABASE_REPORT_USER", "testgen_report")
|
|
116
|
+
"""
|
|
117
|
+
User to be created into the testgen application postgres database. Will
|
|
118
|
+
be granted read_only access to all tables.
|
|
119
|
+
|
|
120
|
+
from env variable: `DATABASE_REPORT_USER`
|
|
121
|
+
defaults to: `testgen_report`
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
DATABASE_HOST: str = os.getenv("TG_METADATA_DB_HOST", "localhost")
|
|
125
|
+
"""
|
|
126
|
+
Hostname where the testgen application postgres database is running in.
|
|
127
|
+
|
|
128
|
+
from env variable: `TG_METADATA_DB_HOST`
|
|
129
|
+
defaults to: `localhost`
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
DATABASE_PORT: str = os.getenv("TG_METADATA_DB_PORT", "5432")
|
|
133
|
+
"""
|
|
134
|
+
Port at which the testgen application postgres database is exposed by
|
|
135
|
+
the host.
|
|
136
|
+
|
|
137
|
+
from env variable: `TG_METADATA_DB_PORT`
|
|
138
|
+
defaults to: `5432`
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
DATABASE_NAME: str = os.getenv("TG_METADATA_DB_NAME", "datakitchen")
|
|
142
|
+
"""
|
|
143
|
+
Name of the database in postgres on which to store testgen metadata.
|
|
144
|
+
|
|
145
|
+
from env variable: `TG_METADATA_DB_NAME`
|
|
146
|
+
defaults to: `datakitchen`
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
DATABASE_SCHEMA: str = os.getenv("TG_METADATA_DB_SCHEMA", "testgen")
|
|
150
|
+
"""
|
|
151
|
+
Name of the schema inside the postgres database on which to store
|
|
152
|
+
testgen metadata.
|
|
153
|
+
|
|
154
|
+
from env variable: `TG_METADATA_DB_SCHEMA`
|
|
155
|
+
defaults to: `testgen`
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
PROJECT_KEY: str = os.getenv("PROJECT_KEY", "DEFAULT")
|
|
159
|
+
"""
|
|
160
|
+
Code used to uniquely identify the auto generated project.
|
|
161
|
+
|
|
162
|
+
from env variable: `PROJECT_KEY`
|
|
163
|
+
defaults to: `DEFAULT`
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
PROJECT_NAME: str = os.getenv("PROJECT_NAME", "Demo")
|
|
167
|
+
"""
|
|
168
|
+
Name to assign to the auto generated project.
|
|
169
|
+
|
|
170
|
+
from env variable: `DEFAULT_PROJECT_NAME`
|
|
171
|
+
defaults to: `Demo`
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
PROJECT_SQL_FLAVOR: str = os.getenv("PROJECT_SQL_FLAVOR", "postgresql")
|
|
175
|
+
"""
|
|
176
|
+
SQL flavor of the database the auto generated project will run tests
|
|
177
|
+
against.
|
|
178
|
+
|
|
179
|
+
Supported flavors are:
|
|
180
|
+
_ redshift
|
|
181
|
+
_ snowflake
|
|
182
|
+
_ mssql
|
|
183
|
+
_ postgresql
|
|
184
|
+
|
|
185
|
+
from env variable: `PROJECT_SQL_FLAVOR`
|
|
186
|
+
defaults to: `postgresql`
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
PROJECT_CONNECTION_NAME: str = os.getenv("PROJECT_CONNECTION_NAME", "default")
|
|
190
|
+
"""
|
|
191
|
+
Name assigned to identify the connection to the project database.
|
|
192
|
+
|
|
193
|
+
from env variable: `PROJECT_CONNECTION_NAME`
|
|
194
|
+
defaults to: `default`
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
PROJECT_CONNECTION_MAX_THREADS: int = int(os.getenv("PROJECT_CONNECTION_MAX_THREADS", "4"))
|
|
198
|
+
"""
|
|
199
|
+
Maximum number of concurrent queries executed when fetching data from
|
|
200
|
+
the project database.
|
|
201
|
+
|
|
202
|
+
from env variable: `PROJECT_CONNECTION_MAX_THREADS`
|
|
203
|
+
defaults to: `4`
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
PROJECT_CONNECTION_MAX_QUERY_CHAR: int = int(os.getenv("PROJECT_CONNECTION_MAX_QUERY_CHAR", "5000"))
|
|
207
|
+
"""
|
|
208
|
+
Determine how many tests are grouped together in a single query.
|
|
209
|
+
Increase for better performance or decrease to better isolate test
|
|
210
|
+
failures. Accepted values are 500 to 14 000.
|
|
211
|
+
|
|
212
|
+
from env variable: `PROJECT_CONNECTION_MAX_QUERY_CHAR`
|
|
213
|
+
defaults to: `5000`
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
PROJECT_QC_SCHEMA: str = os.getenv("PROJECT_QC_SCHEMA", "qc")
|
|
217
|
+
"""
|
|
218
|
+
Name of the schema to be created in the project database.
|
|
219
|
+
|
|
220
|
+
from env variable: `PROJECT_QC_SCHEMA`
|
|
221
|
+
defaults to: `qc`
|
|
222
|
+
"""
|
|
223
|
+
|
|
224
|
+
PROJECT_DATABASE_NAME: str = os.getenv("PROJECT_DATABASE_NAME", "demo_db")
|
|
225
|
+
"""
|
|
226
|
+
Name of the database the auto generated project will run test
|
|
227
|
+
against.
|
|
228
|
+
|
|
229
|
+
from env variable: `PROJECT_DATABASE_NAME`
|
|
230
|
+
defaults to: `demo_db`
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
PROJECT_DATABASE_SCHEMA: str = os.getenv("PROJECT_DATABASE_SCHEMA", "demo")
|
|
234
|
+
"""
|
|
235
|
+
Name of the schema inside the project database the tests will be run
|
|
236
|
+
against.
|
|
237
|
+
|
|
238
|
+
from env variable: `PROJECT_DATABASE_SCHEMA`
|
|
239
|
+
defaults to: `demo`
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
PROJECT_DATABASE_USER: str = os.getenv("PROJECT_DATABASE_USER", DATABASE_USER)
|
|
243
|
+
"""
|
|
244
|
+
User to be used by the auto generated project to connect to the database
|
|
245
|
+
under testing.
|
|
246
|
+
|
|
247
|
+
from env variable: `PROJECT_DATABASE_USER`
|
|
248
|
+
defaults to: `environ[DATABASE_USER]`
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
PROJECT_DATABASE_PASSWORD: str = os.getenv("PROJECT_DATABASE_PASSWORD", DATABASE_PASSWORD)
|
|
252
|
+
"""
|
|
253
|
+
Password to be used by the auto generated project to connect to the
|
|
254
|
+
database under testing.
|
|
255
|
+
|
|
256
|
+
from env variable: `PROJECT_DATABASE_USER`
|
|
257
|
+
defaults to: `environ[DATABASE_PASSWORD]`
|
|
258
|
+
"""
|
|
259
|
+
|
|
260
|
+
PROJECT_DATABASE_HOST: str = os.getenv("PROJECT_DATABASE_HOST", DATABASE_HOST)
|
|
261
|
+
"""
|
|
262
|
+
Hostname where the database under testing is running in.
|
|
263
|
+
|
|
264
|
+
from env variable: `PROJECT_DATABASE_HOST`
|
|
265
|
+
defaults to: `environ[DATABASE_HOST]`
|
|
266
|
+
"""
|
|
267
|
+
|
|
268
|
+
PROJECT_DATABASE_PORT: str = os.getenv("PROJECT_DATABASE_PORT", DATABASE_PORT)
|
|
269
|
+
"""
|
|
270
|
+
Port at which the database under testing is exposed by the host.
|
|
271
|
+
|
|
272
|
+
from env variable: `PROJECT_DATABASE_PORT`
|
|
273
|
+
defaults to: `environ[DATABASE_PORT]`
|
|
274
|
+
"""
|
|
275
|
+
|
|
276
|
+
SKIP_DATABASE_CERTIFICATE_VERIFICATION: bool = os.getenv("TG_TARGET_DB_TRUST_SERVER_CERTIFICATE", "no").lower() == "yes"
|
|
277
|
+
"""
|
|
278
|
+
When True for supported SQL flavors, set up the SQLAlchemy connection to
|
|
279
|
+
trust the database server certificate.
|
|
280
|
+
|
|
281
|
+
from env variable: `TG_TARGET_DB_TRUST_SERVER_CERTIFICATE`
|
|
282
|
+
defaults to: `True`
|
|
283
|
+
"""
|
|
284
|
+
|
|
285
|
+
DEFAULT_TABLE_GROUPS_NAME: str = os.getenv("DEFAULT_TABLE_GROUPS_NAME", "default")
|
|
286
|
+
"""
|
|
287
|
+
Name assigned to the auto generated table group.
|
|
288
|
+
|
|
289
|
+
from env variable: `DEFAULT_TABLE_GROUPS_NAME`
|
|
290
|
+
defaults to: `default`
|
|
291
|
+
"""
|
|
292
|
+
|
|
293
|
+
DEFAULT_TEST_SUITE_KEY: str = os.getenv("DEFAULT_TEST_SUITE_NAME", "default-suite-1")
|
|
294
|
+
"""
|
|
295
|
+
Key to be assgined to the auto generated test suite.
|
|
296
|
+
|
|
297
|
+
from env variable: `DEFAULT_TEST_SUITE_NAME`
|
|
298
|
+
defaults to: `default-suite-1`
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
DEFAULT_TEST_SUITE_DESCRIPTION: str = os.getenv("DEFAULT_TEST_SUITE_DESCRIPTION", "default_suite_desc")
|
|
302
|
+
"""
|
|
303
|
+
Description for the auto generated test suite.
|
|
304
|
+
|
|
305
|
+
from env variable: `DEFAULT_TEST_SUITE_DESCRIPTION`
|
|
306
|
+
defaults to: `default_suite_desc`
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
DEFAULT_PROFILING_TABLE_SET = os.getenv("DEFAULT_PROFILING_TABLE_SET", "")
|
|
310
|
+
"""
|
|
311
|
+
Comma separated list of specific table names to include when running
|
|
312
|
+
profiling for the project database.
|
|
313
|
+
|
|
314
|
+
from env variable: `DEFAULT_PROFILING_TABLE_SET`
|
|
315
|
+
"""
|
|
316
|
+
|
|
317
|
+
DEFAULT_PROFILING_INCLUDE_MASK = os.getenv("DEFAULT_PROFILING_INCLUDE_MASK", "%")
|
|
318
|
+
"""
|
|
319
|
+
A SQL filter supported by the project database's `LIKE` operator for
|
|
320
|
+
table names to include.
|
|
321
|
+
|
|
322
|
+
from env variable: `DEFAULT_PROFILING_INCLUDE_MASK`
|
|
323
|
+
defaults to: `%`
|
|
324
|
+
"""
|
|
325
|
+
|
|
326
|
+
DEFAULT_PROFILING_EXCLUDE_MASK = os.getenv("DEFAULT_PROFILING_EXCLUDE_MASK", "tmp%")
|
|
327
|
+
"""
|
|
328
|
+
A SQL filter supported by the project database's `LIKE` operator for
|
|
329
|
+
table names to exclude.
|
|
330
|
+
|
|
331
|
+
from env variable: `DEFAULT_PROFILING_EXCLUDE_MASK`
|
|
332
|
+
defaults to: `tmp%`
|
|
333
|
+
"""
|
|
334
|
+
|
|
335
|
+
DEFAULT_PROFILING_ID_COLUMN_MASK = os.getenv("DEFAULT_PROFILING_ID_COLUMN_MASK", "%id")
|
|
336
|
+
"""
|
|
337
|
+
A SQL filter supported by the project database's `LIKE` operator
|
|
338
|
+
representing ID columns.
|
|
339
|
+
|
|
340
|
+
from env variable: `DEFAULT_PROFILING_ID_COLUMN_MASK`
|
|
341
|
+
defaults to: `%id`
|
|
342
|
+
"""
|
|
343
|
+
|
|
344
|
+
DEFAULT_PROFILING_SK_COLUMN_MASK = os.getenv("DEFAULT_PROFILING_SK_COLUMN_MASK", "%sk")
|
|
345
|
+
"""
|
|
346
|
+
A SQL filter supported by the project database's `LIKE` operator
|
|
347
|
+
representing surrogate key columns.
|
|
348
|
+
|
|
349
|
+
from env variable: `DEFAULT_PROFILING_SK_COLUMN_MASK`
|
|
350
|
+
defaults to: `%sk`
|
|
351
|
+
"""
|
|
352
|
+
|
|
353
|
+
DEFAULT_PROFILING_USE_SAMPLING: str = os.getenv("DEFAULT_PROFILING_USE_SAMPLING", "N")
|
|
354
|
+
"""
|
|
355
|
+
Toggle on to base profiling on a sample of records instead of the full
|
|
356
|
+
table. Accepts `Y` or `N`
|
|
357
|
+
|
|
358
|
+
from env variable: `DEFAULT_PROFILING_USE_SAMPLING`
|
|
359
|
+
defaults to: `N`
|
|
360
|
+
"""
|
|
361
|
+
|
|
362
|
+
OBSERVABILITY_API_URL: str = os.getenv("OBSERVABILITY_API_URL", "")
|
|
363
|
+
"""
|
|
364
|
+
API URL of your instance of Observability where to send events to for
|
|
365
|
+
the project.
|
|
366
|
+
|
|
367
|
+
You can configure this from the UI settings page.
|
|
368
|
+
|
|
369
|
+
from env variable: `OBSERVABILITY_API_URL`
|
|
370
|
+
"""
|
|
371
|
+
|
|
372
|
+
OBSERVABILITY_API_KEY: str = os.getenv("OBSERVABILITY_API_KEY", "")
|
|
373
|
+
"""
|
|
374
|
+
Authentication key with permissions to send events created in your
|
|
375
|
+
instance of Observability.
|
|
376
|
+
|
|
377
|
+
You can configure this from the UI settings page.
|
|
378
|
+
|
|
379
|
+
from env variable: `OBSERVABILITY_API_KEY`
|
|
380
|
+
"""
|
|
381
|
+
|
|
382
|
+
OBSERVABILITY_VERIFY_SSL: bool = os.getenv("TG_EXPORT_TO_OBSERVABILITY_VERIFY_SSL", "yes").lower() in ["yes", "true"]
|
|
383
|
+
"""
|
|
384
|
+
When False, exporting events to your instance of Observabilty will skip
|
|
385
|
+
SSL verification.
|
|
386
|
+
|
|
387
|
+
from env variable: `TG_EXPORT_TO_OBSERVABILITY_VERIFY_SSL`
|
|
388
|
+
defaults to: `True`
|
|
389
|
+
"""
|
|
390
|
+
|
|
391
|
+
OBSERVABILITY_EXPORT_LIMIT: int = int(os.getenv("TG_OBSERVABILITY_EXPORT_MAX_QTY", "5000"))
|
|
392
|
+
"""
|
|
393
|
+
When exporting to your instance of Observabilty, the maximum number of
|
|
394
|
+
events that will be sent to the events API on a single export.
|
|
395
|
+
|
|
396
|
+
from env variable: `TG_OBSERVABILITY_EXPORT_MAX_QTY`
|
|
397
|
+
defaults to: `5000`
|
|
398
|
+
"""
|
|
399
|
+
|
|
400
|
+
OBSERVABILITY_DEFAULT_COMPONENT_TYPE: str = os.getenv("OBSERVABILITY_DEFAULT_COMPONENT_TYPE", "dataset")
|
|
401
|
+
"""
|
|
402
|
+
When exporting to your instance of Observabilty, the type of event that
|
|
403
|
+
will be sent to the events API.
|
|
404
|
+
|
|
405
|
+
from env variable: `OBSERVABILITY_DEFAULT_COMPONENT_TYPE`
|
|
406
|
+
defaults to: `dataset`
|
|
407
|
+
"""
|
|
408
|
+
|
|
409
|
+
OBSERVABILITY_DEFAULT_COMPONENT_KEY: str = os.getenv("OBSERVABILITY_DEFAULT_COMPONENT_KEY", "default")
|
|
410
|
+
"""
|
|
411
|
+
When exporting to your instance of Observabilty, the key sent to the
|
|
412
|
+
events API to identify the components.
|
|
413
|
+
|
|
414
|
+
from env variable: `OBSERVABILITY_DEFAULT_COMPONENT_KEY`
|
|
415
|
+
defaults to: `default`
|
|
416
|
+
"""
|
|
417
|
+
|
|
418
|
+
CHECK_FOR_LATEST_VERSION: bool = os.getenv("TG_DOCKER_RELEASE_CHECK_ENABLED", "yes").lower() == "yes"
|
|
419
|
+
"""
|
|
420
|
+
When True, enables calling Docker Hub API to fetch the latest released
|
|
421
|
+
image tag. The fetched tag is displayed in the UI menu.
|
|
422
|
+
|
|
423
|
+
from env variable: `TG_DOCKER_RELEASE_CHECK_ENABLED`
|
|
424
|
+
defaults to: `True`
|
|
425
|
+
"""
|
|
426
|
+
|
|
427
|
+
VERSION: str = os.getenv("TESTGEN_VERSION", "unknown")
|
|
428
|
+
"""
|
|
429
|
+
Current deployed version. The value is displayed in the UI menu.
|
|
430
|
+
|
|
431
|
+
from env variable: `TESTGEN_VERSION`
|
|
432
|
+
defaults to: `unknown`
|
|
433
|
+
"""
|
|
434
|
+
|
|
435
|
+
SSL_CERT_FILE: str = os.getenv("SSL_CERT_FILE", "")
|
|
436
|
+
SSL_KEY_FILE: str = os.getenv("SSL_KEY_FILE", "")
|
|
437
|
+
"""
|
|
438
|
+
File paths for SSL certificate and private key to support HTTPS.
|
|
439
|
+
Both files must be provided.
|
|
440
|
+
"""
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.datediff(difftype character varying, firstdate timestamp without time zone, seconddate timestamp without time zone) returns bigint
|
|
2
|
+
language plpgsql
|
|
3
|
+
as
|
|
4
|
+
$$
|
|
5
|
+
BEGIN
|
|
6
|
+
RETURN
|
|
7
|
+
CASE
|
|
8
|
+
WHEN UPPER(difftype) IN ('DAY', 'DD')
|
|
9
|
+
THEN DATE_PART('day', seconddate - firstdate)
|
|
10
|
+
WHEN UPPER(difftype) IN ('WEEK','WK')
|
|
11
|
+
THEN TRUNC(DATE_PART('day', seconddate - firstdate)/7)
|
|
12
|
+
WHEN UPPER(difftype) IN ('MON', 'MM')
|
|
13
|
+
THEN 12 * (DATE_PART('year', seconddate) - DATE_PART('year', firstdate))
|
|
14
|
+
+ (DATE_PART('month', seconddate) - DATE_PART('month', firstdate))
|
|
15
|
+
WHEN UPPER(difftype) IN ('QUARTER', 'QTR')
|
|
16
|
+
THEN 4 * (DATE_PART('year', seconddate) - DATE_PART('year', firstdate))
|
|
17
|
+
+ (DATE_PART('qtr', seconddate) - DATE_PART('month', firstdate))
|
|
18
|
+
WHEN UPPER(difftype) IN ('YEAR', 'YY')
|
|
19
|
+
THEN DATE_PART('year', seconddate) - DATE_PART('year', firstdate)
|
|
20
|
+
END;
|
|
21
|
+
END;
|
|
22
|
+
$$;
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.fn_charcount(instring character varying, searchstring character varying) returns bigint
|
|
26
|
+
language plpgsql
|
|
27
|
+
as
|
|
28
|
+
$$
|
|
29
|
+
BEGIN
|
|
30
|
+
RETURN (CHAR_LENGTH(instring) - CHAR_LENGTH(REPLACE(instring, searchstring, ''))) / CHAR_LENGTH(searchstring);
|
|
31
|
+
END;
|
|
32
|
+
$$;
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.fn_parsefreq(top_freq_values VARCHAR(1000), rowno INTEGER, colno INTEGER) returns VARCHAR(1000)
|
|
36
|
+
LANGUAGE SQL
|
|
37
|
+
STABLE
|
|
38
|
+
as
|
|
39
|
+
$$
|
|
40
|
+
WITH first AS
|
|
41
|
+
(
|
|
42
|
+
SELECT SPLIT_PART(top_freq_values, CHR(10), rowno) AS first_row
|
|
43
|
+
)
|
|
44
|
+
SELECT
|
|
45
|
+
CASE
|
|
46
|
+
WHEN colno = 1 THEN CAST(TRIM(LEADING '|' FROM SUBSTRING(first_row, POSITION('|' IN first_row), LENGTH(first_row) - POSITION('|' IN REVERSE(first_row)))) AS VARCHAR)
|
|
47
|
+
WHEN colno = 2 THEN CAST(TRIM(SUBSTRING(first_row, LENGTH(first_row) - POSITION('|' IN REVERSE(first_row)) + 2)) AS VARCHAR)
|
|
48
|
+
ELSE NULL
|
|
49
|
+
END
|
|
50
|
+
FROM first
|
|
51
|
+
$$;
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.fn_PrepColumnName(value_to_check TEXT)
|
|
55
|
+
RETURNS TEXT AS
|
|
56
|
+
$$
|
|
57
|
+
DECLARE
|
|
58
|
+
keyword_arr TEXT[] := ARRAY ['ALL', 'ALTER', 'ANALYSE', 'ANALYZE', 'AND', 'ANY', 'ARRAY', 'AS', 'ASC', 'ASYMMETRIC',
|
|
59
|
+
'AUTHORIZATION', 'BINARY', 'BOTH', 'CASE', 'CAST', 'CHECK', 'COLLATE', 'COLLATION',
|
|
60
|
+
'COLUMN', 'CONCURRENTLY', 'CONSTRAINT', 'CREATE', 'CROSS', 'CURRENT_CATALOG',
|
|
61
|
+
'CURRENT_DATE', 'CURRENT_ROLE', 'CURRENT_SCHEMA', 'CURRENT_TIME', 'CURRENT_TIMESTAMP',
|
|
62
|
+
'CURRENT_USER', 'CREDENTIALS',
|
|
63
|
+
'DEFAULT', 'DEFERRABLE', 'DESC', 'DISTINCT', 'DO', 'DROP',
|
|
64
|
+
'ELSE', 'END', 'EXCEPT', 'FALSE', 'FETCH', 'FOR', 'FOREIGN', 'FREEZE', 'FROM', 'FULL',
|
|
65
|
+
'GRANT', 'GROUP', 'HAVING', 'ILIKE', 'IN', 'INITIALLY', 'INNER', 'INTERSECT', 'INTO',
|
|
66
|
+
'IS', 'ISNULL', 'JOIN', 'LATERAL', 'LEADING', 'LEFT', 'LIKE', 'LIMIT', 'LOCALTIME',
|
|
67
|
+
'LOCALTIMESTAMP', 'NATURAL', 'NOT', 'NOTNULL', 'NULL', 'OFFSET', 'ON', 'ONLY', 'OR',
|
|
68
|
+
'ORDER', 'OUTER', 'OVERLAPS', 'PLACING', 'PRIMARY', 'REFERENCES', 'RETURNING', 'RIGHT',
|
|
69
|
+
'SELECT', 'SESSION_USER', 'SIMILAR', 'SOME', 'SYMMETRIC', 'TABLE', 'TABLESAMPLE',
|
|
70
|
+
'THEN', 'TIMESTAMP', 'TIMEZONE', 'TO', 'TRAILING', 'TRUE', 'UNION', 'UNIQUE', 'USER', 'USING',
|
|
71
|
+
'VARIADIC', 'VERBOSE', 'WHEN', 'WHERE', 'WINDOW', 'WITH']; -- Add more keywords here
|
|
72
|
+
BEGIN
|
|
73
|
+
-- Check if the value matches any of the keywords (case-insensitive)
|
|
74
|
+
IF value_to_check ILIKE ANY (keyword_arr) THEN
|
|
75
|
+
RETURN '"' || value_to_check || '"';
|
|
76
|
+
-- Check if the value contains a space or a comma or it starts with a number
|
|
77
|
+
ELSIF value_to_check !~ '^[a-zA-Z_][a-zA-Z0-9_]*$' THEN
|
|
78
|
+
RETURN '"' || value_to_check || '"';
|
|
79
|
+
ELSE
|
|
80
|
+
RETURN value_to_check;
|
|
81
|
+
END IF;
|
|
82
|
+
END;
|
|
83
|
+
$$ LANGUAGE plpgsql;
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.fn_pct(numerator NUMERIC, denominator NUMERIC, decs INTEGER DEFAULT 0) returns NUMERIC
|
|
87
|
+
language plpgsql
|
|
88
|
+
as
|
|
89
|
+
$$
|
|
90
|
+
BEGIN
|
|
91
|
+
RETURN ROUND((100.0 * numerator/denominator), decs);
|
|
92
|
+
END;
|
|
93
|
+
$$;
|
|
94
|
+
|
|
95
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.fn_quote_literal_escape(var_value varchar, sql_flavor varchar) RETURNS varchar
|
|
96
|
+
LANGUAGE plpgsql
|
|
97
|
+
AS
|
|
98
|
+
$$
|
|
99
|
+
DECLARE
|
|
100
|
+
escaped_value varchar;
|
|
101
|
+
lower_case_sql_flavor varchar;
|
|
102
|
+
BEGIN
|
|
103
|
+
lower_case_sql_flavor := LOWER(sql_flavor);
|
|
104
|
+
|
|
105
|
+
IF lower_case_sql_flavor = 'postgres' OR lower_case_sql_flavor = 'postgresql' THEN
|
|
106
|
+
escaped_value := QUOTE_LITERAL(var_value);
|
|
107
|
+
ELSIF lower_case_sql_flavor = 'redshift' OR lower_case_sql_flavor = 'snowflake' THEN
|
|
108
|
+
escaped_value := TRIM(LEADING 'E' FROM QUOTE_LITERAL(var_value));
|
|
109
|
+
ELSIF lower_case_sql_flavor = 'mssql' THEN
|
|
110
|
+
escaped_value := '''' || REPLACE(var_value, '''', '''''') || '''';
|
|
111
|
+
ELSE
|
|
112
|
+
RAISE EXCEPTION 'Invalid sql_flavor name: %', sql_flavor;
|
|
113
|
+
END IF;
|
|
114
|
+
|
|
115
|
+
RETURN escaped_value;
|
|
116
|
+
END;
|
|
117
|
+
$$;
|
|
118
|
+
|
|
119
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.fn_format_csv_no_quotes(str_csv TEXT) returns TEXT
|
|
120
|
+
LANGUAGE SQL
|
|
121
|
+
IMMUTABLE
|
|
122
|
+
as
|
|
123
|
+
$$
|
|
124
|
+
SELECT
|
|
125
|
+
REGEXP_REPLACE(
|
|
126
|
+
REGEXP_REPLACE(str_csv::VARCHAR, '''', '', 'g'), -- Remove single quotes
|
|
127
|
+
'\s*,\s*', -- Match comma, with or without surrounding spaces
|
|
128
|
+
', ', -- Replace with comma followed by a space
|
|
129
|
+
'g' -- Global replace
|
|
130
|
+
) AS formatted_value
|
|
131
|
+
$$;
|
|
132
|
+
|
|
133
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.fn_format_csv_quotes(str_csv TEXT) returns TEXT
|
|
134
|
+
LANGUAGE SQL
|
|
135
|
+
IMMUTABLE
|
|
136
|
+
as
|
|
137
|
+
$$
|
|
138
|
+
SELECT
|
|
139
|
+
'''' || REGEXP_REPLACE(str_csv::VARCHAR, '\s*,\s*', ''', ''', 'g') || ''''
|
|
140
|
+
AS formatted_value
|
|
141
|
+
$$;
|
|
142
|
+
|
|
143
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.fn_count_intersecting_items(list1 VARCHAR, list2 VARCHAR, separator VARCHAR)
|
|
144
|
+
RETURNS BIGINT AS $$
|
|
145
|
+
SELECT COUNT(*)
|
|
146
|
+
FROM (
|
|
147
|
+
SELECT unnest(string_to_array(list1, separator)) AS element
|
|
148
|
+
INTERSECT
|
|
149
|
+
SELECT unnest(string_to_array(list2, separator))
|
|
150
|
+
) AS intersection
|
|
151
|
+
$$ LANGUAGE sql;
|
|
152
|
+
|
|
153
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.fn_extract_intersecting_items(list1 VARCHAR, list2 VARCHAR, separator VARCHAR)
|
|
154
|
+
RETURNS VARCHAR AS $$
|
|
155
|
+
SELECT STRING_AGG(DISTINCT element, separator) as shared_vals
|
|
156
|
+
FROM (
|
|
157
|
+
SELECT unnest(string_to_array(list1, separator)) AS element
|
|
158
|
+
INTERSECT
|
|
159
|
+
SELECT unnest(string_to_array(list2, separator))
|
|
160
|
+
) AS intersection
|
|
161
|
+
$$ LANGUAGE sql;
|
|
162
|
+
|
|
163
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.fn_extract_distinct_items(list VARCHAR, separator VARCHAR)
|
|
164
|
+
RETURNS VARCHAR AS $$
|
|
165
|
+
SELECT STRING_AGG(DISTINCT element, separator) as distinct_items
|
|
166
|
+
FROM (
|
|
167
|
+
SELECT unnest(string_to_array(list, separator)) AS element
|
|
168
|
+
) AS all_items
|
|
169
|
+
$$ LANGUAGE sql;
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.fn_extract_top_values(input_string TEXT)
|
|
173
|
+
RETURNS TEXT AS $$
|
|
174
|
+
SELECT string_agg(trim(split_part(value, '|', 2)), '|') AS values_only
|
|
175
|
+
FROM (
|
|
176
|
+
SELECT unnest(regexp_split_to_array(input_string, E'\n')) AS value
|
|
177
|
+
) AS t
|
|
178
|
+
WHERE trim(value) <> ''
|
|
179
|
+
$$ LANGUAGE sql;
|