ob-postgres 0.1.0__py3-none-any.whl
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_postgres/__init__.py +157 -0
- ob_postgres/compiler.py +8 -0
- ob_postgres/connection.py +65 -0
- ob_postgres/cursor.py +158 -0
- ob_postgres/exceptions.py +32 -0
- ob_postgres/type_codes.py +45 -0
- ob_postgres-0.1.0.dist-info/METADATA +37 -0
- ob_postgres-0.1.0.dist-info/RECORD +11 -0
- ob_postgres-0.1.0.dist-info/WHEEL +4 -0
- ob_postgres-0.1.0.dist-info/entry_points.txt +2 -0
- ob_postgres-0.1.0.dist-info/licenses/LICENSE +70 -0
ob_postgres/__init__.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""ob-postgres — OrionBelt Semantic Layer driver for PostgreSQL (PEP 249 DB-API 2.0).
|
|
2
|
+
|
|
3
|
+
Uses ``adbc-driver-postgresql`` for native Arrow support. ADBC provides
|
|
4
|
+
zero-copy Arrow results directly from the PostgreSQL wire protocol, enabling
|
|
5
|
+
efficient Arrow Flight SQL streaming.
|
|
6
|
+
|
|
7
|
+
Requires the OrionBelt REST API running in single-model mode (MODEL_FILE set).
|
|
8
|
+
OBML queries are compiled to SQL via ``POST /v1/query/sql``.
|
|
9
|
+
|
|
10
|
+
Usage::
|
|
11
|
+
|
|
12
|
+
import ob_postgres
|
|
13
|
+
|
|
14
|
+
conn = ob_postgres.connect(dbname="mydb", user="me", password="secret")
|
|
15
|
+
with conn.cursor() as cur:
|
|
16
|
+
cur.execute("select:\\n dimensions:\\n - Region\\n measures:\\n - Revenue")
|
|
17
|
+
print(cur.fetchall())
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import Any
|
|
23
|
+
from urllib.parse import quote_plus, urlencode
|
|
24
|
+
|
|
25
|
+
import adbc_driver_postgresql.dbapi
|
|
26
|
+
|
|
27
|
+
from ob_postgres.connection import Connection
|
|
28
|
+
from ob_postgres.exceptions import (
|
|
29
|
+
DatabaseError,
|
|
30
|
+
DataError,
|
|
31
|
+
Error,
|
|
32
|
+
IntegrityError,
|
|
33
|
+
InterfaceError,
|
|
34
|
+
InternalError,
|
|
35
|
+
NotSupportedError,
|
|
36
|
+
OperationalError,
|
|
37
|
+
ProgrammingError,
|
|
38
|
+
Warning,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# PEP 249 module-level constants
|
|
42
|
+
apilevel = "2.0"
|
|
43
|
+
threadsafety = 1 # threads may share the module but not connections
|
|
44
|
+
paramstyle = "qmark" # ADBC uses ? placeholders
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _build_pg_uri(
|
|
48
|
+
*,
|
|
49
|
+
host: str,
|
|
50
|
+
port: int,
|
|
51
|
+
dbname: str,
|
|
52
|
+
user: str | None,
|
|
53
|
+
password: str | None,
|
|
54
|
+
sslmode: str | None,
|
|
55
|
+
) -> str:
|
|
56
|
+
"""Build a PostgreSQL connection URI from keyword arguments."""
|
|
57
|
+
userinfo = ""
|
|
58
|
+
if user is not None:
|
|
59
|
+
userinfo = quote_plus(user)
|
|
60
|
+
if password is not None:
|
|
61
|
+
userinfo += f":{quote_plus(password)}"
|
|
62
|
+
userinfo += "@"
|
|
63
|
+
params: dict[str, str] = {}
|
|
64
|
+
if sslmode is not None:
|
|
65
|
+
params["sslmode"] = sslmode
|
|
66
|
+
query = f"?{urlencode(params)}" if params else ""
|
|
67
|
+
return f"postgresql://{userinfo}{host}:{port}/{dbname}{query}"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def connect(
|
|
71
|
+
dsn: str | None = None,
|
|
72
|
+
*,
|
|
73
|
+
host: str = "localhost",
|
|
74
|
+
port: int = 5432,
|
|
75
|
+
dbname: str = "postgres",
|
|
76
|
+
user: str | None = None,
|
|
77
|
+
password: str | None = None,
|
|
78
|
+
sslmode: str | None = None,
|
|
79
|
+
schema: str | None = None,
|
|
80
|
+
options: dict[str, Any] | None = None,
|
|
81
|
+
# OrionBelt parameters
|
|
82
|
+
ob_api_url: str = "http://localhost:8000",
|
|
83
|
+
ob_timeout: int = 30,
|
|
84
|
+
) -> Connection:
|
|
85
|
+
"""Open a PostgreSQL connection with OBML support (ADBC driver).
|
|
86
|
+
|
|
87
|
+
Parameters
|
|
88
|
+
----------
|
|
89
|
+
dsn : str, optional
|
|
90
|
+
Full PostgreSQL URI (overrides individual params).
|
|
91
|
+
host : str
|
|
92
|
+
PostgreSQL host (default: ``localhost``).
|
|
93
|
+
port : int
|
|
94
|
+
PostgreSQL port (default: ``5432``).
|
|
95
|
+
dbname : str
|
|
96
|
+
Database name (default: ``postgres``).
|
|
97
|
+
user : str, optional
|
|
98
|
+
Username.
|
|
99
|
+
password : str, optional
|
|
100
|
+
Password.
|
|
101
|
+
sslmode : str, optional
|
|
102
|
+
SSL mode (``disable``, ``require``, ``verify-full``, etc.).
|
|
103
|
+
schema : str, optional
|
|
104
|
+
PostgreSQL schema — sets ``search_path`` after connecting.
|
|
105
|
+
options : dict, optional
|
|
106
|
+
Extra connection options (added as URI query parameters).
|
|
107
|
+
ob_api_url : str
|
|
108
|
+
OrionBelt REST API URL (must be running in single-model mode).
|
|
109
|
+
ob_timeout : int
|
|
110
|
+
HTTP timeout in seconds for OBML compilation.
|
|
111
|
+
"""
|
|
112
|
+
if dsn is not None:
|
|
113
|
+
uri = dsn
|
|
114
|
+
else:
|
|
115
|
+
# Include search_path as a connection option if schema is specified
|
|
116
|
+
extra_options = dict(options) if options else {}
|
|
117
|
+
if schema:
|
|
118
|
+
extra_options["options"] = f"-csearch_path={schema}"
|
|
119
|
+
|
|
120
|
+
uri = _build_pg_uri(
|
|
121
|
+
host=host,
|
|
122
|
+
port=port,
|
|
123
|
+
dbname=dbname,
|
|
124
|
+
user=user,
|
|
125
|
+
password=password,
|
|
126
|
+
sslmode=sslmode,
|
|
127
|
+
)
|
|
128
|
+
if extra_options:
|
|
129
|
+
sep = "&" if "?" in uri else "?"
|
|
130
|
+
uri += sep + urlencode(extra_options)
|
|
131
|
+
|
|
132
|
+
native = adbc_driver_postgresql.dbapi.connect(uri)
|
|
133
|
+
|
|
134
|
+
return Connection(
|
|
135
|
+
native,
|
|
136
|
+
ob_api_url=ob_api_url,
|
|
137
|
+
ob_timeout=ob_timeout,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
__all__ = [
|
|
142
|
+
"apilevel",
|
|
143
|
+
"threadsafety",
|
|
144
|
+
"paramstyle",
|
|
145
|
+
"connect",
|
|
146
|
+
"Connection",
|
|
147
|
+
"Warning",
|
|
148
|
+
"Error",
|
|
149
|
+
"InterfaceError",
|
|
150
|
+
"DatabaseError",
|
|
151
|
+
"DataError",
|
|
152
|
+
"OperationalError",
|
|
153
|
+
"IntegrityError",
|
|
154
|
+
"InternalError",
|
|
155
|
+
"ProgrammingError",
|
|
156
|
+
"NotSupportedError",
|
|
157
|
+
]
|
ob_postgres/compiler.py
ADDED
|
@@ -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,65 @@
|
|
|
1
|
+
"""PEP 249 Connection wrapping ``adbc_driver_postgresql.dbapi.Connection``."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ob_postgres.cursor import Cursor
|
|
8
|
+
from ob_postgres.exceptions import ProgrammingError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Connection:
|
|
12
|
+
"""DB-API 2.0 connection that wraps an ADBC PostgreSQL connection.
|
|
13
|
+
|
|
14
|
+
ADBC provides native Arrow support — cursors created from this connection
|
|
15
|
+
support ``fetch_arrow_table()`` for zero-copy Arrow Flight SQL streaming.
|
|
16
|
+
OBML queries are compiled to SQL via the OrionBelt REST API.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
native: Any,
|
|
22
|
+
*,
|
|
23
|
+
ob_api_url: str = "http://localhost:8000",
|
|
24
|
+
ob_timeout: int = 30,
|
|
25
|
+
) -> None:
|
|
26
|
+
self._native = native
|
|
27
|
+
self._closed = False
|
|
28
|
+
self._ob_api_url = ob_api_url
|
|
29
|
+
self._ob_timeout = ob_timeout
|
|
30
|
+
|
|
31
|
+
def _check_open(self) -> None:
|
|
32
|
+
if self._closed:
|
|
33
|
+
raise ProgrammingError("Connection is closed.")
|
|
34
|
+
|
|
35
|
+
def cursor(self) -> Cursor:
|
|
36
|
+
"""Return a new Cursor for this connection."""
|
|
37
|
+
self._check_open()
|
|
38
|
+
native_cursor = self._native.cursor()
|
|
39
|
+
return Cursor(
|
|
40
|
+
native_cursor,
|
|
41
|
+
ob_api_url=self._ob_api_url,
|
|
42
|
+
ob_timeout=self._ob_timeout,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def commit(self) -> None:
|
|
46
|
+
"""Commit the current transaction."""
|
|
47
|
+
self._check_open()
|
|
48
|
+
self._native.commit()
|
|
49
|
+
|
|
50
|
+
def rollback(self) -> None:
|
|
51
|
+
"""Rollback the current transaction."""
|
|
52
|
+
self._check_open()
|
|
53
|
+
self._native.rollback()
|
|
54
|
+
|
|
55
|
+
def close(self) -> None:
|
|
56
|
+
"""Close the connection."""
|
|
57
|
+
if not self._closed:
|
|
58
|
+
self._native.close()
|
|
59
|
+
self._closed = True
|
|
60
|
+
|
|
61
|
+
def __enter__(self) -> Connection:
|
|
62
|
+
return self
|
|
63
|
+
|
|
64
|
+
def __exit__(self, *exc: object) -> None:
|
|
65
|
+
self.close()
|
ob_postgres/cursor.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""PEP 249 Cursor with OBML interception for PostgreSQL.
|
|
2
|
+
|
|
3
|
+
Uses ``adbc-driver-postgresql`` (Arrow Database Connectivity) for native
|
|
4
|
+
Arrow support. ``fetch_arrow_table()`` returns a PyArrow Table directly
|
|
5
|
+
from the ADBC cursor — zero-copy columnar transfer for Arrow Flight SQL.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from ob_postgres.compiler import compile_obml, is_obml, parse_obml
|
|
13
|
+
from ob_postgres.exceptions import NotSupportedError, ProgrammingError
|
|
14
|
+
from ob_postgres.type_codes import PG_OID_MAP, STRING
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Cursor:
|
|
18
|
+
"""DB-API 2.0 cursor that intercepts OBML YAML queries.
|
|
19
|
+
|
|
20
|
+
If the query is OBML, it is compiled to PostgreSQL SQL via the OrionBelt
|
|
21
|
+
REST API before execution. Plain SQL is passed through unchanged.
|
|
22
|
+
|
|
23
|
+
Wraps an ``adbc_driver_postgresql.dbapi`` cursor which natively supports
|
|
24
|
+
``fetch_arrow_table()`` for zero-copy Arrow results.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
arraysize: int = 1
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
native: Any,
|
|
32
|
+
*,
|
|
33
|
+
ob_api_url: str = "http://localhost:8000",
|
|
34
|
+
ob_timeout: int = 30,
|
|
35
|
+
) -> None:
|
|
36
|
+
self._native = native
|
|
37
|
+
self._closed = False
|
|
38
|
+
self._ob_api_url = ob_api_url
|
|
39
|
+
self._ob_timeout = ob_timeout
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def description(
|
|
43
|
+
self,
|
|
44
|
+
) -> tuple[tuple[str, Any, None, None, None, None, None], ...] | None:
|
|
45
|
+
"""PEP 249 cursor description — 7-item tuples per column."""
|
|
46
|
+
native_desc = self._native.description
|
|
47
|
+
if native_desc is None:
|
|
48
|
+
return None
|
|
49
|
+
cols: list[tuple[str, Any, None, None, None, None, None]] = []
|
|
50
|
+
for col in native_desc:
|
|
51
|
+
name = col[0]
|
|
52
|
+
type_code = col[1]
|
|
53
|
+
# ADBC PG driver may return OIDs or other type identifiers
|
|
54
|
+
mapped = PG_OID_MAP.get(type_code, STRING) if isinstance(type_code, int) else STRING
|
|
55
|
+
cols.append((name, mapped, None, None, None, None, None))
|
|
56
|
+
return tuple(cols)
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def rowcount(self) -> int:
|
|
60
|
+
return self._native.rowcount
|
|
61
|
+
|
|
62
|
+
def _check_open(self) -> None:
|
|
63
|
+
if self._closed:
|
|
64
|
+
raise ProgrammingError("Cursor is closed.")
|
|
65
|
+
|
|
66
|
+
def execute(self, operation: str, parameters: Any = None) -> Cursor:
|
|
67
|
+
"""Execute a query — OBML YAML or plain SQL."""
|
|
68
|
+
self._check_open()
|
|
69
|
+
sql = self._resolve_sql(operation)
|
|
70
|
+
if parameters is not None:
|
|
71
|
+
self._native.execute(sql, parameters)
|
|
72
|
+
else:
|
|
73
|
+
self._native.execute(sql)
|
|
74
|
+
return self
|
|
75
|
+
|
|
76
|
+
def executemany(self, operation: str, seq_of_parameters: Any) -> None:
|
|
77
|
+
"""Execute against all parameter sequences.
|
|
78
|
+
|
|
79
|
+
OBML queries are not supported with executemany — raises NotSupportedError.
|
|
80
|
+
"""
|
|
81
|
+
self._check_open()
|
|
82
|
+
if is_obml(operation):
|
|
83
|
+
raise NotSupportedError("executemany() is not supported for OBML queries.")
|
|
84
|
+
for params in seq_of_parameters:
|
|
85
|
+
self._native.execute(operation, params)
|
|
86
|
+
|
|
87
|
+
def _resolve_sql(self, operation: str) -> str:
|
|
88
|
+
"""Compile OBML to SQL or return plain SQL unchanged."""
|
|
89
|
+
if not is_obml(operation):
|
|
90
|
+
return operation
|
|
91
|
+
obml = parse_obml(operation)
|
|
92
|
+
return compile_obml(
|
|
93
|
+
obml,
|
|
94
|
+
dialect="postgres",
|
|
95
|
+
ob_api_url=self._ob_api_url,
|
|
96
|
+
ob_timeout=self._ob_timeout,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
def fetchone(self) -> tuple[Any, ...] | None:
|
|
100
|
+
"""Fetch the next row."""
|
|
101
|
+
self._check_open()
|
|
102
|
+
row = self._native.fetchone()
|
|
103
|
+
return tuple(row) if row is not None else None
|
|
104
|
+
|
|
105
|
+
def fetchmany(self, size: int | None = None) -> list[tuple[Any, ...]]:
|
|
106
|
+
"""Fetch the next *size* rows."""
|
|
107
|
+
self._check_open()
|
|
108
|
+
n = size if size is not None else self.arraysize
|
|
109
|
+
rows = self._native.fetchmany(n)
|
|
110
|
+
return [tuple(r) for r in rows]
|
|
111
|
+
|
|
112
|
+
def fetchall(self) -> list[tuple[Any, ...]]:
|
|
113
|
+
"""Fetch all remaining rows."""
|
|
114
|
+
self._check_open()
|
|
115
|
+
rows = self._native.fetchall()
|
|
116
|
+
return [tuple(r) for r in rows]
|
|
117
|
+
|
|
118
|
+
def fetch_arrow_table(self) -> Any:
|
|
119
|
+
"""Fetch all remaining rows as a PyArrow Table (ADBC native).
|
|
120
|
+
|
|
121
|
+
ADBC provides zero-copy Arrow results directly from the PostgreSQL
|
|
122
|
+
wire protocol. Significantly more memory-efficient than materialising
|
|
123
|
+
Python row objects and enables efficient Arrow Flight SQL streaming.
|
|
124
|
+
"""
|
|
125
|
+
self._check_open()
|
|
126
|
+
return self._native.fetch_arrow_table()
|
|
127
|
+
|
|
128
|
+
def close(self) -> None:
|
|
129
|
+
"""Close the cursor."""
|
|
130
|
+
if not self._closed:
|
|
131
|
+
self._native.close()
|
|
132
|
+
self._closed = True
|
|
133
|
+
|
|
134
|
+
def setinputsizes(self, sizes: Any) -> None:
|
|
135
|
+
"""No-op — required by PEP 249."""
|
|
136
|
+
|
|
137
|
+
def setoutputsize(self, size: int, column: int | None = None) -> None:
|
|
138
|
+
"""No-op — required by PEP 249."""
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def lastrowid(self) -> None:
|
|
142
|
+
"""PostgreSQL does not expose lastrowid via ADBC cursor."""
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
def __enter__(self) -> Cursor:
|
|
146
|
+
return self
|
|
147
|
+
|
|
148
|
+
def __exit__(self, *exc: object) -> None:
|
|
149
|
+
self.close()
|
|
150
|
+
|
|
151
|
+
def __iter__(self) -> Cursor:
|
|
152
|
+
return self
|
|
153
|
+
|
|
154
|
+
def __next__(self) -> tuple[Any, ...]:
|
|
155
|
+
row = self.fetchone()
|
|
156
|
+
if row is None:
|
|
157
|
+
raise StopIteration
|
|
158
|
+
return row
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""PEP 249 exceptions — re-exported from ob-driver-core for convenience.
|
|
2
|
+
|
|
3
|
+
Allows users to do: ``from ob_postgres.exceptions import ProgrammingError``
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from ob_driver_core.exceptions import (
|
|
9
|
+
DataError,
|
|
10
|
+
DatabaseError,
|
|
11
|
+
Error,
|
|
12
|
+
IntegrityError,
|
|
13
|
+
InterfaceError,
|
|
14
|
+
InternalError,
|
|
15
|
+
NotSupportedError,
|
|
16
|
+
OperationalError,
|
|
17
|
+
ProgrammingError,
|
|
18
|
+
Warning,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"Warning",
|
|
23
|
+
"Error",
|
|
24
|
+
"InterfaceError",
|
|
25
|
+
"DatabaseError",
|
|
26
|
+
"DataError",
|
|
27
|
+
"OperationalError",
|
|
28
|
+
"IntegrityError",
|
|
29
|
+
"InternalError",
|
|
30
|
+
"ProgrammingError",
|
|
31
|
+
"NotSupportedError",
|
|
32
|
+
]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""PEP 249 type objects — re-exported from ob-driver-core plus Postgres OID mapping.
|
|
2
|
+
|
|
3
|
+
psycopg2 cursor.description returns integer OIDs as type_code.
|
|
4
|
+
The PG_OID_MAP maps common OIDs to PEP 249 type objects.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from ob_driver_core.type_codes import BINARY, DATETIME, NUMBER, ROWID, STRING
|
|
10
|
+
|
|
11
|
+
__all__ = ["STRING", "BINARY", "NUMBER", "DATETIME", "ROWID", "PG_OID_MAP"]
|
|
12
|
+
|
|
13
|
+
# Common PostgreSQL OIDs — see pg_type catalog
|
|
14
|
+
# https://www.postgresql.org/docs/current/catalog-pg-type.html
|
|
15
|
+
PG_OID_MAP: dict[int, object] = {
|
|
16
|
+
# Boolean
|
|
17
|
+
16: STRING, # bool
|
|
18
|
+
# Numeric types
|
|
19
|
+
20: NUMBER, # int8 (bigint)
|
|
20
|
+
21: NUMBER, # int2 (smallint)
|
|
21
|
+
23: NUMBER, # int4 (integer)
|
|
22
|
+
26: NUMBER, # oid
|
|
23
|
+
700: NUMBER, # float4
|
|
24
|
+
701: NUMBER, # float8
|
|
25
|
+
790: NUMBER, # money
|
|
26
|
+
1700: NUMBER, # numeric/decimal
|
|
27
|
+
# String types
|
|
28
|
+
18: STRING, # char
|
|
29
|
+
19: STRING, # name
|
|
30
|
+
25: STRING, # text
|
|
31
|
+
1042: STRING, # bpchar (char(n))
|
|
32
|
+
1043: STRING, # varchar
|
|
33
|
+
2950: STRING, # uuid
|
|
34
|
+
114: STRING, # json
|
|
35
|
+
3802: STRING, # jsonb
|
|
36
|
+
# Date/time types
|
|
37
|
+
1082: DATETIME, # date
|
|
38
|
+
1083: DATETIME, # time
|
|
39
|
+
1114: DATETIME, # timestamp
|
|
40
|
+
1184: DATETIME, # timestamptz
|
|
41
|
+
1186: DATETIME, # interval
|
|
42
|
+
1266: DATETIME, # timetz
|
|
43
|
+
# Binary types
|
|
44
|
+
17: BINARY, # bytea
|
|
45
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ob-postgres
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: OrionBelt Semantic Layer driver for PostgreSQL (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,obml,orionbelt,postgres,semantic-layer
|
|
9
|
+
Requires-Python: >=3.12
|
|
10
|
+
Requires-Dist: adbc-driver-postgresql>=1.0
|
|
11
|
+
Requires-Dist: ob-driver-core>=0.1
|
|
12
|
+
Requires-Dist: pyarrow>=16.0
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
15
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
17
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
18
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
19
|
+
Provides-Extra: sqlalchemy
|
|
20
|
+
Requires-Dist: sqlalchemy>=2.0; extra == 'sqlalchemy'
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# ob-postgres
|
|
24
|
+
|
|
25
|
+
OrionBelt Semantic Layer driver for PostgreSQL (DB-API 2.0)
|
|
26
|
+
|
|
27
|
+
Part of the [OrionBelt Semantic Layer](https://github.com/ralfbecher/orionbelt-semantic-layer) project.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install ob-postgres
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## License
|
|
36
|
+
|
|
37
|
+
BSL-1.1 — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
ob_postgres/__init__.py,sha256=qtrEuq_lXWQBdUCzFIXqCUOrX2aeBPRnPf5RYeqNqX4,4295
|
|
2
|
+
ob_postgres/compiler.py,sha256=WTYZzdsJJiOxgIDS3NpDOpk_SG7_0weT4el-xuuBGsE,264
|
|
3
|
+
ob_postgres/connection.py,sha256=FV5Rt08T6RZ6jqDssIo1fHG3DJv-wJCrRhVcSBH92Fw,1835
|
|
4
|
+
ob_postgres/cursor.py,sha256=VaTQUbBVUJtNuZegfjloTX2bw9G4Z_-n9bAoUlfiCYI,5311
|
|
5
|
+
ob_postgres/exceptions.py,sha256=ijpN5kj3_faOS8jlH5FXCY1ynyX2plnJ7fqukG-81_8,638
|
|
6
|
+
ob_postgres/type_codes.py,sha256=EEsdrqmzHDo3dz1VtQ1y1c1Grw1Z2gXZQaG9vSDlUaM,1341
|
|
7
|
+
ob_postgres-0.1.0.dist-info/METADATA,sha256=qagacjqfnd5j67FGnlLBwHW_F1f-Ood_LuMHBEd7VIs,1054
|
|
8
|
+
ob_postgres-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
9
|
+
ob_postgres-0.1.0.dist-info/entry_points.txt,sha256=y2fG3zJChKHGb1X9heLZhzusl87wpiL6I4l9gJyQ3TY,74
|
|
10
|
+
ob_postgres-0.1.0.dist-info/licenses/LICENSE,sha256=t-vr73N5s2w6yxpCnwo5r_QuB5_u6FuEovAYMjlfe7E,3378
|
|
11
|
+
ob_postgres-0.1.0.dist-info/RECORD,,
|
|
@@ -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/.
|