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.
Files changed (24) hide show
  1. dbt_benostreamdb-1.8.0/PKG-INFO +54 -0
  2. dbt_benostreamdb-1.8.0/README.md +29 -0
  3. dbt_benostreamdb-1.8.0/dbt/adapters/benostreamdb/__init__.py +12 -0
  4. dbt_benostreamdb-1.8.0/dbt/adapters/benostreamdb/__version__.py +4 -0
  5. dbt_benostreamdb-1.8.0/dbt/adapters/benostreamdb/connections.py +206 -0
  6. dbt_benostreamdb-1.8.0/dbt/adapters/benostreamdb/impl.py +97 -0
  7. dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/__init__.py +3 -0
  8. dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/dbt_project.yml +5 -0
  9. dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/adapters.sql +90 -0
  10. dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/ddl.sql +63 -0
  11. dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/graph.sql +503 -0
  12. dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/json.sql +115 -0
  13. dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/materializations/incremental.sql +108 -0
  14. dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/materializations/table.sql +19 -0
  15. dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/search.sql +55 -0
  16. dbt_benostreamdb-1.8.0/dbt/include/benostreamdb/macros/vector.sql +349 -0
  17. dbt_benostreamdb-1.8.0/dbt_benostreamdb.egg-info/PKG-INFO +54 -0
  18. dbt_benostreamdb-1.8.0/dbt_benostreamdb.egg-info/SOURCES.txt +22 -0
  19. dbt_benostreamdb-1.8.0/dbt_benostreamdb.egg-info/dependency_links.txt +1 -0
  20. dbt_benostreamdb-1.8.0/dbt_benostreamdb.egg-info/requires.txt +4 -0
  21. dbt_benostreamdb-1.8.0/dbt_benostreamdb.egg-info/top_level.txt +1 -0
  22. dbt_benostreamdb-1.8.0/pyproject.toml +48 -0
  23. dbt_benostreamdb-1.8.0/setup.cfg +4 -0
  24. 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,4 @@
1
+ # dbt adapters version as `<dbt-core-major>.<minor>.<patch>` so pip can resolve
2
+ # the adapter for the installed dbt-core (e.g. 1.8.x supports dbt-core 1.8.x).
3
+ # This is independent of the BenoStreamDB engine version.
4
+ version = "1.8.0"
@@ -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,3 @@
1
+ import os
2
+
3
+ PACKAGE_PATH = os.path.dirname(__file__)
@@ -0,0 +1,5 @@
1
+ name: dbt_benostreamdb
2
+ version: 0.1.0
3
+ config-version: 2
4
+
5
+ macro-paths: ["macros"]
@@ -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 %}