Skip to content

Commit 2592c5c

Browse files
fresioASmattiasthalenerindru
authored
feat: Add support for Microsoft Fabric Warehouse (#4751)
Co-authored-by: Mattias Thalén <bitter-polders0x@icloud.com> Co-authored-by: Erin Drummond <erin.dru@gmail.com>
1 parent 7157652 commit 2592c5c

File tree

18 files changed

+613
-12
lines changed

18 files changed

+613
-12
lines changed

.circleci/continue_config.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ workflows:
304304
- bigquery
305305
- clickhouse-cloud
306306
- athena
307+
# todo: enable fabric when cicd catalog create/drop implemented in manage-test-db.sh
308+
#- fabric
307309
- gcp-postgres
308310
filters:
309311
branches:

.circleci/install-prerequisites.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fi
1212

1313
ENGINE="$1"
1414

15-
COMMON_DEPENDENCIES="libpq-dev netcat-traditional"
15+
COMMON_DEPENDENCIES="libpq-dev netcat-traditional unixodbc-dev"
1616
ENGINE_DEPENDENCIES=""
1717

1818
if [ "$ENGINE" == "spark" ]; then

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ clickhouse-cloud-test: guard-CLICKHOUSE_CLOUD_HOST guard-CLICKHOUSE_CLOUD_USERNA
173173
athena-test: guard-AWS_ACCESS_KEY_ID guard-AWS_SECRET_ACCESS_KEY guard-ATHENA_S3_WAREHOUSE_LOCATION engine-athena-install
174174
pytest -n auto -m "athena" --retries 3 --junitxml=test-results/junit-athena.xml
175175

176+
fabric-test: guard-FABRIC_HOST guard-FABRIC_CLIENT_ID guard-FABRIC_CLIENT_SECRET guard-FABRIC_DATABASE engine-fabric-install
177+
pytest -n auto -m "fabric" --retries 3 --junitxml=test-results/junit-fabric.xml
178+
176179
gcp-postgres-test: guard-GCP_POSTGRES_INSTANCE_CONNECTION_STRING guard-GCP_POSTGRES_USER guard-GCP_POSTGRES_PASSWORD guard-GCP_POSTGRES_KEYFILE_JSON engine-gcppostgres-install
177180
pytest -n auto -m "gcp_postgres" --retries 3 --junitxml=test-results/junit-gcp-postgres.xml
178181

docs/guides/configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,7 @@ These pages describe the connection configuration options for each execution eng
909909
* [BigQuery](../integrations/engines/bigquery.md)
910910
* [Databricks](../integrations/engines/databricks.md)
911911
* [DuckDB](../integrations/engines/duckdb.md)
912+
* [Fabric](../integrations/engines/fabric.md)
912913
* [MotherDuck](../integrations/engines/motherduck.md)
913914
* [MySQL](../integrations/engines/mysql.md)
914915
* [MSSQL](../integrations/engines/mssql.md)

docs/integrations/engines/fabric.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Fabric
2+
3+
## Local/Built-in Scheduler
4+
**Engine Adapter Type**: `fabric`
5+
6+
NOTE: Fabric Warehouse is not recommended to be used for the SQLMesh [state connection](../../reference/configuration.md#connections).
7+
8+
### Installation
9+
#### Microsoft Entra ID / Azure Active Directory Authentication:
10+
```
11+
pip install "sqlmesh[fabric]"
12+
```
13+
14+
### Connection options
15+
16+
| Option | Description | Type | Required |
17+
| ----------------- | ------------------------------------------------------------ | :----------: | :------: |
18+
| `type` | Engine type name - must be `fabric` | string | Y |
19+
| `host` | The hostname of the Fabric Warehouse server | string | Y |
20+
| `user` | The client id to use for authentication with the Fabric Warehouse server | string | N |
21+
| `password` | The client secret to use for authentication with the Fabric Warehouse server | string | N |
22+
| `port` | The port number of the Fabric Warehouse server | int | N |
23+
| `database` | The target database | string | N |
24+
| `charset` | The character set used for the connection | string | N |
25+
| `timeout` | The query timeout in seconds. Default: no timeout | int | N |
26+
| `login_timeout` | The timeout for connection and login in seconds. Default: 60 | int | N |
27+
| `appname` | The application name to use for the connection | string | N |
28+
| `conn_properties` | The list of connection properties | list[string] | N |
29+
| `autocommit` | Is autocommit mode enabled. Default: false | bool | N |
30+
| `driver` | The driver to use for the connection. Default: pyodbc | string | N |
31+
| `driver_name` | The driver name to use for the connection. E.g., *ODBC Driver 18 for SQL Server* | string | N |
32+
| `tenant_id` | The Azure / Entra tenant UUID | string | Y |
33+
| `workspace_id` | The Fabric workspace UUID. The preferred way to retrieve it is by running `notebookutils.runtime.context.get("currentWorkspaceId")` in a python notebook. | string | Y |
34+
| `odbc_properties` | The dict of ODBC connection properties. E.g., authentication: ActiveDirectoryServicePrincipal. See more [here](https://learn.microsoft.com/en-us/sql/connect/odbc/dsn-connection-string-attribute?view=sql-server-ver16). | dict | N |

docs/integrations/overview.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ SQLMesh supports the following execution engines for running SQLMesh projects (e
1717
* [ClickHouse](./engines/clickhouse.md) (clickhouse)
1818
* [Databricks](./engines/databricks.md) (databricks)
1919
* [DuckDB](./engines/duckdb.md) (duckdb)
20+
* [Fabric](./engines/fabric.md) (fabric)
2021
* [MotherDuck](./engines/motherduck.md) (motherduck)
2122
* [MSSQL](./engines/mssql.md) (mssql)
2223
* [MySQL](./engines/mysql.md) (mysql)

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ nav:
8383
- integrations/engines/clickhouse.md
8484
- integrations/engines/databricks.md
8585
- integrations/engines/duckdb.md
86+
- integrations/engines/fabric.md
8687
- integrations/engines/motherduck.md
8788
- integrations/engines/mssql.md
8889
- integrations/engines/mysql.md

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ dev = [
103103
dbt = ["dbt-core<2"]
104104
dlt = ["dlt"]
105105
duckdb = []
106+
fabric = ["pyodbc>=5.0.0"]
106107
gcppostgres = ["cloud-sql-python-connector[pg8000]>=1.8.0"]
107108
github = ["PyGithub>=2.6.0"]
108109
llm = ["langchain", "openai"]
@@ -253,6 +254,7 @@ markers = [
253254
"clickhouse_cloud: test for Clickhouse (cloud mode)",
254255
"databricks: test for Databricks",
255256
"duckdb: test for DuckDB",
257+
"fabric: test for Fabric",
256258
"motherduck: test for MotherDuck",
257259
"mssql: test for MSSQL",
258260
"mysql: test for MySQL",

sqlmesh/core/config/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
ConnectionConfig as ConnectionConfig,
1414
DatabricksConnectionConfig as DatabricksConnectionConfig,
1515
DuckDBConnectionConfig as DuckDBConnectionConfig,
16+
FabricConnectionConfig as FabricConnectionConfig,
1617
GCPPostgresConnectionConfig as GCPPostgresConnectionConfig,
1718
MotherDuckConnectionConfig as MotherDuckConnectionConfig,
1819
MSSQLConnectionConfig as MSSQLConnectionConfig,

sqlmesh/core/config/connection.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@
4343

4444
logger = logging.getLogger(__name__)
4545

46-
RECOMMENDED_STATE_SYNC_ENGINES = {"postgres", "gcp_postgres", "mysql", "mssql", "azuresql"}
46+
RECOMMENDED_STATE_SYNC_ENGINES = {
47+
"postgres",
48+
"gcp_postgres",
49+
"mysql",
50+
"mssql",
51+
"azuresql",
52+
}
4753
FORBIDDEN_STATE_SYNC_ENGINES = {
4854
# Do not support row-level operations
4955
"spark",
@@ -1684,6 +1690,55 @@ def _extra_engine_config(self) -> t.Dict[str, t.Any]:
16841690
return {"catalog_support": CatalogSupport.SINGLE_CATALOG_ONLY}
16851691

16861692

1693+
class FabricConnectionConfig(MSSQLConnectionConfig):
1694+
"""
1695+
Fabric Connection Configuration.
1696+
Inherits most settings from MSSQLConnectionConfig and sets the type to 'fabric'.
1697+
It is recommended to use the 'pyodbc' driver for Fabric.
1698+
"""
1699+
1700+
type_: t.Literal["fabric"] = Field(alias="type", default="fabric") # type: ignore
1701+
DIALECT: t.ClassVar[t.Literal["fabric"]] = "fabric" # type: ignore
1702+
DISPLAY_NAME: t.ClassVar[t.Literal["Fabric"]] = "Fabric" # type: ignore
1703+
DISPLAY_ORDER: t.ClassVar[t.Literal[17]] = 17 # type: ignore
1704+
driver: t.Literal["pyodbc"] = "pyodbc"
1705+
workspace_id: str
1706+
tenant_id: str
1707+
autocommit: t.Optional[bool] = True
1708+
1709+
@property
1710+
def _engine_adapter(self) -> t.Type[EngineAdapter]:
1711+
from sqlmesh.core.engine_adapter.fabric import FabricEngineAdapter
1712+
1713+
return FabricEngineAdapter
1714+
1715+
@property
1716+
def _connection_factory(self) -> t.Callable:
1717+
# Override to support catalog switching for Fabric
1718+
base_factory = super()._connection_factory
1719+
1720+
def create_fabric_connection(
1721+
target_catalog: t.Optional[str] = None, *args: t.Any, **kwargs: t.Any
1722+
) -> t.Callable:
1723+
kwargs["database"] = target_catalog or self.database
1724+
return base_factory(*args, **kwargs)
1725+
1726+
return create_fabric_connection
1727+
1728+
@property
1729+
def _extra_engine_config(self) -> t.Dict[str, t.Any]:
1730+
return {
1731+
"database": self.database,
1732+
# more operations than not require a specific catalog to be already active
1733+
# in particular, create/drop view, create/drop schema and querying information_schema
1734+
"catalog_support": CatalogSupport.REQUIRES_SET_CATALOG,
1735+
"workspace_id": self.workspace_id,
1736+
"tenant_id": self.tenant_id,
1737+
"user": self.user,
1738+
"password": self.password,
1739+
}
1740+
1741+
16871742
class SparkConnectionConfig(ConnectionConfig):
16881743
"""
16891744
Vanilla Spark Connection Configuration. Use `DatabricksConnectionConfig` for Databricks.

0 commit comments

Comments
 (0)