sqlspec 0.9.0__tar.gz → 0.10.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.
Potentially problematic release.
This version of sqlspec might be problematic. Click here for more details.
- {sqlspec-0.9.0 → sqlspec-0.10.0}/PKG-INFO +147 -3
- {sqlspec-0.9.0 → sqlspec-0.10.0}/README.md +145 -2
- {sqlspec-0.9.0 → sqlspec-0.10.0}/pyproject.toml +3 -3
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/__init__.py +2 -1
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/adbc/__init__.py +2 -1
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/adbc/config.py +7 -13
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/adbc/driver.py +160 -21
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/aiosqlite/__init__.py +2 -1
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/aiosqlite/config.py +10 -12
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/aiosqlite/driver.py +160 -22
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/asyncmy/__init__.py +2 -1
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/asyncmy/driver.py +158 -22
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/asyncpg/config.py +1 -3
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/asyncpg/driver.py +143 -5
- sqlspec-0.10.0/sqlspec/adapters/bigquery/__init__.py +4 -0
- sqlspec-0.10.0/sqlspec/adapters/bigquery/config/__init__.py +3 -0
- sqlspec-0.10.0/sqlspec/adapters/bigquery/config/_common.py +40 -0
- sqlspec-0.10.0/sqlspec/adapters/bigquery/config/_sync.py +87 -0
- sqlspec-0.10.0/sqlspec/adapters/bigquery/driver.py +701 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/duckdb/__init__.py +2 -1
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/duckdb/config.py +17 -18
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/duckdb/driver.py +165 -27
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/oracledb/__init__.py +8 -1
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/oracledb/config/_asyncio.py +7 -8
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/oracledb/config/_sync.py +6 -7
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/oracledb/driver.py +311 -42
- sqlspec-0.10.0/sqlspec/adapters/psqlpy/__init__.py +9 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/psqlpy/config.py +11 -19
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/psqlpy/driver.py +171 -19
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/psycopg/__init__.py +8 -1
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/psycopg/config/__init__.py +10 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/psycopg/config/_async.py +6 -7
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/psycopg/config/_sync.py +7 -8
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/psycopg/driver.py +344 -86
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/sqlite/__init__.py +2 -1
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/sqlite/config.py +12 -11
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/sqlite/driver.py +160 -51
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/base.py +402 -63
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/exceptions.py +9 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/extensions/litestar/config.py +3 -11
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/extensions/litestar/handlers.py +2 -1
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/extensions/litestar/plugin.py +6 -2
- sqlspec-0.10.0/sqlspec/mixins.py +156 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/typing.py +19 -1
- sqlspec-0.10.0/tests/integration/test_adapters/test_bigquery/conftest.py +31 -0
- sqlspec-0.10.0/tests/integration/test_adapters/test_bigquery/test_connection.py +14 -0
- sqlspec-0.10.0/tests/integration/test_adapters/test_bigquery/test_driver.py +288 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_aiosqlite/test_config.py +0 -3
- {sqlspec-0.9.0 → sqlspec-0.10.0}/uv.lock +9 -7
- {sqlspec-0.9.0 → sqlspec-0.10.0}/.gitignore +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/.pre-commit-config.yaml +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/CONTRIBUTING.rst +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/LICENSE +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/Makefile +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/NOTICE +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/__metadata__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/_serialization.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/_typing.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/asyncmy/config.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/asyncpg/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/oracledb/config/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/oracledb/config/_common.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/adapters/psycopg/config/_common.py +0 -0
- {sqlspec-0.9.0/sqlspec/adapters/psqlpy → sqlspec-0.10.0/sqlspec/extensions}/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/extensions/litestar/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/extensions/litestar/_utils.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/filters.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/py.typed +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/statement.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/utils/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/utils/deprecation.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/utils/fixtures.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/utils/module_loader.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/utils/sync_tools.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/sqlspec/utils/text.py +0 -0
- {sqlspec-0.9.0/sqlspec/extensions → sqlspec-0.10.0/tests}/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/conftest.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/fixtures/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/fixtures/example_usage.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/fixtures/sql_utils.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_adbc/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_adbc/conftest.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_adbc/test_connection.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_adbc/test_driver_bigquery.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_adbc/test_driver_duckdb.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_adbc/test_driver_postgres.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_adbc/test_driver_sqlite.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_aiosqlite/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_aiosqlite/test_connection.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_aiosqlite/test_driver.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_asyncmy/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_asyncmy/test_connection.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_asyncmy/test_driver.py +0 -0
- {sqlspec-0.9.0/tests → sqlspec-0.10.0/tests/integration/test_adapters/test_asyncpg}/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_asyncpg/test_connection.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_asyncpg/test_driver.py +0 -0
- {sqlspec-0.9.0/tests/integration/test_adapters/test_asyncpg → sqlspec-0.10.0/tests/integration/test_adapters/test_bigquery}/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_duckdb/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_duckdb/test_connection.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_duckdb/test_driver.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_oracledb/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_oracledb/test_connection.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_oracledb/test_driver_async.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_oracledb/test_driver_sync.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_psqlpy/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_psqlpy/test_connection.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_psqlpy/test_driver.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_psycopg/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_psycopg/test_connection.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_psycopg/test_driver.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_sqlite/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_sqlite/test_connection.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/integration/test_adapters/test_sqlite/test_driver.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_adbc/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_adbc/test_config.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_aiosqlite/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_asyncmy/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_asyncmy/test_config.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_asyncpg/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_asyncpg/test_config.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_duckdb/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_duckdb/test_config.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_oracledb/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_oracledb/test_async_config.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_oracledb/test_sync_config.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_psycopg/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_psycopg/test_async_config.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_psycopg/test_sync_config.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_sqlite/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_adapters/test_sqlite/test_config.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_base.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_typing.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_utils/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_utils/test_module_loader.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_utils/test_sync_tools.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tests/unit/test_utils/test_text.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tools/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tools/build_docs.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tools/pypi_readme.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tools/sphinx_ext/__init__.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tools/sphinx_ext/changelog.py +0 -0
- {sqlspec-0.9.0 → sqlspec-0.10.0}/tools/sphinx_ext/missing_references.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlspec
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: SQL Experiments in Python
|
|
5
5
|
Author-email: Cody Fincher <cody@litestar.dev>
|
|
6
6
|
Maintainer-email: Litestar Developers <hello@litestar.dev>
|
|
@@ -41,6 +41,7 @@ Requires-Dist: oracledb; extra == 'oracledb'
|
|
|
41
41
|
Provides-Extra: orjson
|
|
42
42
|
Requires-Dist: orjson; extra == 'orjson'
|
|
43
43
|
Provides-Extra: performance
|
|
44
|
+
Requires-Dist: msgspec; extra == 'performance'
|
|
44
45
|
Requires-Dist: sqlglot[rs]; extra == 'performance'
|
|
45
46
|
Provides-Extra: psqlpy
|
|
46
47
|
Requires-Dist: psqlpy; extra == 'psqlpy'
|
|
@@ -83,6 +84,149 @@ SQLSpec is an experimental Python library designed to streamline and modernize y
|
|
|
83
84
|
|
|
84
85
|
SQLSpec is a work in progress. While it offers a solid foundation for modern SQL interactions, it does not yet include every feature you might find in a mature ORM or database toolkit. The focus is on building a robust, flexible core that can be extended over time.
|
|
85
86
|
|
|
87
|
+
## Examples
|
|
88
|
+
|
|
89
|
+
We've talked about what SQLSpec is not, so let's look at what it can do.
|
|
90
|
+
|
|
91
|
+
These are just a few of the examples that demonstrate SQLSpec's flexibility and each of the bundled adapters offer the same config and driver interfaces.
|
|
92
|
+
|
|
93
|
+
### DuckDB LLM
|
|
94
|
+
|
|
95
|
+
This is a quick implementation using some of the built in Secret and Extension management features of SQLSpec's DuckDB integration.
|
|
96
|
+
|
|
97
|
+
It allows you to communicate with any compatible OpenAPI conversations endpoint (such as Ollama). This examples:
|
|
98
|
+
|
|
99
|
+
- auto installs the `open_prompt` DuckDB extensions
|
|
100
|
+
- automatically creates the correct `open_prompt` comptaible secret required to use the extension
|
|
101
|
+
|
|
102
|
+
```py
|
|
103
|
+
# /// script
|
|
104
|
+
# dependencies = [
|
|
105
|
+
# "sqlspec[duckdb,performance]",
|
|
106
|
+
# ]
|
|
107
|
+
# ///
|
|
108
|
+
import os
|
|
109
|
+
|
|
110
|
+
from sqlspec import SQLSpec
|
|
111
|
+
from sqlspec.adapters.duckdb import DuckDBConfig
|
|
112
|
+
from pydantic import BaseModel
|
|
113
|
+
|
|
114
|
+
class ChatMessage(BaseModel):
|
|
115
|
+
message: str
|
|
116
|
+
|
|
117
|
+
sql = SQLSpec()
|
|
118
|
+
etl_config = sql.add_config(
|
|
119
|
+
DuckDBConfig(
|
|
120
|
+
extensions=[{"name": "open_prompt"}],
|
|
121
|
+
secrets=[
|
|
122
|
+
{
|
|
123
|
+
"secret_type": "open_prompt",
|
|
124
|
+
"name": "open_prompt",
|
|
125
|
+
"value": {
|
|
126
|
+
"api_url": "http://127.0.0.1:11434/v1/chat/completions",
|
|
127
|
+
"model_name": "gemma3:1b",
|
|
128
|
+
"api_timeout": "120",
|
|
129
|
+
},
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
)
|
|
133
|
+
)
|
|
134
|
+
with sql.provide_session(etl_config) as session:
|
|
135
|
+
result = session.select_one(
|
|
136
|
+
"SELECT open_prompt(?)",
|
|
137
|
+
"Can you write a haiku about DuckDB?",
|
|
138
|
+
schema_type=ChatMessage
|
|
139
|
+
)
|
|
140
|
+
print(result) # result is a ChatMessage pydantic model
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### DuckDB Gemini Embeddings
|
|
144
|
+
|
|
145
|
+
In this example, we are again using DuckDB. However, we are going to use the built in to call the Google Gemini embeddings service directly from the database.
|
|
146
|
+
|
|
147
|
+
This example will
|
|
148
|
+
|
|
149
|
+
- auto installs the `http_client` and `vss` (vector similarity search) DuckDB extensions
|
|
150
|
+
- when a connection is created, it ensures that the `generate_embeddings` macro exists in the DuckDB database.
|
|
151
|
+
- Execute a simple query to call the Google API
|
|
152
|
+
|
|
153
|
+
```py
|
|
154
|
+
# /// script
|
|
155
|
+
# dependencies = [
|
|
156
|
+
# "sqlspec[duckdb,performance]",
|
|
157
|
+
# ]
|
|
158
|
+
# ///
|
|
159
|
+
import os
|
|
160
|
+
|
|
161
|
+
from sqlspec import SQLSpec
|
|
162
|
+
from sqlspec.adapters.duckdb import DuckDBConfig
|
|
163
|
+
|
|
164
|
+
EMBEDDING_MODEL = "gemini-embedding-exp-03-07"
|
|
165
|
+
GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
|
|
166
|
+
API_URL = (
|
|
167
|
+
f"https://generativelanguage.googleapis.com/v1beta/models/{EMBEDDING_MODEL}:embedContent?key=${GOOGLE_API_KEY}"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
sql = SQLSpec()
|
|
171
|
+
etl_config = sql.add_config(
|
|
172
|
+
DuckDBConfig(
|
|
173
|
+
extensions=[{"name": "vss"}, {"name": "http_client"}],
|
|
174
|
+
on_connection_create=lambda connection: connection.execute(f"""
|
|
175
|
+
CREATE IF NOT EXISTS MACRO generate_embedding(q) AS (
|
|
176
|
+
WITH __request AS (
|
|
177
|
+
SELECT http_post(
|
|
178
|
+
'{API_URL}',
|
|
179
|
+
headers => MAP {{
|
|
180
|
+
'accept': 'application/json',
|
|
181
|
+
}},
|
|
182
|
+
params => MAP {{
|
|
183
|
+
'model': 'models/{EMBEDDING_MODEL}',
|
|
184
|
+
'parts': [{{ 'text': q }}],
|
|
185
|
+
'taskType': 'SEMANTIC_SIMILARITY'
|
|
186
|
+
}}
|
|
187
|
+
) AS response
|
|
188
|
+
)
|
|
189
|
+
SELECT *
|
|
190
|
+
FROM __request,
|
|
191
|
+
);
|
|
192
|
+
"""),
|
|
193
|
+
)
|
|
194
|
+
)
|
|
195
|
+
with sql.provide_session(etl_config) as session:
|
|
196
|
+
result = session.select_one("SELECT generate_embedding('example text')")
|
|
197
|
+
print(result) # result is a dictionary when `schema_type` is omitted.
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Basic Litestar Integration
|
|
201
|
+
|
|
202
|
+
In this example we are going to demonstrate how to create a basic configuration that integrates into Litestar.
|
|
203
|
+
|
|
204
|
+
```py
|
|
205
|
+
# /// script
|
|
206
|
+
# dependencies = [
|
|
207
|
+
# "sqlspec[aiosqlite]",
|
|
208
|
+
# "litestar[standard]",
|
|
209
|
+
# ]
|
|
210
|
+
# ///
|
|
211
|
+
|
|
212
|
+
from aiosqlite import Connection
|
|
213
|
+
from litestar import Litestar, get
|
|
214
|
+
|
|
215
|
+
from sqlspec.adapters.aiosqlite import AiosqliteConfig, AiosqliteDriver
|
|
216
|
+
from sqlspec.extensions.litestar import SQLSpec
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@get("/")
|
|
220
|
+
async def simple_sqlite(db_session: AiosqliteDriver) -> dict[str, str]:
|
|
221
|
+
return await db_session.select_one("SELECT 'Hello, world!' AS greeting")
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
sqlspec = SQLSpec(config=DatabaseConfig(
|
|
225
|
+
config=[AiosqliteConfig(), commit_mode="autocommit")],
|
|
226
|
+
)
|
|
227
|
+
app = Litestar(route_handlers=[simple_sqlite], plugins=[sqlspec])
|
|
228
|
+
```
|
|
229
|
+
|
|
86
230
|
## Inspiration and Future Direction
|
|
87
231
|
|
|
88
232
|
SQLSpec originally drew inspiration from features found in the `aiosql` library. This is a great library for working with and executed SQL stored in files. It's unclear how much of an overlap there will be between the two libraries, but it's possible that some features will be contributed back to `aiosql` where appropriate.
|
|
@@ -110,7 +254,7 @@ This list is not final. If you have a driver you'd like to see added, please ope
|
|
|
110
254
|
| [`oracledb`](https://oracle.github.io/python-oracledb/) | Oracle | Async | ✅ |
|
|
111
255
|
| [`oracledb`](https://oracle.github.io/python-oracledb/) | Oracle | Sync | ✅ |
|
|
112
256
|
| [`duckdb`](https://duckdb.org/) | DuckDB | Sync | ✅ |
|
|
113
|
-
| [`bigquery`](https://googleapis.dev/python/bigquery/latest/index.html) | BigQuery | Sync |
|
|
257
|
+
| [`bigquery`](https://googleapis.dev/python/bigquery/latest/index.html) | BigQuery | Sync | ✅ |
|
|
114
258
|
| [`spanner`](https://googleapis.dev/python/spanner/latest/index.html) | Spanner | Sync | 🗓️ |
|
|
115
259
|
| [`sqlserver`](https://docs.microsoft.com/en-us/sql/connect/python/pyodbc/python-sql-driver-for-pyodbc?view=sql-server-ver16) | SQL Server | Sync | 🗓️ |
|
|
116
260
|
| [`mysql`](https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysql-connector-python.html) | MySQL | Sync | 🗓️ |
|
|
@@ -121,7 +265,7 @@ This list is not final. If you have a driver you'd like to see added, please ope
|
|
|
121
265
|
- `sqlspec/`:
|
|
122
266
|
- `adapters/`: Contains all database drivers and associated configuration.
|
|
123
267
|
- `extensions/`:
|
|
124
|
-
- `litestar/`:
|
|
268
|
+
- `litestar/`: Litestar framework integration ✅
|
|
125
269
|
- `fastapi/`: Future home of `fastapi` integration.
|
|
126
270
|
- `flask/`: Future home of `flask` integration.
|
|
127
271
|
- `*/`: Future home of your favorite framework integration 🔌 ✨
|
|
@@ -22,6 +22,149 @@ SQLSpec is an experimental Python library designed to streamline and modernize y
|
|
|
22
22
|
|
|
23
23
|
SQLSpec is a work in progress. While it offers a solid foundation for modern SQL interactions, it does not yet include every feature you might find in a mature ORM or database toolkit. The focus is on building a robust, flexible core that can be extended over time.
|
|
24
24
|
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
We've talked about what SQLSpec is not, so let's look at what it can do.
|
|
28
|
+
|
|
29
|
+
These are just a few of the examples that demonstrate SQLSpec's flexibility and each of the bundled adapters offer the same config and driver interfaces.
|
|
30
|
+
|
|
31
|
+
### DuckDB LLM
|
|
32
|
+
|
|
33
|
+
This is a quick implementation using some of the built in Secret and Extension management features of SQLSpec's DuckDB integration.
|
|
34
|
+
|
|
35
|
+
It allows you to communicate with any compatible OpenAPI conversations endpoint (such as Ollama). This examples:
|
|
36
|
+
|
|
37
|
+
- auto installs the `open_prompt` DuckDB extensions
|
|
38
|
+
- automatically creates the correct `open_prompt` comptaible secret required to use the extension
|
|
39
|
+
|
|
40
|
+
```py
|
|
41
|
+
# /// script
|
|
42
|
+
# dependencies = [
|
|
43
|
+
# "sqlspec[duckdb,performance]",
|
|
44
|
+
# ]
|
|
45
|
+
# ///
|
|
46
|
+
import os
|
|
47
|
+
|
|
48
|
+
from sqlspec import SQLSpec
|
|
49
|
+
from sqlspec.adapters.duckdb import DuckDBConfig
|
|
50
|
+
from pydantic import BaseModel
|
|
51
|
+
|
|
52
|
+
class ChatMessage(BaseModel):
|
|
53
|
+
message: str
|
|
54
|
+
|
|
55
|
+
sql = SQLSpec()
|
|
56
|
+
etl_config = sql.add_config(
|
|
57
|
+
DuckDBConfig(
|
|
58
|
+
extensions=[{"name": "open_prompt"}],
|
|
59
|
+
secrets=[
|
|
60
|
+
{
|
|
61
|
+
"secret_type": "open_prompt",
|
|
62
|
+
"name": "open_prompt",
|
|
63
|
+
"value": {
|
|
64
|
+
"api_url": "http://127.0.0.1:11434/v1/chat/completions",
|
|
65
|
+
"model_name": "gemma3:1b",
|
|
66
|
+
"api_timeout": "120",
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
with sql.provide_session(etl_config) as session:
|
|
73
|
+
result = session.select_one(
|
|
74
|
+
"SELECT open_prompt(?)",
|
|
75
|
+
"Can you write a haiku about DuckDB?",
|
|
76
|
+
schema_type=ChatMessage
|
|
77
|
+
)
|
|
78
|
+
print(result) # result is a ChatMessage pydantic model
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### DuckDB Gemini Embeddings
|
|
82
|
+
|
|
83
|
+
In this example, we are again using DuckDB. However, we are going to use the built in to call the Google Gemini embeddings service directly from the database.
|
|
84
|
+
|
|
85
|
+
This example will
|
|
86
|
+
|
|
87
|
+
- auto installs the `http_client` and `vss` (vector similarity search) DuckDB extensions
|
|
88
|
+
- when a connection is created, it ensures that the `generate_embeddings` macro exists in the DuckDB database.
|
|
89
|
+
- Execute a simple query to call the Google API
|
|
90
|
+
|
|
91
|
+
```py
|
|
92
|
+
# /// script
|
|
93
|
+
# dependencies = [
|
|
94
|
+
# "sqlspec[duckdb,performance]",
|
|
95
|
+
# ]
|
|
96
|
+
# ///
|
|
97
|
+
import os
|
|
98
|
+
|
|
99
|
+
from sqlspec import SQLSpec
|
|
100
|
+
from sqlspec.adapters.duckdb import DuckDBConfig
|
|
101
|
+
|
|
102
|
+
EMBEDDING_MODEL = "gemini-embedding-exp-03-07"
|
|
103
|
+
GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
|
|
104
|
+
API_URL = (
|
|
105
|
+
f"https://generativelanguage.googleapis.com/v1beta/models/{EMBEDDING_MODEL}:embedContent?key=${GOOGLE_API_KEY}"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
sql = SQLSpec()
|
|
109
|
+
etl_config = sql.add_config(
|
|
110
|
+
DuckDBConfig(
|
|
111
|
+
extensions=[{"name": "vss"}, {"name": "http_client"}],
|
|
112
|
+
on_connection_create=lambda connection: connection.execute(f"""
|
|
113
|
+
CREATE IF NOT EXISTS MACRO generate_embedding(q) AS (
|
|
114
|
+
WITH __request AS (
|
|
115
|
+
SELECT http_post(
|
|
116
|
+
'{API_URL}',
|
|
117
|
+
headers => MAP {{
|
|
118
|
+
'accept': 'application/json',
|
|
119
|
+
}},
|
|
120
|
+
params => MAP {{
|
|
121
|
+
'model': 'models/{EMBEDDING_MODEL}',
|
|
122
|
+
'parts': [{{ 'text': q }}],
|
|
123
|
+
'taskType': 'SEMANTIC_SIMILARITY'
|
|
124
|
+
}}
|
|
125
|
+
) AS response
|
|
126
|
+
)
|
|
127
|
+
SELECT *
|
|
128
|
+
FROM __request,
|
|
129
|
+
);
|
|
130
|
+
"""),
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
with sql.provide_session(etl_config) as session:
|
|
134
|
+
result = session.select_one("SELECT generate_embedding('example text')")
|
|
135
|
+
print(result) # result is a dictionary when `schema_type` is omitted.
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Basic Litestar Integration
|
|
139
|
+
|
|
140
|
+
In this example we are going to demonstrate how to create a basic configuration that integrates into Litestar.
|
|
141
|
+
|
|
142
|
+
```py
|
|
143
|
+
# /// script
|
|
144
|
+
# dependencies = [
|
|
145
|
+
# "sqlspec[aiosqlite]",
|
|
146
|
+
# "litestar[standard]",
|
|
147
|
+
# ]
|
|
148
|
+
# ///
|
|
149
|
+
|
|
150
|
+
from aiosqlite import Connection
|
|
151
|
+
from litestar import Litestar, get
|
|
152
|
+
|
|
153
|
+
from sqlspec.adapters.aiosqlite import AiosqliteConfig, AiosqliteDriver
|
|
154
|
+
from sqlspec.extensions.litestar import SQLSpec
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@get("/")
|
|
158
|
+
async def simple_sqlite(db_session: AiosqliteDriver) -> dict[str, str]:
|
|
159
|
+
return await db_session.select_one("SELECT 'Hello, world!' AS greeting")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
sqlspec = SQLSpec(config=DatabaseConfig(
|
|
163
|
+
config=[AiosqliteConfig(), commit_mode="autocommit")],
|
|
164
|
+
)
|
|
165
|
+
app = Litestar(route_handlers=[simple_sqlite], plugins=[sqlspec])
|
|
166
|
+
```
|
|
167
|
+
|
|
25
168
|
## Inspiration and Future Direction
|
|
26
169
|
|
|
27
170
|
SQLSpec originally drew inspiration from features found in the `aiosql` library. This is a great library for working with and executed SQL stored in files. It's unclear how much of an overlap there will be between the two libraries, but it's possible that some features will be contributed back to `aiosql` where appropriate.
|
|
@@ -49,7 +192,7 @@ This list is not final. If you have a driver you'd like to see added, please ope
|
|
|
49
192
|
| [`oracledb`](https://oracle.github.io/python-oracledb/) | Oracle | Async | ✅ |
|
|
50
193
|
| [`oracledb`](https://oracle.github.io/python-oracledb/) | Oracle | Sync | ✅ |
|
|
51
194
|
| [`duckdb`](https://duckdb.org/) | DuckDB | Sync | ✅ |
|
|
52
|
-
| [`bigquery`](https://googleapis.dev/python/bigquery/latest/index.html) | BigQuery | Sync |
|
|
195
|
+
| [`bigquery`](https://googleapis.dev/python/bigquery/latest/index.html) | BigQuery | Sync | ✅ |
|
|
53
196
|
| [`spanner`](https://googleapis.dev/python/spanner/latest/index.html) | Spanner | Sync | 🗓️ |
|
|
54
197
|
| [`sqlserver`](https://docs.microsoft.com/en-us/sql/connect/python/pyodbc/python-sql-driver-for-pyodbc?view=sql-server-ver16) | SQL Server | Sync | 🗓️ |
|
|
55
198
|
| [`mysql`](https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysql-connector-python.html) | MySQL | Sync | 🗓️ |
|
|
@@ -60,7 +203,7 @@ This list is not final. If you have a driver you'd like to see added, please ope
|
|
|
60
203
|
- `sqlspec/`:
|
|
61
204
|
- `adapters/`: Contains all database drivers and associated configuration.
|
|
62
205
|
- `extensions/`:
|
|
63
|
-
- `litestar/`:
|
|
206
|
+
- `litestar/`: Litestar framework integration ✅
|
|
64
207
|
- `fastapi/`: Future home of `fastapi` integration.
|
|
65
208
|
- `flask/`: Future home of `flask` integration.
|
|
66
209
|
- `*/`: Future home of your favorite framework integration 🔌 ✨
|
|
@@ -7,7 +7,7 @@ maintainers = [{ name = "Litestar Developers", email = "hello@litestar.dev" }]
|
|
|
7
7
|
name = "sqlspec"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
requires-python = ">=3.9, <4.0"
|
|
10
|
-
version = "0.
|
|
10
|
+
version = "0.10.0"
|
|
11
11
|
|
|
12
12
|
[project.optional-dependencies]
|
|
13
13
|
adbc = ["adbc_driver_manager", "pyarrow"]
|
|
@@ -24,7 +24,7 @@ msgspec = ["msgspec"]
|
|
|
24
24
|
nanoid = ["fastnanoid>=0.4.1"]
|
|
25
25
|
oracledb = ["oracledb"]
|
|
26
26
|
orjson = ["orjson"]
|
|
27
|
-
performance = ["sqlglot[rs]"]
|
|
27
|
+
performance = ["sqlglot[rs]", "msgspec"]
|
|
28
28
|
psqlpy = ["psqlpy"]
|
|
29
29
|
psycopg = ["psycopg[binary,pool]"]
|
|
30
30
|
pydantic = ["pydantic", "pydantic-extra-types"]
|
|
@@ -109,7 +109,7 @@ packages = ["sqlspec"]
|
|
|
109
109
|
allow_dirty = true
|
|
110
110
|
commit = false
|
|
111
111
|
commit_args = "--no-verify"
|
|
112
|
-
current_version = "0.
|
|
112
|
+
current_version = "0.10.0"
|
|
113
113
|
ignore_missing_files = false
|
|
114
114
|
ignore_missing_version = false
|
|
115
115
|
message = "chore(release): bump to v{new_version}"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from sqlspec import adapters, base, exceptions, extensions, filters, typing, utils
|
|
1
|
+
from sqlspec import adapters, base, exceptions, extensions, filters, mixins, typing, utils
|
|
2
2
|
from sqlspec.__metadata__ import __version__
|
|
3
3
|
from sqlspec.base import SQLSpec
|
|
4
4
|
|
|
@@ -10,6 +10,7 @@ __all__ = (
|
|
|
10
10
|
"exceptions",
|
|
11
11
|
"extensions",
|
|
12
12
|
"filters",
|
|
13
|
+
"mixins",
|
|
13
14
|
"typing",
|
|
14
15
|
"utils",
|
|
15
16
|
)
|
|
@@ -2,9 +2,7 @@ from contextlib import contextmanager
|
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
3
|
from typing import TYPE_CHECKING, Any, Callable, Optional, Union, cast
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
from sqlspec.adapters.adbc.driver import AdbcDriver
|
|
5
|
+
from sqlspec.adapters.adbc.driver import AdbcConnection, AdbcDriver
|
|
8
6
|
from sqlspec.base import NoPoolSyncConfig
|
|
9
7
|
from sqlspec.exceptions import ImproperConfigurationError
|
|
10
8
|
from sqlspec.typing import Empty, EmptyType
|
|
@@ -18,7 +16,7 @@ __all__ = ("AdbcConfig",)
|
|
|
18
16
|
|
|
19
17
|
|
|
20
18
|
@dataclass
|
|
21
|
-
class AdbcConfig(NoPoolSyncConfig["
|
|
19
|
+
class AdbcConfig(NoPoolSyncConfig["AdbcConnection", "AdbcDriver"]):
|
|
22
20
|
"""Configuration for ADBC connections.
|
|
23
21
|
|
|
24
22
|
This class provides configuration options for ADBC database connections using the
|
|
@@ -33,20 +31,16 @@ class AdbcConfig(NoPoolSyncConfig["Connection", "AdbcDriver"]):
|
|
|
33
31
|
"""Additional database-specific connection parameters"""
|
|
34
32
|
conn_kwargs: "Optional[dict[str, Any]]" = None
|
|
35
33
|
"""Additional database-specific connection parameters"""
|
|
36
|
-
connection_type: "type[
|
|
34
|
+
connection_type: "type[AdbcConnection]" = field(init=False, default_factory=lambda: AdbcConnection)
|
|
37
35
|
"""Type of the connection object"""
|
|
38
36
|
driver_type: "type[AdbcDriver]" = field(init=False, default_factory=lambda: AdbcDriver) # type: ignore[type-abstract,unused-ignore]
|
|
39
37
|
"""Type of the driver object"""
|
|
40
|
-
pool_instance: None = field(init=False, default=None)
|
|
38
|
+
pool_instance: None = field(init=False, default=None, hash=False)
|
|
41
39
|
"""No connection pool is used for ADBC connections"""
|
|
42
|
-
_is_in_memory: bool = field(init=False, default=False)
|
|
43
|
-
"""Flag indicating if the connection is for an in-memory database"""
|
|
44
40
|
|
|
45
41
|
def _set_adbc(self) -> str: # noqa: PLR0912
|
|
46
42
|
"""Identify the driver type based on the URI (if provided) or preset driver name.
|
|
47
43
|
|
|
48
|
-
Also sets the `_is_in_memory` flag for specific in-memory URIs.
|
|
49
|
-
|
|
50
44
|
Raises:
|
|
51
45
|
ImproperConfigurationError: If the driver name is not recognized or supported.
|
|
52
46
|
|
|
@@ -143,7 +137,7 @@ class AdbcConfig(NoPoolSyncConfig["Connection", "AdbcDriver"]):
|
|
|
143
137
|
config["conn_kwargs"] = conn_kwargs
|
|
144
138
|
return config
|
|
145
139
|
|
|
146
|
-
def _get_connect_func(self) -> "Callable[...,
|
|
140
|
+
def _get_connect_func(self) -> "Callable[..., AdbcConnection]":
|
|
147
141
|
self._set_adbc()
|
|
148
142
|
driver_path = cast("str", self.driver_name)
|
|
149
143
|
try:
|
|
@@ -166,7 +160,7 @@ class AdbcConfig(NoPoolSyncConfig["Connection", "AdbcDriver"]):
|
|
|
166
160
|
raise ImproperConfigurationError(msg)
|
|
167
161
|
return connect_func # type: ignore[no-any-return]
|
|
168
162
|
|
|
169
|
-
def create_connection(self) -> "
|
|
163
|
+
def create_connection(self) -> "AdbcConnection":
|
|
170
164
|
"""Create and return a new database connection using the specific driver.
|
|
171
165
|
|
|
172
166
|
Returns:
|
|
@@ -189,7 +183,7 @@ class AdbcConfig(NoPoolSyncConfig["Connection", "AdbcDriver"]):
|
|
|
189
183
|
raise ImproperConfigurationError(msg) from e
|
|
190
184
|
|
|
191
185
|
@contextmanager
|
|
192
|
-
def provide_connection(self, *args: "Any", **kwargs: "Any") -> "Generator[
|
|
186
|
+
def provide_connection(self, *args: "Any", **kwargs: "Any") -> "Generator[AdbcConnection, None, None]":
|
|
193
187
|
"""Create and provide a database connection using the specific driver.
|
|
194
188
|
|
|
195
189
|
Yields:
|