sqlspec 0.11.1__py3-none-any.whl → 0.12.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.
Potentially problematic release.
This version of sqlspec might be problematic. Click here for more details.
- sqlspec/__init__.py +16 -3
- sqlspec/_serialization.py +3 -10
- sqlspec/_sql.py +1147 -0
- sqlspec/_typing.py +343 -41
- sqlspec/adapters/adbc/__init__.py +2 -6
- sqlspec/adapters/adbc/config.py +474 -149
- sqlspec/adapters/adbc/driver.py +330 -621
- sqlspec/adapters/aiosqlite/__init__.py +2 -6
- sqlspec/adapters/aiosqlite/config.py +143 -57
- sqlspec/adapters/aiosqlite/driver.py +269 -431
- sqlspec/adapters/asyncmy/__init__.py +3 -8
- sqlspec/adapters/asyncmy/config.py +247 -202
- sqlspec/adapters/asyncmy/driver.py +218 -436
- sqlspec/adapters/asyncpg/__init__.py +4 -7
- sqlspec/adapters/asyncpg/config.py +329 -176
- sqlspec/adapters/asyncpg/driver.py +417 -487
- sqlspec/adapters/bigquery/__init__.py +2 -2
- sqlspec/adapters/bigquery/config.py +407 -0
- sqlspec/adapters/bigquery/driver.py +600 -553
- sqlspec/adapters/duckdb/__init__.py +4 -1
- sqlspec/adapters/duckdb/config.py +432 -321
- sqlspec/adapters/duckdb/driver.py +392 -406
- sqlspec/adapters/oracledb/__init__.py +3 -8
- sqlspec/adapters/oracledb/config.py +625 -0
- sqlspec/adapters/oracledb/driver.py +548 -921
- sqlspec/adapters/psqlpy/__init__.py +4 -7
- sqlspec/adapters/psqlpy/config.py +372 -203
- sqlspec/adapters/psqlpy/driver.py +197 -533
- sqlspec/adapters/psycopg/__init__.py +3 -8
- sqlspec/adapters/psycopg/config.py +741 -0
- sqlspec/adapters/psycopg/driver.py +734 -694
- sqlspec/adapters/sqlite/__init__.py +2 -6
- sqlspec/adapters/sqlite/config.py +146 -81
- sqlspec/adapters/sqlite/driver.py +242 -405
- sqlspec/base.py +220 -784
- sqlspec/config.py +354 -0
- sqlspec/driver/__init__.py +22 -0
- sqlspec/driver/_async.py +252 -0
- sqlspec/driver/_common.py +338 -0
- sqlspec/driver/_sync.py +261 -0
- sqlspec/driver/mixins/__init__.py +17 -0
- sqlspec/driver/mixins/_pipeline.py +523 -0
- sqlspec/driver/mixins/_result_utils.py +122 -0
- sqlspec/driver/mixins/_sql_translator.py +35 -0
- sqlspec/driver/mixins/_storage.py +993 -0
- sqlspec/driver/mixins/_type_coercion.py +131 -0
- sqlspec/exceptions.py +299 -7
- sqlspec/extensions/aiosql/__init__.py +10 -0
- sqlspec/extensions/aiosql/adapter.py +474 -0
- sqlspec/extensions/litestar/__init__.py +1 -6
- sqlspec/extensions/litestar/_utils.py +1 -5
- sqlspec/extensions/litestar/config.py +5 -6
- sqlspec/extensions/litestar/handlers.py +13 -12
- sqlspec/extensions/litestar/plugin.py +22 -24
- sqlspec/extensions/litestar/providers.py +37 -55
- sqlspec/loader.py +528 -0
- sqlspec/service/__init__.py +3 -0
- sqlspec/service/base.py +24 -0
- sqlspec/service/pagination.py +26 -0
- sqlspec/statement/__init__.py +21 -0
- sqlspec/statement/builder/__init__.py +54 -0
- sqlspec/statement/builder/_ddl_utils.py +119 -0
- sqlspec/statement/builder/_parsing_utils.py +135 -0
- sqlspec/statement/builder/base.py +328 -0
- sqlspec/statement/builder/ddl.py +1379 -0
- sqlspec/statement/builder/delete.py +80 -0
- sqlspec/statement/builder/insert.py +274 -0
- sqlspec/statement/builder/merge.py +95 -0
- sqlspec/statement/builder/mixins/__init__.py +65 -0
- sqlspec/statement/builder/mixins/_aggregate_functions.py +151 -0
- sqlspec/statement/builder/mixins/_case_builder.py +91 -0
- sqlspec/statement/builder/mixins/_common_table_expr.py +91 -0
- sqlspec/statement/builder/mixins/_delete_from.py +34 -0
- sqlspec/statement/builder/mixins/_from.py +61 -0
- sqlspec/statement/builder/mixins/_group_by.py +119 -0
- sqlspec/statement/builder/mixins/_having.py +35 -0
- sqlspec/statement/builder/mixins/_insert_from_select.py +48 -0
- sqlspec/statement/builder/mixins/_insert_into.py +36 -0
- sqlspec/statement/builder/mixins/_insert_values.py +69 -0
- sqlspec/statement/builder/mixins/_join.py +110 -0
- sqlspec/statement/builder/mixins/_limit_offset.py +53 -0
- sqlspec/statement/builder/mixins/_merge_clauses.py +405 -0
- sqlspec/statement/builder/mixins/_order_by.py +46 -0
- sqlspec/statement/builder/mixins/_pivot.py +82 -0
- sqlspec/statement/builder/mixins/_returning.py +37 -0
- sqlspec/statement/builder/mixins/_select_columns.py +60 -0
- sqlspec/statement/builder/mixins/_set_ops.py +122 -0
- sqlspec/statement/builder/mixins/_unpivot.py +80 -0
- sqlspec/statement/builder/mixins/_update_from.py +54 -0
- sqlspec/statement/builder/mixins/_update_set.py +91 -0
- sqlspec/statement/builder/mixins/_update_table.py +29 -0
- sqlspec/statement/builder/mixins/_where.py +374 -0
- sqlspec/statement/builder/mixins/_window_functions.py +86 -0
- sqlspec/statement/builder/protocols.py +20 -0
- sqlspec/statement/builder/select.py +206 -0
- sqlspec/statement/builder/update.py +178 -0
- sqlspec/statement/filters.py +571 -0
- sqlspec/statement/parameters.py +736 -0
- sqlspec/statement/pipelines/__init__.py +67 -0
- sqlspec/statement/pipelines/analyzers/__init__.py +9 -0
- sqlspec/statement/pipelines/analyzers/_analyzer.py +649 -0
- sqlspec/statement/pipelines/base.py +315 -0
- sqlspec/statement/pipelines/context.py +119 -0
- sqlspec/statement/pipelines/result_types.py +41 -0
- sqlspec/statement/pipelines/transformers/__init__.py +8 -0
- sqlspec/statement/pipelines/transformers/_expression_simplifier.py +256 -0
- sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +623 -0
- sqlspec/statement/pipelines/transformers/_remove_comments.py +66 -0
- sqlspec/statement/pipelines/transformers/_remove_hints.py +81 -0
- sqlspec/statement/pipelines/validators/__init__.py +23 -0
- sqlspec/statement/pipelines/validators/_dml_safety.py +275 -0
- sqlspec/statement/pipelines/validators/_parameter_style.py +297 -0
- sqlspec/statement/pipelines/validators/_performance.py +703 -0
- sqlspec/statement/pipelines/validators/_security.py +990 -0
- sqlspec/statement/pipelines/validators/base.py +67 -0
- sqlspec/statement/result.py +527 -0
- sqlspec/statement/splitter.py +701 -0
- sqlspec/statement/sql.py +1198 -0
- sqlspec/storage/__init__.py +15 -0
- sqlspec/storage/backends/__init__.py +0 -0
- sqlspec/storage/backends/base.py +166 -0
- sqlspec/storage/backends/fsspec.py +315 -0
- sqlspec/storage/backends/obstore.py +464 -0
- sqlspec/storage/protocol.py +170 -0
- sqlspec/storage/registry.py +315 -0
- sqlspec/typing.py +157 -36
- sqlspec/utils/correlation.py +155 -0
- sqlspec/utils/deprecation.py +3 -6
- sqlspec/utils/fixtures.py +6 -11
- sqlspec/utils/logging.py +135 -0
- sqlspec/utils/module_loader.py +45 -43
- sqlspec/utils/serializers.py +4 -0
- sqlspec/utils/singleton.py +6 -8
- sqlspec/utils/sync_tools.py +15 -27
- sqlspec/utils/text.py +58 -26
- {sqlspec-0.11.1.dist-info → sqlspec-0.12.0.dist-info}/METADATA +97 -26
- sqlspec-0.12.0.dist-info/RECORD +145 -0
- sqlspec/adapters/bigquery/config/__init__.py +0 -3
- sqlspec/adapters/bigquery/config/_common.py +0 -40
- sqlspec/adapters/bigquery/config/_sync.py +0 -87
- sqlspec/adapters/oracledb/config/__init__.py +0 -9
- sqlspec/adapters/oracledb/config/_asyncio.py +0 -186
- sqlspec/adapters/oracledb/config/_common.py +0 -131
- sqlspec/adapters/oracledb/config/_sync.py +0 -186
- sqlspec/adapters/psycopg/config/__init__.py +0 -19
- sqlspec/adapters/psycopg/config/_async.py +0 -169
- sqlspec/adapters/psycopg/config/_common.py +0 -56
- sqlspec/adapters/psycopg/config/_sync.py +0 -168
- sqlspec/filters.py +0 -331
- sqlspec/mixins.py +0 -305
- sqlspec/statement.py +0 -378
- sqlspec-0.11.1.dist-info/RECORD +0 -69
- {sqlspec-0.11.1.dist-info → sqlspec-0.12.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.11.1.dist-info → sqlspec-0.12.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.11.1.dist-info → sqlspec-0.12.0.dist-info}/licenses/NOTICE +0 -0
sqlspec/utils/text.py
CHANGED
|
@@ -6,25 +6,20 @@ from functools import lru_cache
|
|
|
6
6
|
from typing import Optional
|
|
7
7
|
|
|
8
8
|
# Compiled regex for slugify
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
_SLUGIFY_REMOVE_NON_ALPHANUMERIC = re.compile(r"[^\w]+", re.UNICODE)
|
|
10
|
+
_SLUGIFY_HYPHEN_COLLAPSE = re.compile(r"-+")
|
|
11
11
|
|
|
12
12
|
# Compiled regex for snake_case
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
#
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
__all__ = (
|
|
23
|
-
"camelize",
|
|
24
|
-
"check_email",
|
|
25
|
-
"slugify",
|
|
26
|
-
"snake_case",
|
|
27
|
-
)
|
|
13
|
+
# Insert underscore between lowercase/digit and uppercase letter
|
|
14
|
+
_SNAKE_CASE_LOWER_OR_DIGIT_TO_UPPER = re.compile(r"(?<=[a-z0-9])(?=[A-Z])", re.UNICODE)
|
|
15
|
+
# Insert underscore between uppercase letter and uppercase followed by lowercase
|
|
16
|
+
_SNAKE_CASE_UPPER_TO_UPPER_LOWER = re.compile(r"(?<=[A-Z])(?=[A-Z][a-z])", re.UNICODE)
|
|
17
|
+
# Replace hyphens, spaces, dots, and @ symbols with underscores for snake_case
|
|
18
|
+
_SNAKE_CASE_HYPHEN_SPACE = re.compile(r"[.\s@-]+", re.UNICODE)
|
|
19
|
+
# Collapse multiple underscores
|
|
20
|
+
_SNAKE_CASE_MULTIPLE_UNDERSCORES = re.compile(r"__+", re.UNICODE)
|
|
21
|
+
|
|
22
|
+
__all__ = ("camelize", "check_email", "slugify", "snake_case")
|
|
28
23
|
|
|
29
24
|
|
|
30
25
|
def check_email(email: str) -> str:
|
|
@@ -68,10 +63,22 @@ def slugify(value: str, allow_unicode: bool = False, separator: Optional[str] =
|
|
|
68
63
|
value = unicodedata.normalize("NFKC", value)
|
|
69
64
|
else:
|
|
70
65
|
value = unicodedata.normalize("NFKD", value).encode("ascii", "ignore").decode("ascii")
|
|
71
|
-
value =
|
|
72
|
-
if separator is not None
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
value = value.lower().strip()
|
|
67
|
+
sep = separator if separator is not None else "-"
|
|
68
|
+
if not sep:
|
|
69
|
+
# Remove all non-alphanumeric characters and return
|
|
70
|
+
return _SLUGIFY_REMOVE_NON_ALPHANUMERIC.sub("", value)
|
|
71
|
+
# Replace all runs of non-alphanumeric chars with the separator
|
|
72
|
+
value = _SLUGIFY_REMOVE_NON_ALPHANUMERIC.sub(sep, value)
|
|
73
|
+
# Remove leading/trailing separators and collapse multiple separators
|
|
74
|
+
# For dynamic separators, we need to use re.sub with escaped separator
|
|
75
|
+
if sep == "-":
|
|
76
|
+
# Use pre-compiled regex for common case
|
|
77
|
+
value = value.strip("-")
|
|
78
|
+
return _SLUGIFY_HYPHEN_COLLAPSE.sub("-", value)
|
|
79
|
+
# For other separators, use dynamic regex
|
|
80
|
+
value = re.sub(rf"^{re.escape(sep)}+|{re.escape(sep)}+$", "", value)
|
|
81
|
+
return re.sub(rf"{re.escape(sep)}+", sep, value)
|
|
75
82
|
|
|
76
83
|
|
|
77
84
|
@lru_cache(maxsize=100)
|
|
@@ -94,6 +101,7 @@ def snake_case(string: str) -> str:
|
|
|
94
101
|
Handles CamelCase, PascalCase, strings with spaces, hyphens, or dots
|
|
95
102
|
as separators, and ensures single underscores. It also correctly
|
|
96
103
|
handles acronyms (e.g., "HTTPRequest" becomes "http_request").
|
|
104
|
+
Handles Unicode letters and numbers.
|
|
97
105
|
|
|
98
106
|
Args:
|
|
99
107
|
string: The string to convert.
|
|
@@ -101,8 +109,32 @@ def snake_case(string: str) -> str:
|
|
|
101
109
|
Returns:
|
|
102
110
|
The snake_case version of the string.
|
|
103
111
|
"""
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
s =
|
|
108
|
-
|
|
112
|
+
if not string:
|
|
113
|
+
return ""
|
|
114
|
+
# 1. Replace hyphens and spaces with underscores
|
|
115
|
+
s = _SNAKE_CASE_HYPHEN_SPACE.sub("_", string)
|
|
116
|
+
|
|
117
|
+
# 2. Remove all non-alphanumeric characters except underscores
|
|
118
|
+
# TODO: move to a compiled regex at the top of the file
|
|
119
|
+
s = re.sub(r"[^\w]+", "", s, flags=re.UNICODE)
|
|
120
|
+
|
|
121
|
+
# 3. Insert an underscore between a lowercase/digit and an uppercase letter.
|
|
122
|
+
# e.g., "helloWorld" -> "hello_World"
|
|
123
|
+
# e.g., "Python3IsGreat" -> "Python3_IsGreat"
|
|
124
|
+
# Uses a positive lookbehind `(?<=[...])` and a positive lookahead `(?=[...])`
|
|
125
|
+
s = _SNAKE_CASE_LOWER_OR_DIGIT_TO_UPPER.sub("_", s)
|
|
126
|
+
|
|
127
|
+
# 4. Insert an underscore between an uppercase letter and another
|
|
128
|
+
# uppercase letter followed by a lowercase letter.
|
|
129
|
+
# e.g., "HTTPRequest" -> "HTTP_Request"
|
|
130
|
+
# This handles acronyms gracefully.
|
|
131
|
+
s = _SNAKE_CASE_UPPER_TO_UPPER_LOWER.sub("_", s)
|
|
132
|
+
|
|
133
|
+
# 5. Convert the entire string to lowercase.
|
|
134
|
+
s = s.lower()
|
|
135
|
+
|
|
136
|
+
# 6. Remove any leading or trailing underscores that might have been created.
|
|
137
|
+
s = s.strip("_")
|
|
138
|
+
|
|
139
|
+
# 7. Collapse multiple consecutive underscores into a single one.
|
|
140
|
+
return _SNAKE_CASE_MULTIPLE_UNDERSCORES.sub("_", s)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlspec
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: SQL Experiments in Python
|
|
5
5
|
Project-URL: Discord, https://discord.gg/litestar
|
|
6
6
|
Project-URL: Issue, https://github.com/litestar-org/sqlspec/issues/
|
|
@@ -11,14 +11,17 @@ License-Expression: MIT
|
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
License-File: NOTICE
|
|
13
13
|
Requires-Python: <4.0,>=3.9
|
|
14
|
+
Requires-Dist: click
|
|
14
15
|
Requires-Dist: eval-type-backport; python_version < '3.10'
|
|
15
|
-
Requires-Dist: sqlglot
|
|
16
|
+
Requires-Dist: sqlglot>=19.9.0
|
|
16
17
|
Requires-Dist: typing-extensions
|
|
17
18
|
Provides-Extra: adbc
|
|
18
19
|
Requires-Dist: adbc-driver-manager; extra == 'adbc'
|
|
19
20
|
Requires-Dist: pyarrow; extra == 'adbc'
|
|
20
21
|
Provides-Extra: aioodbc
|
|
21
22
|
Requires-Dist: aioodbc; extra == 'aioodbc'
|
|
23
|
+
Provides-Extra: aiosql
|
|
24
|
+
Requires-Dist: aiosql; extra == 'aiosql'
|
|
22
25
|
Provides-Extra: aiosqlite
|
|
23
26
|
Requires-Dist: aiosqlite; extra == 'aiosqlite'
|
|
24
27
|
Provides-Extra: asyncmy
|
|
@@ -27,28 +30,41 @@ Provides-Extra: asyncpg
|
|
|
27
30
|
Requires-Dist: asyncpg; extra == 'asyncpg'
|
|
28
31
|
Provides-Extra: bigquery
|
|
29
32
|
Requires-Dist: google-cloud-bigquery; extra == 'bigquery'
|
|
33
|
+
Provides-Extra: cli
|
|
34
|
+
Requires-Dist: rich-click; extra == 'cli'
|
|
30
35
|
Provides-Extra: duckdb
|
|
31
36
|
Requires-Dist: duckdb; extra == 'duckdb'
|
|
32
37
|
Provides-Extra: fastapi
|
|
33
38
|
Requires-Dist: fastapi; extra == 'fastapi'
|
|
34
39
|
Provides-Extra: flask
|
|
35
40
|
Requires-Dist: flask; extra == 'flask'
|
|
41
|
+
Provides-Extra: fsspec
|
|
42
|
+
Requires-Dist: fsspec; extra == 'fsspec'
|
|
36
43
|
Provides-Extra: litestar
|
|
37
44
|
Requires-Dist: litestar; extra == 'litestar'
|
|
38
45
|
Provides-Extra: msgspec
|
|
39
46
|
Requires-Dist: msgspec; extra == 'msgspec'
|
|
40
47
|
Provides-Extra: nanoid
|
|
41
48
|
Requires-Dist: fastnanoid>=0.4.1; extra == 'nanoid'
|
|
49
|
+
Provides-Extra: obstore
|
|
50
|
+
Requires-Dist: obstore; extra == 'obstore'
|
|
51
|
+
Provides-Extra: opentelemetry
|
|
52
|
+
Requires-Dist: opentelemetry-instrumentation; extra == 'opentelemetry'
|
|
42
53
|
Provides-Extra: oracledb
|
|
43
54
|
Requires-Dist: oracledb; extra == 'oracledb'
|
|
44
55
|
Provides-Extra: orjson
|
|
45
56
|
Requires-Dist: orjson; extra == 'orjson'
|
|
57
|
+
Provides-Extra: pandas
|
|
58
|
+
Requires-Dist: pandas; extra == 'pandas'
|
|
59
|
+
Requires-Dist: pyarrow; extra == 'pandas'
|
|
46
60
|
Provides-Extra: performance
|
|
47
61
|
Requires-Dist: msgspec; extra == 'performance'
|
|
48
62
|
Requires-Dist: sqlglot[rs]; extra == 'performance'
|
|
49
63
|
Provides-Extra: polars
|
|
50
64
|
Requires-Dist: polars; extra == 'polars'
|
|
51
65
|
Requires-Dist: pyarrow; extra == 'polars'
|
|
66
|
+
Provides-Extra: prometheus
|
|
67
|
+
Requires-Dist: prometheus-client; extra == 'prometheus'
|
|
52
68
|
Provides-Extra: psqlpy
|
|
53
69
|
Requires-Dist: psqlpy; extra == 'psqlpy'
|
|
54
70
|
Provides-Extra: psycopg
|
|
@@ -63,7 +79,7 @@ Requires-Dist: pymysql; extra == 'pymysql'
|
|
|
63
79
|
Provides-Extra: spanner
|
|
64
80
|
Requires-Dist: google-cloud-spanner; extra == 'spanner'
|
|
65
81
|
Provides-Extra: uuid
|
|
66
|
-
Requires-Dist: uuid-utils
|
|
82
|
+
Requires-Dist: uuid-utils; extra == 'uuid'
|
|
67
83
|
Description-Content-Type: text/markdown
|
|
68
84
|
|
|
69
85
|
# SQLSpec
|
|
@@ -72,18 +88,26 @@ Description-Content-Type: text/markdown
|
|
|
72
88
|
|
|
73
89
|
SQLSpec is an experimental Python library designed to streamline and modernize your SQL interactions across a variety of database systems. While still in its early stages, SQLSpec aims to provide a flexible, typed, and extensible interface for working with SQL in Python.
|
|
74
90
|
|
|
75
|
-
**Note**: SQLSpec is currently under active development and the API is subject to change.
|
|
91
|
+
**Note**: SQLSpec is currently under active development and the API is subject to change. It is not yet ready for production use. Contributions are welcome!
|
|
76
92
|
|
|
77
|
-
## Core Features (
|
|
93
|
+
## Core Features (Current and Planned)
|
|
94
|
+
|
|
95
|
+
### Currently Implemented
|
|
78
96
|
|
|
79
97
|
- **Consistent Database Session Interface**: Provides a consistent connectivity interface for interacting with one or more database systems, including SQLite, Postgres, DuckDB, MySQL, Oracle, SQL Server, Spanner, BigQuery, and more.
|
|
80
|
-
- **Emphasis on RAW SQL and Minimal Abstractions
|
|
98
|
+
- **Emphasis on RAW SQL and Minimal Abstractions**: SQLSpec is a library for working with SQL in Python. Its goals are to offer minimal abstractions between the user and the database. It does not aim to be an ORM library.
|
|
81
99
|
- **Type-Safe Queries**: Quickly map SQL queries to typed objects using libraries such as Pydantic, Msgspec, Attrs, etc.
|
|
82
|
-
- **Extensible Design**: Easily add support for new database dialects or extend existing functionality to meet your specific needs.
|
|
83
|
-
- **Minimal Dependencies**: SQLSpec is designed to be lightweight and can run on
|
|
84
|
-
- **Dynamic Query Manipulation**: Easily apply filters to pre-defined queries with a fluent, Pythonic API. Safely manipulate queries without the risk of SQL injection.
|
|
85
|
-
- **Dialect Validation and Conversion**: Use `sqlglot` to validate your SQL against specific dialects and seamlessly convert between them.
|
|
100
|
+
- **Extensible Design**: Easily add support for new database dialects or extend existing functionality to meet your specific needs. Easily add support for async and sync database drivers.
|
|
101
|
+
- **Minimal Dependencies**: SQLSpec is designed to be lightweight and can run on its own or with other libraries such as `litestar`, `fastapi`, `flask` and more. (Contributions welcome!)
|
|
86
102
|
- **Support for Async and Sync Database Drivers**: SQLSpec supports both async and sync database drivers, allowing you to choose the style that best fits your application.
|
|
103
|
+
|
|
104
|
+
### Experimental Features (API will change rapidly)
|
|
105
|
+
|
|
106
|
+
- **SQL Builder API**: Type-safe query builder with method chaining (experimental and subject to significant changes)
|
|
107
|
+
- **Dynamic Query Manipulation**: Apply filters to pre-defined queries with a fluent API. Safely manipulate queries without SQL injection risk.
|
|
108
|
+
- **Dialect Validation and Conversion**: Use `sqlglot` to validate your SQL against specific dialects and seamlessly convert between them.
|
|
109
|
+
- **Storage Operations**: Direct export to Parquet, CSV, JSON with Arrow integration
|
|
110
|
+
- **Instrumentation**: OpenTelemetry and Prometheus metrics support
|
|
87
111
|
- **Basic Migration Management**: A mechanism to generate empty migration files where you can add your own SQL and intelligently track which migrations have been applied.
|
|
88
112
|
|
|
89
113
|
## What SQLSpec Is Not (Yet)
|
|
@@ -94,16 +118,60 @@ SQLSpec is a work in progress. While it offers a solid foundation for modern SQL
|
|
|
94
118
|
|
|
95
119
|
We've talked about what SQLSpec is not, so let's look at what it can do.
|
|
96
120
|
|
|
97
|
-
These are just a few
|
|
121
|
+
These are just a few examples that demonstrate SQLSpec's flexibility. Each of the bundled adapters offers the same config and driver interfaces.
|
|
122
|
+
|
|
123
|
+
### Basic Usage
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from sqlspec import SQLSpec
|
|
127
|
+
from sqlspec.adapters.sqlite import SqliteConfig
|
|
128
|
+
from pydantic import BaseModel
|
|
129
|
+
# Create SQLSpec instance and configure database
|
|
130
|
+
sql = SQLSpec()
|
|
131
|
+
config = sql.add_config(SqliteConfig(database=":memory:"))
|
|
132
|
+
|
|
133
|
+
# Execute queries with automatic result mapping
|
|
134
|
+
with sql.provide_session(config) as session:
|
|
135
|
+
# Simple query
|
|
136
|
+
result = session.execute("SELECT 'Hello, SQLSpec!' as message")
|
|
137
|
+
print(result.get_first()) # {'message': 'Hello, SQLSpec!'}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### SQL Builder Example (Experimental)
|
|
141
|
+
|
|
142
|
+
**Warning**: The SQL Builder API is highly experimental and will change significantly.
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from sqlspec import sql
|
|
146
|
+
|
|
147
|
+
# Build a simple query
|
|
148
|
+
query = sql.select("id", "name", "email").from_("users").where("active = ?", True)
|
|
149
|
+
print(query.build().sql) # SELECT id, name, email FROM users WHERE active = ?
|
|
150
|
+
|
|
151
|
+
# More complex example with joins
|
|
152
|
+
query = (
|
|
153
|
+
sql.select("u.name", "COUNT(o.id) as order_count")
|
|
154
|
+
.from_("users u")
|
|
155
|
+
.left_join("orders o", "u.id = o.user_id")
|
|
156
|
+
.where("u.created_at > ?", "2024-01-01")
|
|
157
|
+
.group_by("u.name")
|
|
158
|
+
.having("COUNT(o.id) > ?", 5)
|
|
159
|
+
.order_by("order_count", desc=True)
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# Execute the built query
|
|
163
|
+
with sql.provide_session(config) as session:
|
|
164
|
+
results = session.execute(query.build())
|
|
165
|
+
```
|
|
98
166
|
|
|
99
167
|
### DuckDB LLM
|
|
100
168
|
|
|
101
|
-
This is a quick implementation using some of the built
|
|
169
|
+
This is a quick implementation using some of the built-in Secret and Extension management features of SQLSpec's DuckDB integration.
|
|
102
170
|
|
|
103
|
-
It allows you to communicate with any compatible OpenAPI conversations endpoint (such as Ollama).
|
|
171
|
+
It allows you to communicate with any compatible OpenAPI conversations endpoint (such as Ollama). This example:
|
|
104
172
|
|
|
105
173
|
- auto installs the `open_prompt` DuckDB extensions
|
|
106
|
-
- automatically creates the correct `open_prompt`
|
|
174
|
+
- automatically creates the correct `open_prompt` compatible secret required to use the extension
|
|
107
175
|
|
|
108
176
|
```py
|
|
109
177
|
# /// script
|
|
@@ -148,12 +216,12 @@ with sql.provide_session(etl_config) as session:
|
|
|
148
216
|
|
|
149
217
|
### DuckDB Gemini Embeddings
|
|
150
218
|
|
|
151
|
-
In this example, we are again using DuckDB.
|
|
219
|
+
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.
|
|
152
220
|
|
|
153
|
-
This example will
|
|
221
|
+
This example will:
|
|
154
222
|
|
|
155
223
|
- auto installs the `http_client` and `vss` (vector similarity search) DuckDB extensions
|
|
156
|
-
- when a connection is created, it ensures that the `generate_embeddings` macro exists in the DuckDB database
|
|
224
|
+
- when a connection is created, it ensures that the `generate_embeddings` macro exists in the DuckDB database
|
|
157
225
|
- Execute a simple query to call the Google API
|
|
158
226
|
|
|
159
227
|
```py
|
|
@@ -199,8 +267,8 @@ etl_config = sql.add_config(
|
|
|
199
267
|
)
|
|
200
268
|
)
|
|
201
269
|
with sql.provide_session(etl_config) as session:
|
|
202
|
-
result = session.
|
|
203
|
-
print(result) # result is a dictionary when `schema_type` is omitted.
|
|
270
|
+
result = session.execute("SELECT generate_embedding('example text')")
|
|
271
|
+
print(result.get_first()) # result is a dictionary when `schema_type` is omitted.
|
|
204
272
|
```
|
|
205
273
|
|
|
206
274
|
### Basic Litestar Integration
|
|
@@ -215,11 +283,10 @@ In this example we are going to demonstrate how to create a basic configuration
|
|
|
215
283
|
# ]
|
|
216
284
|
# ///
|
|
217
285
|
|
|
218
|
-
from aiosqlite import Connection
|
|
219
286
|
from litestar import Litestar, get
|
|
220
287
|
|
|
221
288
|
from sqlspec.adapters.aiosqlite import AiosqliteConfig, AiosqliteDriver
|
|
222
|
-
from sqlspec.extensions.litestar import SQLSpec
|
|
289
|
+
from sqlspec.extensions.litestar import DatabaseConfig, SQLSpec
|
|
223
290
|
|
|
224
291
|
|
|
225
292
|
@get("/")
|
|
@@ -227,15 +294,18 @@ async def simple_sqlite(db_session: AiosqliteDriver) -> dict[str, str]:
|
|
|
227
294
|
return await db_session.select_one("SELECT 'Hello, world!' AS greeting")
|
|
228
295
|
|
|
229
296
|
|
|
230
|
-
sqlspec = SQLSpec(
|
|
231
|
-
config=
|
|
297
|
+
sqlspec = SQLSpec(
|
|
298
|
+
config=DatabaseConfig(
|
|
299
|
+
config=AiosqliteConfig(),
|
|
300
|
+
commit_mode="autocommit"
|
|
301
|
+
)
|
|
232
302
|
)
|
|
233
303
|
app = Litestar(route_handlers=[simple_sqlite], plugins=[sqlspec])
|
|
234
304
|
```
|
|
235
305
|
|
|
236
306
|
## Inspiration and Future Direction
|
|
237
307
|
|
|
238
|
-
SQLSpec originally drew inspiration from features found in the `aiosql` library.
|
|
308
|
+
SQLSpec originally drew inspiration from features found in the `aiosql` library. This is a great library for working with and executing 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.
|
|
239
309
|
|
|
240
310
|
## Current Focus: Universal Connectivity
|
|
241
311
|
|
|
@@ -275,9 +345,10 @@ This list is not final. If you have a driver you'd like to see added, please ope
|
|
|
275
345
|
- `litestar/`: Litestar framework integration ✅
|
|
276
346
|
- `fastapi/`: Future home of `fastapi` integration.
|
|
277
347
|
- `flask/`: Future home of `flask` integration.
|
|
278
|
-
- `*/`: Future home of your favorite framework integration
|
|
348
|
+
- `*/`: Future home of your favorite framework integration
|
|
279
349
|
- `base.py`: Contains base protocols for database configurations.
|
|
280
|
-
- `
|
|
350
|
+
- `statement/`: Contains the SQL statement system with builders, validation, and transformation.
|
|
351
|
+
- `storage/`: Contains unified storage operations for data import/export.
|
|
281
352
|
- `utils/`: Contains utility functions used throughout the project.
|
|
282
353
|
- `exceptions.py`: Contains custom exceptions for SQLSpec.
|
|
283
354
|
- `typing.py`: Contains type hints, type guards and several facades for optional libraries that are not required for the core functionality of SQLSpec.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
sqlspec/__init__.py,sha256=hyVFQsYsgDWOZ2EPnW1LnATQVxGcYu3liBvSOvk4EQk,705
|
|
2
|
+
sqlspec/__metadata__.py,sha256=hNP3wXvtk8fQVPKGjRLpZ9mP-gaPJqzrmgm3UqpDIXQ,460
|
|
3
|
+
sqlspec/_serialization.py,sha256=7zox4G9zIps-DCdIEwYs4gwALfEOy1g_sWS4r5kpzO8,2604
|
|
4
|
+
sqlspec/_sql.py,sha256=VvSttObOgEDN_qECiOZu07_c3pgC1f9cdOORn-xWc88,42463
|
|
5
|
+
sqlspec/_typing.py,sha256=Vn1CTCfedAHZV3pKZP-l_mPw9pTxesCzRKVRypzNY_k,17903
|
|
6
|
+
sqlspec/base.py,sha256=a7adbCUzohf1MU-iP0TxazGsk9fsJhJmxuFKNWkgC6o,18355
|
|
7
|
+
sqlspec/config.py,sha256=a5VZj3UvK_St2XSchUw7NL3YBDpYp_FlaoVM8OkaI8I,13144
|
|
8
|
+
sqlspec/exceptions.py,sha256=Qdfd1k9Q4rTDH15zja2UzCOYAbR7idN3xGutDYGg3eg,13934
|
|
9
|
+
sqlspec/loader.py,sha256=1htipEcioTGrORu4sEYbK5w-zMnpWIZ4xSQlN-pJSf0,18336
|
|
10
|
+
sqlspec/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
sqlspec/typing.py,sha256=Wxc-ctN0hJ41U-qDzOaBA_HwTwAaQ7pN1nu0FpCNruA,20792
|
|
12
|
+
sqlspec/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
sqlspec/adapters/adbc/__init__.py,sha256=v9bs7501PgEyzR1XIsEpE2Wdrj9DOYkZ4grysw72UXk,218
|
|
14
|
+
sqlspec/adapters/adbc/config.py,sha256=-wkuxXj-cqTFeIA7_mnPD37oZCHrnVjkOYKIwTZkD1Y,20159
|
|
15
|
+
sqlspec/adapters/adbc/driver.py,sha256=22P16Pz6Bk399TSjoODLK1ZRcXxTHMGmjp_3KuCSUzM,16462
|
|
16
|
+
sqlspec/adapters/aiosqlite/__init__.py,sha256=7wPmhXQeu4jRi-LZzPxAPTdgRmgmyqCn9U-4wnCWoLM,258
|
|
17
|
+
sqlspec/adapters/aiosqlite/config.py,sha256=K8vPiGSDeSCTFIm4XgCEGbXG8uIAX6JjYHv2890RbTw,7174
|
|
18
|
+
sqlspec/adapters/aiosqlite/driver.py,sha256=DelxxH9_TKHmqYDG3HbXEs4ypk8r-FUdBnGZOBNvHek,12398
|
|
19
|
+
sqlspec/adapters/asyncmy/__init__.py,sha256=zYpebEt_PrNCifLcqXiCcWVm0Zl-LvWbFDromWwSTw8,270
|
|
20
|
+
sqlspec/adapters/asyncmy/config.py,sha256=ZCwg63zsa-SEiHjJjCZYvnu-hl5cdw-o8j3u01_r7W4,10402
|
|
21
|
+
sqlspec/adapters/asyncmy/driver.py,sha256=Q3dVCcm24z-Cvd2GcHaZKfP95cb5uk7u1-b8zuMQJpo,9982
|
|
22
|
+
sqlspec/adapters/asyncpg/__init__.py,sha256=svnbKlOin8jRL88AdAqflBEU-WEAzp0Thc2y50QsxIo,310
|
|
23
|
+
sqlspec/adapters/asyncpg/config.py,sha256=IHovVNGryGsu_ulYBY9TJrXaz_mPpqIgnh4c-juIglA,13033
|
|
24
|
+
sqlspec/adapters/asyncpg/driver.py,sha256=U32J4W4RXvW5iQfqBI6_uhVqc4Kyaj2IpUe9BRJS8r4,19105
|
|
25
|
+
sqlspec/adapters/bigquery/__init__.py,sha256=fWRH-BoCNX4rYwhU2DK64cXWpfkYpWIExddJAti0bxM,250
|
|
26
|
+
sqlspec/adapters/bigquery/config.py,sha256=bTmos8OcJcy7kPmBds-0EPLe5XyREnwOR0YYd5fkZjg,16971
|
|
27
|
+
sqlspec/adapters/bigquery/driver.py,sha256=46m5D-03mFnKM0rLwuvmeGAkRotbwm_qh6X0Re88H1I,28412
|
|
28
|
+
sqlspec/adapters/duckdb/__init__.py,sha256=I1f6szfpKKrq6WhyDoUXD3i3NN4yjsh94_fhP1URI5M,351
|
|
29
|
+
sqlspec/adapters/duckdb/config.py,sha256=az9WFJXyw1M0yiNw2tqf7GYM-9tblHj_0BHLYzFytXk,20413
|
|
30
|
+
sqlspec/adapters/duckdb/driver.py,sha256=Vnr6xYJtqBKHAf76xy9o18GYly_oexkEfAd25Jd_CZ4,17676
|
|
31
|
+
sqlspec/adapters/oracledb/__init__.py,sha256=nn3whn0UyBThoXnE1-5_byVuc9PJjvB2P896p7LpNZI,474
|
|
32
|
+
sqlspec/adapters/oracledb/config.py,sha256=HQpgGMf0oMSWr2k4q3uPEF4LWR7QPnzZE6lxLDq723U,22737
|
|
33
|
+
sqlspec/adapters/oracledb/driver.py,sha256=YQnudVnP1EizI4eN3_llITdJ7TjpbLNxFkYlkSJVaQs,25463
|
|
34
|
+
sqlspec/adapters/psqlpy/__init__.py,sha256=dp0-96V4SAbNEvOqlJ8PWEyJMYzZGElVoyneZqJ-fbQ,297
|
|
35
|
+
sqlspec/adapters/psqlpy/config.py,sha256=NKlHHDjKr5dF4LQprYA5ivJsNy2UXkvYg8B-kXOvvjE,16342
|
|
36
|
+
sqlspec/adapters/psqlpy/driver.py,sha256=xI89mFdkQulcntbH4ALTOOHn5b6_skCgSbjYDUfvyG4,8650
|
|
37
|
+
sqlspec/adapters/psycopg/__init__.py,sha256=ukkCUPrJPyAG78v4rOqcK4WZDs26PeB9Ra9qkFrGJ3E,484
|
|
38
|
+
sqlspec/adapters/psycopg/config.py,sha256=pNgh0FAB_5dpRHBY9zKEs9uofDtUod2IV4pjCY_jWK8,27723
|
|
39
|
+
sqlspec/adapters/psycopg/driver.py,sha256=oTdhj5OXx1gtnA0ZIS0Fdvqu8erXhItn1fl0-lRxatI,33474
|
|
40
|
+
sqlspec/adapters/sqlite/__init__.py,sha256=1lYrJ-DojUAOvXMoZRUJNEVyMmYhO41hMJnDWCEeXlw,234
|
|
41
|
+
sqlspec/adapters/sqlite/config.py,sha256=7yHe1eeVGFZvmTdxUPF2XcIiEcgZFUdncuGf_6qG8Xc,6153
|
|
42
|
+
sqlspec/adapters/sqlite/driver.py,sha256=aQ7JOWyC6pfSq2cRz3OrjQ67NChhU0UercgvgomU0Ec,10703
|
|
43
|
+
sqlspec/driver/__init__.py,sha256=0udRS5IlJ17HzOCvzapG8c_88yAwTQri1XLD_3fZxZU,671
|
|
44
|
+
sqlspec/driver/_async.py,sha256=JYn-8E_IQHBCpAPfZ3g0IpNc_0yCwYu98lKgcHxWdPU,10130
|
|
45
|
+
sqlspec/driver/_common.py,sha256=ceAvzvI9zV3xBotEAMCuJeEbCHaeV82UJyfYYNnrspk,14680
|
|
46
|
+
sqlspec/driver/_sync.py,sha256=8jyP-TInSM3iLNhyOMNthvoE6vNwPp2wV8oAQhObuqc,10255
|
|
47
|
+
sqlspec/driver/mixins/__init__.py,sha256=-FSWLYq644NftRsmjmXMA9Q7_l7tIFAIh1ZyK0yrba8,652
|
|
48
|
+
sqlspec/driver/mixins/_pipeline.py,sha256=XCr4PTUvvzvte2Yw1g-hqje5dg3bgrsi46kj8kdy8Hw,20083
|
|
49
|
+
sqlspec/driver/mixins/_result_utils.py,sha256=j6BrFCC9E6xbnn-mH0sd2JBlxZFjA30LWKrYZh8gjXM,4882
|
|
50
|
+
sqlspec/driver/mixins/_sql_translator.py,sha256=p_PR4KBg9NKNpRpiEqA0hcUIttpdillHpnLUVJEcxuE,1519
|
|
51
|
+
sqlspec/driver/mixins/_storage.py,sha256=yosmC_nJI-3dg4aVy6iloy4V-d9DBDoC_8G2RLTsenI,43106
|
|
52
|
+
sqlspec/driver/mixins/_type_coercion.py,sha256=17HC2Vsd70tRlUawO0CkUeoJUd2jG5R5Yb1A6Jr-1Tc,4716
|
|
53
|
+
sqlspec/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
|
+
sqlspec/extensions/aiosql/__init__.py,sha256=-9cefc9pYPf9vCgALoB-y1DtmcgRjKe2azfl6RIarAA,414
|
|
55
|
+
sqlspec/extensions/aiosql/adapter.py,sha256=EcMzTQ2-EzH-C2G1nJ6dw5O09rUzdAclmgbFb9wkJ8E,16993
|
|
56
|
+
sqlspec/extensions/litestar/__init__.py,sha256=aXF2g4-U86pdJHoOA6RCvZgnyHVBbjRhlWqcSuRX2gg,243
|
|
57
|
+
sqlspec/extensions/litestar/_utils.py,sha256=o-FuUj1_WkDrLxQxiP6hXDak66XfyRP3QLyEVKrIRjI,1954
|
|
58
|
+
sqlspec/extensions/litestar/config.py,sha256=vLXM425tCV3IbJiNO1ZG90ctjBTb9oQCuLsqCaUYmo8,4685
|
|
59
|
+
sqlspec/extensions/litestar/handlers.py,sha256=q-peGdWgvEI_s9rWt0SRIQvuhON_ItrjiVxIF2Pwm1U,10546
|
|
60
|
+
sqlspec/extensions/litestar/plugin.py,sha256=itsduzXN-YzDm1wVqUcJQLcYGp3ogF9Aw2IU3i46iqk,5596
|
|
61
|
+
sqlspec/extensions/litestar/providers.py,sha256=9wAr3c09ObOJmej1hQ3YizrK3YMN3S2xfBh23r-KSzE,21749
|
|
62
|
+
sqlspec/service/__init__.py,sha256=EfyTy8X8GXxV0drxaBMJ0aRRqg3ZnwD6iu5oCTAQc1k,79
|
|
63
|
+
sqlspec/service/base.py,sha256=vbJFO0EywWUgGr8WHHYxUCP-7sGF1Rxfi7ov51LWg50,521
|
|
64
|
+
sqlspec/service/pagination.py,sha256=ndLQwsvswoISWEE_3IG9nmdHt42OZkVMJvr-2HTWsLw,619
|
|
65
|
+
sqlspec/statement/__init__.py,sha256=NDvdrpr1EqAZXp4HmhTVaRnWVscahPSHpmSO8DHSoMY,536
|
|
66
|
+
sqlspec/statement/filters.py,sha256=SPDupr8mJK1Ua3z2sXvE8dWAkamDAhE2MHn6yEM_6uU,21850
|
|
67
|
+
sqlspec/statement/parameters.py,sha256=HjKg6Y-1ImBiigNlodGxsVOMPma1pBoJRISrQu_iqfM,31183
|
|
68
|
+
sqlspec/statement/result.py,sha256=rEShBX-NGK3-0K6q1XwB0zQvPEygVVB_-rXodiUMbSo,18307
|
|
69
|
+
sqlspec/statement/splitter.py,sha256=Y1eubbNSn3IRhvQhAZVzBB-oDZ5K5uoJYOGti1ds_5E,24850
|
|
70
|
+
sqlspec/statement/sql.py,sha256=7H2LOwQ8H2pONFPF7RcK6WkF7g_J-FUeuoiSXD05AUs,51033
|
|
71
|
+
sqlspec/statement/builder/__init__.py,sha256=7mITd7RG_Sc4RBgQJoAAosLAV9WdF4-E-CzvUA-hT0A,1584
|
|
72
|
+
sqlspec/statement/builder/_ddl_utils.py,sha256=or0DpLIUupCIxs3u6kMJQgmfj_P21TxMDHbM0rdSNnY,4745
|
|
73
|
+
sqlspec/statement/builder/_parsing_utils.py,sha256=OKOB-V1UhOCUNVoJHDArUl0WKIMVPshCFFrJcjKvs9Y,5613
|
|
74
|
+
sqlspec/statement/builder/base.py,sha256=swpCj0Oga3HyLKKmriwsu046puvkTxTZ528SPa9v_kk,12771
|
|
75
|
+
sqlspec/statement/builder/ddl.py,sha256=0GjjPc8u3FP_5kFza-J2kw0B0PBlibgjAu7kCgDMwXI,50394
|
|
76
|
+
sqlspec/statement/builder/delete.py,sha256=yv78i2vWpRZ0NbQCkJz1JAYekius2MOZ_zmiVaP4fcw,2423
|
|
77
|
+
sqlspec/statement/builder/insert.py,sha256=EduHjewraoauM4mH3r4OyrBc31FbCAad93B8vg9WpYc,9922
|
|
78
|
+
sqlspec/statement/builder/merge.py,sha256=tNV81MiDUmQJ9KiInP8rEGvxQ50JAD2Itmdbr5921vI,2811
|
|
79
|
+
sqlspec/statement/builder/protocols.py,sha256=ihy6uNv6lGdj1UHu-qWn08YhIn_YfjPup0qsBnaB1zU,575
|
|
80
|
+
sqlspec/statement/builder/select.py,sha256=13dNa7XXHjGlSeRsjWTrOCZX0uK61mMbiRzk1gTq8is,8436
|
|
81
|
+
sqlspec/statement/builder/update.py,sha256=K2DxlZM9e0DoO4T5MbeVNL9BCkhov7z8c6L9zuvjttc,5950
|
|
82
|
+
sqlspec/statement/builder/mixins/__init__.py,sha256=B5GhsdySb_-DN3SvBlA2oimmymAJX3Rf4A7Xnz3uNN4,2887
|
|
83
|
+
sqlspec/statement/builder/mixins/_aggregate_functions.py,sha256=RU91GKzwKABod-nHxhrT2nCoYFAf-kSE4VHmF23n__Y,6109
|
|
84
|
+
sqlspec/statement/builder/mixins/_case_builder.py,sha256=fGdevoEZxmoJjsDV9Wwfom8vu3lmgF9B_o5HXCf25Kg,3047
|
|
85
|
+
sqlspec/statement/builder/mixins/_common_table_expr.py,sha256=1e8KKoQjuMGKuutjZ4KFWhsH7mbRMhXsANqLLJ71SzA,3741
|
|
86
|
+
sqlspec/statement/builder/mixins/_delete_from.py,sha256=GtuTYfG7N9RPAbyXIGKCoirRTg_gcHyoGI6pAFhUkEY,1026
|
|
87
|
+
sqlspec/statement/builder/mixins/_from.py,sha256=YOYG-Bvpis9Wt2RI4byr_eRef35OXS6rBuigGsEOGW0,2618
|
|
88
|
+
sqlspec/statement/builder/mixins/_group_by.py,sha256=qefERqljQY58PmJ3Q0nF8NNSO31fa2XDbevIpjiPzJs,4190
|
|
89
|
+
sqlspec/statement/builder/mixins/_having.py,sha256=X8-hdwEeJg4RYxyjhaYLvlkpzE0AwIPl6t8SPGz5gi0,1112
|
|
90
|
+
sqlspec/statement/builder/mixins/_insert_from_select.py,sha256=XBahvM2VA-qwzx3PLTRaqT21fFaRYwHACOADQ6mZwUE,1851
|
|
91
|
+
sqlspec/statement/builder/mixins/_insert_into.py,sha256=7979JCYqKM_NRTHwkrJJY6l9lS2AQ-evZYRU8fs3yw0,1049
|
|
92
|
+
sqlspec/statement/builder/mixins/_insert_values.py,sha256=RE2ApSc6OwVqToXTVwy1bhRFomfNOmrnSte8fVjEINg,2923
|
|
93
|
+
sqlspec/statement/builder/mixins/_join.py,sha256=g3OxKMEiyNSGZRiBgdPT1Lvcr-h3u_3O0msN59B1Itg,5128
|
|
94
|
+
sqlspec/statement/builder/mixins/_limit_offset.py,sha256=nyeajD1cYj0Wvki1GLYJbsfQzfaH5tyMkeGVU9fGWL0,1762
|
|
95
|
+
sqlspec/statement/builder/mixins/_merge_clauses.py,sha256=3w22HImSoQvDMMTa9xJAHw4cx0-KrteLumFpQvg2o0I,16868
|
|
96
|
+
sqlspec/statement/builder/mixins/_order_by.py,sha256=pcqEQIkpJ-KgLNLIqXFQQgdzGypXw0Umndn-X8TgKis,1729
|
|
97
|
+
sqlspec/statement/builder/mixins/_pivot.py,sha256=GyLEFkhRlG_fxeRfzGRTVd5wZVtuA5HkNrvmOi7PF3Q,3442
|
|
98
|
+
sqlspec/statement/builder/mixins/_returning.py,sha256=O39j2MEIcqiiUhFFGnyGwIXhLS7KrGigfZ9kPxFjjtI,1349
|
|
99
|
+
sqlspec/statement/builder/mixins/_select_columns.py,sha256=6UXpHHDmka8NbrtbR-G-Xd1ux4DUazEonZndAXecWJI,2302
|
|
100
|
+
sqlspec/statement/builder/mixins/_set_ops.py,sha256=uWV32ZAi2tojbS9b6Q0ZDIn1Rhbx4cCE42jhbVdm90I,5291
|
|
101
|
+
sqlspec/statement/builder/mixins/_unpivot.py,sha256=dXdYk4UdFbDf7yNFRPrX3G5XtOgfw_BzaEI9au3ltKw,3296
|
|
102
|
+
sqlspec/statement/builder/mixins/_update_from.py,sha256=r8-_iy5Kdp79eo34oNmNVLSnWsy3WUvwETODnKzBgZY,2461
|
|
103
|
+
sqlspec/statement/builder/mixins/_update_set.py,sha256=tSnZ6cLKfta-OKHYAkoInQScMbxp9rxtFj0SBGnpGZ0,4041
|
|
104
|
+
sqlspec/statement/builder/mixins/_update_table.py,sha256=FX3KezuHdu7YLQI4i5iniHWk1Lbzph8MzLcOM6iTd70,936
|
|
105
|
+
sqlspec/statement/builder/mixins/_where.py,sha256=KZhOykAWrDYaD6p_W-nbVkh3-9ZS9paw77L3JttoeT8,19452
|
|
106
|
+
sqlspec/statement/builder/mixins/_window_functions.py,sha256=8ldy06gK6jOlGg31oa1dCrG7IkfCVYvVr_f-lx0YcgU,3745
|
|
107
|
+
sqlspec/statement/pipelines/__init__.py,sha256=vmFxkD7vnpyfMbuDsOF67B3DWDeCz183326pg1G0-5k,2206
|
|
108
|
+
sqlspec/statement/pipelines/base.py,sha256=ylXSyab6P4v9PY0tDPlcHeCEkdFPECDq0Jjooi3E2ek,13019
|
|
109
|
+
sqlspec/statement/pipelines/context.py,sha256=fhEKicpUcHXbyhgBpJnYnYPd4vWpkFoVuLWydsSB2dE,4371
|
|
110
|
+
sqlspec/statement/pipelines/result_types.py,sha256=G34HofWjcK0SFMTyqVBFv-t17jkWKP9cCugA4Rds4qk,1046
|
|
111
|
+
sqlspec/statement/pipelines/analyzers/__init__.py,sha256=RY7W0AiWG-8qdrTmRSGlEofjrPPJCJUnNK-LRukKt5Q,330
|
|
112
|
+
sqlspec/statement/pipelines/analyzers/_analyzer.py,sha256=8Cfxr4gZZlfmn4v3tatyqF4i10s6L9lFXRYwcVB_zn4,27741
|
|
113
|
+
sqlspec/statement/pipelines/transformers/__init__.py,sha256=wwhAWQQCCoL2WhVZQ7ptt9mn4B_AY8pK9M2SUjj5DtU,550
|
|
114
|
+
sqlspec/statement/pipelines/transformers/_expression_simplifier.py,sha256=90u62-WMG0l1_2S_u-93Oo3rVnAjvlTJkPf1IzgaP2E,11630
|
|
115
|
+
sqlspec/statement/pipelines/transformers/_literal_parameterizer.py,sha256=NMzSYZ6HfqoujOm_M5pS95oxOhF3_kWrQZjWln4UGEI,26624
|
|
116
|
+
sqlspec/statement/pipelines/transformers/_remove_comments.py,sha256=PW1q7B2D-E_x2V1mTEUw_Uijj9W5-B6OteWE96aH7i8,2781
|
|
117
|
+
sqlspec/statement/pipelines/transformers/_remove_hints.py,sha256=D13MDx9vG3n_y5VV6swTNx2z1zHnTAuRwOiKp0VYg2k,3334
|
|
118
|
+
sqlspec/statement/pipelines/validators/__init__.py,sha256=cdlwdLhOT2OwTbueIsA7bfRG2b6y-j7dw9pMzl5AP0M,747
|
|
119
|
+
sqlspec/statement/pipelines/validators/_dml_safety.py,sha256=FUfF7iWUc0tgmg-OwDgpYA3ZRy3z01PfGadDcaqENTM,10078
|
|
120
|
+
sqlspec/statement/pipelines/validators/_parameter_style.py,sha256=I6tTeYBQFeg2uPlQWDyy7sMRidm_tt7ItTzhauhNrWA,13583
|
|
121
|
+
sqlspec/statement/pipelines/validators/_performance.py,sha256=sSIknorC-VJghFJAATqfnnNUyUnQ0bN_GpXmmGZkkkA,25800
|
|
122
|
+
sqlspec/statement/pipelines/validators/_security.py,sha256=62k5F4RCz1O_bb1rIPjm2BjHyp3YDObq2hjv74zY8Ac,43589
|
|
123
|
+
sqlspec/statement/pipelines/validators/base.py,sha256=6xd0FCPOTpS77cn-abT1auubxASs5HPY2fgjhX1WZZQ,2166
|
|
124
|
+
sqlspec/storage/__init__.py,sha256=dS1Qt2cTJpIBOKnw3ih3Z7FPFePFPPSazhkEbkV5DxU,516
|
|
125
|
+
sqlspec/storage/protocol.py,sha256=4hiGGmWtMZFkwCaNYXHt416j-i281xha0Hj7-EynVBs,6430
|
|
126
|
+
sqlspec/storage/registry.py,sha256=it3S-jxf-rXcYwgquydiSo0AeXXqnBEhAVQ2Gk11GNU,11724
|
|
127
|
+
sqlspec/storage/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
128
|
+
sqlspec/storage/backends/base.py,sha256=34XYQuz1tQ-q_ZZwOz-Kimgvl088SR3VUYJoA-STslc,6350
|
|
129
|
+
sqlspec/storage/backends/fsspec.py,sha256=bCaNkubANlcb3UlUC0EchHn44XJRS3Z-99fnZMgW-yc,12527
|
|
130
|
+
sqlspec/storage/backends/obstore.py,sha256=HdnEGQOPvQY9q7xEsjdy7JIqj-tWNBLkmEmllbDgAWA,20659
|
|
131
|
+
sqlspec/utils/__init__.py,sha256=_Ya8IZuc2cZIstXr_xjgnSfxICXHXvu5mfWsi2USDrw,183
|
|
132
|
+
sqlspec/utils/correlation.py,sha256=qzqw3CnhasS14hv0uHKh9DehbOX3dEHuB_NNz6Kg6QQ,4457
|
|
133
|
+
sqlspec/utils/deprecation.py,sha256=zrmb_eKRlLWVA6dWrjUbN3Vz6D3_-Z_15Ixk4H-sDRk,3850
|
|
134
|
+
sqlspec/utils/fixtures.py,sha256=q_Pghpmw2VgJ9P0TfkyjSF5PvdaD5Y2Laha0Bj4IDrA,1838
|
|
135
|
+
sqlspec/utils/logging.py,sha256=g8lZXfbr79Ayu0YnnoOcwzGGeg9HUg_JyFpAbbUCd_0,4064
|
|
136
|
+
sqlspec/utils/module_loader.py,sha256=9LcmEhy4T0jgkCaDVkxX47PSgJOMeJ8IV67yXEWBp-U,3074
|
|
137
|
+
sqlspec/utils/serializers.py,sha256=TKsRryRcYMnb8Z8MGkYGClIxcYvC8CW7MsrPQTJqEcY,154
|
|
138
|
+
sqlspec/utils/singleton.py,sha256=KZ7481tlDAxq6gcAlpULVqPLNc9P0XkHOEp7hfWIHcI,1096
|
|
139
|
+
sqlspec/utils/sync_tools.py,sha256=9ZL_7wJks896ZsRGVB4mS8DgIwK3tKmZClvLblEx8q4,8954
|
|
140
|
+
sqlspec/utils/text.py,sha256=Bit0I0nBgETvfumzguOQFiqrqwplqaoTeEfGdLzgPOk,5083
|
|
141
|
+
sqlspec-0.12.0.dist-info/METADATA,sha256=fUqPZZSl8key5koLqohfDZ2IUlyJ1Z1qbokEcLYdSS8,16663
|
|
142
|
+
sqlspec-0.12.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
143
|
+
sqlspec-0.12.0.dist-info/licenses/LICENSE,sha256=MdujfZ6l5HuLz4mElxlu049itenOR3gnhN1_Nd3nVcM,1078
|
|
144
|
+
sqlspec-0.12.0.dist-info/licenses/NOTICE,sha256=Lyir8ozXWov7CyYS4huVaOCNrtgL17P-bNV-5daLntQ,1634
|
|
145
|
+
sqlspec-0.12.0.dist-info/RECORD,,
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass, field
|
|
2
|
-
from typing import TYPE_CHECKING, Optional
|
|
3
|
-
|
|
4
|
-
from google.cloud.bigquery import LoadJobConfig, QueryJobConfig
|
|
5
|
-
|
|
6
|
-
if TYPE_CHECKING:
|
|
7
|
-
from google.api_core.client_info import ClientInfo
|
|
8
|
-
from google.api_core.client_options import ClientOptions
|
|
9
|
-
from google.auth.credentials import Credentials
|
|
10
|
-
|
|
11
|
-
__all__ = ("BigQueryConnectionConfigCommon",)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@dataclass
|
|
15
|
-
class BigQueryConnectionConfigCommon:
|
|
16
|
-
"""Common configuration options for BigQuery."""
|
|
17
|
-
|
|
18
|
-
project: "Optional[str]" = field(default=None)
|
|
19
|
-
"""Google Cloud project ID."""
|
|
20
|
-
location: "Optional[str]" = field(default=None)
|
|
21
|
-
"""Default geographic location for jobs and datasets."""
|
|
22
|
-
credentials: "Optional[Credentials]" = field(default=None, hash=False)
|
|
23
|
-
"""Credentials to use for authentication."""
|
|
24
|
-
dataset_id: "Optional[str]" = field(default=None)
|
|
25
|
-
"""Default dataset ID to use if not specified in queries."""
|
|
26
|
-
credentials_path: "Optional[str]" = field(default=None)
|
|
27
|
-
"""Path to Google Cloud service account key file (JSON). If None, attempts default authentication."""
|
|
28
|
-
client_options: "Optional[ClientOptions]" = field(default=None, hash=False)
|
|
29
|
-
"""Client options used to set user options on the client (e.g., api_endpoint)."""
|
|
30
|
-
default_query_job_config: "Optional[QueryJobConfig]" = field(default=None, hash=False)
|
|
31
|
-
"""Default QueryJobConfig settings."""
|
|
32
|
-
default_load_job_config: "Optional[LoadJobConfig]" = field(default=None, hash=False)
|
|
33
|
-
"""Default LoadJobConfig settings."""
|
|
34
|
-
client_info: "Optional[ClientInfo]" = field(default=None, hash=False)
|
|
35
|
-
"""Client info used to send a user-agent string along with API requests."""
|
|
36
|
-
|
|
37
|
-
def __post_init__(self) -> None:
|
|
38
|
-
"""Post-initialization hook."""
|
|
39
|
-
if self.default_query_job_config is None:
|
|
40
|
-
self.default_query_job_config = QueryJobConfig(default_dataset=self.dataset_id)
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import contextlib
|
|
2
|
-
from dataclasses import dataclass, field
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Optional
|
|
4
|
-
|
|
5
|
-
from sqlspec.adapters.bigquery.config._common import BigQueryConnectionConfigCommon
|
|
6
|
-
from sqlspec.adapters.bigquery.driver import BigQueryConnection, BigQueryDriver
|
|
7
|
-
from sqlspec.base import NoPoolSyncConfig
|
|
8
|
-
from sqlspec.typing import dataclass_to_dict
|
|
9
|
-
|
|
10
|
-
if TYPE_CHECKING:
|
|
11
|
-
from collections.abc import Iterator
|
|
12
|
-
|
|
13
|
-
__all__ = ("BigQueryConfig", "BigQueryConnectionConfig")
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class BigQueryConnectionConfig(BigQueryConnectionConfigCommon):
|
|
17
|
-
"""BigQuery Connection Configuration."""
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@dataclass
|
|
21
|
-
class BigQueryConfig(NoPoolSyncConfig["BigQueryConnection", "BigQueryDriver"]):
|
|
22
|
-
"""BigQuery Synchronous Driver Configuration."""
|
|
23
|
-
|
|
24
|
-
connection_config: "BigQueryConnectionConfig" = field(default_factory=BigQueryConnectionConfig)
|
|
25
|
-
"""BigQuery Connection Configuration."""
|
|
26
|
-
driver_type: "type[BigQueryDriver]" = field(init=False, repr=False, default=BigQueryDriver)
|
|
27
|
-
"""BigQuery Driver Type."""
|
|
28
|
-
connection_type: "type[BigQueryConnection]" = field(init=False, repr=False, default=BigQueryConnection)
|
|
29
|
-
"""BigQuery Connection Type."""
|
|
30
|
-
pool_instance: "None" = field(init=False, repr=False, default=None, hash=False)
|
|
31
|
-
"""This is set to have a init=False since BigQuery does not support pooling."""
|
|
32
|
-
connection_instance: "Optional[BigQueryConnection]" = field(init=False, repr=False, default=None, hash=False)
|
|
33
|
-
"""BigQuery Connection Instance."""
|
|
34
|
-
|
|
35
|
-
@property
|
|
36
|
-
def connection_config_dict(self) -> "dict[str, Any]":
|
|
37
|
-
"""Return the connection configuration as a dict.
|
|
38
|
-
|
|
39
|
-
Returns:
|
|
40
|
-
A string keyed dict of config kwargs for the BigQueryConnection constructor.
|
|
41
|
-
"""
|
|
42
|
-
return dataclass_to_dict(
|
|
43
|
-
self.connection_config,
|
|
44
|
-
exclude_empty=True,
|
|
45
|
-
exclude_none=True,
|
|
46
|
-
exclude={"dataset_id", "credentials_path"},
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
def create_connection(self) -> "BigQueryConnection":
|
|
50
|
-
"""Create a BigQuery Client instance.
|
|
51
|
-
|
|
52
|
-
Returns:
|
|
53
|
-
A BigQuery Client instance.
|
|
54
|
-
"""
|
|
55
|
-
if self.connection_instance is not None:
|
|
56
|
-
return self.connection_instance
|
|
57
|
-
|
|
58
|
-
self.connection_instance = self.connection_type(**self.connection_config_dict)
|
|
59
|
-
return self.connection_instance
|
|
60
|
-
|
|
61
|
-
@contextlib.contextmanager
|
|
62
|
-
def provide_connection(self, *args: Any, **kwargs: Any) -> "Iterator[BigQueryConnection]":
|
|
63
|
-
"""Provide a BigQuery client within a context manager.
|
|
64
|
-
|
|
65
|
-
Args:
|
|
66
|
-
*args: Additional arguments to pass to the connection.
|
|
67
|
-
**kwargs: Additional keyword arguments to pass to the connection.
|
|
68
|
-
|
|
69
|
-
Yields:
|
|
70
|
-
An iterator of BigQuery Client instances.
|
|
71
|
-
"""
|
|
72
|
-
conn = self.create_connection()
|
|
73
|
-
yield conn
|
|
74
|
-
|
|
75
|
-
@contextlib.contextmanager
|
|
76
|
-
def provide_session(self, *args: Any, **kwargs: Any) -> "Iterator[BigQueryDriver]":
|
|
77
|
-
"""Provide a BigQuery driver session within a context manager.
|
|
78
|
-
|
|
79
|
-
Args:
|
|
80
|
-
*args: Additional arguments to pass to the driver.
|
|
81
|
-
**kwargs: Additional keyword arguments to pass to the driver.
|
|
82
|
-
|
|
83
|
-
Yields:
|
|
84
|
-
An iterator of BigQueryDriver instances.
|
|
85
|
-
"""
|
|
86
|
-
conn = self.create_connection()
|
|
87
|
-
yield self.driver_type(connection=conn)
|