soda-synapse 4.0.5__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.
- soda_synapse-4.0.5/PKG-INFO +6 -0
- soda_synapse-4.0.5/setup.cfg +4 -0
- soda_synapse-4.0.5/setup.py +24 -0
- soda_synapse-4.0.5/src/soda_synapse/common/data_sources/synapse_data_source.py +91 -0
- soda_synapse-4.0.5/src/soda_synapse/common/data_sources/synapse_data_source_connection.py +70 -0
- soda_synapse-4.0.5/src/soda_synapse/test_helpers/synapse_data_source_test_helper.py +32 -0
- soda_synapse-4.0.5/src/soda_synapse.egg-info/PKG-INFO +6 -0
- soda_synapse-4.0.5/src/soda_synapse.egg-info/SOURCES.txt +10 -0
- soda_synapse-4.0.5/src/soda_synapse.egg-info/dependency_links.txt +1 -0
- soda_synapse-4.0.5/src/soda_synapse.egg-info/entry_points.txt +2 -0
- soda_synapse-4.0.5/src/soda_synapse.egg-info/requires.txt +2 -0
- soda_synapse-4.0.5/src/soda_synapse.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
from setuptools import setup
|
|
4
|
+
|
|
5
|
+
package_name = "soda-synapse"
|
|
6
|
+
package_version = "4.0.5"
|
|
7
|
+
description = "Soda Synapse V4"
|
|
8
|
+
|
|
9
|
+
requires = [
|
|
10
|
+
f"soda-core=={package_version}",
|
|
11
|
+
f"soda-sqlserver=={package_version}",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
setup(
|
|
15
|
+
name=package_name,
|
|
16
|
+
version=package_version,
|
|
17
|
+
install_requires=requires,
|
|
18
|
+
package_dir={"": "src"},
|
|
19
|
+
entry_points={
|
|
20
|
+
"soda.plugins.data_source.synapse": [
|
|
21
|
+
"SynapseDataSourceImpl = soda_synapse.common.data_sources.synapse_data_source:SynapseDataSourceImpl",
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from soda_core.common.data_source_connection import DataSourceConnection
|
|
5
|
+
from soda_core.common.dataset_identifier import DatasetIdentifier
|
|
6
|
+
from soda_core.common.logging_constants import soda_logger
|
|
7
|
+
from soda_core.common.sql_ast import COLUMN, INSERT_INTO, VALUES, VALUES_ROW
|
|
8
|
+
from soda_core.common.sql_dialect import SqlDialect
|
|
9
|
+
from soda_sqlserver.common.data_sources.sqlserver_data_source import (
|
|
10
|
+
SqlServerDataSourceImpl,
|
|
11
|
+
SqlServerSqlDialect,
|
|
12
|
+
)
|
|
13
|
+
from soda_synapse.common.data_sources.synapse_data_source_connection import (
|
|
14
|
+
SynapseDataSource as SynapseDataSourceModel,
|
|
15
|
+
)
|
|
16
|
+
from soda_synapse.common.data_sources.synapse_data_source_connection import (
|
|
17
|
+
SynapseDataSourceConnection,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
logger: logging.Logger = soda_logger
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SynapseDataSourceImpl(SqlServerDataSourceImpl, model_class=SynapseDataSourceModel):
|
|
24
|
+
def __init__(self, data_source_model: SynapseDataSourceModel):
|
|
25
|
+
super().__init__(data_source_model=data_source_model)
|
|
26
|
+
|
|
27
|
+
def _create_sql_dialect(self) -> SqlDialect:
|
|
28
|
+
return SynapseSqlDialect(data_source_impl=self)
|
|
29
|
+
|
|
30
|
+
def _create_data_source_connection(self) -> DataSourceConnection:
|
|
31
|
+
return SynapseDataSourceConnection(
|
|
32
|
+
name=self.data_source_model.name, connection_properties=self.data_source_model.connection_properties
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SynapseSqlDialect(SqlServerSqlDialect):
|
|
37
|
+
def sql_expr_timestamp_truncate_day(self, timestamp_literal: str) -> str:
|
|
38
|
+
return f"DATETIMEFROMPARTS((datepart(YEAR, {timestamp_literal})), (datepart(MONTH, {timestamp_literal})), (datepart(DAY, {timestamp_literal})), 0, 0, 0, 0)"
|
|
39
|
+
|
|
40
|
+
def _build_insert_into_values_sql(self, insert_into: INSERT_INTO) -> str:
|
|
41
|
+
values_sql: str = "\n" + "\nUNION ALL ".join(
|
|
42
|
+
[self._build_insert_into_values_row_sql(value) for value in insert_into.values]
|
|
43
|
+
)
|
|
44
|
+
return values_sql
|
|
45
|
+
|
|
46
|
+
def _build_insert_into_values_row_sql(self, values: VALUES_ROW) -> str:
|
|
47
|
+
values_sql: str = "SELECT " + ", ".join([self.literal(value) for value in values.values])
|
|
48
|
+
values_sql = self.encode_string_for_sql(values_sql)
|
|
49
|
+
return values_sql
|
|
50
|
+
|
|
51
|
+
def build_cte_values_sql(self, values: VALUES, alias_columns: list[COLUMN] | None) -> str:
|
|
52
|
+
return "\nUNION ALL\n".join(["SELECT " + self.build_expression_sql(value) for value in values.values])
|
|
53
|
+
|
|
54
|
+
def select_all_paginated_sql(
|
|
55
|
+
self,
|
|
56
|
+
dataset_identifier: DatasetIdentifier,
|
|
57
|
+
columns: list[str],
|
|
58
|
+
filter: Optional[str],
|
|
59
|
+
order_by: list[str],
|
|
60
|
+
limit: int,
|
|
61
|
+
offset: int,
|
|
62
|
+
) -> str:
|
|
63
|
+
"""TODO: Synapse uses completely different pagination syntax, AST does not have enough flexibility for this yet."""
|
|
64
|
+
where_clauses = []
|
|
65
|
+
|
|
66
|
+
if filter:
|
|
67
|
+
where_clauses.append(SqlExpressionStr(filter))
|
|
68
|
+
|
|
69
|
+
select_statements = self._build_select_sql_lines([SELECT(columns or [STAR()])])
|
|
70
|
+
select = ", ".join(select_statements)
|
|
71
|
+
order_by_statements = self._build_order_by_lines([ORDER_BY_ASC(c) for c in order_by])
|
|
72
|
+
order_by = ", ".join(order_by_statements)
|
|
73
|
+
where_statements = self._build_where_sql_lines([WHERE.optional(AND.optional(where_clauses))])
|
|
74
|
+
where = ", ".join(where_statements)
|
|
75
|
+
|
|
76
|
+
query = f"""WITH src AS (
|
|
77
|
+
{select}, ROW_NUMBER()
|
|
78
|
+
OVER (
|
|
79
|
+
{order_by}
|
|
80
|
+
) AS rn
|
|
81
|
+
FROM {self.build_fully_qualified_sql_name(dataset_identifier)} AS t
|
|
82
|
+
{where}
|
|
83
|
+
)
|
|
84
|
+
SELECT *
|
|
85
|
+
FROM src
|
|
86
|
+
WHERE rn > {offset}
|
|
87
|
+
AND rn <= {offset + limit}
|
|
88
|
+
ORDER BY rn;
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
return query
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from abc import ABC
|
|
5
|
+
from typing import Literal, Union
|
|
6
|
+
|
|
7
|
+
from pydantic import Field
|
|
8
|
+
from soda_core.common.logging_constants import soda_logger
|
|
9
|
+
from soda_core.model.data_source.data_source import DataSourceBase
|
|
10
|
+
from soda_sqlserver.common.data_sources.sqlserver_data_source_connection import (
|
|
11
|
+
SqlServerActiveDirectoryAuthentication,
|
|
12
|
+
SqlServerActiveDirectoryInteractiveAuthentication,
|
|
13
|
+
SqlServerActiveDirectoryPasswordAuthentication,
|
|
14
|
+
SqlServerActiveDirectoryServicePrincipalAuthentication,
|
|
15
|
+
SqlServerConnectionProperties,
|
|
16
|
+
SqlServerDataSourceConnection,
|
|
17
|
+
SqlServerPasswordAuth,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
logger: logging.Logger = soda_logger
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
CONTEXT_AUTHENTICATION_DESCRIPTION = "Use context authentication"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# All of these classes are just copies of the SQLServerConnectionProperties classes, but with the Synapse type
|
|
27
|
+
class SynapseConnectionProperties(SqlServerConnectionProperties, ABC):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SynapsePasswordAuth(SqlServerPasswordAuth, SynapseConnectionProperties):
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class SynapseActiveDirectoryAuthentication(SqlServerActiveDirectoryAuthentication, SynapseConnectionProperties):
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class SynapseActiveDirectoryInteractiveAuthentication(
|
|
40
|
+
SqlServerActiveDirectoryInteractiveAuthentication, SynapseConnectionProperties
|
|
41
|
+
):
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class SynapseActiveDirectoryPasswordAuthentication(
|
|
46
|
+
SqlServerActiveDirectoryPasswordAuthentication, SynapseConnectionProperties
|
|
47
|
+
):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class SynapseActiveDirectoryServicePrincipalAuthentication(
|
|
52
|
+
SqlServerActiveDirectoryServicePrincipalAuthentication, SynapseConnectionProperties
|
|
53
|
+
):
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class SynapseDataSource(DataSourceBase, ABC):
|
|
58
|
+
type: Literal["synapse"] = Field("synapse")
|
|
59
|
+
|
|
60
|
+
connection_properties: Union[
|
|
61
|
+
SynapsePasswordAuth,
|
|
62
|
+
SynapseActiveDirectoryInteractiveAuthentication,
|
|
63
|
+
SynapseActiveDirectoryPasswordAuthentication,
|
|
64
|
+
SynapseActiveDirectoryServicePrincipalAuthentication,
|
|
65
|
+
] = Field(..., alias="connection", description="Synapse connection configuration")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class SynapseDataSourceConnection(SqlServerDataSourceConnection):
|
|
69
|
+
def _get_autocommit_setting(self) -> bool:
|
|
70
|
+
return True # Synapse requires autocommit to be True.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from soda_sqlserver.test_helpers.sqlserver_data_source_test_helper import (
|
|
7
|
+
SqlServerDataSourceTestHelper,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SynapseDataSourceTestHelper(SqlServerDataSourceTestHelper):
|
|
12
|
+
def _create_database_name(self) -> Optional[str]:
|
|
13
|
+
return os.getenv("SYNAPSE_DATABASE", "sodatestingsynapse")
|
|
14
|
+
|
|
15
|
+
def _create_data_source_yaml_str(self) -> str:
|
|
16
|
+
"""
|
|
17
|
+
Called in _create_data_source_impl to initialized self.data_source_impl
|
|
18
|
+
self.database_name and self.schema_name are available if appropriate for the data source type
|
|
19
|
+
"""
|
|
20
|
+
return f"""
|
|
21
|
+
type: synapse
|
|
22
|
+
name: {self.name}
|
|
23
|
+
connection:
|
|
24
|
+
host: '{os.getenv("SYNAPSE_HOST", "localhost")}'
|
|
25
|
+
port: '{os.getenv("SYNAPSE_PORT", "1433")}'
|
|
26
|
+
database: '{os.getenv("SYNAPSE_DATABASE", "sodatestingsynapse")}'
|
|
27
|
+
authentication: '{os.getenv("SYNAPSE_AUTHENTICATION_TYPE", "activedirectoryserviceprincipal")}'
|
|
28
|
+
client_id: '{os.getenv("SYNAPSE_CLIENT_ID")}'
|
|
29
|
+
client_secret: '{os.getenv("SYNAPSE_CLIENT_SECRET")}'
|
|
30
|
+
trust_server_certificate: true
|
|
31
|
+
driver: '{os.getenv("SYNAPSE_DRIVER", "ODBC Driver 18 for SQL Server")}'
|
|
32
|
+
"""
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
setup.py
|
|
2
|
+
src/soda_synapse.egg-info/PKG-INFO
|
|
3
|
+
src/soda_synapse.egg-info/SOURCES.txt
|
|
4
|
+
src/soda_synapse.egg-info/dependency_links.txt
|
|
5
|
+
src/soda_synapse.egg-info/entry_points.txt
|
|
6
|
+
src/soda_synapse.egg-info/requires.txt
|
|
7
|
+
src/soda_synapse.egg-info/top_level.txt
|
|
8
|
+
src/soda_synapse/common/data_sources/synapse_data_source.py
|
|
9
|
+
src/soda_synapse/common/data_sources/synapse_data_source_connection.py
|
|
10
|
+
src/soda_synapse/test_helpers/synapse_data_source_test_helper.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
soda_synapse
|