sqlmesh-gizmosql 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlmesh-gizmosql
3
+ Version: 0.1.0
4
+ Summary: GizmoSQL engine adapter for SQLMesh
5
+ Author: Philip
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/gizmodata/sqlmesh-gizmosql
8
+ Project-URL: Repository, https://github.com/gizmodata/sqlmesh-gizmosql
9
+ Project-URL: Documentation, https://github.com/gizmodata/sqlmesh-gizmosql#readme
10
+ Keywords: sqlmesh,gizmosql,duckdb,arrow,flight-sql,data-engineering
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Database
23
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ Requires-Dist: sqlmesh>=0.100.0
27
+ Requires-Dist: adbc-driver-flightsql>=1.10.0
28
+ Requires-Dist: pyarrow>=22.0.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
31
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
32
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
33
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
34
+
35
+ # SQLMesh GizmoSQL Adapter
36
+
37
+ A [SQLMesh](https://sqlmesh.com) engine adapter for [GizmoSQL](https://github.com/gizmodata/gizmosql) - a database server that uses DuckDB as its execution engine and exposes an Arrow Flight SQL interface for remote connections.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install sqlmesh-gizmosql
43
+ ```
44
+
45
+ This will install `sqlmesh`, `adbc-driver-flightsql`, and `pyarrow` as dependencies.
46
+
47
+ ## Usage
48
+
49
+ ### 1. Import the adapter
50
+
51
+ Simply import the package before using SQLMesh. The adapter registers itself automatically:
52
+
53
+ ```python
54
+ import sqlmesh_gizmosql # Registers GizmoSQL adapter
55
+ from sqlmesh import Context
56
+
57
+ context = Context(paths="path/to/project")
58
+ ```
59
+
60
+ ### 2. Configure your connection
61
+
62
+ Add a GizmoSQL connection to your `config.yaml`:
63
+
64
+ ```yaml
65
+ gateways:
66
+ my_gizmosql:
67
+ connection:
68
+ type: gizmosql
69
+ host: localhost
70
+ port: 31337
71
+ username: your_username
72
+ password: your_password
73
+ database: my_database # optional, default catalog
74
+ use_encryption: true # default: true (uses TLS)
75
+ disable_certificate_verification: false # for self-signed certs
76
+ ```
77
+
78
+ ### 3. Use SQLMesh as normal
79
+
80
+ ```bash
81
+ sqlmesh plan
82
+ sqlmesh run
83
+ ```
84
+
85
+ ## Configuration Options
86
+
87
+ | Option | Type | Default | Description |
88
+ |--------|------|---------|-------------|
89
+ | `host` | str | `localhost` | GizmoSQL server hostname |
90
+ | `port` | int | `31337` | GizmoSQL server port |
91
+ | `username` | str | *required* | Authentication username |
92
+ | `password` | str | *required* | Authentication password |
93
+ | `database` | str | `None` | Default database/catalog |
94
+ | `use_encryption` | bool | `True` | Use TLS encryption |
95
+ | `disable_certificate_verification` | bool | `False` | Skip TLS cert verification |
96
+ | `concurrent_tasks` | int | `4` | Max concurrent tasks |
97
+ | `register_comments` | bool | `True` | Register model comments |
98
+ | `pre_ping` | bool | `False` | Pre-ping connections |
99
+
100
+ ## Features
101
+
102
+ - **Arrow Flight SQL**: Efficient data transfer using Arrow's columnar format
103
+ - **Full Catalog Support**: Create, drop, and switch between databases
104
+ - **Transaction Support**: Full transaction control via SQL statements
105
+ - **ADBC Bulk Ingestion**: Fast data loading using Arrow-native bulk operations
106
+ - **DuckDB Compatibility**: Uses DuckDB SQL dialect for query generation
107
+
108
+ ## Requirements
109
+
110
+ - Python >= 3.10
111
+ - SQLMesh >= 0.100.0
112
+ - A running GizmoSQL server with DuckDB backend
113
+
114
+ ## Development
115
+
116
+ ```bash
117
+ # Clone the repository
118
+ git clone https://github.com/philip/sqlmesh-gizmosql.git
119
+ cd sqlmesh-gizmosql
120
+
121
+ # Install dev dependencies
122
+ pip install -e ".[dev]"
123
+
124
+ # Run tests
125
+ pytest
126
+
127
+ # Run linting
128
+ ruff check .
129
+ mypy sqlmesh_gizmosql
130
+ ```
131
+
132
+ ## License
133
+
134
+ Apache 2.0
@@ -0,0 +1,100 @@
1
+ # SQLMesh GizmoSQL Adapter
2
+
3
+ A [SQLMesh](https://sqlmesh.com) engine adapter for [GizmoSQL](https://github.com/gizmodata/gizmosql) - a database server that uses DuckDB as its execution engine and exposes an Arrow Flight SQL interface for remote connections.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install sqlmesh-gizmosql
9
+ ```
10
+
11
+ This will install `sqlmesh`, `adbc-driver-flightsql`, and `pyarrow` as dependencies.
12
+
13
+ ## Usage
14
+
15
+ ### 1. Import the adapter
16
+
17
+ Simply import the package before using SQLMesh. The adapter registers itself automatically:
18
+
19
+ ```python
20
+ import sqlmesh_gizmosql # Registers GizmoSQL adapter
21
+ from sqlmesh import Context
22
+
23
+ context = Context(paths="path/to/project")
24
+ ```
25
+
26
+ ### 2. Configure your connection
27
+
28
+ Add a GizmoSQL connection to your `config.yaml`:
29
+
30
+ ```yaml
31
+ gateways:
32
+ my_gizmosql:
33
+ connection:
34
+ type: gizmosql
35
+ host: localhost
36
+ port: 31337
37
+ username: your_username
38
+ password: your_password
39
+ database: my_database # optional, default catalog
40
+ use_encryption: true # default: true (uses TLS)
41
+ disable_certificate_verification: false # for self-signed certs
42
+ ```
43
+
44
+ ### 3. Use SQLMesh as normal
45
+
46
+ ```bash
47
+ sqlmesh plan
48
+ sqlmesh run
49
+ ```
50
+
51
+ ## Configuration Options
52
+
53
+ | Option | Type | Default | Description |
54
+ |--------|------|---------|-------------|
55
+ | `host` | str | `localhost` | GizmoSQL server hostname |
56
+ | `port` | int | `31337` | GizmoSQL server port |
57
+ | `username` | str | *required* | Authentication username |
58
+ | `password` | str | *required* | Authentication password |
59
+ | `database` | str | `None` | Default database/catalog |
60
+ | `use_encryption` | bool | `True` | Use TLS encryption |
61
+ | `disable_certificate_verification` | bool | `False` | Skip TLS cert verification |
62
+ | `concurrent_tasks` | int | `4` | Max concurrent tasks |
63
+ | `register_comments` | bool | `True` | Register model comments |
64
+ | `pre_ping` | bool | `False` | Pre-ping connections |
65
+
66
+ ## Features
67
+
68
+ - **Arrow Flight SQL**: Efficient data transfer using Arrow's columnar format
69
+ - **Full Catalog Support**: Create, drop, and switch between databases
70
+ - **Transaction Support**: Full transaction control via SQL statements
71
+ - **ADBC Bulk Ingestion**: Fast data loading using Arrow-native bulk operations
72
+ - **DuckDB Compatibility**: Uses DuckDB SQL dialect for query generation
73
+
74
+ ## Requirements
75
+
76
+ - Python >= 3.10
77
+ - SQLMesh >= 0.100.0
78
+ - A running GizmoSQL server with DuckDB backend
79
+
80
+ ## Development
81
+
82
+ ```bash
83
+ # Clone the repository
84
+ git clone https://github.com/philip/sqlmesh-gizmosql.git
85
+ cd sqlmesh-gizmosql
86
+
87
+ # Install dev dependencies
88
+ pip install -e ".[dev]"
89
+
90
+ # Run tests
91
+ pytest
92
+
93
+ # Run linting
94
+ ruff check .
95
+ mypy sqlmesh_gizmosql
96
+ ```
97
+
98
+ ## License
99
+
100
+ Apache 2.0
@@ -0,0 +1,76 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sqlmesh-gizmosql"
7
+ version = "0.1.0"
8
+ description = "GizmoSQL engine adapter for SQLMesh"
9
+ readme = "README.md"
10
+ license = {text = "Apache-2.0"}
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ {name = "Philip"}
14
+ ]
15
+ keywords = ["sqlmesh", "gizmosql", "duckdb", "arrow", "flight-sql", "data-engineering"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "Intended Audience :: Science/Research",
20
+ "License :: OSI Approved :: Apache Software License",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ "Topic :: Database",
29
+ "Topic :: Scientific/Engineering :: Information Analysis",
30
+ ]
31
+
32
+ dependencies = [
33
+ "sqlmesh>=0.100.0",
34
+ "adbc-driver-flightsql>=1.10.0",
35
+ "pyarrow>=22.0.0",
36
+ ]
37
+
38
+ [project.optional-dependencies]
39
+ dev = [
40
+ "pytest>=7.0.0",
41
+ "pytest-cov>=4.0.0",
42
+ "mypy>=1.0.0",
43
+ "ruff>=0.1.0",
44
+ ]
45
+
46
+ [project.urls]
47
+ Homepage = "https://github.com/gizmodata/sqlmesh-gizmosql"
48
+ Repository = "https://github.com/gizmodata/sqlmesh-gizmosql"
49
+ Documentation = "https://github.com/gizmodata/sqlmesh-gizmosql#readme"
50
+
51
+ [tool.setuptools.packages.find]
52
+ include = ["sqlmesh_gizmosql*"]
53
+
54
+ [tool.pytest.ini_options]
55
+ testpaths = ["tests"]
56
+ python_files = ["test_*.py"]
57
+ python_functions = ["test_*"]
58
+ addopts = "-v --tb=short -m 'not integration'"
59
+ markers = [
60
+ "integration: marks tests as integration tests (require Docker)",
61
+ "docker: marks tests that require Docker",
62
+ ]
63
+
64
+ [tool.mypy]
65
+ python_version = "3.10"
66
+ warn_return_any = true
67
+ warn_unused_configs = true
68
+ ignore_missing_imports = true
69
+
70
+ [tool.ruff]
71
+ line-length = 100
72
+ target-version = "py310"
73
+
74
+ [tool.ruff.lint]
75
+ select = ["E", "F", "I", "W"]
76
+ ignore = ["E501"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,65 @@
1
+ """
2
+ SQLMesh GizmoSQL Adapter.
3
+
4
+ This package provides GizmoSQL support for SQLMesh. When imported, it automatically
5
+ registers the GizmoSQL engine adapter and connection configuration with SQLMesh.
6
+
7
+ Usage:
8
+ # Option 1: Explicit import (recommended for clarity)
9
+ import sqlmesh_gizmosql
10
+ from sqlmesh import Context
11
+
12
+ # Option 2: Just import - registration happens automatically
13
+ import sqlmesh_gizmosql # noqa: F401
14
+
15
+ # Then use SQLMesh normally with type: gizmosql in your config
16
+
17
+ Example config.yaml:
18
+ gateways:
19
+ my_gizmosql:
20
+ connection:
21
+ type: gizmosql
22
+ host: localhost
23
+ port: 31337
24
+ username: user
25
+ password: pass
26
+ database: my_database
27
+ """
28
+ from sqlmesh_gizmosql.adapter import GizmoSQLEngineAdapter
29
+ from sqlmesh_gizmosql.connection import GizmoSQLConnectionConfig
30
+
31
+ __version__ = "0.1.0"
32
+ __all__ = ["GizmoSQLEngineAdapter", "GizmoSQLConnectionConfig", "register", "__version__"]
33
+
34
+ _registered = False
35
+
36
+
37
+ def register() -> None:
38
+ """
39
+ Register GizmoSQL adapter and connection config with SQLMesh.
40
+
41
+ This function is called automatically when the module is imported,
42
+ but can also be called explicitly if needed.
43
+ """
44
+ global _registered
45
+ if _registered:
46
+ return
47
+
48
+ # Register the engine adapter
49
+ from sqlmesh.core import engine_adapter
50
+ if "gizmosql" not in engine_adapter.DIALECT_TO_ENGINE_ADAPTER:
51
+ engine_adapter.DIALECT_TO_ENGINE_ADAPTER["gizmosql"] = GizmoSQLEngineAdapter
52
+
53
+ # Register the connection config
54
+ from sqlmesh.core.config import connection as conn_module
55
+ if "gizmosql" not in conn_module.CONNECTION_CONFIG_TO_TYPE:
56
+ conn_module.CONNECTION_CONFIG_TO_TYPE["gizmosql"] = GizmoSQLConnectionConfig
57
+
58
+ if "gizmosql" not in conn_module.DIALECT_TO_TYPE:
59
+ conn_module.DIALECT_TO_TYPE["gizmosql"] = GizmoSQLConnectionConfig.DIALECT
60
+
61
+ _registered = True
62
+
63
+
64
+ # Auto-register on import
65
+ register()
@@ -0,0 +1,289 @@
1
+ """
2
+ GizmoSQL Engine Adapter for SQLMesh.
3
+
4
+ GizmoSQL is a database server that uses DuckDB as its execution engine and
5
+ exposes an Arrow Flight SQL interface for remote connections.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import contextlib
10
+ import typing as t
11
+
12
+ from sqlglot import exp
13
+ from sqlmesh.core.engine_adapter.mixins import (
14
+ GetCurrentCatalogFromFunctionMixin,
15
+ LogicalMergeMixin,
16
+ PandasNativeFetchDFSupportMixin,
17
+ RowDiffMixin,
18
+ )
19
+ from sqlmesh.core.engine_adapter.shared import (
20
+ CatalogSupport,
21
+ CommentCreationTable,
22
+ CommentCreationView,
23
+ DataObject,
24
+ DataObjectType,
25
+ SourceQuery,
26
+ set_catalog,
27
+ )
28
+
29
+ if t.TYPE_CHECKING:
30
+ from sqlmesh.core._typing import SchemaName, TableName
31
+ from sqlmesh.core.engine_adapter._typing import DF
32
+
33
+
34
+ @set_catalog(override_mapping={"_get_data_objects": CatalogSupport.REQUIRES_SET_CATALOG})
35
+ class GizmoSQLEngineAdapter(
36
+ LogicalMergeMixin,
37
+ GetCurrentCatalogFromFunctionMixin,
38
+ PandasNativeFetchDFSupportMixin,
39
+ RowDiffMixin,
40
+ ):
41
+ """
42
+ GizmoSQL Engine Adapter.
43
+
44
+ GizmoSQL is a database server that uses DuckDB as its execution engine and
45
+ exposes an Arrow Flight SQL interface for remote connections. This adapter
46
+ uses ADBC (Arrow Database Connectivity) with the Flight SQL driver to
47
+ communicate with GizmoSQL servers.
48
+
49
+ Key characteristics:
50
+ - Uses DuckDB SQL dialect for query generation
51
+ - Connects remotely via Arrow Flight SQL (ADBC)
52
+ - Supports full catalog operations
53
+ - Returns data as Arrow tables for efficient transfer
54
+ """
55
+
56
+ DIALECT = "duckdb"
57
+ SUPPORTS_TRANSACTIONS = True
58
+ SCHEMA_DIFFER_KWARGS = {
59
+ "parameterized_type_defaults": {
60
+ exp.DataType.build("DECIMAL", dialect="duckdb").this: [(18, 3), (0,)],
61
+ },
62
+ }
63
+ COMMENT_CREATION_TABLE = CommentCreationTable.COMMENT_COMMAND_ONLY
64
+ COMMENT_CREATION_VIEW = CommentCreationView.COMMENT_COMMAND_ONLY
65
+ SUPPORTS_CREATE_DROP_CATALOG = True
66
+ SUPPORTED_DROP_CASCADE_OBJECT_KINDS = ["SCHEMA", "TABLE", "VIEW"]
67
+
68
+ @property
69
+ def catalog_support(self) -> CatalogSupport:
70
+ return CatalogSupport.FULL_SUPPORT
71
+
72
+ # DDL/DML keywords that need fetch to trigger GizmoSQL's lazy execution
73
+ _DDL_DML_KEYWORDS = frozenset({
74
+ "CREATE", "DROP", "ALTER", "TRUNCATE", "RENAME", "COMMENT", "USE", "SET",
75
+ "INSERT", "UPDATE", "DELETE", "MERGE", "COPY", "ATTACH", "DETACH",
76
+ })
77
+
78
+ def _execute(self, sql: str, track_rows_processed: bool = False, **kwargs: t.Any) -> None:
79
+ """
80
+ Execute a SQL statement.
81
+
82
+ GizmoSQL uses lazy execution - statements are not actually executed
83
+ until results are fetched. For DDL/DML statements, we call fetchall()
84
+ to ensure immediate execution. For SELECT queries, we let the caller
85
+ fetch the results.
86
+ """
87
+ self.cursor.execute(sql, **kwargs)
88
+
89
+ # For DDL/DML, fetch to trigger GizmoSQL's lazy execution
90
+ sql_upper = sql.strip().upper()
91
+ first_word = sql_upper.split()[0] if sql_upper else ""
92
+ if first_word in self._DDL_DML_KEYWORDS:
93
+ self.cursor.fetchall()
94
+
95
+ @contextlib.contextmanager
96
+ def transaction(
97
+ self,
98
+ condition: t.Optional[bool] = None,
99
+ ) -> t.Iterator[None]:
100
+ """
101
+ A transaction context manager using SQL statements.
102
+
103
+ GizmoSQL's ADBC connection doesn't support the standard begin/commit/rollback
104
+ methods, so we use explicit SQL statements (BEGIN TRANSACTION, COMMIT, ROLLBACK)
105
+ for transaction control.
106
+ """
107
+ if (
108
+ self._connection_pool.is_transaction_active
109
+ or (condition is not None and not condition)
110
+ ):
111
+ yield
112
+ return
113
+
114
+ self._connection_pool.begin()
115
+ self.cursor.execute("BEGIN TRANSACTION")
116
+ self.cursor.fetchall()
117
+ try:
118
+ yield
119
+ except Exception as e:
120
+ self.cursor.execute("ROLLBACK")
121
+ self.cursor.fetchall()
122
+ self._connection_pool.rollback()
123
+ raise e
124
+ else:
125
+ self.cursor.execute("COMMIT")
126
+ self.cursor.fetchall()
127
+ self._connection_pool.commit()
128
+
129
+ def set_current_catalog(self, catalog: str) -> None:
130
+ """Sets the catalog name of the current connection."""
131
+ self.execute(exp.Use(this=exp.to_identifier(catalog)))
132
+
133
+ def _create_catalog(self, catalog_name: exp.Identifier) -> None:
134
+ """Creates a new catalog (database) in GizmoSQL."""
135
+ self.execute(
136
+ exp.Create(this=exp.Table(this=catalog_name), kind="DATABASE", exists=True)
137
+ )
138
+
139
+ def _drop_catalog(self, catalog_name: exp.Identifier) -> None:
140
+ """Drops a catalog (database) from GizmoSQL."""
141
+ self.execute(
142
+ exp.Drop(
143
+ this=exp.Table(this=catalog_name), kind="DATABASE", cascade=True, exists=True
144
+ )
145
+ )
146
+
147
+ def _df_to_source_queries(
148
+ self,
149
+ df: DF,
150
+ target_columns_to_types: t.Dict[str, exp.DataType],
151
+ batch_size: int,
152
+ target_table: TableName,
153
+ source_columns: t.Optional[t.List[str]] = None,
154
+ ) -> t.List[SourceQuery]:
155
+ """
156
+ Convert a DataFrame to source queries for insertion.
157
+
158
+ Uses ADBC bulk ingestion (adbc_ingest) for efficient Arrow-native data transfer
159
+ to GizmoSQL, avoiding row-by-row insertion overhead.
160
+ """
161
+ import pyarrow as pa
162
+
163
+ temp_table = self._get_temp_table(target_table)
164
+
165
+ # Select only the source columns in the right order
166
+ source_columns_to_types = (
167
+ {col: target_columns_to_types[col] for col in source_columns}
168
+ if source_columns
169
+ else target_columns_to_types
170
+ )
171
+ ordered_df = df[list(source_columns_to_types.keys())]
172
+
173
+ # Convert DataFrame to PyArrow Table for bulk ingestion
174
+ arrow_table = pa.Table.from_pandas(ordered_df)
175
+
176
+ # Use ADBC bulk ingestion with temporary table
177
+ # Note: DuckDB temporary tables cannot have catalog/schema prefixes,
178
+ # so we only pass the table name when temporary=True
179
+ self.cursor.adbc_ingest(
180
+ table_name=temp_table.name,
181
+ data=arrow_table,
182
+ mode="create",
183
+ temporary=True,
184
+ )
185
+
186
+ # Reference temp table by name only (no schema prefix for temporary tables)
187
+ temp_table_name = exp.to_table(temp_table.name)
188
+
189
+ return [
190
+ SourceQuery(
191
+ query_factory=lambda: self._select_columns(target_columns_to_types).from_(
192
+ temp_table_name
193
+ ),
194
+ cleanup_func=lambda: self.drop_table(temp_table_name),
195
+ )
196
+ ]
197
+
198
+ def _get_data_objects(
199
+ self, schema_name: SchemaName, object_names: t.Optional[t.Set[str]] = None
200
+ ) -> t.List[DataObject]:
201
+ """
202
+ Returns all the data objects that exist in the given schema and optionally catalog.
203
+ """
204
+ catalog = self.get_current_catalog()
205
+
206
+ if isinstance(schema_name, exp.Table):
207
+ # Ensures we don't generate identifier quotes
208
+ schema_name = ".".join(part.name for part in schema_name.parts)
209
+
210
+ query = (
211
+ exp.select(
212
+ exp.column("table_name").as_("name"),
213
+ exp.column("table_schema").as_("schema"),
214
+ exp.case(exp.column("table_type"))
215
+ .when(
216
+ exp.Literal.string("BASE TABLE"),
217
+ exp.Literal.string("table"),
218
+ )
219
+ .when(
220
+ exp.Literal.string("VIEW"),
221
+ exp.Literal.string("view"),
222
+ )
223
+ .when(
224
+ exp.Literal.string("LOCAL TEMPORARY"),
225
+ exp.Literal.string("table"),
226
+ )
227
+ .as_("type"),
228
+ )
229
+ .from_(exp.to_table("information_schema.tables"))
230
+ .where(
231
+ exp.column("table_catalog").eq(catalog), exp.column("table_schema").eq(schema_name)
232
+ )
233
+ )
234
+ if object_names:
235
+ query = query.where(exp.column("table_name").isin(*object_names))
236
+ df = self.fetchdf(query)
237
+ return [
238
+ DataObject(
239
+ catalog=catalog, # type: ignore
240
+ schema=row.schema, # type: ignore
241
+ name=row.name, # type: ignore
242
+ type=DataObjectType.from_str(row.type), # type: ignore
243
+ )
244
+ for row in df.itertuples()
245
+ ]
246
+
247
+ def _normalize_decimal_value(self, col: exp.Expression, precision: int) -> exp.Expression:
248
+ """
249
+ GizmoSQL (via DuckDB) truncates instead of rounding when casting to decimal.
250
+
251
+ other databases: select cast(3.14159 as decimal(38,3)) -> 3.142
252
+ duckdb: select cast(3.14159 as decimal(38,3)) -> 3.141
253
+
254
+ however, we can get the behaviour of other databases by casting to double first:
255
+ select cast(cast(3.14159 as double) as decimal(38, 3)) -> 3.142
256
+ """
257
+ return exp.cast(
258
+ exp.cast(col, "DOUBLE"),
259
+ f"DECIMAL(38, {precision})",
260
+ )
261
+
262
+ def _fetch_native_df(
263
+ self, query: t.Union[exp.Expression, str], quote_identifiers: bool = False
264
+ ) -> DF:
265
+ """
266
+ Fetches a Pandas DataFrame from a SQL query.
267
+
268
+ GizmoSQL returns Arrow tables which can be efficiently converted to Pandas.
269
+ """
270
+ import pandas as pd
271
+
272
+ sql = (
273
+ self._to_sql(query, quote=quote_identifiers)
274
+ if isinstance(query, exp.Expression)
275
+ else query
276
+ )
277
+
278
+ cursor = self.cursor
279
+ cursor.execute(sql)
280
+
281
+ # ADBC cursors support fetch_arrow_table() for efficient Arrow->Pandas conversion
282
+ if hasattr(cursor, "fetch_arrow_table"):
283
+ arrow_table = cursor.fetch_arrow_table()
284
+ return arrow_table.to_pandas()
285
+
286
+ # Fallback to standard fetchall + DataFrame construction
287
+ result = cursor.fetchall()
288
+ columns = [desc[0] for desc in cursor.description] if cursor.description else []
289
+ return pd.DataFrame(result, columns=columns)
@@ -0,0 +1,134 @@
1
+ """
2
+ GizmoSQL Connection Configuration for SQLMesh.
3
+
4
+ Provides the connection configuration class for GizmoSQL servers.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import typing as t
9
+
10
+ from pydantic import Field
11
+ from sqlmesh.core.config.common import concurrent_tasks_validator
12
+ from sqlmesh.core.config.connection import ConnectionConfig
13
+ from sqlmesh.core.engine_adapter import EngineAdapter
14
+ from sqlmesh.utils.errors import ConfigError
15
+ from sqlmesh.utils.pydantic import model_validator
16
+
17
+ from sqlmesh_gizmosql.adapter import GizmoSQLEngineAdapter
18
+
19
+
20
+ def _gizmosql_import_validator(cls: t.Any, data: t.Any) -> t.Any:
21
+ """Validate that ADBC Flight SQL driver is installed."""
22
+ check_import = (
23
+ data.pop("check_import", True) if isinstance(data, dict) else True
24
+ )
25
+ if not check_import:
26
+ return data
27
+ try:
28
+ import adbc_driver_flightsql # noqa: F401
29
+ except ImportError:
30
+ raise ConfigError(
31
+ "Failed to import the 'adbc_driver_flightsql' library. "
32
+ "Please install it with: pip install sqlmesh-gizmosql[gizmosql] "
33
+ "or pip install adbc-driver-flightsql pyarrow"
34
+ )
35
+ return data
36
+
37
+
38
+ class GizmoSQLConnectionConfig(ConnectionConfig):
39
+ """
40
+ GizmoSQL connection configuration.
41
+
42
+ GizmoSQL is a database server that uses DuckDB as its execution engine and
43
+ exposes an Arrow Flight SQL interface for remote connections. This configuration
44
+ uses ADBC (Arrow Database Connectivity) with the Flight SQL driver.
45
+
46
+ Args:
47
+ host: The hostname of the GizmoSQL server.
48
+ port: The port of the GizmoSQL server (default: 31337).
49
+ username: The username for authentication.
50
+ password: The password for authentication.
51
+ use_encryption: Whether to use TLS encryption (default: True).
52
+ disable_certificate_verification: Whether to skip TLS certificate verification.
53
+ Useful for self-signed certificates in development (default: False).
54
+ database: The default database/catalog to use.
55
+ concurrent_tasks: The maximum number of concurrent tasks.
56
+ register_comments: Whether to register model comments.
57
+ pre_ping: Whether to pre-ping the connection.
58
+ """
59
+
60
+ host: str = "localhost"
61
+ port: int = 31337
62
+ username: str
63
+ password: str
64
+ use_encryption: bool = True
65
+ disable_certificate_verification: bool = False
66
+ database: t.Optional[str] = None
67
+
68
+ concurrent_tasks: int = 4
69
+ register_comments: bool = True
70
+ pre_ping: bool = False
71
+
72
+ type_: t.Literal["gizmosql"] = Field(alias="type", default="gizmosql")
73
+ DIALECT: t.ClassVar[t.Literal["duckdb"]] = "duckdb"
74
+ DISPLAY_NAME: t.ClassVar[t.Literal["GizmoSQL"]] = "GizmoSQL"
75
+ DISPLAY_ORDER: t.ClassVar[t.Literal[17]] = 17
76
+
77
+ _engine_import_validator = model_validator(mode="before")(_gizmosql_import_validator)
78
+ _concurrent_tasks_validator = concurrent_tasks_validator
79
+
80
+ @property
81
+ def _connection_kwargs_keys(self) -> t.Set[str]:
82
+ # ADBC uses a different connection pattern, so we don't pass these directly
83
+ return set()
84
+
85
+ @property
86
+ def _engine_adapter(self) -> t.Type[EngineAdapter]:
87
+ return GizmoSQLEngineAdapter
88
+
89
+ @property
90
+ def _connection_factory(self) -> t.Callable:
91
+ """
92
+ Create a connection factory for GizmoSQL using ADBC Flight SQL driver.
93
+
94
+ The connection is established using the Arrow Flight SQL protocol over gRPC.
95
+ """
96
+ import re
97
+
98
+ from adbc_driver_flightsql import DatabaseOptions
99
+ from adbc_driver_flightsql import dbapi as flightsql
100
+
101
+ def connect() -> t.Any:
102
+ # Build the URI for the Flight SQL connection
103
+ protocol = "grpc+tls" if self.use_encryption else "grpc"
104
+ uri = f"{protocol}://{self.host}:{self.port}"
105
+
106
+ # ADBC database-level options (passed to the driver)
107
+ db_kwargs: t.Dict[str, str] = {
108
+ "username": self.username,
109
+ "password": self.password,
110
+ }
111
+
112
+ # Add TLS skip verify option using the proper DatabaseOptions enum
113
+ if self.use_encryption and self.disable_certificate_verification:
114
+ db_kwargs[DatabaseOptions.TLS_SKIP_VERIFY.value] = "true"
115
+
116
+ # Create the connection - uri is first positional arg, db_kwargs is for driver options
117
+ # Explicit autocommit=True since GizmoSQL doesn't support manual transaction commits
118
+ conn = flightsql.connect(uri, db_kwargs=db_kwargs, autocommit=True)
119
+
120
+ # Verify the backend is DuckDB - this adapter only supports the DuckDB backend
121
+ vendor_version = conn.adbc_get_info().get("vendor_version", "")
122
+ if not re.search(pattern=r"^duckdb ", string=vendor_version):
123
+ conn.close()
124
+ raise ConfigError(
125
+ f"Unsupported GizmoSQL server backend: '{vendor_version}'. "
126
+ "This adapter only supports the DuckDB backend for GizmoSQL."
127
+ )
128
+
129
+ return conn
130
+
131
+ return connect
132
+
133
+ def get_catalog(self) -> t.Optional[str]:
134
+ return self.database
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlmesh-gizmosql
3
+ Version: 0.1.0
4
+ Summary: GizmoSQL engine adapter for SQLMesh
5
+ Author: Philip
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/gizmodata/sqlmesh-gizmosql
8
+ Project-URL: Repository, https://github.com/gizmodata/sqlmesh-gizmosql
9
+ Project-URL: Documentation, https://github.com/gizmodata/sqlmesh-gizmosql#readme
10
+ Keywords: sqlmesh,gizmosql,duckdb,arrow,flight-sql,data-engineering
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Database
23
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ Requires-Dist: sqlmesh>=0.100.0
27
+ Requires-Dist: adbc-driver-flightsql>=1.10.0
28
+ Requires-Dist: pyarrow>=22.0.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
31
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
32
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
33
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
34
+
35
+ # SQLMesh GizmoSQL Adapter
36
+
37
+ A [SQLMesh](https://sqlmesh.com) engine adapter for [GizmoSQL](https://github.com/gizmodata/gizmosql) - a database server that uses DuckDB as its execution engine and exposes an Arrow Flight SQL interface for remote connections.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install sqlmesh-gizmosql
43
+ ```
44
+
45
+ This will install `sqlmesh`, `adbc-driver-flightsql`, and `pyarrow` as dependencies.
46
+
47
+ ## Usage
48
+
49
+ ### 1. Import the adapter
50
+
51
+ Simply import the package before using SQLMesh. The adapter registers itself automatically:
52
+
53
+ ```python
54
+ import sqlmesh_gizmosql # Registers GizmoSQL adapter
55
+ from sqlmesh import Context
56
+
57
+ context = Context(paths="path/to/project")
58
+ ```
59
+
60
+ ### 2. Configure your connection
61
+
62
+ Add a GizmoSQL connection to your `config.yaml`:
63
+
64
+ ```yaml
65
+ gateways:
66
+ my_gizmosql:
67
+ connection:
68
+ type: gizmosql
69
+ host: localhost
70
+ port: 31337
71
+ username: your_username
72
+ password: your_password
73
+ database: my_database # optional, default catalog
74
+ use_encryption: true # default: true (uses TLS)
75
+ disable_certificate_verification: false # for self-signed certs
76
+ ```
77
+
78
+ ### 3. Use SQLMesh as normal
79
+
80
+ ```bash
81
+ sqlmesh plan
82
+ sqlmesh run
83
+ ```
84
+
85
+ ## Configuration Options
86
+
87
+ | Option | Type | Default | Description |
88
+ |--------|------|---------|-------------|
89
+ | `host` | str | `localhost` | GizmoSQL server hostname |
90
+ | `port` | int | `31337` | GizmoSQL server port |
91
+ | `username` | str | *required* | Authentication username |
92
+ | `password` | str | *required* | Authentication password |
93
+ | `database` | str | `None` | Default database/catalog |
94
+ | `use_encryption` | bool | `True` | Use TLS encryption |
95
+ | `disable_certificate_verification` | bool | `False` | Skip TLS cert verification |
96
+ | `concurrent_tasks` | int | `4` | Max concurrent tasks |
97
+ | `register_comments` | bool | `True` | Register model comments |
98
+ | `pre_ping` | bool | `False` | Pre-ping connections |
99
+
100
+ ## Features
101
+
102
+ - **Arrow Flight SQL**: Efficient data transfer using Arrow's columnar format
103
+ - **Full Catalog Support**: Create, drop, and switch between databases
104
+ - **Transaction Support**: Full transaction control via SQL statements
105
+ - **ADBC Bulk Ingestion**: Fast data loading using Arrow-native bulk operations
106
+ - **DuckDB Compatibility**: Uses DuckDB SQL dialect for query generation
107
+
108
+ ## Requirements
109
+
110
+ - Python >= 3.10
111
+ - SQLMesh >= 0.100.0
112
+ - A running GizmoSQL server with DuckDB backend
113
+
114
+ ## Development
115
+
116
+ ```bash
117
+ # Clone the repository
118
+ git clone https://github.com/philip/sqlmesh-gizmosql.git
119
+ cd sqlmesh-gizmosql
120
+
121
+ # Install dev dependencies
122
+ pip install -e ".[dev]"
123
+
124
+ # Run tests
125
+ pytest
126
+
127
+ # Run linting
128
+ ruff check .
129
+ mypy sqlmesh_gizmosql
130
+ ```
131
+
132
+ ## License
133
+
134
+ Apache 2.0
@@ -0,0 +1,11 @@
1
+ README.md
2
+ pyproject.toml
3
+ sqlmesh_gizmosql/__init__.py
4
+ sqlmesh_gizmosql/adapter.py
5
+ sqlmesh_gizmosql/connection.py
6
+ sqlmesh_gizmosql.egg-info/PKG-INFO
7
+ sqlmesh_gizmosql.egg-info/SOURCES.txt
8
+ sqlmesh_gizmosql.egg-info/dependency_links.txt
9
+ sqlmesh_gizmosql.egg-info/requires.txt
10
+ sqlmesh_gizmosql.egg-info/top_level.txt
11
+ tests/test_gizmosql.py
@@ -0,0 +1,9 @@
1
+ sqlmesh>=0.100.0
2
+ adbc-driver-flightsql>=1.10.0
3
+ pyarrow>=22.0.0
4
+
5
+ [dev]
6
+ pytest>=7.0.0
7
+ pytest-cov>=4.0.0
8
+ mypy>=1.0.0
9
+ ruff>=0.1.0
@@ -0,0 +1 @@
1
+ sqlmesh_gizmosql
@@ -0,0 +1,235 @@
1
+ """Unit tests for GizmoSQL engine adapter and connection config.
2
+
3
+ These tests don't require a running GizmoSQL server - they test
4
+ configuration validation and adapter properties.
5
+ """
6
+
7
+ from unittest.mock import MagicMock, patch
8
+
9
+ import pytest
10
+ from sqlmesh.utils.errors import ConfigError
11
+
12
+ from sqlmesh_gizmosql.adapter import GizmoSQLEngineAdapter
13
+ from sqlmesh_gizmosql.connection import GizmoSQLConnectionConfig
14
+
15
+
16
+ class TestGizmoSQLConnectionConfig:
17
+ """Tests for GizmoSQLConnectionConfig."""
18
+
19
+ def test_default_values(self):
20
+ """Test default configuration values."""
21
+ config = GizmoSQLConnectionConfig(
22
+ username="user",
23
+ password="pass",
24
+ )
25
+
26
+ assert config.host == "localhost"
27
+ assert config.port == 31337
28
+ assert config.use_encryption is True
29
+ assert config.disable_certificate_verification is False
30
+ assert config.database is None
31
+ assert config.concurrent_tasks == 4
32
+
33
+ def test_custom_values(self):
34
+ """Test custom configuration values."""
35
+ config = GizmoSQLConnectionConfig(
36
+ host="gizmosql.example.com",
37
+ port=12345,
38
+ username="testuser",
39
+ password="testpass",
40
+ use_encryption=False,
41
+ disable_certificate_verification=True,
42
+ database="mydb",
43
+ concurrent_tasks=8,
44
+ )
45
+
46
+ assert config.host == "gizmosql.example.com"
47
+ assert config.port == 12345
48
+ assert config.username == "testuser"
49
+ assert config.password == "testpass"
50
+ assert config.use_encryption is False
51
+ assert config.disable_certificate_verification is True
52
+ assert config.database == "mydb"
53
+ assert config.concurrent_tasks == 8
54
+
55
+ def test_dialect_is_duckdb(self):
56
+ """Test that the dialect is set to duckdb."""
57
+ config = GizmoSQLConnectionConfig(
58
+ username="user",
59
+ password="pass",
60
+ )
61
+ assert config.DIALECT == "duckdb"
62
+
63
+ def test_type_is_gizmosql(self):
64
+ """Test that the type is set to gizmosql."""
65
+ config = GizmoSQLConnectionConfig(
66
+ username="user",
67
+ password="pass",
68
+ )
69
+ assert config.type_ == "gizmosql"
70
+
71
+ def test_get_catalog(self):
72
+ """Test get_catalog returns database."""
73
+ config = GizmoSQLConnectionConfig(
74
+ username="user",
75
+ password="pass",
76
+ database="mydb",
77
+ )
78
+ assert config.get_catalog() == "mydb"
79
+
80
+ def test_get_catalog_none(self):
81
+ """Test get_catalog returns None when database not set."""
82
+ config = GizmoSQLConnectionConfig(
83
+ username="user",
84
+ password="pass",
85
+ )
86
+ assert config.get_catalog() is None
87
+
88
+ def test_connection_factory_builds_correct_uri_with_tls(self):
89
+ """Test connection factory builds correct URI with TLS."""
90
+ mock_flightsql = MagicMock()
91
+ mock_conn = MagicMock()
92
+ mock_conn.adbc_get_info.return_value = {"vendor_version": "duckdb v1.0.0"}
93
+ mock_flightsql.connect.return_value = mock_conn
94
+
95
+ # Mock DatabaseOptions enum
96
+ mock_db_options = MagicMock()
97
+ mock_db_options.TLS_SKIP_VERIFY.value = "adbc.flight.sql.client_option.tls_skip_verify"
98
+
99
+ config = GizmoSQLConnectionConfig(
100
+ host="example.com",
101
+ port=31337,
102
+ username="user",
103
+ password="pass",
104
+ use_encryption=True,
105
+ disable_certificate_verification=False,
106
+ )
107
+
108
+ mock_module = MagicMock()
109
+ mock_module.dbapi = mock_flightsql
110
+ mock_module.DatabaseOptions = mock_db_options
111
+
112
+ with patch.dict("sys.modules", {"adbc_driver_flightsql": mock_module}):
113
+ factory = config._connection_factory
114
+ factory()
115
+
116
+ # Verify connect was called with correct URI (first positional arg)
117
+ call_args = mock_flightsql.connect.call_args
118
+ assert call_args[0][0] == "grpc+tls://example.com:31337"
119
+ # Verify db_kwargs contains credentials
120
+ db_kwargs = call_args[1]["db_kwargs"]
121
+ assert db_kwargs["username"] == "user"
122
+ assert db_kwargs["password"] == "pass"
123
+
124
+ def test_connection_factory_builds_correct_uri_without_tls(self):
125
+ """Test connection factory builds correct URI without TLS."""
126
+ mock_flightsql = MagicMock()
127
+ mock_conn = MagicMock()
128
+ mock_conn.adbc_get_info.return_value = {"vendor_version": "duckdb v1.0.0"}
129
+ mock_flightsql.connect.return_value = mock_conn
130
+
131
+ # Mock DatabaseOptions enum
132
+ mock_db_options = MagicMock()
133
+ mock_db_options.TLS_SKIP_VERIFY.value = "adbc.flight.sql.client_option.tls_skip_verify"
134
+
135
+ config = GizmoSQLConnectionConfig(
136
+ host="example.com",
137
+ port=31337,
138
+ username="user",
139
+ password="pass",
140
+ use_encryption=False,
141
+ )
142
+
143
+ mock_module = MagicMock()
144
+ mock_module.dbapi = mock_flightsql
145
+ mock_module.DatabaseOptions = mock_db_options
146
+
147
+ with patch.dict("sys.modules", {"adbc_driver_flightsql": mock_module}):
148
+ factory = config._connection_factory
149
+ factory()
150
+
151
+ call_args = mock_flightsql.connect.call_args
152
+ assert call_args[0][0] == "grpc://example.com:31337"
153
+
154
+ def test_connection_factory_rejects_non_duckdb_backend(self):
155
+ """Test connection factory raises error for non-DuckDB backend."""
156
+ mock_flightsql = MagicMock()
157
+ mock_conn = MagicMock()
158
+ mock_conn.adbc_get_info.return_value = {"vendor_version": "sqlite v3.40.0"}
159
+ mock_flightsql.connect.return_value = mock_conn
160
+
161
+ # Mock DatabaseOptions enum
162
+ mock_db_options = MagicMock()
163
+ mock_db_options.TLS_SKIP_VERIFY.value = "adbc.flight.sql.client_option.tls_skip_verify"
164
+
165
+ config = GizmoSQLConnectionConfig(
166
+ host="example.com",
167
+ port=31337,
168
+ username="user",
169
+ password="pass",
170
+ )
171
+
172
+ mock_module = MagicMock()
173
+ mock_module.dbapi = mock_flightsql
174
+ mock_module.DatabaseOptions = mock_db_options
175
+
176
+ with patch.dict("sys.modules", {"adbc_driver_flightsql": mock_module}):
177
+ factory = config._connection_factory
178
+ with pytest.raises(ConfigError, match="Unsupported GizmoSQL server backend"):
179
+ factory()
180
+
181
+ # Verify connection was closed after rejection
182
+ mock_conn.close.assert_called_once()
183
+
184
+
185
+ class TestGizmoSQLEngineAdapter:
186
+ """Tests for GizmoSQLEngineAdapter properties."""
187
+
188
+ def test_dialect(self):
189
+ """Test that dialect is duckdb."""
190
+ assert GizmoSQLEngineAdapter.DIALECT == "duckdb"
191
+
192
+ def test_supports_transactions(self):
193
+ """Test transactions are supported via SQL statements."""
194
+ assert GizmoSQLEngineAdapter.SUPPORTS_TRANSACTIONS is True
195
+
196
+ def test_supports_create_drop_catalog(self):
197
+ """Test catalog operations are supported."""
198
+ assert GizmoSQLEngineAdapter.SUPPORTS_CREATE_DROP_CATALOG is True
199
+
200
+ def test_supported_drop_cascade_object_kinds(self):
201
+ """Test cascade drop is supported for schemas, tables, and views."""
202
+ assert "SCHEMA" in GizmoSQLEngineAdapter.SUPPORTED_DROP_CASCADE_OBJECT_KINDS
203
+ assert "TABLE" in GizmoSQLEngineAdapter.SUPPORTED_DROP_CASCADE_OBJECT_KINDS
204
+ assert "VIEW" in GizmoSQLEngineAdapter.SUPPORTED_DROP_CASCADE_OBJECT_KINDS
205
+
206
+
207
+ class TestRegistration:
208
+ """Tests for automatic registration with SQLMesh."""
209
+
210
+ def test_adapter_registered(self):
211
+ """Test that adapter is registered in SQLMesh's dialect map."""
212
+ from sqlmesh.core import engine_adapter
213
+
214
+ import sqlmesh_gizmosql # noqa: F401
215
+
216
+ assert "gizmosql" in engine_adapter.DIALECT_TO_ENGINE_ADAPTER
217
+ assert engine_adapter.DIALECT_TO_ENGINE_ADAPTER["gizmosql"] is GizmoSQLEngineAdapter
218
+
219
+ def test_connection_config_registered(self):
220
+ """Test that connection config is registered in SQLMesh."""
221
+ from sqlmesh.core.config import connection as conn_module
222
+
223
+ import sqlmesh_gizmosql # noqa: F401
224
+
225
+ assert "gizmosql" in conn_module.CONNECTION_CONFIG_TO_TYPE
226
+ assert conn_module.CONNECTION_CONFIG_TO_TYPE["gizmosql"] is GizmoSQLConnectionConfig
227
+
228
+ def test_dialect_type_registered(self):
229
+ """Test that dialect type is registered."""
230
+ from sqlmesh.core.config import connection as conn_module
231
+
232
+ import sqlmesh_gizmosql # noqa: F401
233
+
234
+ assert "gizmosql" in conn_module.DIALECT_TO_TYPE
235
+ assert conn_module.DIALECT_TO_TYPE["gizmosql"] == "duckdb"