mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-10 07:53:35 +00:00
Fix correct snowflake object types in source url (#23612)
This commit is contained in:
parent
ae503c26e5
commit
22a0925cd2
@ -14,6 +14,9 @@ Snowflake constants
|
|||||||
|
|
||||||
from sqlalchemy.sql.sqltypes import BOOLEANTYPE, VARCHAR
|
from sqlalchemy.sql.sqltypes import BOOLEANTYPE, VARCHAR
|
||||||
|
|
||||||
|
from metadata.generated.schema.entity.data.storedProcedure import StoredProcedureType
|
||||||
|
from metadata.generated.schema.entity.data.table import TableType
|
||||||
|
|
||||||
DEFAULT_STREAM_COLUMNS = [
|
DEFAULT_STREAM_COLUMNS = [
|
||||||
{
|
{
|
||||||
"name": "METADATA$ACTION",
|
"name": "METADATA$ACTION",
|
||||||
@ -49,3 +52,18 @@ DEFAULT_STREAM_COLUMNS = [
|
|||||||
|
|
||||||
SNOWFLAKE_TAG_DESCRIPTION = "SNOWFLAKE TAG VALUE"
|
SNOWFLAKE_TAG_DESCRIPTION = "SNOWFLAKE TAG VALUE"
|
||||||
SNOWFLAKE_CLASSIFICATION_DESCRIPTION = "SNOWFLAKE TAG NAME"
|
SNOWFLAKE_CLASSIFICATION_DESCRIPTION = "SNOWFLAKE TAG NAME"
|
||||||
|
|
||||||
|
TABLE_TYPE_URL_MAP = {
|
||||||
|
TableType.Regular: "table",
|
||||||
|
TableType.Transient: "table",
|
||||||
|
TableType.Dynamic: "dynamic-table",
|
||||||
|
TableType.External: "external-table",
|
||||||
|
TableType.View: "view",
|
||||||
|
TableType.MaterializedView: "materialized-view",
|
||||||
|
TableType.Stream: "stream",
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCEDURE_TYPE_URL_MAP = {
|
||||||
|
StoredProcedureType.StoredProcedure: "procedure",
|
||||||
|
StoredProcedureType.UDF: "user-function",
|
||||||
|
}
|
||||||
|
|||||||
@ -74,8 +74,10 @@ from metadata.ingestion.source.database.incremental_metadata_extraction import (
|
|||||||
from metadata.ingestion.source.database.multi_db_source import MultiDBSource
|
from metadata.ingestion.source.database.multi_db_source import MultiDBSource
|
||||||
from metadata.ingestion.source.database.snowflake.constants import (
|
from metadata.ingestion.source.database.snowflake.constants import (
|
||||||
DEFAULT_STREAM_COLUMNS,
|
DEFAULT_STREAM_COLUMNS,
|
||||||
|
PROCEDURE_TYPE_URL_MAP,
|
||||||
SNOWFLAKE_CLASSIFICATION_DESCRIPTION,
|
SNOWFLAKE_CLASSIFICATION_DESCRIPTION,
|
||||||
SNOWFLAKE_TAG_DESCRIPTION,
|
SNOWFLAKE_TAG_DESCRIPTION,
|
||||||
|
TABLE_TYPE_URL_MAP,
|
||||||
)
|
)
|
||||||
from metadata.ingestion.source.database.snowflake.models import (
|
from metadata.ingestion.source.database.snowflake.models import (
|
||||||
STORED_PROC_LANGUAGE_MAP,
|
STORED_PROC_LANGUAGE_MAP,
|
||||||
@ -688,11 +690,11 @@ class SnowflakeSource(
|
|||||||
table_type: Optional[TableType] = None,
|
table_type: Optional[TableType] = None,
|
||||||
) -> Optional[str]:
|
) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Method to get the source url for snowflake
|
Method to get the source url for snowflake tables
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if self.account and self.org_name:
|
if self.account and self.org_name:
|
||||||
tab_type = "view" if table_type == TableType.View else "table"
|
tab_type = TABLE_TYPE_URL_MAP.get(table_type, "table")
|
||||||
url = self._get_source_url_root(
|
url = self._get_source_url_root(
|
||||||
database_name=database_name, schema_name=schema_name
|
database_name=database_name, schema_name=schema_name
|
||||||
)
|
)
|
||||||
@ -704,6 +706,41 @@ class SnowflakeSource(
|
|||||||
logger.error(f"Unable to get source url: {exc}")
|
logger.error(f"Unable to get source url: {exc}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_procedure_source_url(
|
||||||
|
self,
|
||||||
|
database_name: Optional[str] = None,
|
||||||
|
schema_name: Optional[str] = None,
|
||||||
|
procedure_name: Optional[str] = None,
|
||||||
|
procedure_signature: Optional[str] = None,
|
||||||
|
procedure_type: Optional[str] = None,
|
||||||
|
) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
Method to get the source url for snowflake stored procedures
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if self.account and self.org_name:
|
||||||
|
url = self._get_source_url_root(
|
||||||
|
database_name=database_name, schema_name=schema_name
|
||||||
|
)
|
||||||
|
|
||||||
|
# Convert string procedure type to enum and get URL mapping
|
||||||
|
proc_type_enum = (
|
||||||
|
StoredProcedureType(procedure_type)
|
||||||
|
if procedure_type
|
||||||
|
else StoredProcedureType.StoredProcedure
|
||||||
|
)
|
||||||
|
tab_type = PROCEDURE_TYPE_URL_MAP.get(proc_type_enum, "procedure")
|
||||||
|
|
||||||
|
if procedure_name:
|
||||||
|
full_name = f"{procedure_name}{procedure_signature or ''}"
|
||||||
|
url = f"{url}/{tab_type}/{full_name}"
|
||||||
|
|
||||||
|
return url
|
||||||
|
except Exception as exc:
|
||||||
|
logger.debug(traceback.format_exc())
|
||||||
|
logger.error(f"Unable to get procedure source url: {exc}")
|
||||||
|
return None
|
||||||
|
|
||||||
def _get_view_names_and_types(
|
def _get_view_names_and_types(
|
||||||
self, schema_name: str, materialized_views: bool = False
|
self, schema_name: str, materialized_views: bool = False
|
||||||
) -> List[TableNameAndType]:
|
) -> List[TableNameAndType]:
|
||||||
@ -844,12 +881,13 @@ class SnowflakeSource(
|
|||||||
schema_name=self.context.get().database_schema,
|
schema_name=self.context.get().database_schema,
|
||||||
),
|
),
|
||||||
sourceUrl=SourceUrl(
|
sourceUrl=SourceUrl(
|
||||||
self._get_source_url_root(
|
self.get_procedure_source_url(
|
||||||
database_name=self.context.get().database,
|
database_name=self.context.get().database,
|
||||||
schema_name=self.context.get().database_schema,
|
schema_name=self.context.get().database_schema,
|
||||||
|
procedure_name=stored_procedure.name,
|
||||||
|
procedure_signature=stored_procedure.signature,
|
||||||
|
procedure_type=stored_procedure.procedure_type,
|
||||||
)
|
)
|
||||||
+ f"/procedure/{stored_procedure.name}"
|
|
||||||
+ f"{stored_procedure.signature if stored_procedure.signature else ''}"
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
yield Either(right=stored_procedure_request)
|
yield Either(right=stored_procedure_request)
|
||||||
|
|||||||
@ -140,10 +140,30 @@ MOCK_SCHEMA_NAME_1 = "INFORMATION_SCHEMA"
|
|||||||
MOCK_SCHEMA_NAME_2 = "TPCDS_SF10TCL"
|
MOCK_SCHEMA_NAME_2 = "TPCDS_SF10TCL"
|
||||||
MOCK_VIEW_NAME = "COLUMNS"
|
MOCK_VIEW_NAME = "COLUMNS"
|
||||||
MOCK_TABLE_NAME = "CALL_CENTER"
|
MOCK_TABLE_NAME = "CALL_CENTER"
|
||||||
EXPECTED_SNOW_URL_VIEW = "https://app.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/view/COLUMNS"
|
|
||||||
|
# Table URLs
|
||||||
EXPECTED_SNOW_URL_TABLE = "https://app.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/TPCDS_SF10TCL/table/CALL_CENTER"
|
EXPECTED_SNOW_URL_TABLE = "https://app.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/TPCDS_SF10TCL/table/CALL_CENTER"
|
||||||
EXPECTED_SNOW_URL_VIEW_CUSTOM = "https://custom.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/view/COLUMNS"
|
|
||||||
EXPECTED_SNOW_URL_TABLE_CUSTOM = "https://custom.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/TPCDS_SF10TCL/table/CALL_CENTER"
|
EXPECTED_SNOW_URL_TABLE_CUSTOM = "https://custom.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/TPCDS_SF10TCL/table/CALL_CENTER"
|
||||||
|
EXPECTED_SNOW_URL_TRANSIENT = "https://app.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/table/TEST_TRANSIENT"
|
||||||
|
EXPECTED_SNOW_URL_TRANSIENT_CUSTOM = "https://custom.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/table/TEST_TRANSIENT"
|
||||||
|
EXPECTED_SNOW_URL_DYNAMIC = "https://app.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/dynamic-table/TEST_DYNAMIC"
|
||||||
|
EXPECTED_SNOW_URL_DYNAMIC_CUSTOM = "https://custom.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/dynamic-table/TEST_DYNAMIC"
|
||||||
|
EXPECTED_SNOW_URL_EXTERNAL = "https://app.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/external-table/TEST_EXTERNAL"
|
||||||
|
EXPECTED_SNOW_URL_EXTERNAL_CUSTOM = "https://custom.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/external-table/TEST_EXTERNAL"
|
||||||
|
|
||||||
|
EXPECTED_SNOW_URL_VIEW = "https://app.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/view/COLUMNS"
|
||||||
|
EXPECTED_SNOW_URL_VIEW_CUSTOM = "https://custom.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/view/COLUMNS"
|
||||||
|
EXPECTED_SNOW_URL_MATERIALIZED_VIEW = "https://app.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/materialized-view/TEST_MV"
|
||||||
|
EXPECTED_SNOW_URL_MATERIALIZED_VIEW_CUSTOM = "https://custom.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/materialized-view/TEST_MV"
|
||||||
|
|
||||||
|
EXPECTED_SNOW_URL_STREAM = "https://app.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/stream/TEST_STREAM"
|
||||||
|
EXPECTED_SNOW_URL_STREAM_CUSTOM = "https://custom.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/stream/TEST_STREAM"
|
||||||
|
|
||||||
|
# Procedure URLs
|
||||||
|
EXPECTED_SNOW_URL_PROCEDURE = "https://app.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/procedure/TEST_PROC(VARCHAR)"
|
||||||
|
EXPECTED_SNOW_URL_PROCEDURE_CUSTOM = "https://custom.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/procedure/TEST_PROC(VARCHAR)"
|
||||||
|
EXPECTED_SNOW_URL_UDF = "https://app.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/user-function/TEST_UDF(NUMBER)"
|
||||||
|
EXPECTED_SNOW_URL_UDF_CUSTOM = "https://custom.snowflake.com/random_org/random_account/#/data/databases/SNOWFLAKE_SAMPLE_DATA/schemas/INFORMATION_SCHEMA/user-function/TEST_UDF(NUMBER)"
|
||||||
|
|
||||||
|
|
||||||
def get_snowflake_sources():
|
def get_snowflake_sources():
|
||||||
@ -225,10 +245,28 @@ class SnowflakeUnitTest(TestCase):
|
|||||||
for source_key, source in self.sources.items():
|
for source_key, source in self.sources.items():
|
||||||
if source_key == "custom_host":
|
if source_key == "custom_host":
|
||||||
expected_table_url = EXPECTED_SNOW_URL_TABLE_CUSTOM
|
expected_table_url = EXPECTED_SNOW_URL_TABLE_CUSTOM
|
||||||
|
expected_transient_url = EXPECTED_SNOW_URL_TRANSIENT_CUSTOM
|
||||||
|
expected_dynamic_url = EXPECTED_SNOW_URL_DYNAMIC_CUSTOM
|
||||||
|
expected_external_url = EXPECTED_SNOW_URL_EXTERNAL_CUSTOM
|
||||||
expected_view_url = EXPECTED_SNOW_URL_VIEW_CUSTOM
|
expected_view_url = EXPECTED_SNOW_URL_VIEW_CUSTOM
|
||||||
|
expected_materialized_view_url = (
|
||||||
|
EXPECTED_SNOW_URL_MATERIALIZED_VIEW_CUSTOM
|
||||||
|
)
|
||||||
|
expected_stream_url = EXPECTED_SNOW_URL_STREAM_CUSTOM
|
||||||
|
expected_procedure_url = EXPECTED_SNOW_URL_PROCEDURE_CUSTOM
|
||||||
|
expected_udf_url = EXPECTED_SNOW_URL_UDF_CUSTOM
|
||||||
else:
|
else:
|
||||||
expected_table_url = EXPECTED_SNOW_URL_TABLE
|
expected_table_url = EXPECTED_SNOW_URL_TABLE
|
||||||
|
expected_transient_url = EXPECTED_SNOW_URL_TRANSIENT
|
||||||
|
expected_dynamic_url = EXPECTED_SNOW_URL_DYNAMIC
|
||||||
|
expected_external_url = EXPECTED_SNOW_URL_EXTERNAL
|
||||||
expected_view_url = EXPECTED_SNOW_URL_VIEW
|
expected_view_url = EXPECTED_SNOW_URL_VIEW
|
||||||
|
expected_materialized_view_url = EXPECTED_SNOW_URL_MATERIALIZED_VIEW
|
||||||
|
expected_stream_url = EXPECTED_SNOW_URL_STREAM
|
||||||
|
expected_procedure_url = EXPECTED_SNOW_URL_PROCEDURE
|
||||||
|
expected_udf_url = EXPECTED_SNOW_URL_UDF
|
||||||
|
|
||||||
|
# Test regular table URL
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
source.get_source_url(
|
source.get_source_url(
|
||||||
database_name=MOCK_DB_NAME,
|
database_name=MOCK_DB_NAME,
|
||||||
@ -239,6 +277,40 @@ class SnowflakeUnitTest(TestCase):
|
|||||||
expected_table_url,
|
expected_table_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Test transient table URL (should use 'table')
|
||||||
|
self.assertEqual(
|
||||||
|
source.get_source_url(
|
||||||
|
database_name=MOCK_DB_NAME,
|
||||||
|
schema_name=MOCK_SCHEMA_NAME_1,
|
||||||
|
table_name="TEST_TRANSIENT",
|
||||||
|
table_type=TableType.Transient,
|
||||||
|
),
|
||||||
|
expected_transient_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test dynamic table URL
|
||||||
|
self.assertEqual(
|
||||||
|
source.get_source_url(
|
||||||
|
database_name=MOCK_DB_NAME,
|
||||||
|
schema_name=MOCK_SCHEMA_NAME_1,
|
||||||
|
table_name="TEST_DYNAMIC",
|
||||||
|
table_type=TableType.Dynamic,
|
||||||
|
),
|
||||||
|
expected_dynamic_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test external table URL
|
||||||
|
self.assertEqual(
|
||||||
|
source.get_source_url(
|
||||||
|
database_name=MOCK_DB_NAME,
|
||||||
|
schema_name=MOCK_SCHEMA_NAME_1,
|
||||||
|
table_name="TEST_EXTERNAL",
|
||||||
|
table_type=TableType.External,
|
||||||
|
),
|
||||||
|
expected_external_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test view URL
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
source.get_source_url(
|
source.get_source_url(
|
||||||
database_name=MOCK_DB_NAME,
|
database_name=MOCK_DB_NAME,
|
||||||
@ -249,6 +321,52 @@ class SnowflakeUnitTest(TestCase):
|
|||||||
expected_view_url,
|
expected_view_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Test materialized view URL
|
||||||
|
self.assertEqual(
|
||||||
|
source.get_source_url(
|
||||||
|
database_name=MOCK_DB_NAME,
|
||||||
|
schema_name=MOCK_SCHEMA_NAME_1,
|
||||||
|
table_name="TEST_MV",
|
||||||
|
table_type=TableType.MaterializedView,
|
||||||
|
),
|
||||||
|
expected_materialized_view_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test stream URL
|
||||||
|
self.assertEqual(
|
||||||
|
source.get_source_url(
|
||||||
|
database_name=MOCK_DB_NAME,
|
||||||
|
schema_name=MOCK_SCHEMA_NAME_1,
|
||||||
|
table_name="TEST_STREAM",
|
||||||
|
table_type=TableType.Stream,
|
||||||
|
),
|
||||||
|
expected_stream_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test stored procedure URL
|
||||||
|
self.assertEqual(
|
||||||
|
source.get_procedure_source_url(
|
||||||
|
database_name=MOCK_DB_NAME,
|
||||||
|
schema_name=MOCK_SCHEMA_NAME_1,
|
||||||
|
procedure_name="TEST_PROC",
|
||||||
|
procedure_signature="(VARCHAR)",
|
||||||
|
procedure_type="StoredProcedure",
|
||||||
|
),
|
||||||
|
expected_procedure_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test UDF URL
|
||||||
|
self.assertEqual(
|
||||||
|
source.get_procedure_source_url(
|
||||||
|
database_name=MOCK_DB_NAME,
|
||||||
|
schema_name=MOCK_SCHEMA_NAME_1,
|
||||||
|
procedure_name="TEST_UDF",
|
||||||
|
procedure_signature="(NUMBER)",
|
||||||
|
procedure_type="UDF",
|
||||||
|
),
|
||||||
|
expected_udf_url,
|
||||||
|
)
|
||||||
|
|
||||||
def test_source_url(self):
|
def test_source_url(self):
|
||||||
"""
|
"""
|
||||||
method to test source url
|
method to test source url
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user