sqlspec 0.13.1__py3-none-any.whl → 0.16.2__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.

Files changed (185) hide show
  1. sqlspec/__init__.py +71 -8
  2. sqlspec/__main__.py +12 -0
  3. sqlspec/__metadata__.py +1 -3
  4. sqlspec/_serialization.py +1 -2
  5. sqlspec/_sql.py +930 -136
  6. sqlspec/_typing.py +278 -142
  7. sqlspec/adapters/adbc/__init__.py +4 -3
  8. sqlspec/adapters/adbc/_types.py +12 -0
  9. sqlspec/adapters/adbc/config.py +116 -285
  10. sqlspec/adapters/adbc/driver.py +462 -340
  11. sqlspec/adapters/aiosqlite/__init__.py +18 -3
  12. sqlspec/adapters/aiosqlite/_types.py +13 -0
  13. sqlspec/adapters/aiosqlite/config.py +202 -150
  14. sqlspec/adapters/aiosqlite/driver.py +226 -247
  15. sqlspec/adapters/asyncmy/__init__.py +18 -3
  16. sqlspec/adapters/asyncmy/_types.py +12 -0
  17. sqlspec/adapters/asyncmy/config.py +80 -199
  18. sqlspec/adapters/asyncmy/driver.py +257 -215
  19. sqlspec/adapters/asyncpg/__init__.py +19 -4
  20. sqlspec/adapters/asyncpg/_types.py +17 -0
  21. sqlspec/adapters/asyncpg/config.py +81 -214
  22. sqlspec/adapters/asyncpg/driver.py +284 -359
  23. sqlspec/adapters/bigquery/__init__.py +17 -3
  24. sqlspec/adapters/bigquery/_types.py +12 -0
  25. sqlspec/adapters/bigquery/config.py +191 -299
  26. sqlspec/adapters/bigquery/driver.py +474 -634
  27. sqlspec/adapters/duckdb/__init__.py +14 -3
  28. sqlspec/adapters/duckdb/_types.py +12 -0
  29. sqlspec/adapters/duckdb/config.py +414 -397
  30. sqlspec/adapters/duckdb/driver.py +342 -393
  31. sqlspec/adapters/oracledb/__init__.py +19 -5
  32. sqlspec/adapters/oracledb/_types.py +14 -0
  33. sqlspec/adapters/oracledb/config.py +123 -458
  34. sqlspec/adapters/oracledb/driver.py +505 -531
  35. sqlspec/adapters/psqlpy/__init__.py +13 -3
  36. sqlspec/adapters/psqlpy/_types.py +11 -0
  37. sqlspec/adapters/psqlpy/config.py +93 -307
  38. sqlspec/adapters/psqlpy/driver.py +504 -213
  39. sqlspec/adapters/psycopg/__init__.py +19 -5
  40. sqlspec/adapters/psycopg/_types.py +17 -0
  41. sqlspec/adapters/psycopg/config.py +143 -472
  42. sqlspec/adapters/psycopg/driver.py +704 -825
  43. sqlspec/adapters/sqlite/__init__.py +14 -3
  44. sqlspec/adapters/sqlite/_types.py +11 -0
  45. sqlspec/adapters/sqlite/config.py +208 -142
  46. sqlspec/adapters/sqlite/driver.py +263 -278
  47. sqlspec/base.py +105 -9
  48. sqlspec/{statement/builder → builder}/__init__.py +12 -14
  49. sqlspec/{statement/builder/base.py → builder/_base.py} +184 -86
  50. sqlspec/{statement/builder/column.py → builder/_column.py} +97 -60
  51. sqlspec/{statement/builder/ddl.py → builder/_ddl.py} +61 -131
  52. sqlspec/{statement/builder → builder}/_ddl_utils.py +4 -10
  53. sqlspec/{statement/builder/delete.py → builder/_delete.py} +10 -30
  54. sqlspec/builder/_insert.py +421 -0
  55. sqlspec/builder/_merge.py +71 -0
  56. sqlspec/{statement/builder → builder}/_parsing_utils.py +49 -26
  57. sqlspec/builder/_select.py +170 -0
  58. sqlspec/{statement/builder/update.py → builder/_update.py} +16 -20
  59. sqlspec/builder/mixins/__init__.py +55 -0
  60. sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
  61. sqlspec/{statement/builder/mixins/_delete_from.py → builder/mixins/_delete_operations.py} +8 -1
  62. sqlspec/builder/mixins/_insert_operations.py +244 -0
  63. sqlspec/{statement/builder/mixins/_join.py → builder/mixins/_join_operations.py} +45 -13
  64. sqlspec/{statement/builder/mixins/_merge_clauses.py → builder/mixins/_merge_operations.py} +188 -30
  65. sqlspec/builder/mixins/_order_limit_operations.py +135 -0
  66. sqlspec/builder/mixins/_pivot_operations.py +153 -0
  67. sqlspec/builder/mixins/_select_operations.py +604 -0
  68. sqlspec/builder/mixins/_update_operations.py +202 -0
  69. sqlspec/builder/mixins/_where_clause.py +644 -0
  70. sqlspec/cli.py +247 -0
  71. sqlspec/config.py +183 -138
  72. sqlspec/core/__init__.py +63 -0
  73. sqlspec/core/cache.py +871 -0
  74. sqlspec/core/compiler.py +417 -0
  75. sqlspec/core/filters.py +830 -0
  76. sqlspec/core/hashing.py +310 -0
  77. sqlspec/core/parameters.py +1237 -0
  78. sqlspec/core/result.py +677 -0
  79. sqlspec/{statement → core}/splitter.py +321 -191
  80. sqlspec/core/statement.py +676 -0
  81. sqlspec/driver/__init__.py +7 -10
  82. sqlspec/driver/_async.py +422 -163
  83. sqlspec/driver/_common.py +545 -287
  84. sqlspec/driver/_sync.py +426 -160
  85. sqlspec/driver/mixins/__init__.py +2 -13
  86. sqlspec/driver/mixins/_result_tools.py +193 -0
  87. sqlspec/driver/mixins/_sql_translator.py +65 -14
  88. sqlspec/exceptions.py +5 -252
  89. sqlspec/extensions/aiosql/adapter.py +93 -96
  90. sqlspec/extensions/litestar/__init__.py +2 -1
  91. sqlspec/extensions/litestar/cli.py +48 -0
  92. sqlspec/extensions/litestar/config.py +0 -1
  93. sqlspec/extensions/litestar/handlers.py +15 -26
  94. sqlspec/extensions/litestar/plugin.py +21 -16
  95. sqlspec/extensions/litestar/providers.py +17 -52
  96. sqlspec/loader.py +423 -104
  97. sqlspec/migrations/__init__.py +35 -0
  98. sqlspec/migrations/base.py +414 -0
  99. sqlspec/migrations/commands.py +443 -0
  100. sqlspec/migrations/loaders.py +402 -0
  101. sqlspec/migrations/runner.py +213 -0
  102. sqlspec/migrations/tracker.py +140 -0
  103. sqlspec/migrations/utils.py +129 -0
  104. sqlspec/protocols.py +51 -186
  105. sqlspec/storage/__init__.py +1 -1
  106. sqlspec/storage/backends/base.py +37 -40
  107. sqlspec/storage/backends/fsspec.py +136 -112
  108. sqlspec/storage/backends/obstore.py +138 -160
  109. sqlspec/storage/capabilities.py +5 -4
  110. sqlspec/storage/registry.py +57 -106
  111. sqlspec/typing.py +136 -115
  112. sqlspec/utils/__init__.py +2 -2
  113. sqlspec/utils/correlation.py +0 -3
  114. sqlspec/utils/deprecation.py +6 -6
  115. sqlspec/utils/fixtures.py +6 -6
  116. sqlspec/utils/logging.py +0 -2
  117. sqlspec/utils/module_loader.py +7 -12
  118. sqlspec/utils/singleton.py +0 -1
  119. sqlspec/utils/sync_tools.py +17 -38
  120. sqlspec/utils/text.py +12 -51
  121. sqlspec/utils/type_guards.py +482 -235
  122. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/METADATA +7 -2
  123. sqlspec-0.16.2.dist-info/RECORD +134 -0
  124. sqlspec-0.16.2.dist-info/entry_points.txt +2 -0
  125. sqlspec/driver/connection.py +0 -207
  126. sqlspec/driver/mixins/_csv_writer.py +0 -91
  127. sqlspec/driver/mixins/_pipeline.py +0 -512
  128. sqlspec/driver/mixins/_result_utils.py +0 -140
  129. sqlspec/driver/mixins/_storage.py +0 -926
  130. sqlspec/driver/mixins/_type_coercion.py +0 -130
  131. sqlspec/driver/parameters.py +0 -138
  132. sqlspec/service/__init__.py +0 -4
  133. sqlspec/service/_util.py +0 -147
  134. sqlspec/service/base.py +0 -1131
  135. sqlspec/service/pagination.py +0 -26
  136. sqlspec/statement/__init__.py +0 -21
  137. sqlspec/statement/builder/insert.py +0 -288
  138. sqlspec/statement/builder/merge.py +0 -95
  139. sqlspec/statement/builder/mixins/__init__.py +0 -65
  140. sqlspec/statement/builder/mixins/_aggregate_functions.py +0 -250
  141. sqlspec/statement/builder/mixins/_case_builder.py +0 -91
  142. sqlspec/statement/builder/mixins/_common_table_expr.py +0 -90
  143. sqlspec/statement/builder/mixins/_from.py +0 -63
  144. sqlspec/statement/builder/mixins/_group_by.py +0 -118
  145. sqlspec/statement/builder/mixins/_having.py +0 -35
  146. sqlspec/statement/builder/mixins/_insert_from_select.py +0 -47
  147. sqlspec/statement/builder/mixins/_insert_into.py +0 -36
  148. sqlspec/statement/builder/mixins/_insert_values.py +0 -67
  149. sqlspec/statement/builder/mixins/_limit_offset.py +0 -53
  150. sqlspec/statement/builder/mixins/_order_by.py +0 -46
  151. sqlspec/statement/builder/mixins/_pivot.py +0 -79
  152. sqlspec/statement/builder/mixins/_returning.py +0 -37
  153. sqlspec/statement/builder/mixins/_select_columns.py +0 -61
  154. sqlspec/statement/builder/mixins/_set_ops.py +0 -122
  155. sqlspec/statement/builder/mixins/_unpivot.py +0 -77
  156. sqlspec/statement/builder/mixins/_update_from.py +0 -55
  157. sqlspec/statement/builder/mixins/_update_set.py +0 -94
  158. sqlspec/statement/builder/mixins/_update_table.py +0 -29
  159. sqlspec/statement/builder/mixins/_where.py +0 -401
  160. sqlspec/statement/builder/mixins/_window_functions.py +0 -86
  161. sqlspec/statement/builder/select.py +0 -221
  162. sqlspec/statement/filters.py +0 -596
  163. sqlspec/statement/parameter_manager.py +0 -220
  164. sqlspec/statement/parameters.py +0 -867
  165. sqlspec/statement/pipelines/__init__.py +0 -210
  166. sqlspec/statement/pipelines/analyzers/__init__.py +0 -9
  167. sqlspec/statement/pipelines/analyzers/_analyzer.py +0 -646
  168. sqlspec/statement/pipelines/context.py +0 -115
  169. sqlspec/statement/pipelines/transformers/__init__.py +0 -7
  170. sqlspec/statement/pipelines/transformers/_expression_simplifier.py +0 -88
  171. sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +0 -1247
  172. sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py +0 -76
  173. sqlspec/statement/pipelines/validators/__init__.py +0 -23
  174. sqlspec/statement/pipelines/validators/_dml_safety.py +0 -290
  175. sqlspec/statement/pipelines/validators/_parameter_style.py +0 -370
  176. sqlspec/statement/pipelines/validators/_performance.py +0 -718
  177. sqlspec/statement/pipelines/validators/_security.py +0 -967
  178. sqlspec/statement/result.py +0 -435
  179. sqlspec/statement/sql.py +0 -1704
  180. sqlspec/statement/sql_compiler.py +0 -140
  181. sqlspec/utils/cached_property.py +0 -25
  182. sqlspec-0.13.1.dist-info/RECORD +0 -150
  183. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/WHEEL +0 -0
  184. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/LICENSE +0 -0
  185. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/NOTICE +0 -0
