Skip to content

Commit a0cd368

Browse files
authored
fix: view create and drop (#349)
1 parent 7491303 commit a0cd368

5 files changed

Lines changed: 144 additions & 4 deletions

File tree

dcs_core/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
__version__ = "0.9.7"
15+
__version__ = "0.9.8"

dcs_core/core/datasource/sql_datasource.py

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import secrets
16+
import string
17+
import time
1518
from datetime import datetime
1619
from typing import Dict, List, Optional, Tuple, Union
1720

1821
from loguru import logger
1922
from sqlalchemy import inspect, text
20-
from sqlalchemy.engine import Connection
23+
from sqlalchemy.engine import Connection, Engine
2124

2225
from dcs_core.core.datasource.base import DataSource
2326

@@ -1047,3 +1050,87 @@ def query_timestamp_date_not_in_future_metric(
10471050
except Exception as e:
10481051
logger.error(f"Error occurred: {e}")
10491052
return 0, 0
1053+
1054+
def generate_view_name(self, view_name: str | None = None) -> str:
1055+
if view_name is not None:
1056+
return view_name
1057+
random_string = "".join(
1058+
secrets.choice(string.ascii_letters + string.digits) for _ in range(8)
1059+
)
1060+
timestamp = int(time.time())
1061+
return f"dcs_view_{timestamp}_{random_string.lower()}"
1062+
1063+
def create_view(
1064+
self,
1065+
query: str | None = None,
1066+
schema: str | None = None,
1067+
view_name: str | None = None,
1068+
) -> str | None:
1069+
view_name = self.generate_view_name(view_name=view_name)
1070+
schema_prefix = f"{schema}." if schema else ""
1071+
view_name_full = f"{schema_prefix}{view_name}"
1072+
1073+
if query is None:
1074+
sql = f"CREATE VIEW {view_name_full} AS SELECT 1 AS dummy WHERE 1 = 0"
1075+
else:
1076+
sql = f"CREATE VIEW {view_name_full} AS {query}"
1077+
1078+
try:
1079+
if isinstance(self.connection, (Connection, Engine)):
1080+
if isinstance(self.connection, Engine):
1081+
with self.connection.connect() as conn:
1082+
conn.execute(text(sql))
1083+
conn.commit()
1084+
else:
1085+
self.connection.execute(text(sql))
1086+
try:
1087+
self.connection.commit()
1088+
except Exception:
1089+
pass
1090+
else:
1091+
plain_sql = str(sql)
1092+
if hasattr(self.connection, "cursor"):
1093+
cur = self.connection.cursor()
1094+
cur.execute(plain_sql)
1095+
try:
1096+
self.connection.commit()
1097+
except Exception:
1098+
pass
1099+
else:
1100+
self.connection.execute(plain_sql)
1101+
1102+
return view_name_full
1103+
except Exception as e:
1104+
logger.error(f"Error creating view {view_name_full}: {e}")
1105+
return None
1106+
1107+
def drop_view(self, view_name: str, schema: str | None) -> bool:
1108+
schema_prefix = f"{schema}." if schema else ""
1109+
full_view_name = f"{schema_prefix}{view_name}"
1110+
drop_query = f"DROP VIEW {full_view_name}"
1111+
try:
1112+
if isinstance(self.connection, (Connection, Engine)):
1113+
if isinstance(self.connection, Engine):
1114+
with self.connection.connect() as conn:
1115+
conn.execute(text(drop_query))
1116+
conn.commit()
1117+
else:
1118+
self.connection.execute(text(drop_query))
1119+
try:
1120+
self.connection.commit()
1121+
except Exception:
1122+
pass
1123+
else:
1124+
if hasattr(self.connection, "cursor"):
1125+
cur = self.connection.cursor()
1126+
cur.execute(drop_query)
1127+
try:
1128+
self.connection.commit()
1129+
except Exception:
1130+
pass
1131+
else:
1132+
self.connection.execute(str(drop_query))
1133+
return True
1134+
except Exception as e:
1135+
logger.error(f"Error dropping view {full_view_name}: {e}")
1136+
return False

dcs_core/integrations/databases/bigquery.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import base64
1616
import json
1717
import os
18-
from typing import Any, Dict, List
18+
from typing import Any, Dict, List, Optional
1919

2020
from loguru import logger
2121
from sqlalchemy import create_engine
@@ -162,3 +162,44 @@ def query_get_table_columns(
162162
for r in rows
163163
}
164164
return column_info
165+
166+
def create_view(
167+
self,
168+
query: Optional[str] = None,
169+
dataset: Optional[str] = None,
170+
view_name: Optional[str] = None,
171+
) -> str | None:
172+
view_name = self.generate_view_name(view_name=view_name)
173+
full_name = (
174+
f"`{self.project}`.`{dataset}`.`{view_name}`"
175+
if dataset
176+
else f"`{view_name}`"
177+
)
178+
try:
179+
if query is None:
180+
create_view_query = (
181+
f"CREATE VIEW {full_name} AS SELECT 1 AS dummy_column WHERE FALSE"
182+
)
183+
self.connection.execute(create_view_query)
184+
return full_name
185+
else:
186+
create_view_query = f"CREATE VIEW {full_name} AS {query}"
187+
self.connection.execute(create_view_query)
188+
return full_name
189+
except Exception as e:
190+
logger.error(f"Error creating view: {e}")
191+
return None
192+
193+
def drop_view(self, view_name: str, dataset: Optional[str] = None) -> bool:
194+
full_name = (
195+
f"`{self.project}`.`{dataset}`.`{view_name}`"
196+
if dataset
197+
else f"`{view_name}`"
198+
)
199+
try:
200+
drop_view_query = f"DROP VIEW {full_name}"
201+
self.connection.execute(drop_view_query)
202+
return True
203+
except Exception as e:
204+
logger.error(f"Error dropping view: {e}")
205+
return False

dcs_core/integrations/databases/oracle.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import secrets
16+
import string
17+
import time
1518
from datetime import datetime
1619
from typing import Any, Dict, List, Optional, Tuple, Union
1720

@@ -690,3 +693,12 @@ def query_get_all_space_count(
690693
return round((result[0] / result[1]) * 100) if result[1] > 0 else 0
691694

692695
return result[0] if result else 0
696+
697+
def generate_view_name(self, view_name: str | None = None) -> str:
698+
if view_name is not None:
699+
return view_name.upper()
700+
random_string = "".join(
701+
secrets.choice(string.ascii_letters + string.digits) for _ in range(8)
702+
)
703+
timestamp = int(time.time())
704+
return f"dcs_view_{timestamp}_{random_string.lower()}".upper()

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "dcs-core"
3-
version = "0.9.7"
3+
version = "0.9.8"
44
description = "Open Source Data Quality Monitoring"
55
license = "Apache-2.0"
66
authors = [

0 commit comments

Comments
 (0)