This is an automated email from the ASF dual-hosted git repository.
villebro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 420eff4 feat: add Firebolt DB engine spec (#16903)
420eff4 is described below
commit 420eff42b8fc01a1e0a7fe0f74f0b4b018a81960
Author: apurva-sigmoid <[email protected]>
AuthorDate: Fri Oct 1 22:13:15 2021 +0530
feat: add Firebolt DB engine spec (#16903)
* New branch from superset for integration with firebolt sqlalchemy adapter
* Added db_engine_spec file for Firebolt
* Removed firebolt code from superset repo
* Deleted virtual env commit
* Adding time grain changes to firebolt.py
* Updated README.md
Added steps to install and run Superset with Firebolt SQLAlchemy Adapter
* Update README.md
Reduced installation steps. Using PyPi installation for adapter now
* Revert "Update README.md"
This reverts commit 5ed17c7a4545998ed07693c93738ebe7bff2580e.
* Revert "Updated README.md"
This reverts commit 45c5072649a7926fc4d15d2eb0b9cc5a89e5d7b2.
* added epoch methods, added test cases for firebolt db engine spec and
edited setup.py
* Added license to files
* Added documentation for Firebolt-SQLAlchemy
* Removed trailing whitespace
Co-authored-by: raghavsharma <[email protected]>
Co-authored-by: raghavSharmaSigmoid
<[email protected]>
---
.../docs/Connecting to Databases/firebolt.mdx | 24 ++++++++++
.../pages/docs/Connecting to Databases/index.mdx | 1 +
setup.py | 1 +
superset/db_engine_specs/firebolt.py | 56 ++++++++++++++++++++++
.../db_engine_specs/firebolt_tests.py | 39 +++++++++++++++
5 files changed, 121 insertions(+)
diff --git a/docs/src/pages/docs/Connecting to Databases/firebolt.mdx
b/docs/src/pages/docs/Connecting to Databases/firebolt.mdx
new file mode 100644
index 0000000..c1d11ff
--- /dev/null
+++ b/docs/src/pages/docs/Connecting to Databases/firebolt.mdx
@@ -0,0 +1,24 @@
+---
+name: Firebolt
+menu: Connecting to Databases
+route: /docs/databases/firebolt
+index: 31
+version: 1
+---
+
+## Firebolt
+
+The recommended connector library for Firebolt is
[firebolt-sqlalchemy](https://pypi.org/project/firebolt-sqlalchemy/).
+Superset has been tested on `firebolt-sqlalchemy>=0.0.1`.
+
+The recommended connection string is:
+
+```
+firebolt://{username}:{password}@{host}/{database}
+```
+
+Here's a connection string example of Superset connecting to a Firebolt
database:
+
+```
+firebolt://email@domain:password@host/sample_database
+```
diff --git a/docs/src/pages/docs/Connecting to Databases/index.mdx
b/docs/src/pages/docs/Connecting to Databases/index.mdx
index 0704dc7..5d7ec9f 100644
--- a/docs/src/pages/docs/Connecting to Databases/index.mdx
+++ b/docs/src/pages/docs/Connecting to Databases/index.mdx
@@ -42,6 +42,7 @@ A list of some of the recommended packages.
|[Elasticsearch](/docs/databases/elasticsearch)|```pip install
elasticsearch-dbapi```|```elasticsearch+http://{user}:{password}@{host}:9200/```|
|[Exasol](/docs/databases/exasol)|```pip install
sqlalchemy-exasol```|```exa+pyodbc://{username}:{password}@{hostname}:{port}/my_schema?CONNECTIONLCALL=en_US.UTF-8&driver=EXAODBC```|
|[Google Sheets](/docs/databases/google-sheets)|```pip install
shillelagh[gsheetsapi]```|```gsheets://```|
+|[Firebolt](/docs/databases/firebolt)|```pip install
firebolt-sqlalchemy```|```firebolt://{username}:{password}@{host}/{database}```|
|[Hologres](/docs/databases/hologres)|```pip install
psycopg2```|```postgresql+psycopg2://<UserName>:<DBPassword>@<Database
Host>/<Database Name>```|
|[IBM Db2](/docs/databases/ibm-db2)|```pip install
ibm_db_sa```|```db2+ibm_db://```|
|[IBM Netezza Performance Server](/docs/databases/netezza)|```pip install
nzalchemy```|```netezza+nzpy://<UserName>:<DBPassword>@<Database
Host>/<Database Name>```|
diff --git a/setup.py b/setup.py
index 8f72eb7..7baf648 100644
--- a/setup.py
+++ b/setup.py
@@ -134,6 +134,7 @@ setup(
"exasol": ["sqlalchemy-exasol>=2.1.0, <2.2"],
"excel": ["xlrd>=1.2.0, <1.3"],
"firebird": ["sqlalchemy-firebird>=0.7.0, <0.8"],
+ "firebolt": ["firebolt-sqlalchemy>=0.0.1"],
"gsheets": ["shillelagh[gsheetsapi]>=1.0.3, <2"],
"hana": ["hdbcli==2.4.162", "sqlalchemy_hana==0.4.0"],
"hive": ["pyhive[hive]>=0.6.1", "tableschema", "thrift>=0.11.0,
<1.0.0"],
diff --git a/superset/db_engine_specs/firebolt.py
b/superset/db_engine_specs/firebolt.py
new file mode 100644
index 0000000..ea5091f
--- /dev/null
+++ b/superset/db_engine_specs/firebolt.py
@@ -0,0 +1,56 @@
+# 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 Optional
+
+from superset.db_engine_specs.base import BaseEngineSpec
+from superset.utils import core as utils
+
+
+class FireboltEngineSpec(BaseEngineSpec):
+ """Engine spec for Firebolt"""
+
+ engine = "firebolt"
+ engine_name = "Firebolt"
+ default_driver = "firebolt"
+
+ _time_grain_expressions = {
+ None: "{col}",
+ "PT1S": "date_trunc('second', CAST({col} AS TIMESTAMP))",
+ "PT1M": "date_trunc('minute', CAST({col} AS TIMESTAMP))",
+ "PT1H": "date_trunc('hour', CAST({col} AS TIMESTAMP))",
+ "P1D": "date_trunc('day', CAST({col} AS TIMESTAMP))",
+ "P1W": "date_trunc('week', CAST({col} AS TIMESTAMP))",
+ "P1M": "date_trunc('month', CAST({col} AS TIMESTAMP))",
+ "P0.25Y": "date_trunc('quarter', CAST({col} AS TIMESTAMP))",
+ "P1Y": "date_trunc('year', CAST({col} AS TIMESTAMP))",
+ }
+
+ @classmethod
+ def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
+ tt = target_type.upper()
+ if tt == utils.TemporalType.DATE:
+ return f"CAST('{dttm.date().isoformat()}' AS DATE)"
+ if tt == utils.TemporalType.DATETIME:
+ return f"""CAST('{dttm.isoformat(timespec="seconds")}' AS
DATETIME)"""
+ if tt == utils.TemporalType.TIMESTAMP:
+ return f"""CAST('{dttm.isoformat(timespec="seconds")}' AS
TIMESTAMP)"""
+ return None
+
+ @classmethod
+ def epoch_to_dttm(cls) -> str:
+ return "from_unixtime({col})"
diff --git a/tests/integration_tests/db_engine_specs/firebolt_tests.py
b/tests/integration_tests/db_engine_specs/firebolt_tests.py
new file mode 100644
index 0000000..793b329
--- /dev/null
+++ b/tests/integration_tests/db_engine_specs/firebolt_tests.py
@@ -0,0 +1,39 @@
+# 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 superset.db_engine_specs.firebolt import FireboltEngineSpec
+from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec
+
+
+class TestFireboltDbEngineSpec(TestDbEngineSpec):
+ def test_convert_dttm(self):
+ dttm = self.get_dttm()
+ test_cases = {
+ "DATE": "CAST('2019-01-02' AS DATE)",
+ "DATETIME": "CAST('2019-01-02T03:04:05' AS DATETIME)",
+ "TIMESTAMP": "CAST('2019-01-02T03:04:05' AS TIMESTAMP)",
+ "UNKNOWNTYPE": None,
+ }
+
+ for target_type, expected in test_cases.items():
+ actual = FireboltEngineSpec.convert_dttm(target_type, dttm)
+ self.assertEqual(actual, expected)
+
+ def test_epoch_to_dttm(self):
+ assert (
+ FireboltEngineSpec.epoch_to_dttm().format(col="timestamp_column")
+ == "from_unixtime(timestamp_column)"
+ )