feat: add MotherDuck DB engine spec (#24934)

This commit is contained in:
Beto Dealmeida 2023-08-09 16:42:14 -07:00 committed by GitHub
parent f6c3f0cbbb
commit 9c54280d85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 42 additions and 21 deletions

View File

@ -150,6 +150,7 @@ setup(
"dremio": ["sqlalchemy-dremio>=1.1.5, <1.3"], "dremio": ["sqlalchemy-dremio>=1.1.5, <1.3"],
"drill": ["sqlalchemy-drill==0.1.dev"], "drill": ["sqlalchemy-drill==0.1.dev"],
"druid": ["pydruid>=0.6.5,<0.7"], "druid": ["pydruid>=0.6.5,<0.7"],
"duckdb": ["duckdb-engine==0.8.1"],
"dynamodb": ["pydynamodb>=0.4.2"], "dynamodb": ["pydynamodb>=0.4.2"],
"solr": ["sqlalchemy-solr >= 0.2.0"], "solr": ["sqlalchemy-solr >= 0.2.0"],
"elasticsearch": ["elasticsearch-dbapi>=0.2.9, <0.3.0"], "elasticsearch": ["elasticsearch-dbapi>=0.2.9, <0.3.0"],

View File

@ -38,17 +38,13 @@ const SqlAlchemyTab = ({
testInProgress?: boolean; testInProgress?: boolean;
children?: ReactNode; children?: ReactNode;
}) => { }) => {
let fallbackDocsUrl; const fallbackDocsUrl =
let fallbackDisplayText; SupersetText?.DB_MODAL_SQLALCHEMY_FORM?.SQLALCHEMY_DOCS_URL ||
if (SupersetText) { 'https://docs.sqlalchemy.org/en/13/core/engines.html';
fallbackDocsUrl = const fallbackDisplayText =
SupersetText.DB_MODAL_SQLALCHEMY_FORM?.SQLALCHEMY_DOCS_URL; SupersetText?.DB_MODAL_SQLALCHEMY_FORM?.SQLALCHEMY_DISPLAY_TEXT ||
fallbackDisplayText = 'SQLAlchemy docs';
SupersetText.DB_MODAL_SQLALCHEMY_FORM?.SQLALCHEMY_DISPLAY_TEXT;
} else {
fallbackDocsUrl = 'https://docs.sqlalchemy.org/en/13/core/engines.html';
fallbackDisplayText = 'SQLAlchemy docs';
}
return ( return (
<> <>
<StyledInputContainer> <StyledInputContainer>
@ -82,9 +78,10 @@ const SqlAlchemyTab = ({
data-test="sqlalchemy-uri-input" data-test="sqlalchemy-uri-input"
value={db?.sqlalchemy_uri || ''} value={db?.sqlalchemy_uri || ''}
autoComplete="off" autoComplete="off"
placeholder={t( placeholder={
'dialect+driver://username:password@host:port/database', db?.sqlalchemy_uri_placeholder ||
)} t('dialect+driver://username:password@host:port/database')
}
onChange={onInputChange} onChange={onInputChange}
/> />
</div> </div>

View File

@ -202,6 +202,7 @@ export type DBReducerActionType =
configuration_method: CONFIGURATION_METHOD; configuration_method: CONFIGURATION_METHOD;
engine_information?: {}; engine_information?: {};
driver?: string; driver?: string;
sqlalchemy_uri_placeholder?: string;
}; };
} }
| { | {
@ -946,8 +947,13 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
const selectedDbModel = availableDbs?.databases.filter( const selectedDbModel = availableDbs?.databases.filter(
(db: DatabaseObject) => db.name === database_name, (db: DatabaseObject) => db.name === database_name,
)[0]; )[0];
const { engine, parameters, engine_information, default_driver } = const {
selectedDbModel; engine,
parameters,
engine_information,
default_driver,
sqlalchemy_uri_placeholder,
} = selectedDbModel;
const isDynamic = parameters !== undefined; const isDynamic = parameters !== undefined;
setDB({ setDB({
type: ActionType.dbSelected, type: ActionType.dbSelected,
@ -959,6 +965,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
: CONFIGURATION_METHOD.SQLALCHEMY_URI, : CONFIGURATION_METHOD.SQLALCHEMY_URI,
engine_information, engine_information,
driver: default_driver, driver: default_driver,
sqlalchemy_uri_placeholder,
}, },
}); });

View File

@ -52,6 +52,7 @@ export type DatabaseObject = {
name: string; // synonym to database_name name: string; // synonym to database_name
paramProperties?: Record<string, any>; paramProperties?: Record<string, any>;
sqlalchemy_uri?: string; sqlalchemy_uri?: string;
sqlalchemy_uri_placeholder?: string;
parameters?: { parameters?: {
access_token?: string; access_token?: string;
database_name?: string; database_name?: string;

View File

@ -1293,6 +1293,9 @@ class DatabaseRestApi(BaseSupersetModelRestApi):
type: array type: array
items: items:
type: string type: string
sqlalchemy_uri_placeholder:
description: Placeholder for the SQLAlchemy URI
type: string
default_driver: default_driver:
description: Default driver for the engine description: Default driver for the engine
type: string type: string
@ -1330,6 +1333,7 @@ class DatabaseRestApi(BaseSupersetModelRestApi):
"name": engine_spec.engine_name, "name": engine_spec.engine_name,
"engine": engine_spec.engine, "engine": engine_spec.engine,
"available_drivers": sorted(drivers), "available_drivers": sorted(drivers),
"sqlalchemy_uri_placeholder": engine_spec.sqlalchemy_uri_placeholder,
"preferred": engine_spec.engine_name in preferred_databases, "preferred": engine_spec.engine_name in preferred_databases,
"engine_information": engine_spec.get_public_information(), "engine_information": engine_spec.get_public_information(),
} }

View File

@ -185,6 +185,12 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
engine_aliases: set[str] = set() engine_aliases: set[str] = set()
drivers: dict[str, str] = {} drivers: dict[str, str] = {}
default_driver: str | None = None default_driver: str | None = None
# placeholder with the SQLAlchemy URI template
sqlalchemy_uri_placeholder = (
"engine+driver://user:password@host:port/dbname[?key=value&key=value...]"
)
disable_ssh_tunneling = False disable_ssh_tunneling = False
_date_trunc_functions: dict[str, str] = {} _date_trunc_functions: dict[str, str] = {}
@ -1958,11 +1964,6 @@ class BasicParametersMixin:
# recommended driver name for the DB engine spec # recommended driver name for the DB engine spec
default_driver = "" default_driver = ""
# placeholder with the SQLAlchemy URI template
sqlalchemy_uri_placeholder = (
"engine+driver://user:password@host:port/dbname[?key=value&key=value...]"
)
# query parameter to enable encryption in the database connection # query parameter to enable encryption in the database connection
# for Postgres this would be `{"sslmode": "verify-ca"}`, eg. # for Postgres this would be `{"sslmode": "verify-ca"}`, eg.
encryption_parameters: dict[str, str] = {} encryption_parameters: dict[str, str] = {}

View File

@ -80,3 +80,10 @@ class DuckDBEngineSpec(BaseEngineSpec):
cls, database: Database, inspector: Inspector, schema: str | None cls, database: Database, inspector: Inspector, schema: str | None
) -> set[str]: ) -> set[str]:
return set(inspector.get_table_names(schema)) return set(inspector.get_table_names(schema))
class MotherDuckEngineSpec(DuckDBEngineSpec):
engine = "duckdb"
engine_name = "MotherDuck"
sqlalchemy_uri_placeholder = "duckdb:///md:{SERVICE_TOKEN}@{database_name}"

View File

@ -3217,6 +3217,7 @@ class TestDatabaseApi(SupersetTestCase):
"engine": "hana", "engine": "hana",
"name": "SAP HANA", "name": "SAP HANA",
"preferred": False, "preferred": False,
"sqlalchemy_uri_placeholder": "engine+driver://user:password@host:port/dbname[?key=value&key=value...]",
"engine_information": { "engine_information": {
"supports_file_upload": True, "supports_file_upload": True,
"disable_ssh_tunneling": False, "disable_ssh_tunneling": False,
@ -3248,6 +3249,7 @@ class TestDatabaseApi(SupersetTestCase):
"engine": "mysql", "engine": "mysql",
"name": "MySQL", "name": "MySQL",
"preferred": True, "preferred": True,
"sqlalchemy_uri_placeholder": "mysql://user:password@host:port/dbname[?key=value&key=value...]",
"engine_information": { "engine_information": {
"supports_file_upload": True, "supports_file_upload": True,
"disable_ssh_tunneling": False, "disable_ssh_tunneling": False,
@ -3258,6 +3260,7 @@ class TestDatabaseApi(SupersetTestCase):
"engine": "hana", "engine": "hana",
"name": "SAP HANA", "name": "SAP HANA",
"preferred": False, "preferred": False,
"sqlalchemy_uri_placeholder": "engine+driver://user:password@host:port/dbname[?key=value&key=value...]",
"engine_information": { "engine_information": {
"supports_file_upload": True, "supports_file_upload": True,
"disable_ssh_tunneling": False, "disable_ssh_tunneling": False,