Skip to content

Commit

Permalink
Added engine spec for Virtuoso DBMS
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergey Malinin committed May 14, 2024
1 parent 78d5b47 commit c8e7b8c
Showing 1 changed file with 95 additions and 0 deletions.
95 changes: 95 additions & 0 deletions superset/db_engine_specs/virtuoso.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from datetime import datetime
from typing import Any, Optional

from sqlalchemy import types

from superset.constants import TimeGrain
from superset.db_engine_specs.base import BaseEngineSpec, LimitMethod


class VirtuosoEngineSpec(BaseEngineSpec):
"""Engine for Virtuoso"""

engine = "virtuoso"
engine_name = "Virtuoso"

sqlalchemy_uri_placeholder = (
"virtuoso+pyodbc://user:password@dsn"
)

# Virtuoso uses FIRST to limit: `SELECT FIRST 10 * FROM table`
limit_method = LimitMethod.FETCH_MANY
max_column_name_length = 100
# supports_catalog = True
disable_ssh_tunneling = True

_time_grain_expressions = {
None: "{col}",
TimeGrain.SECOND: (
"CAST(CAST({col} AS DATE) "
"|| ' ' "
"|| EXTRACT(HOUR FROM {col}) "
"|| ':' "
"|| EXTRACT(MINUTE FROM {col}) "
"|| ':' "
"|| FLOOR(EXTRACT(SECOND FROM {col})) AS TIMESTAMP)"
),
TimeGrain.MINUTE: (
"CAST(CAST({col} AS DATE) "
"|| ' ' "
"|| EXTRACT(HOUR FROM {col}) "
"|| ':' "
"|| EXTRACT(MINUTE FROM {col}) "
"|| ':00' AS TIMESTAMP)"
),
TimeGrain.HOUR: (
"CAST(CAST({col} AS DATE) "
"|| ' ' "
"|| EXTRACT(HOUR FROM {col}) "
"|| ':00:00' AS TIMESTAMP)"
),
TimeGrain.DAY: "CAST({col} AS DATE)",
TimeGrain.MONTH: (
"CAST(EXTRACT(YEAR FROM {col}) "
"|| '-' "
"|| EXTRACT(MONTH FROM {col}) "
"|| '-01' AS DATE)"
),
TimeGrain.YEAR: "CAST(EXTRACT(YEAR FROM {col}) || '-01-01' AS DATE)",
}

@classmethod
def epoch_to_dttm(cls) -> str:
return "DATEADD('second', {col}, stringdate('1970-01-01'))"

@classmethod
def convert_dttm(
cls, target_type: str, dttm: datetime, db_extra: Optional[dict[str, Any]] = None
) -> Optional[str]:
sqla_type = cls.get_sqla_column_type(target_type)

if isinstance(sqla_type, types.Date):
return f"CAST('{dttm.date().isoformat()}' AS DATE)"
if isinstance(sqla_type, types.DateTime):
dttm_formatted = dttm.isoformat(sep=" ")
dttm_valid_precision = dttm_formatted[: len("YYYY-MM-DD HH:MM:SS.MMMM")]
return f"CAST('{dttm_valid_precision}' AS TIMESTAMP)"
if isinstance(sqla_type, types.Time):
return f"CAST('{dttm.time().isoformat()}' AS TIME)"
return None

0 comments on commit c8e7b8c

Please sign in to comment.