ob-dremio 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.
- ob_dremio-0.1.0/.gitignore +35 -0
- ob_dremio-0.1.0/CLAUDE.md +107 -0
- ob_dremio-0.1.0/LICENSE +70 -0
- ob_dremio-0.1.0/PKG-INFO +36 -0
- ob_dremio-0.1.0/README.md +15 -0
- ob_dremio-0.1.0/pyproject.toml +51 -0
- ob_dremio-0.1.0/src/ob_dremio/__init__.py +110 -0
- ob_dremio-0.1.0/src/ob_dremio/compiler.py +8 -0
- ob_dremio-0.1.0/src/ob_dremio/connection.py +69 -0
- ob_dremio-0.1.0/src/ob_dremio/cursor.py +235 -0
- ob_dremio-0.1.0/src/ob_dremio/exceptions.py +32 -0
- ob_dremio-0.1.0/src/ob_dremio/type_codes.py +48 -0
- ob_dremio-0.1.0/tests/test_driver.py +725 -0
- ob_dremio-0.1.0/tests/test_yaml_detection.py +29 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.so
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
*.egg
|
|
9
|
+
.eggs/
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
.env
|
|
13
|
+
*.db
|
|
14
|
+
*.duckdb
|
|
15
|
+
*.sqlite3
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
htmlcov/
|
|
20
|
+
.coverage
|
|
21
|
+
.coverage.*
|
|
22
|
+
*.log
|
|
23
|
+
.DS_Store
|
|
24
|
+
.claude/
|
|
25
|
+
security/
|
|
26
|
+
infra/
|
|
27
|
+
site/
|
|
28
|
+
scripts/
|
|
29
|
+
.mcpregistry_github_token
|
|
30
|
+
.mcpregistry_registry_token
|
|
31
|
+
_*/
|
|
32
|
+
blog/
|
|
33
|
+
review*
|
|
34
|
+
design/
|
|
35
|
+
examples/test*
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# ob-dremio — OrionBelt Semantic Layer Driver for Dremio
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
PEP 249 DB-API 2.0 driver wrapping `pyarrow = ">=16.0"
|
|
6
|
+
pyarrow-hotfix = ">=0.6"` that intercepts OBML YAML
|
|
7
|
+
queries, compiles them to dremio SQL via the OrionBelt CompilationPipeline
|
|
8
|
+
(direct import) or OB REST API (standalone), and executes them natively.
|
|
9
|
+
|
|
10
|
+
**OB dialect string:** `"dremio"`
|
|
11
|
+
**Author:** Ralf Becher / RALFORION d.o.o. (info@orionbelt.ai)
|
|
12
|
+
**License:** Apache 2.0
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Module Map
|
|
17
|
+
|
|
18
|
+
| File | Responsibility |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `__init__.py` | PEP 249 connect() + module constants |
|
|
21
|
+
| `connection.py` | Connection class |
|
|
22
|
+
| `cursor.py` | Cursor class — OBML detection + execution |
|
|
23
|
+
| `compiler.py` | Direct OB import or REST fallback |
|
|
24
|
+
| `exceptions.py` | PEP 249 exception hierarchy |
|
|
25
|
+
| `type_codes.py` | PEP 249 type objects |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## connect() Parameters
|
|
30
|
+
|
|
31
|
+
### dremio-specific
|
|
32
|
+
| host | str | Dremio host |
|
|
33
|
+
| port | int | Arrow Flight port (default: 32010) |
|
|
34
|
+
| username | str | Dremio username |
|
|
35
|
+
| password | str | Dremio password |
|
|
36
|
+
| schema | str | Space/schema path (e.g. "@user.myspace") |
|
|
37
|
+
| tls | bool | Use TLS (default: False for LAN) |
|
|
38
|
+
|
|
39
|
+
### OrionBelt parameters (same across all vendors)
|
|
40
|
+
| Parameter | Default | Description |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| ob_model_id | None | Pre-loaded OB model ID |
|
|
43
|
+
| ob_model_yaml | None | OBML YAML string to load |
|
|
44
|
+
| ob_model_file | None | Path to .obml.yaml file |
|
|
45
|
+
| ob_api_url | http://localhost:8000 | OB REST API URL (standalone mode only) |
|
|
46
|
+
| ob_timeout | 30 | HTTP timeout in seconds |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Compiler Bridge (compiler.py)
|
|
51
|
+
|
|
52
|
+
Auto-detects whether OB core is importable (same process as orionbelt-api)
|
|
53
|
+
or whether to fall back to REST:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
def compile_obml(obml: dict, model, dialect: str) -> str:
|
|
57
|
+
try:
|
|
58
|
+
# Direct call — zero overhead, used when embedded in orionbelt-api
|
|
59
|
+
from orionbelt.compiler.pipeline import CompilationPipeline
|
|
60
|
+
result = CompilationPipeline().compile(obml, model, dialect)
|
|
61
|
+
return result.sql
|
|
62
|
+
except ImportError:
|
|
63
|
+
# Standalone mode — call REST API
|
|
64
|
+
return _compile_via_rest(obml, dialect)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Vendor-Specific Notes
|
|
70
|
+
|
|
71
|
+
- Dremio connects via Arrow Flight (port 32010), NOT JDBC/ODBC
|
|
72
|
+
- Use pyarrow.flight.FlightClient with BasicAuth middleware for auth
|
|
73
|
+
- execute() sends query via do_get() with TicketStatementQuery
|
|
74
|
+
- This driver is unique: it IS already a Flight client internally
|
|
75
|
+
- COPY INTO SQL with German locale formatting was a prior pain point — always use . as decimal separator
|
|
76
|
+
- Space paths use dot notation: SELECT * FROM "myspace"."mytable"
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Type System
|
|
81
|
+
|
|
82
|
+
Dremio uses Arrow Flight natively — cursor maps Arrow schema directly.
|
|
83
|
+
pa.int32() → int, pa.float64() → float, pa.utf8() → str, pa.timestamp() → datetime.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Build Order
|
|
88
|
+
|
|
89
|
+
Session 1: exceptions.py + type_codes.py + compiler.py + unit tests
|
|
90
|
+
Session 2: connection.py + cursor.py (OBML detection, core execute)
|
|
91
|
+
Session 3: __init__.py + connect() + integration tests
|
|
92
|
+
Session 4: SQLAlchemy dialect (ob+dremio:// URL scheme)
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Dependencies
|
|
97
|
+
|
|
98
|
+
```toml
|
|
99
|
+
[project.dependencies]
|
|
100
|
+
pyarrow = ">=16.0"
|
|
101
|
+
pyarrow-hotfix = ">=0.6"
|
|
102
|
+
pyyaml = ">=6.0"
|
|
103
|
+
|
|
104
|
+
[project.optional-dependencies]
|
|
105
|
+
sqlalchemy = ["sqlalchemy>=2.0"]
|
|
106
|
+
dev = ["pytest>=8.0", "pytest-asyncio>=0.23", "mypy>=1.10", "ruff>=0.4", "respx>=0.21"]
|
|
107
|
+
```
|
ob_dremio-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Parameters
|
|
4
|
+
|
|
5
|
+
Licensor: RALFORION d.o.o.
|
|
6
|
+
Licensed Work: OrionBelt Semantic Layer 1.0
|
|
7
|
+
The Licensed Work is (c) 2025 RALFORION d.o.o.
|
|
8
|
+
Additional Use Grant: You may use the Licensed Work for any purpose,
|
|
9
|
+
including production use, PROVIDED THAT you may
|
|
10
|
+
not embed OrionBelt in a commercial product or
|
|
11
|
+
provide it as part of a commercial service
|
|
12
|
+
without purchasing a commercial license from
|
|
13
|
+
the Licensor. Contact licensing@ralforion.com
|
|
14
|
+
for commercial licensing inquiries.
|
|
15
|
+
Change Date: 2030-03-16
|
|
16
|
+
Change License: Apache License, Version 2.0
|
|
17
|
+
|
|
18
|
+
-----------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
Business Source License 1.1
|
|
21
|
+
|
|
22
|
+
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
|
|
23
|
+
"Business Source License" is a trademark of MariaDB Corporation Ab.
|
|
24
|
+
|
|
25
|
+
Terms
|
|
26
|
+
|
|
27
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
28
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
29
|
+
Licensor may make an Additional Use Grant, above, permitting limited
|
|
30
|
+
production use.
|
|
31
|
+
|
|
32
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
33
|
+
available distribution of a specific version of the Licensed Work under this
|
|
34
|
+
License, whichever comes first, the Licensor hereby grants you rights under
|
|
35
|
+
the terms of the Change License, and the rights granted in the paragraph
|
|
36
|
+
above terminate.
|
|
37
|
+
|
|
38
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
39
|
+
currently in effect as described in this License, you must purchase a
|
|
40
|
+
commercial license from the Licensor, its affiliated entities, or authorized
|
|
41
|
+
resellers, or you must refrain from using the Licensed Work.
|
|
42
|
+
|
|
43
|
+
All copies of the original and modified Licensed Work, and derivative works
|
|
44
|
+
of the Licensed Work, are subject to this License. This License applies
|
|
45
|
+
separately for each version of the Licensed Work and the Change Date may vary
|
|
46
|
+
for each version of the Licensed Work released by Licensor.
|
|
47
|
+
|
|
48
|
+
You must conspicuously display this License on each original or modified copy
|
|
49
|
+
of the Licensed Work. If you receive the Licensed Work in original or
|
|
50
|
+
modified form from a third party, the terms and conditions set forth in this
|
|
51
|
+
License apply to your use of that work.
|
|
52
|
+
|
|
53
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
54
|
+
terminate your rights under this License for the current and all other
|
|
55
|
+
versions of the Licensed Work.
|
|
56
|
+
|
|
57
|
+
This License does not grant you any right in any trademark or logo of
|
|
58
|
+
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
59
|
+
Licensor as expressly required by this License).
|
|
60
|
+
|
|
61
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
62
|
+
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
63
|
+
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
64
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
65
|
+
TITLE.
|
|
66
|
+
|
|
67
|
+
MariaDB hereby grants you permission to use this License's text to license
|
|
68
|
+
your works, and to refer to it using the trademark "Business Source License",
|
|
69
|
+
as long as you comply with the Covenants of Licensor of MariaDB's Business Source
|
|
70
|
+
License Trademark Policy available at https://mariadb.com/bsl11/.
|
ob_dremio-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ob-dremio
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: OrionBelt Semantic Layer driver for Dremio (DB-API 2.0)
|
|
5
|
+
Author-email: Ralf Becher <info@orionbelt.ai>
|
|
6
|
+
License: BSL-1.1
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: db-api,dremio,obml,orionbelt,semantic-layer
|
|
9
|
+
Requires-Python: >=3.12
|
|
10
|
+
Requires-Dist: ob-driver-core>=0.1
|
|
11
|
+
Requires-Dist: pyarrow>=16.0
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
14
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
15
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
16
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
17
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
18
|
+
Provides-Extra: sqlalchemy
|
|
19
|
+
Requires-Dist: sqlalchemy>=2.0; extra == 'sqlalchemy'
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# ob-dremio
|
|
23
|
+
|
|
24
|
+
OrionBelt Semantic Layer driver for Dremio (DB-API 2.0)
|
|
25
|
+
|
|
26
|
+
Part of the [OrionBelt Semantic Layer](https://github.com/ralfbecher/orionbelt-semantic-layer) project.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install ob-dremio
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## License
|
|
35
|
+
|
|
36
|
+
BSL-1.1 — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# ob-dremio
|
|
2
|
+
|
|
3
|
+
OrionBelt Semantic Layer driver for Dremio (DB-API 2.0)
|
|
4
|
+
|
|
5
|
+
Part of the [OrionBelt Semantic Layer](https://github.com/ralfbecher/orionbelt-semantic-layer) project.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install ob-dremio
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## License
|
|
14
|
+
|
|
15
|
+
BSL-1.1 — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ob-dremio"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "OrionBelt Semantic Layer driver for Dremio (DB-API 2.0)"
|
|
9
|
+
license = { text = "BSL-1.1" }
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
authors = [{ name = "Ralf Becher", email = "info@orionbelt.ai" }]
|
|
12
|
+
keywords = ["dremio", "semantic-layer", "obml", "db-api", "orionbelt"]
|
|
13
|
+
requires-python = ">=3.12"
|
|
14
|
+
dependencies = [
|
|
15
|
+
"ob-driver-core>=0.1",
|
|
16
|
+
"pyarrow>=16.0",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
sqlalchemy = ["sqlalchemy>=2.0"]
|
|
21
|
+
dev = [
|
|
22
|
+
"pytest>=8.0",
|
|
23
|
+
"pytest-asyncio>=0.23",
|
|
24
|
+
"mypy>=1.10",
|
|
25
|
+
"ruff>=0.4",
|
|
26
|
+
"respx>=0.21",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.entry-points."sqlalchemy.dialects"]
|
|
30
|
+
"ob.dremio" = "ob_dremio.dialect:OBDremioDialect"
|
|
31
|
+
|
|
32
|
+
[tool.hatch.build.targets.wheel]
|
|
33
|
+
packages = ["src/ob_dremio"]
|
|
34
|
+
|
|
35
|
+
[tool.ruff]
|
|
36
|
+
line-length = 100
|
|
37
|
+
target-version = "py312"
|
|
38
|
+
|
|
39
|
+
[tool.ruff.lint]
|
|
40
|
+
select = ["E", "F", "I", "UP", "B", "SIM", "ANN"]
|
|
41
|
+
|
|
42
|
+
[tool.mypy]
|
|
43
|
+
python_version = "3.12"
|
|
44
|
+
strict = true
|
|
45
|
+
files = ["src/ob_dremio"]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
asyncio_mode = "auto"
|
|
49
|
+
testpaths = ["tests"]
|
|
50
|
+
markers = ["integration: requires live DB + OB API"]
|
|
51
|
+
addopts = "-m 'not integration'"
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""ob-dremio — OrionBelt Semantic Layer driver for Dremio (PEP 249 DB-API 2.0).
|
|
2
|
+
|
|
3
|
+
Requires the OrionBelt REST API running in single-model mode (MODEL_FILE set).
|
|
4
|
+
OBML queries are compiled to SQL via ``POST /v1/query/sql``.
|
|
5
|
+
|
|
6
|
+
Dremio is accessed via Arrow Flight protocol using ``pyarrow.flight``.
|
|
7
|
+
|
|
8
|
+
Usage::
|
|
9
|
+
|
|
10
|
+
import ob_dremio
|
|
11
|
+
|
|
12
|
+
conn = ob_dremio.connect(host="localhost", username="user", password="pass")
|
|
13
|
+
with conn.cursor() as cur:
|
|
14
|
+
cur.execute("select:\\n dimensions:\\n - Region\\n measures:\\n - Revenue")
|
|
15
|
+
print(cur.fetchall())
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from ob_dremio.connection import Connection
|
|
21
|
+
from ob_dremio.exceptions import (
|
|
22
|
+
DataError,
|
|
23
|
+
DatabaseError,
|
|
24
|
+
Error,
|
|
25
|
+
IntegrityError,
|
|
26
|
+
InterfaceError,
|
|
27
|
+
InternalError,
|
|
28
|
+
NotSupportedError,
|
|
29
|
+
OperationalError,
|
|
30
|
+
ProgrammingError,
|
|
31
|
+
Warning,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# PEP 249 module-level constants
|
|
35
|
+
apilevel = "2.0"
|
|
36
|
+
threadsafety = 1 # threads may share the module but not connections
|
|
37
|
+
paramstyle = "qmark" # Dremio SQL uses ? placeholders
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def connect(
|
|
41
|
+
*,
|
|
42
|
+
host: str = "localhost",
|
|
43
|
+
port: int = 32010,
|
|
44
|
+
username: str | None = None,
|
|
45
|
+
password: str | None = None,
|
|
46
|
+
tls: bool = False,
|
|
47
|
+
# OrionBelt parameters
|
|
48
|
+
ob_api_url: str = "http://localhost:8000",
|
|
49
|
+
ob_timeout: int = 30,
|
|
50
|
+
) -> Connection:
|
|
51
|
+
"""Open a Dremio connection via Arrow Flight with OBML support.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
host : str
|
|
56
|
+
Dremio host (default: ``localhost``).
|
|
57
|
+
port : int
|
|
58
|
+
Arrow Flight port (default: ``32010``).
|
|
59
|
+
username : str, optional
|
|
60
|
+
Dremio username for authentication.
|
|
61
|
+
password : str, optional
|
|
62
|
+
Dremio password for authentication.
|
|
63
|
+
tls : bool
|
|
64
|
+
Use TLS for the Flight connection (default: ``False``).
|
|
65
|
+
ob_api_url : str
|
|
66
|
+
OrionBelt REST API URL (must be running in single-model mode).
|
|
67
|
+
ob_timeout : int
|
|
68
|
+
HTTP timeout in seconds for OBML compilation.
|
|
69
|
+
"""
|
|
70
|
+
import pyarrow.flight
|
|
71
|
+
|
|
72
|
+
scheme = "grpc+tls" if tls else "grpc"
|
|
73
|
+
location = f"{scheme}://{host}:{port}"
|
|
74
|
+
client = pyarrow.flight.FlightClient(location)
|
|
75
|
+
|
|
76
|
+
if username is not None and password is not None:
|
|
77
|
+
token_pair = client.authenticate_basic_token(username, password)
|
|
78
|
+
# Store the bearer token as default call options via a header factory.
|
|
79
|
+
# pyarrow Flight uses call options for auth headers on each RPC.
|
|
80
|
+
options = pyarrow.flight.FlightCallOptions(
|
|
81
|
+
headers=[token_pair],
|
|
82
|
+
)
|
|
83
|
+
# Wrap the client so that default options are applied.
|
|
84
|
+
# For simplicity, we store the options on the client object.
|
|
85
|
+
client._ob_call_options = options # type: ignore[attr-defined]
|
|
86
|
+
|
|
87
|
+
return Connection(
|
|
88
|
+
client,
|
|
89
|
+
ob_api_url=ob_api_url,
|
|
90
|
+
ob_timeout=ob_timeout,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
__all__ = [
|
|
95
|
+
"apilevel",
|
|
96
|
+
"threadsafety",
|
|
97
|
+
"paramstyle",
|
|
98
|
+
"connect",
|
|
99
|
+
"Connection",
|
|
100
|
+
"Warning",
|
|
101
|
+
"Error",
|
|
102
|
+
"InterfaceError",
|
|
103
|
+
"DatabaseError",
|
|
104
|
+
"DataError",
|
|
105
|
+
"OperationalError",
|
|
106
|
+
"IntegrityError",
|
|
107
|
+
"InternalError",
|
|
108
|
+
"ProgrammingError",
|
|
109
|
+
"NotSupportedError",
|
|
110
|
+
]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""OrionBelt compilation bridge — delegates to ob-driver-core."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ob_driver_core.compiler import compile_obml
|
|
6
|
+
from ob_driver_core.detection import is_obml, parse_obml
|
|
7
|
+
|
|
8
|
+
__all__ = ["compile_obml", "is_obml", "parse_obml"]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""PEP 249 Connection wrapping a pyarrow Flight client for Dremio.
|
|
2
|
+
|
|
3
|
+
Dremio has no transactions — ``commit()`` and ``rollback()`` are no-ops
|
|
4
|
+
that simply verify the connection is still open.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from ob_dremio.cursor import Cursor
|
|
12
|
+
from ob_dremio.exceptions import ProgrammingError
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Connection:
|
|
16
|
+
"""DB-API 2.0 connection wrapping a pyarrow FlightClient for Dremio.
|
|
17
|
+
|
|
18
|
+
OBML queries are compiled to SQL via the OrionBelt REST API
|
|
19
|
+
(single-model mode, ``/v1/query/sql`` shortcut).
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
client: Any,
|
|
25
|
+
*,
|
|
26
|
+
ob_api_url: str = "http://localhost:8000",
|
|
27
|
+
ob_timeout: int = 30,
|
|
28
|
+
) -> None:
|
|
29
|
+
self._client = client
|
|
30
|
+
self._closed = False
|
|
31
|
+
self._ob_api_url = ob_api_url
|
|
32
|
+
self._ob_timeout = ob_timeout
|
|
33
|
+
|
|
34
|
+
def _check_open(self) -> None:
|
|
35
|
+
if self._closed:
|
|
36
|
+
raise ProgrammingError("Connection is closed.")
|
|
37
|
+
|
|
38
|
+
def cursor(self) -> Cursor:
|
|
39
|
+
"""Return a new Cursor backed by the shared FlightClient.
|
|
40
|
+
|
|
41
|
+
pyarrow FlightClient does not have its own cursor concept — our
|
|
42
|
+
``Cursor`` wraps the client directly.
|
|
43
|
+
"""
|
|
44
|
+
self._check_open()
|
|
45
|
+
return Cursor(
|
|
46
|
+
self._client,
|
|
47
|
+
ob_api_url=self._ob_api_url,
|
|
48
|
+
ob_timeout=self._ob_timeout,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def commit(self) -> None:
|
|
52
|
+
"""No-op — Dremio has no transactions."""
|
|
53
|
+
self._check_open()
|
|
54
|
+
|
|
55
|
+
def rollback(self) -> None:
|
|
56
|
+
"""No-op — Dremio has no transactions."""
|
|
57
|
+
self._check_open()
|
|
58
|
+
|
|
59
|
+
def close(self) -> None:
|
|
60
|
+
"""Close the connection and the underlying FlightClient."""
|
|
61
|
+
if not self._closed:
|
|
62
|
+
self._client.close()
|
|
63
|
+
self._closed = True
|
|
64
|
+
|
|
65
|
+
def __enter__(self) -> Connection:
|
|
66
|
+
return self
|
|
67
|
+
|
|
68
|
+
def __exit__(self, *exc: object) -> None:
|
|
69
|
+
self.close()
|