sqlspec/cli.py ADDED
@@ -0,0 +1,247 @@
1
+ import sys
2
+ from collections.abc import Sequence
3
+ from typing import TYPE_CHECKING, Any, Optional, Union, cast
4
+
5
+ if TYPE_CHECKING:
6
+ from click import Group
7
+
8
+ from sqlspec.config import AsyncDatabaseConfig, SyncDatabaseConfig
9
+
10
+ __all__ = ("add_migration_commands", "get_sqlspec_group")
11
+
12
+
13
+ def get_sqlspec_group() -> "Group":
14
+ """Get the SQLSpec CLI group.
15
+
16
+ Raises:
17
+ MissingDependencyError: If the `click` package is not installed.
18
+
19
+ Returns:
20
+ The SQLSpec CLI group.
21
+ """
22
+ from sqlspec.exceptions import MissingDependencyError
23
+
24
+ try:
25
+ import rich_click as click
26
+ except ImportError:
27
+ try:
28
+ import click # type: ignore[no-redef]
29
+ except ImportError as e:
30
+ raise MissingDependencyError(package="click", install_package="cli") from e
31
+
32
+ @click.group(name="sqlspec")
33
+ @click.option(
34
+ "--config",
35
+ help="Dotted path to SQLSpec config(s) (e.g. 'myapp.config.sqlspec_configs')",
36
+ required=True,
37
+ type=str,
38
+ )
39
+ @click.pass_context
40
+ def sqlspec_group(ctx: "click.Context", config: str) -> None:
41
+ """SQLSpec CLI commands."""
42
+ from rich import get_console
43
+
44
+ from sqlspec.utils import module_loader
45
+
46
+ console = get_console()
47
+ ctx.ensure_object(dict)
48
+ try:
49
+ config_instance = module_loader.import_string(config)
50
+ if isinstance(config_instance, Sequence):
51
+ ctx.obj["configs"] = config_instance
52
+ else:
53
+ ctx.obj["configs"] = [config_instance]
54
+ except ImportError as e:
55
+ console.print(f"[red]Error loading config: {e}[/]")
56
+ ctx.exit(1)
57
+
58
+ return sqlspec_group
59
+
60
+
61
+ def add_migration_commands(database_group: Optional["Group"] = None) -> "Group":
62
+ """Add migration commands to the database group.
63
+
64
+ Args:
65
+ database_group: The database group to add the commands to.
66
+
67
+ Raises:
68
+ MissingDependencyError: If the `click` package is not installed.
69
+
70
+ Returns:
71
+ The database group with the migration commands added.
72
+ """
73
+ from sqlspec.exceptions import MissingDependencyError
74
+
75
+ try:
76
+ import rich_click as click
77
+ except ImportError:
78
+ try:
79
+ import click # type: ignore[no-redef]
80
+ except ImportError as e:
81
+ raise MissingDependencyError(package="click", install_package="cli") from e
82
+ from rich import get_console
83
+
84
+ console = get_console()
85
+
86
+ if database_group is None:
87
+ database_group = get_sqlspec_group()
88
+
89
+ bind_key_option = click.option(
90
+ "--bind-key", help="Specify which SQLSpec config to use by bind key", type=str, default=None
91
+ )
92
+ verbose_option = click.option("--verbose", help="Enable verbose output.", type=bool, default=False, is_flag=True)
93
+ no_prompt_option = click.option(
94
+ "--no-prompt",
95
+ help="Do not prompt for confirmation before executing the command.",
96
+ type=bool,
97
+ default=False,
98
+ required=False,
99
+ show_default=True,
100
+ is_flag=True,
101
+ )
102
+
103
+ def get_config_by_bind_key(
104
+ ctx: "click.Context", bind_key: Optional[str]
105
+ ) -> "Union[AsyncDatabaseConfig[Any, Any, Any], SyncDatabaseConfig[Any, Any, Any]]":
106
+ """Get the SQLSpec config for the specified bind key.
107
+
108
+ Args:
109
+ ctx: The click context.
110
+ bind_key: The bind key to get the config for.
111
+
112
+ Returns:
113
+ The SQLSpec config for the specified bind key.
114
+ """
115
+ configs = ctx.obj["configs"]
116
+ if bind_key is None:
117
+ return cast("Union[AsyncDatabaseConfig[Any, Any, Any], SyncDatabaseConfig[Any, Any, Any]]", configs[0])
118
+
119
+ for config in configs:
120
+ config_name = getattr(config, "name", None) or getattr(config, "bind_key", None)
121
+ if config_name == bind_key:
122
+ return cast("Union[AsyncDatabaseConfig[Any, Any, Any], SyncDatabaseConfig[Any, Any, Any]]", config)
123
+
124
+ console.print(f"[red]No config found for bind key: {bind_key}[/]")
125
+ sys.exit(1)
126
+
127
+ @database_group.command(name="show-current-revision", help="Shows the current revision for the database.")
128
+ @bind_key_option
129
+ @verbose_option
130
+ def show_database_revision(bind_key: Optional[str], verbose: bool) -> None: # pyright: ignore[reportUnusedFunction]
131
+ """Show current database revision."""
132
+ from sqlspec.migrations.commands import MigrationCommands
133
+
134
+ ctx = click.get_current_context()
135
+ console.rule("[yellow]Listing current revision[/]", align="left")
136
+ sqlspec_config = get_config_by_bind_key(ctx, bind_key)
137
+ migration_commands = MigrationCommands(config=sqlspec_config)
138
+ migration_commands.current(verbose=verbose)
139
+
140
+ @database_group.command(name="downgrade", help="Downgrade database to a specific revision.")
141
+ @bind_key_option
142
+ @no_prompt_option
143
+ @click.argument("revision", type=str, default="-1")
144
+ def downgrade_database( # pyright: ignore[reportUnusedFunction]
145
+ bind_key: Optional[str], revision: str, no_prompt: bool
146
+ ) -> None:
147
+ """Downgrade the database to the latest revision."""
148
+ from rich.prompt import Confirm
149
+
150
+ from sqlspec.migrations.commands import MigrationCommands
151
+
152
+ ctx = click.get_current_context()
153
+ console.rule("[yellow]Starting database downgrade process[/]", align="left")
154
+ input_confirmed = (
155
+ True
156
+ if no_prompt
157
+ else Confirm.ask(f"Are you sure you want to downgrade the database to the `{revision}` revision?")
158
+ )
159
+ if input_confirmed:
160
+ sqlspec_config = get_config_by_bind_key(ctx, bind_key)
161
+ migration_commands = MigrationCommands(config=sqlspec_config)
162
+ migration_commands.downgrade(revision=revision)
163
+
164
+ @database_group.command(name="upgrade", help="Upgrade database to a specific revision.")
165
+ @bind_key_option
166
+ @no_prompt_option
167
+ @click.argument("revision", type=str, default="head")
168
+ def upgrade_database( # pyright: ignore[reportUnusedFunction]
169
+ bind_key: Optional[str], revision: str, no_prompt: bool
170
+ ) -> None:
171
+ """Upgrade the database to the latest revision."""
172
+ from rich.prompt import Confirm
173
+
174
+ from sqlspec.migrations.commands import MigrationCommands
175
+
176
+ ctx = click.get_current_context()
177
+ console.rule("[yellow]Starting database upgrade process[/]", align="left")
178
+ input_confirmed = (
179
+ True
180
+ if no_prompt
181
+ else Confirm.ask(f"[bold]Are you sure you want migrate the database to the `{revision}` revision?[/]")
182
+ )
183
+ if input_confirmed:
184
+ sqlspec_config = get_config_by_bind_key(ctx, bind_key)
185
+ migration_commands = MigrationCommands(config=sqlspec_config)
186
+ migration_commands.upgrade(revision=revision)
187
+
188
+ @database_group.command(help="Stamp the revision table with the given revision")
189
+ @click.argument("revision", type=str)
190
+ @bind_key_option
191
+ def stamp(bind_key: Optional[str], revision: str) -> None: # pyright: ignore[reportUnusedFunction]
192
+ """Stamp the revision table with the given revision."""
193
+ from sqlspec.migrations.commands import MigrationCommands
194
+
195
+ ctx = click.get_current_context()
196
+ sqlspec_config = get_config_by_bind_key(ctx, bind_key)
197
+ migration_commands = MigrationCommands(config=sqlspec_config)
198
+ migration_commands.stamp(revision=revision)
199
+
200
+ @database_group.command(name="init", help="Initialize migrations for the project.")
201
+ @bind_key_option
202
+ @click.argument("directory", default=None, required=False)
203
+ @click.option("--package", is_flag=True, default=True, help="Create `__init__.py` for created folder")
204
+ @no_prompt_option
205
+ def init_sqlspec( # pyright: ignore[reportUnusedFunction]
206
+ bind_key: Optional[str], directory: Optional[str], package: bool, no_prompt: bool
207
+ ) -> None:
208
+ """Initialize the database migrations."""
209
+ from rich.prompt import Confirm
210
+
211
+ from sqlspec.migrations.commands import MigrationCommands
212
+
213
+ ctx = click.get_current_context()
214
+ console.rule("[yellow]Initializing database migrations.", align="left")
215
+ input_confirmed = (
216
+ True if no_prompt else Confirm.ask("[bold]Are you sure you want initialize migrations for the project?[/]")
217
+ )
218
+ if input_confirmed:
219
+ configs = [get_config_by_bind_key(ctx, bind_key)] if bind_key is not None else ctx.obj["configs"]
220
+ for config in configs:
221
+ migration_config = getattr(config, "migration_config", {})
222
+ directory = migration_config.get("script_location", "migrations") if directory is None else directory
223
+ migration_commands = MigrationCommands(config=config)
224
+ migration_commands.init(directory=cast("str", directory), package=package)
225
+
226
+ @database_group.command(name="make-migrations", help="Create a new migration revision.")
227
+ @bind_key_option
228
+ @click.option("-m", "--message", default=None, help="Revision message")
229
+ @no_prompt_option
230
+ def create_revision( # pyright: ignore[reportUnusedFunction]
231
+ bind_key: Optional[str], message: Optional[str], no_prompt: bool
232
+ ) -> None:
233
+ """Create a new database revision."""
234
+ from rich.prompt import Prompt
235
+
236
+ from sqlspec.migrations.commands import MigrationCommands
237
+
238
+ ctx = click.get_current_context()
239
+ console.rule("[yellow]Creating new migration revision[/]", align="left")
240
+ if message is None:
241
+ message = "new migration" if no_prompt else Prompt.ask("Please enter a message describing this revision")
242
+
243
+ sqlspec_config = get_config_by_bind_key(ctx, bind_key)
244
+ migration_commands = MigrationCommands(config=sqlspec_config)
245
+ migration_commands.revision(message=message)
246
+
247
+ return database_group