dbt-benostreamdb 1.8.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.
- dbt_benostreamdb-1.8.0/PKG-INFO +54 -0
- dbt_benostreamdb-1.8.0/README.md +29 -0
- dbt_benostreamdb-1.8.0/dbt/adapters/benostreamdb/__init__.py +12 -0
- dbt_benostreamdb-1.8.0/dbt/adapters/benostreamdb/__version__.py +4 -0
- dbt_benostreamdb-1.8.0/dbt/adapters/benostreamdb/connections.py +206 -0
- dbt_benostreamdb-1.8.0/dbt/adapters/benostreamdb/impl.py +97 -0
- dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/__init__.py +3 -0
- dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/dbt_project.yml +5 -0
- dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/adapters.sql +90 -0
- dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/ddl.sql +63 -0
- dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/graph.sql +503 -0
- dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/json.sql +115 -0
- dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/materializations/incremental.sql +108 -0
- dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/materializations/table.sql +19 -0
- dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/search.sql +55 -0
- dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/vector.sql +349 -0
- dbt_benostreamdb-1.8.0/dbt_benostreamdb.egg-info/PKG-INFO +54 -0
- dbt_benostreamdb-1.8.0/dbt_benostreamdb.egg-info/SOURCES.txt +22 -0
- dbt_benostreamdb-1.8.0/dbt_benostreamdb.egg-info/dependency_links.txt +1 -0
- dbt_benostreamdb-1.8.0/dbt_benostreamdb.egg-info/requires.txt +4 -0
- dbt_benostreamdb-1.8.0/dbt_benostreamdb.egg-info/top_level.txt +1 -0
- dbt_benostreamdb-1.8.0/pyproject.toml +48 -0
- dbt_benostreamdb-1.8.0/setup.cfg +4 -0
- dbt_benostreamdb-1.8.0/setup.py +10 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dbt-benostreamdb
|
|
3
|
+
Version: 1.8.0
|
|
4
|
+
Summary: The BenoStreamDB adapter plugin for dbt
|
|
5
|
+
Author-email: Richard Albright <rla3rd@gmail.com>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/benolabsai/benostreamdb
|
|
8
|
+
Project-URL: Repository, https://github.com/benolabsai/benostreamdb
|
|
9
|
+
Project-URL: Documentation, https://github.com/benolabsai/benostreamdb/blob/main/dbt-benostreamdb/README.md
|
|
10
|
+
Keywords: dbt,benostreamdb,iceberg,vector-search,analytics
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: dbt-core<1.9.0,>=1.8.0
|
|
22
|
+
Requires-Dist: benostreamdb>=0.12.0
|
|
23
|
+
Requires-Dist: pyarrow>=15.0.0
|
|
24
|
+
Requires-Dist: pandas
|
|
25
|
+
|
|
26
|
+
# dbt Adapter for BenoStreamDB (`dbt-benostreamdb`)
|
|
27
|
+
|
|
28
|
+
`dbt-benostreamdb` is the official dbt adapter enabling analytics engineering, transformation models, and data lineage directly against BenoStreamDB.
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- **Table & View Materializations**: Build standard and optimized Iceberg-format tables.
|
|
33
|
+
- **Incremental Materializations**: Efficient append and merge updates leveraging BenoStreamDB's primary key upserts and delete vector acceleration.
|
|
34
|
+
- **Vector & Graph Extensions**: Built-in macros for vector distance scoring, hybrid search, and graph relationship traversals (`benostreamdb.vector_search(...)`, `benostreamdb.graph_neighbors(...)`).
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install dbt-benostreamdb
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Configuration (`profiles.yml`)
|
|
43
|
+
|
|
44
|
+
```yaml
|
|
45
|
+
benostreamdb_profile:
|
|
46
|
+
target: dev
|
|
47
|
+
outputs:
|
|
48
|
+
dev:
|
|
49
|
+
type: benostreamdb
|
|
50
|
+
database: default
|
|
51
|
+
schema: public
|
|
52
|
+
threads: 4
|
|
53
|
+
uri: "file:///path/to/benostreamdb/warehouse"
|
|
54
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# dbt Adapter for BenoStreamDB (`dbt-benostreamdb`)
|
|
2
|
+
|
|
3
|
+
`dbt-benostreamdb` is the official dbt adapter enabling analytics engineering, transformation models, and data lineage directly against BenoStreamDB.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Table & View Materializations**: Build standard and optimized Iceberg-format tables.
|
|
8
|
+
- **Incremental Materializations**: Efficient append and merge updates leveraging BenoStreamDB's primary key upserts and delete vector acceleration.
|
|
9
|
+
- **Vector & Graph Extensions**: Built-in macros for vector distance scoring, hybrid search, and graph relationship traversals (`benostreamdb.vector_search(...)`, `benostreamdb.graph_neighbors(...)`).
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install dbt-benostreamdb
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration (`profiles.yml`)
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
benostreamdb_profile:
|
|
21
|
+
target: dev
|
|
22
|
+
outputs:
|
|
23
|
+
dev:
|
|
24
|
+
type: benostreamdb
|
|
25
|
+
database: default
|
|
26
|
+
schema: public
|
|
27
|
+
threads: 4
|
|
28
|
+
uri: "file:///path/to/benostreamdb/warehouse"
|
|
29
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from dbt.adapters.base import AdapterPlugin
|
|
2
|
+
from dbt.include import benostreamdb
|
|
3
|
+
|
|
4
|
+
from .connections import BenoStreamDBConnectionManager
|
|
5
|
+
from .connections import BenoStreamDBCredentials
|
|
6
|
+
from .impl import BenoStreamDBAdapter
|
|
7
|
+
|
|
8
|
+
Plugin = AdapterPlugin(
|
|
9
|
+
adapter=BenoStreamDBAdapter,
|
|
10
|
+
credentials=BenoStreamDBCredentials,
|
|
11
|
+
include_path=benostreamdb.PACKAGE_PATH,
|
|
12
|
+
)
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Optional, Tuple, Any
|
|
4
|
+
|
|
5
|
+
from dbt.adapters.contracts.connection import Credentials, Connection, AdapterResponse
|
|
6
|
+
from dbt.adapters.sql import SQLConnectionManager
|
|
7
|
+
from dbt.exceptions import DbtRuntimeError
|
|
8
|
+
from dbt.adapters.events.logging import AdapterLogger
|
|
9
|
+
|
|
10
|
+
import benostreamdb
|
|
11
|
+
|
|
12
|
+
logger = AdapterLogger("BenoStreamDB")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class BenoStreamDBCredentials(Credentials):
|
|
17
|
+
path: str = ":memory:"
|
|
18
|
+
database: Optional[str] = "benostreamdb"
|
|
19
|
+
# Unified lakehouse default schema (matches the engine's DEFAULT_SCHEMA,
|
|
20
|
+
# Spark's default namespace, and Trino's default schema).
|
|
21
|
+
schema: str = "default"
|
|
22
|
+
# Optional GPU device for the embedded engine:
|
|
23
|
+
# auto | cpu | cuda[:N] | mps | intel | rocm.
|
|
24
|
+
gpu_device: Optional[str] = None
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def type(self):
|
|
28
|
+
return "benostreamdb"
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def unique_field(self):
|
|
32
|
+
return self.path
|
|
33
|
+
|
|
34
|
+
def _connection_keys(self):
|
|
35
|
+
return ("path", "database", "schema", "gpu_device")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class BenoStreamDBCursor:
|
|
39
|
+
def __init__(self, session):
|
|
40
|
+
self.session = session
|
|
41
|
+
self.description = None
|
|
42
|
+
self._results = []
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def _prepare_sql(sql: str) -> str:
|
|
46
|
+
"""Normalize a dbt-issued SQL script for the engine's single-statement
|
|
47
|
+
`session.sql` guard (which rejects ';' and '--' anywhere).
|
|
48
|
+
|
|
49
|
+
dbt materializations legitimately emit line comments and a trailing
|
|
50
|
+
semicolon. We strip `--` line comments (quote-aware, so `--` inside a
|
|
51
|
+
string/identifier survives), drop a single trailing semicolon, and
|
|
52
|
+
still reject any *embedded* semicolon so the multi-statement injection
|
|
53
|
+
protection is preserved end to end.
|
|
54
|
+
"""
|
|
55
|
+
out = []
|
|
56
|
+
i, n = 0, len(sql)
|
|
57
|
+
in_str = None
|
|
58
|
+
while i < n:
|
|
59
|
+
c = sql[i]
|
|
60
|
+
if in_str is not None:
|
|
61
|
+
out.append(c)
|
|
62
|
+
if c == in_str:
|
|
63
|
+
if i + 1 < n and sql[i + 1] == in_str: # doubled-quote escape
|
|
64
|
+
out.append(sql[i + 1])
|
|
65
|
+
i += 2
|
|
66
|
+
continue
|
|
67
|
+
in_str = None
|
|
68
|
+
i += 1
|
|
69
|
+
continue
|
|
70
|
+
if c in ("'", '"'):
|
|
71
|
+
in_str = c
|
|
72
|
+
out.append(c)
|
|
73
|
+
i += 1
|
|
74
|
+
continue
|
|
75
|
+
if c == "-" and i + 1 < n and sql[i + 1] == "-":
|
|
76
|
+
nl = sql.find("\n", i)
|
|
77
|
+
i = n if nl == -1 else nl # skip comment, keep the newline
|
|
78
|
+
continue
|
|
79
|
+
out.append(c)
|
|
80
|
+
i += 1
|
|
81
|
+
prepared = "".join(out).strip()
|
|
82
|
+
if prepared.endswith(";"):
|
|
83
|
+
prepared = prepared[:-1].rstrip()
|
|
84
|
+
if ";" in prepared:
|
|
85
|
+
raise DbtRuntimeError(
|
|
86
|
+
"BenoStreamDB executes one statement at a time; "
|
|
87
|
+
"embedded ';' is not supported."
|
|
88
|
+
)
|
|
89
|
+
return prepared
|
|
90
|
+
|
|
91
|
+
def execute(self, sql: str, bindings=None):
|
|
92
|
+
if bindings:
|
|
93
|
+
# Note: dbt-core handles most string formatting. For complex bindings, DBAPI compliance would be needed.
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
sql = self._prepare_sql(sql)
|
|
97
|
+
try:
|
|
98
|
+
arrow_table = self.session.sql(sql)
|
|
99
|
+
if arrow_table is not None and hasattr(arrow_table, "schema"):
|
|
100
|
+
self.description = [(f.name, f.type) for f in arrow_table.schema]
|
|
101
|
+
df = arrow_table.to_pandas()
|
|
102
|
+
self._results = [tuple(x) for x in df.to_numpy()]
|
|
103
|
+
else:
|
|
104
|
+
self.description = None
|
|
105
|
+
self._results = []
|
|
106
|
+
except Exception as e:
|
|
107
|
+
raise Exception(f"Error executing {sql}: {e}")
|
|
108
|
+
|
|
109
|
+
def fetchall(self):
|
|
110
|
+
return self._results
|
|
111
|
+
|
|
112
|
+
def fetchone(self):
|
|
113
|
+
if self._results:
|
|
114
|
+
return self._results.pop(0)
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
def close(self):
|
|
118
|
+
pass
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class BenoStreamDBConnectionWrapper:
|
|
122
|
+
def __init__(self, session):
|
|
123
|
+
self.session = session
|
|
124
|
+
|
|
125
|
+
def cursor(self):
|
|
126
|
+
return BenoStreamDBCursor(self.session)
|
|
127
|
+
|
|
128
|
+
def commit(self):
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
def rollback(self):
|
|
132
|
+
pass
|
|
133
|
+
|
|
134
|
+
def close(self):
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class BenoStreamDBConnectionManager(SQLConnectionManager):
|
|
139
|
+
TYPE = "benostreamdb"
|
|
140
|
+
_session = None
|
|
141
|
+
|
|
142
|
+
@classmethod
|
|
143
|
+
def get_session(cls, credentials):
|
|
144
|
+
if cls._session is None:
|
|
145
|
+
# Instantiate a single embedded engine session for all connections.
|
|
146
|
+
# The profile `path` is the warehouse base location so CREATE
|
|
147
|
+
# TABLE / CREATE TABLE AS SELECT can derive table URIs; the
|
|
148
|
+
# default ":memory:" maps onto the engine's in-memory store.
|
|
149
|
+
path = getattr(credentials, "path", None) or ":memory:"
|
|
150
|
+
warehouse = "memory:/dbt" if path in (":memory:", "") else path
|
|
151
|
+
cls._session = benostreamdb.Session(warehouse=warehouse)
|
|
152
|
+
# Pin the GPU device for the embedded engine (profile `gpu_device`).
|
|
153
|
+
gpu_device = getattr(credentials, "gpu_device", None)
|
|
154
|
+
if gpu_device:
|
|
155
|
+
try:
|
|
156
|
+
resolved = benostreamdb.set_gpu_device(gpu_device)
|
|
157
|
+
logger.debug(f"GPU device set to {resolved}")
|
|
158
|
+
except Exception as e:
|
|
159
|
+
logger.warning(f"Could not set GPU device '{gpu_device}': {e}")
|
|
160
|
+
return cls._session
|
|
161
|
+
|
|
162
|
+
@classmethod
|
|
163
|
+
def open(cls, connection: Connection) -> Connection:
|
|
164
|
+
if connection.state == "open":
|
|
165
|
+
logger.debug("Connection is already open, skipping open.")
|
|
166
|
+
return connection
|
|
167
|
+
|
|
168
|
+
credentials = connection.credentials
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
session = cls.get_session(credentials)
|
|
172
|
+
connection.handle = BenoStreamDBConnectionWrapper(session)
|
|
173
|
+
connection.state = "open"
|
|
174
|
+
except Exception as e:
|
|
175
|
+
logger.error(f"Error initializing BenoStreamDB embedded engine: {e}")
|
|
176
|
+
connection.handle = None
|
|
177
|
+
connection.state = "fail"
|
|
178
|
+
raise DbtRuntimeError(f"Failed to connect to BenoStreamDB: {e}")
|
|
179
|
+
|
|
180
|
+
return connection
|
|
181
|
+
|
|
182
|
+
@classmethod
|
|
183
|
+
def get_response(cls, cursor: Any) -> AdapterResponse:
|
|
184
|
+
return AdapterResponse(_message="OK")
|
|
185
|
+
|
|
186
|
+
def cancel(self, connection: Connection):
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
def begin(self):
|
|
190
|
+
pass
|
|
191
|
+
|
|
192
|
+
def commit(self):
|
|
193
|
+
pass
|
|
194
|
+
|
|
195
|
+
def clear_transaction(self):
|
|
196
|
+
pass
|
|
197
|
+
|
|
198
|
+
@contextmanager
|
|
199
|
+
def exception_handler(self, sql: str):
|
|
200
|
+
try:
|
|
201
|
+
yield
|
|
202
|
+
except Exception as e:
|
|
203
|
+
logger.error(f"Error running SQL: {sql}")
|
|
204
|
+
logger.error(f"Exception: {e}")
|
|
205
|
+
raise DbtRuntimeError(str(e))
|
|
206
|
+
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Portions of this code were inspired by fal-ai/dbt-datafusion
|
|
2
|
+
# Copyright (c) 2022 fal-ai
|
|
3
|
+
# Licensed under the MIT License (or corresponding open source license)
|
|
4
|
+
|
|
5
|
+
from typing import Optional, List, Any
|
|
6
|
+
|
|
7
|
+
from dbt.adapters.base.relation import BaseRelation, RelationType
|
|
8
|
+
from dbt.adapters.sql import SQLAdapter
|
|
9
|
+
from dbt.adapters.events.logging import AdapterLogger
|
|
10
|
+
import dbt.exceptions
|
|
11
|
+
import pandas as pd
|
|
12
|
+
|
|
13
|
+
from .connections import BenoStreamDBConnectionManager
|
|
14
|
+
|
|
15
|
+
logger = AdapterLogger("BenoStreamDB")
|
|
16
|
+
|
|
17
|
+
class BenoStreamDBAdapter(SQLAdapter):
|
|
18
|
+
ConnectionManager = BenoStreamDBConnectionManager
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def date_function(cls):
|
|
22
|
+
return "datenow()"
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def is_cancelable(cls) -> bool:
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
def convert_boolean_type(self, column=None):
|
|
29
|
+
return "boolean"
|
|
30
|
+
|
|
31
|
+
def convert_date_type(self, column=None):
|
|
32
|
+
return "date"
|
|
33
|
+
|
|
34
|
+
def convert_datetime_type(self, column=None):
|
|
35
|
+
raise dbt.exceptions.NotImplementedException(
|
|
36
|
+
"`datetime` is not implemented for this adapter!"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def convert_number_type(self, column=None):
|
|
40
|
+
return "double"
|
|
41
|
+
|
|
42
|
+
def convert_text_type(self, column=None):
|
|
43
|
+
return "string"
|
|
44
|
+
|
|
45
|
+
def convert_time_type(self, column=None):
|
|
46
|
+
return "time"
|
|
47
|
+
|
|
48
|
+
def debug_query(self) -> None:
|
|
49
|
+
self.execute("SELECT 1 as id")
|
|
50
|
+
|
|
51
|
+
# Datafusion / Flight SQL currently prefers standard unquoted or double-quoted identifiers
|
|
52
|
+
def quote(self, identifier: str) -> str:
|
|
53
|
+
return f'"{identifier}"'
|
|
54
|
+
|
|
55
|
+
def list_schemas(self, database: str) -> List[str]:
|
|
56
|
+
# Using standard information schema to fetch schemas
|
|
57
|
+
# DataFusion natively supports information_schema.schemata
|
|
58
|
+
try:
|
|
59
|
+
_, results = self.execute(
|
|
60
|
+
f"SELECT schema_name FROM information_schema.schemata",
|
|
61
|
+
fetch=True
|
|
62
|
+
)
|
|
63
|
+
return [row[0] for row in results]
|
|
64
|
+
except Exception as e:
|
|
65
|
+
logger.error(f"Failed to list schemas: {e}")
|
|
66
|
+
return ["public"]
|
|
67
|
+
|
|
68
|
+
def list_relations_without_caching(
|
|
69
|
+
self, schema_relation: BaseRelation
|
|
70
|
+
) -> List[BaseRelation]:
|
|
71
|
+
schema = schema_relation.schema
|
|
72
|
+
if not schema:
|
|
73
|
+
schema = "public"
|
|
74
|
+
|
|
75
|
+
sql = f"""
|
|
76
|
+
SELECT table_name, table_type
|
|
77
|
+
FROM information_schema.tables
|
|
78
|
+
WHERE table_schema = '{schema}'
|
|
79
|
+
"""
|
|
80
|
+
try:
|
|
81
|
+
_, results = self.execute(sql, fetch=True)
|
|
82
|
+
relations = []
|
|
83
|
+
for row in results:
|
|
84
|
+
table_name = row[0]
|
|
85
|
+
table_type = row[1]
|
|
86
|
+
|
|
87
|
+
rel_type = RelationType.Table if "TABLE" in table_type else RelationType.View
|
|
88
|
+
relations.append(self.Relation.create(
|
|
89
|
+
database=schema_relation.database,
|
|
90
|
+
schema=schema,
|
|
91
|
+
identifier=table_name,
|
|
92
|
+
type=rel_type
|
|
93
|
+
))
|
|
94
|
+
return relations
|
|
95
|
+
except Exception as e:
|
|
96
|
+
logger.error(f"Failed to list relations: {e}")
|
|
97
|
+
return []
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{% macro benostreamdb__create_table_as(temporary, relation, sql) -%}
|
|
2
|
+
{%- set sql_header = config.get('sql_header', none) -%}
|
|
3
|
+
{%- set partition_by = config.get('partition_by') -%}
|
|
4
|
+
{%- if partition_by is none -%}
|
|
5
|
+
{%- set partition_by = config.get('partitioned_by') -%}
|
|
6
|
+
{%- endif -%}
|
|
7
|
+
|
|
8
|
+
{{ sql_header if sql_header is not none }}
|
|
9
|
+
|
|
10
|
+
create table {{ relation }}
|
|
11
|
+
{% if partition_by %}
|
|
12
|
+
{% if partition_by is string %}
|
|
13
|
+
PARTITIONED BY ({{ partition_by }})
|
|
14
|
+
{% else %}
|
|
15
|
+
PARTITIONED BY ({{ partition_by | join(', ') }})
|
|
16
|
+
{% endif %}
|
|
17
|
+
{% endif %}
|
|
18
|
+
as (
|
|
19
|
+
{{ sql }}
|
|
20
|
+
);
|
|
21
|
+
{%- endmacro %}
|
|
22
|
+
|
|
23
|
+
{% macro benostreamdb__create_view_as(relation, sql) -%}
|
|
24
|
+
{%- set sql_header = config.get('sql_header', none) -%}
|
|
25
|
+
|
|
26
|
+
{{ sql_header if sql_header is not none }}
|
|
27
|
+
|
|
28
|
+
create view {{ relation }} as (
|
|
29
|
+
{{ sql }}
|
|
30
|
+
);
|
|
31
|
+
{%- endmacro %}
|
|
32
|
+
|
|
33
|
+
{% macro benostreamdb__drop_relation(relation) -%}
|
|
34
|
+
{% call statement('drop_relation', auto_begin=False) -%}
|
|
35
|
+
drop {{ relation.type or 'table' }} if exists {{ relation }}
|
|
36
|
+
{%- endcall %}
|
|
37
|
+
{% endmacro %}
|
|
38
|
+
|
|
39
|
+
{% macro benostreamdb__rename_relation(from_relation, to_relation) -%}
|
|
40
|
+
{% call statement('rename_relation') -%}
|
|
41
|
+
alter {{ from_relation.type }} {{ from_relation }} rename to {{ to_relation }}
|
|
42
|
+
{%- endcall %}
|
|
43
|
+
{% endmacro %}
|
|
44
|
+
|
|
45
|
+
{% macro benostreamdb__create_schema(relation) -%}
|
|
46
|
+
{%- call statement('create_schema') -%}
|
|
47
|
+
create schema if not exists {{ relation.without_identifier().include(database=False) }}
|
|
48
|
+
{%- endcall -%}
|
|
49
|
+
{% endmacro %}
|
|
50
|
+
|
|
51
|
+
{% macro benostreamdb__drop_schema(relation) -%}
|
|
52
|
+
{%- call statement('drop_schema') -%}
|
|
53
|
+
drop schema if exists {{ relation.without_identifier().include(database=False) }}
|
|
54
|
+
{%- endcall -%}
|
|
55
|
+
{% endmacro %}
|
|
56
|
+
|
|
57
|
+
{% macro benostreamdb__check_schema_exists(information_schema, schema) -%}
|
|
58
|
+
{% call statement('check_schema_exists', fetch_result=True, auto_begin=False) %}
|
|
59
|
+
select count(*)
|
|
60
|
+
from information_schema.schemata
|
|
61
|
+
where schema_name = '{{ schema }}'
|
|
62
|
+
{% endcall %}
|
|
63
|
+
{{ return(load_result('check_schema_exists').table) }}
|
|
64
|
+
{% endmacro %}
|
|
65
|
+
|
|
66
|
+
{% macro benostreamdb__get_columns_in_relation(relation) -%}
|
|
67
|
+
{% call statement('get_columns_in_relation', fetch_result=True) %}
|
|
68
|
+
select
|
|
69
|
+
column_name,
|
|
70
|
+
data_type,
|
|
71
|
+
character_maximum_length,
|
|
72
|
+
numeric_precision,
|
|
73
|
+
numeric_scale
|
|
74
|
+
from information_schema.columns
|
|
75
|
+
where table_name = '{{ relation.identifier }}'
|
|
76
|
+
{% if relation.schema %}
|
|
77
|
+
and table_schema = '{{ relation.schema }}'
|
|
78
|
+
{% endif %}
|
|
79
|
+
order by ordinal_position
|
|
80
|
+
{% endcall %}
|
|
81
|
+
{% set table = load_result('get_columns_in_relation').table %}
|
|
82
|
+
{{ return(sql_convert_columns_in_relation(table)) }}
|
|
83
|
+
{% endmacro %}
|
|
84
|
+
|
|
85
|
+
{% macro benostreamdb__get_create_index_sql(relation, index_dict) -%}
|
|
86
|
+
{%- set index_columns = index_dict.get('columns', []) -%}
|
|
87
|
+
{%- set index_name = index_dict.get('name', relation.identifier ~ '_' ~ index_columns | join('_') ~ '_idx') -%}
|
|
88
|
+
{{ log("BenoStreamDB manages indices natively; skipping CREATE INDEX for " ~ index_name, info=True) }}
|
|
89
|
+
{% do return(None) %}
|
|
90
|
+
{%- endmacro %}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- BenoStreamDB dbt DDL Macros
|
|
3
|
+
-- Index lifecycle (CREATE INDEX / DROP INDEX) over Apache Iceberg tables.
|
|
4
|
+
--
|
|
5
|
+
-- The engine intercepts these statements before DataFusion planning and
|
|
6
|
+
-- dispatches them to the core `Table` API, so they work from any dbt model or
|
|
7
|
+
-- hook. `type` is one of the engine's index algorithms (hnsw, hnsw_pq,
|
|
8
|
+
-- hnsw_tq4, hnsw_tq8, bm25, bloom, bitmap, composite_bitmap, csr_graph,
|
|
9
|
+
-- json_path).
|
|
10
|
+
-- =============================================================================
|
|
11
|
+
|
|
12
|
+
{% macro create_index(relation, column, type='bitmap', name=none) -%}
|
|
13
|
+
{{ return(adapter.dispatch('create_index', 'dbt')(relation, column, type, name)) }}
|
|
14
|
+
{%- endmacro %}
|
|
15
|
+
|
|
16
|
+
{% macro default__create_index(relation, column, type='bitmap', name=none) -%}
|
|
17
|
+
{{ exceptions.raise_compiler_error("create_index is not supported on this adapter") }}
|
|
18
|
+
{%- endmacro %}
|
|
19
|
+
|
|
20
|
+
{% macro benostreamdb__create_index(relation, column, type='bitmap', name=none) -%}
|
|
21
|
+
{%- set idx_name = name if name is not none else relation.identifier ~ '_' ~ column ~ '_idx' -%}
|
|
22
|
+
create index {{ idx_name }} on {{ relation }} ({{ column }}) using {{ type }}
|
|
23
|
+
{%- endmacro %}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
{% macro drop_index(relation, name) -%}
|
|
27
|
+
{{ return(adapter.dispatch('drop_index', 'dbt')(relation, name)) }}
|
|
28
|
+
{%- endmacro %}
|
|
29
|
+
|
|
30
|
+
{% macro default__drop_index(relation, name) -%}
|
|
31
|
+
{{ exceptions.raise_compiler_error("drop_index is not supported on this adapter") }}
|
|
32
|
+
{%- endmacro %}
|
|
33
|
+
|
|
34
|
+
{% macro benostreamdb__drop_index(relation, name) -%}
|
|
35
|
+
alter table {{ relation }} drop index {{ name }}
|
|
36
|
+
{%- endmacro %}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
{% macro add_primary_key(relation, columns) -%}
|
|
40
|
+
{{ return(adapter.dispatch('add_primary_key', 'dbt')(relation, columns)) }}
|
|
41
|
+
{%- endmacro %}
|
|
42
|
+
|
|
43
|
+
{% macro default__add_primary_key(relation, columns) -%}
|
|
44
|
+
{{ exceptions.raise_compiler_error("add_primary_key is not supported on this adapter") }}
|
|
45
|
+
{%- endmacro %}
|
|
46
|
+
|
|
47
|
+
{% macro benostreamdb__add_primary_key(relation, columns) -%}
|
|
48
|
+
{%- set cols = columns if columns is string else columns | join(', ') -%}
|
|
49
|
+
alter table {{ relation }} add primary key ({{ cols }})
|
|
50
|
+
{%- endmacro %}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
{% macro drop_primary_key(relation) -%}
|
|
54
|
+
{{ return(adapter.dispatch('drop_primary_key', 'dbt')(relation)) }}
|
|
55
|
+
{%- endmacro %}
|
|
56
|
+
|
|
57
|
+
{% macro default__drop_primary_key(relation) -%}
|
|
58
|
+
{{ exceptions.raise_compiler_error("drop_primary_key is not supported on this adapter") }}
|
|
59
|
+
{%- endmacro %}
|
|
60
|
+
|
|
61
|
+
{% macro benostreamdb__drop_primary_key(relation) -%}
|
|
62
|
+
alter table {{ relation }} drop primary key
|
|
63
|
+
{%- endmacro %}
|