sqlspec 0.16.1__cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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 (148) hide show
  1. 51ff5a9eadfdefd49f98__mypyc.cpython-312-aarch64-linux-gnu.so +0 -0
  2. sqlspec/__init__.py +92 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_serialization.py +77 -0
  6. sqlspec/_sql.py +1780 -0
  7. sqlspec/_typing.py +680 -0
  8. sqlspec/adapters/__init__.py +0 -0
  9. sqlspec/adapters/adbc/__init__.py +5 -0
  10. sqlspec/adapters/adbc/_types.py +12 -0
  11. sqlspec/adapters/adbc/config.py +361 -0
  12. sqlspec/adapters/adbc/driver.py +512 -0
  13. sqlspec/adapters/aiosqlite/__init__.py +19 -0
  14. sqlspec/adapters/aiosqlite/_types.py +13 -0
  15. sqlspec/adapters/aiosqlite/config.py +253 -0
  16. sqlspec/adapters/aiosqlite/driver.py +248 -0
  17. sqlspec/adapters/asyncmy/__init__.py +19 -0
  18. sqlspec/adapters/asyncmy/_types.py +12 -0
  19. sqlspec/adapters/asyncmy/config.py +180 -0
  20. sqlspec/adapters/asyncmy/driver.py +274 -0
  21. sqlspec/adapters/asyncpg/__init__.py +21 -0
  22. sqlspec/adapters/asyncpg/_types.py +17 -0
  23. sqlspec/adapters/asyncpg/config.py +229 -0
  24. sqlspec/adapters/asyncpg/driver.py +344 -0
  25. sqlspec/adapters/bigquery/__init__.py +18 -0
  26. sqlspec/adapters/bigquery/_types.py +12 -0
  27. sqlspec/adapters/bigquery/config.py +298 -0
  28. sqlspec/adapters/bigquery/driver.py +558 -0
  29. sqlspec/adapters/duckdb/__init__.py +22 -0
  30. sqlspec/adapters/duckdb/_types.py +12 -0
  31. sqlspec/adapters/duckdb/config.py +504 -0
  32. sqlspec/adapters/duckdb/driver.py +368 -0
  33. sqlspec/adapters/oracledb/__init__.py +32 -0
  34. sqlspec/adapters/oracledb/_types.py +14 -0
  35. sqlspec/adapters/oracledb/config.py +317 -0
  36. sqlspec/adapters/oracledb/driver.py +538 -0
  37. sqlspec/adapters/psqlpy/__init__.py +16 -0
  38. sqlspec/adapters/psqlpy/_types.py +11 -0
  39. sqlspec/adapters/psqlpy/config.py +214 -0
  40. sqlspec/adapters/psqlpy/driver.py +530 -0
  41. sqlspec/adapters/psycopg/__init__.py +32 -0
  42. sqlspec/adapters/psycopg/_types.py +17 -0
  43. sqlspec/adapters/psycopg/config.py +426 -0
  44. sqlspec/adapters/psycopg/driver.py +796 -0
  45. sqlspec/adapters/sqlite/__init__.py +15 -0
  46. sqlspec/adapters/sqlite/_types.py +11 -0
  47. sqlspec/adapters/sqlite/config.py +240 -0
  48. sqlspec/adapters/sqlite/driver.py +294 -0
  49. sqlspec/base.py +571 -0
  50. sqlspec/builder/__init__.py +62 -0
  51. sqlspec/builder/_base.py +473 -0
  52. sqlspec/builder/_column.py +320 -0
  53. sqlspec/builder/_ddl.py +1346 -0
  54. sqlspec/builder/_ddl_utils.py +103 -0
  55. sqlspec/builder/_delete.py +76 -0
  56. sqlspec/builder/_insert.py +256 -0
  57. sqlspec/builder/_merge.py +71 -0
  58. sqlspec/builder/_parsing_utils.py +140 -0
  59. sqlspec/builder/_select.py +170 -0
  60. sqlspec/builder/_update.py +188 -0
  61. sqlspec/builder/mixins/__init__.py +55 -0
  62. sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
  63. sqlspec/builder/mixins/_delete_operations.py +41 -0
  64. sqlspec/builder/mixins/_insert_operations.py +244 -0
  65. sqlspec/builder/mixins/_join_operations.py +122 -0
  66. sqlspec/builder/mixins/_merge_operations.py +476 -0
  67. sqlspec/builder/mixins/_order_limit_operations.py +135 -0
  68. sqlspec/builder/mixins/_pivot_operations.py +153 -0
  69. sqlspec/builder/mixins/_select_operations.py +603 -0
  70. sqlspec/builder/mixins/_update_operations.py +187 -0
  71. sqlspec/builder/mixins/_where_clause.py +621 -0
  72. sqlspec/cli.py +247 -0
  73. sqlspec/config.py +395 -0
  74. sqlspec/core/__init__.py +63 -0
  75. sqlspec/core/cache.cpython-312-aarch64-linux-gnu.so +0 -0
  76. sqlspec/core/cache.py +871 -0
  77. sqlspec/core/compiler.cpython-312-aarch64-linux-gnu.so +0 -0
  78. sqlspec/core/compiler.py +417 -0
  79. sqlspec/core/filters.cpython-312-aarch64-linux-gnu.so +0 -0
  80. sqlspec/core/filters.py +830 -0
  81. sqlspec/core/hashing.cpython-312-aarch64-linux-gnu.so +0 -0
  82. sqlspec/core/hashing.py +310 -0
  83. sqlspec/core/parameters.cpython-312-aarch64-linux-gnu.so +0 -0
  84. sqlspec/core/parameters.py +1237 -0
  85. sqlspec/core/result.cpython-312-aarch64-linux-gnu.so +0 -0
  86. sqlspec/core/result.py +677 -0
  87. sqlspec/core/splitter.cpython-312-aarch64-linux-gnu.so +0 -0
  88. sqlspec/core/splitter.py +819 -0
  89. sqlspec/core/statement.cpython-312-aarch64-linux-gnu.so +0 -0
  90. sqlspec/core/statement.py +676 -0
  91. sqlspec/driver/__init__.py +19 -0
  92. sqlspec/driver/_async.py +502 -0
  93. sqlspec/driver/_common.py +631 -0
  94. sqlspec/driver/_sync.py +503 -0
  95. sqlspec/driver/mixins/__init__.py +6 -0
  96. sqlspec/driver/mixins/_result_tools.py +193 -0
  97. sqlspec/driver/mixins/_sql_translator.py +86 -0
  98. sqlspec/exceptions.py +193 -0
  99. sqlspec/extensions/__init__.py +0 -0
  100. sqlspec/extensions/aiosql/__init__.py +10 -0
  101. sqlspec/extensions/aiosql/adapter.py +461 -0
  102. sqlspec/extensions/litestar/__init__.py +6 -0
  103. sqlspec/extensions/litestar/_utils.py +52 -0
  104. sqlspec/extensions/litestar/cli.py +48 -0
  105. sqlspec/extensions/litestar/config.py +92 -0
  106. sqlspec/extensions/litestar/handlers.py +260 -0
  107. sqlspec/extensions/litestar/plugin.py +145 -0
  108. sqlspec/extensions/litestar/providers.py +454 -0
  109. sqlspec/loader.cpython-312-aarch64-linux-gnu.so +0 -0
  110. sqlspec/loader.py +760 -0
  111. sqlspec/migrations/__init__.py +35 -0
  112. sqlspec/migrations/base.py +414 -0
  113. sqlspec/migrations/commands.py +443 -0
  114. sqlspec/migrations/loaders.py +402 -0
  115. sqlspec/migrations/runner.py +213 -0
  116. sqlspec/migrations/tracker.py +140 -0
  117. sqlspec/migrations/utils.py +129 -0
  118. sqlspec/protocols.py +407 -0
  119. sqlspec/py.typed +0 -0
  120. sqlspec/storage/__init__.py +23 -0
  121. sqlspec/storage/backends/__init__.py +0 -0
  122. sqlspec/storage/backends/base.py +163 -0
  123. sqlspec/storage/backends/fsspec.py +386 -0
  124. sqlspec/storage/backends/obstore.py +459 -0
  125. sqlspec/storage/capabilities.py +102 -0
  126. sqlspec/storage/registry.py +239 -0
  127. sqlspec/typing.py +299 -0
  128. sqlspec/utils/__init__.py +3 -0
  129. sqlspec/utils/correlation.py +150 -0
  130. sqlspec/utils/deprecation.py +106 -0
  131. sqlspec/utils/fixtures.cpython-312-aarch64-linux-gnu.so +0 -0
  132. sqlspec/utils/fixtures.py +58 -0
  133. sqlspec/utils/logging.py +127 -0
  134. sqlspec/utils/module_loader.py +89 -0
  135. sqlspec/utils/serializers.py +4 -0
  136. sqlspec/utils/singleton.py +32 -0
  137. sqlspec/utils/sync_tools.cpython-312-aarch64-linux-gnu.so +0 -0
  138. sqlspec/utils/sync_tools.py +237 -0
  139. sqlspec/utils/text.cpython-312-aarch64-linux-gnu.so +0 -0
  140. sqlspec/utils/text.py +96 -0
  141. sqlspec/utils/type_guards.cpython-312-aarch64-linux-gnu.so +0 -0
  142. sqlspec/utils/type_guards.py +1139 -0
  143. sqlspec-0.16.1.dist-info/METADATA +365 -0
  144. sqlspec-0.16.1.dist-info/RECORD +148 -0
  145. sqlspec-0.16.1.dist-info/WHEEL +7 -0
  146. sqlspec-0.16.1.dist-info/entry_points.txt +2 -0
  147. sqlspec-0.16.1.dist-info/licenses/LICENSE +21 -0
  148. sqlspec-0.16.1.dist-info/licenses/NOTICE +29 -0
@@ -0,0 +1,35 @@
1
+ """SQLSpec Migration Tool.
2
+
3
+ A native migration system for SQLSpec that leverages the SQLFileLoader
4
+ and driver architecture for database versioning.
5
+ """
6
+
7
+ from sqlspec.migrations.commands import AsyncMigrationCommands, MigrationCommands, SyncMigrationCommands
8
+ from sqlspec.migrations.loaders import (
9
+ BaseMigrationLoader,
10
+ MigrationLoadError,
11
+ PythonFileLoader,
12
+ SQLFileLoader,
13
+ get_migration_loader,
14
+ )
15
+ from sqlspec.migrations.runner import AsyncMigrationRunner, SyncMigrationRunner
16
+ from sqlspec.migrations.tracker import AsyncMigrationTracker, SyncMigrationTracker
17
+ from sqlspec.migrations.utils import create_migration_file, drop_all, get_author
18
+
19
+ __all__ = (
20
+ "AsyncMigrationCommands",
21
+ "AsyncMigrationRunner",
22
+ "AsyncMigrationTracker",
23
+ "BaseMigrationLoader",
24
+ "MigrationCommands",
25
+ "MigrationLoadError",
26
+ "PythonFileLoader",
27
+ "SQLFileLoader",
28
+ "SyncMigrationCommands",
29
+ "SyncMigrationRunner",
30
+ "SyncMigrationTracker",
31
+ "create_migration_file",
32
+ "drop_all",
33
+ "get_author",
34
+ "get_migration_loader",
35
+ )
@@ -0,0 +1,414 @@
1
+ """Base classes for SQLSpec migrations.
2
+
3
+ This module provides abstract base classes for migration components.
4
+ """
5
+
6
+ import operator
7
+ from abc import ABC, abstractmethod
8
+ from pathlib import Path
9
+ from typing import Any, Generic, Optional, TypeVar
10
+
11
+ from sqlspec._sql import sql
12
+ from sqlspec.builder._ddl import CreateTable
13
+ from sqlspec.core.statement import SQL
14
+ from sqlspec.loader import SQLFileLoader
15
+ from sqlspec.migrations.loaders import get_migration_loader
16
+ from sqlspec.utils.logging import get_logger
17
+ from sqlspec.utils.sync_tools import run_
18
+
19
+ __all__ = ("BaseMigrationCommands", "BaseMigrationRunner", "BaseMigrationTracker")
20
+
21
+
22
+ logger = get_logger("migrations.base")
23
+
24
+ DriverT = TypeVar("DriverT")
25
+ ConfigT = TypeVar("ConfigT")
26
+
27
+
28
+ class BaseMigrationTracker(ABC, Generic[DriverT]):
29
+ """Base class for migration version tracking."""
30
+
31
+ def __init__(self, version_table_name: str = "ddl_migrations") -> None:
32
+ """Initialize the migration tracker.
33
+
34
+ Args:
35
+ version_table_name: Name of the table to track migrations.
36
+ """
37
+ self.version_table = version_table_name
38
+
39
+ def _get_create_table_sql(self) -> SQL:
40
+ """Get SQL for creating the tracking table.
41
+
42
+ Returns:
43
+ SQL object for table creation.
44
+ """
45
+ builder = CreateTable(self.version_table)
46
+ if not hasattr(builder, "_columns"):
47
+ builder._columns = []
48
+ if not hasattr(builder, "_constraints"):
49
+ builder._constraints = []
50
+ if not hasattr(builder, "_table_options"):
51
+ builder._table_options = {}
52
+
53
+ return (
54
+ builder.if_not_exists()
55
+ .column("version_num", "VARCHAR(32)", primary_key=True)
56
+ .column("description", "TEXT")
57
+ .column("applied_at", "TIMESTAMP", not_null=True, default="CURRENT_TIMESTAMP")
58
+ .column("execution_time_ms", "INTEGER")
59
+ .column("checksum", "VARCHAR(64)")
60
+ .column("applied_by", "VARCHAR(255)")
61
+ ).to_statement()
62
+
63
+ def _get_current_version_sql(self) -> SQL:
64
+ """Get SQL for retrieving current version.
65
+
66
+ Returns:
67
+ SQL object for version query.
68
+ """
69
+
70
+ return (
71
+ sql.select("version_num").from_(self.version_table).order_by("version_num DESC").limit(1)
72
+ ).to_statement()
73
+
74
+ def _get_applied_migrations_sql(self) -> SQL:
75
+ """Get SQL for retrieving all applied migrations.
76
+
77
+ Returns:
78
+ SQL object for migrations query.
79
+ """
80
+
81
+ return (sql.select("*").from_(self.version_table).order_by("version_num")).to_statement()
82
+
83
+ def _get_record_migration_sql(
84
+ self, version: str, description: str, execution_time_ms: int, checksum: str, applied_by: str
85
+ ) -> SQL:
86
+ """Get SQL for recording a migration.
87
+
88
+ Args:
89
+ version: Version number of the migration.
90
+ description: Description of the migration.
91
+ execution_time_ms: Execution time in milliseconds.
92
+ checksum: MD5 checksum of the migration content.
93
+ applied_by: User who applied the migration.
94
+
95
+ Returns:
96
+ SQL object for insert.
97
+ """
98
+
99
+ return (
100
+ sql.insert(self.version_table)
101
+ .columns("version_num", "description", "execution_time_ms", "checksum", "applied_by")
102
+ .values(version, description, execution_time_ms, checksum, applied_by)
103
+ ).to_statement()
104
+
105
+ def _get_remove_migration_sql(self, version: str) -> SQL:
106
+ """Get SQL for removing a migration record.
107
+
108
+ Args:
109
+ version: Version number to remove.
110
+
111
+ Returns:
112
+ SQL object for delete.
113
+ """
114
+
115
+ return (sql.delete().from_(self.version_table).where(sql.version_num == version)).to_statement()
116
+
117
+ @abstractmethod
118
+ def ensure_tracking_table(self, driver: DriverT) -> Any:
119
+ """Create the migration tracking table if it doesn't exist."""
120
+ ...
121
+
122
+ @abstractmethod
123
+ def get_current_version(self, driver: DriverT) -> Any:
124
+ """Get the latest applied migration version."""
125
+ ...
126
+
127
+ @abstractmethod
128
+ def get_applied_migrations(self, driver: DriverT) -> Any:
129
+ """Get all applied migrations in order."""
130
+ ...
131
+
132
+ @abstractmethod
133
+ def record_migration(
134
+ self, driver: DriverT, version: str, description: str, execution_time_ms: int, checksum: str
135
+ ) -> Any:
136
+ """Record a successfully applied migration."""
137
+ ...
138
+
139
+ @abstractmethod
140
+ def remove_migration(self, driver: DriverT, version: str) -> Any:
141
+ """Remove a migration record."""
142
+ ...
143
+
144
+
145
+ class BaseMigrationRunner(ABC, Generic[DriverT]):
146
+ """Base class for migration execution."""
147
+
148
+ def __init__(self, migrations_path: Path) -> None:
149
+ """Initialize the migration runner.
150
+
151
+ Args:
152
+ migrations_path: Path to the directory containing migration files.
153
+ """
154
+ self.migrations_path = migrations_path
155
+ self.loader = SQLFileLoader()
156
+ self.project_root: Optional[Path] = None
157
+
158
+ def _extract_version(self, filename: str) -> Optional[str]:
159
+ """Extract version from filename.
160
+
161
+ Args:
162
+ filename: The migration filename.
163
+
164
+ Returns:
165
+ The extracted version string or None.
166
+ """
167
+ parts = filename.split("_", 1)
168
+ return parts[0].zfill(4) if parts and parts[0].isdigit() else None
169
+
170
+ def _calculate_checksum(self, content: str) -> str:
171
+ """Calculate MD5 checksum of migration content.
172
+
173
+ Args:
174
+ content: The migration file content.
175
+
176
+ Returns:
177
+ MD5 checksum hex string.
178
+ """
179
+ import hashlib
180
+
181
+ return hashlib.md5(content.encode()).hexdigest() # noqa: S324
182
+
183
+ def _get_migration_files_sync(self) -> "list[tuple[str, Path]]":
184
+ """Get all migration files sorted by version.
185
+
186
+ Returns:
187
+ List of tuples containing (version, file_path).
188
+ """
189
+ if not self.migrations_path.exists():
190
+ return []
191
+
192
+ migrations = []
193
+ for pattern in ["*.sql", "*.py"]:
194
+ for file_path in self.migrations_path.glob(pattern):
195
+ if file_path.name.startswith("."):
196
+ continue
197
+ version = self._extract_version(file_path.name)
198
+ if version:
199
+ migrations.append((version, file_path))
200
+
201
+ return sorted(migrations, key=operator.itemgetter(0))
202
+
203
+ def _load_migration_metadata(self, file_path: Path) -> "dict[str, Any]":
204
+ """Load migration metadata from file.
205
+
206
+ Args:
207
+ file_path: Path to the migration file.
208
+
209
+ Returns:
210
+ Migration metadata dictionary.
211
+ """
212
+
213
+ loader = get_migration_loader(file_path, self.migrations_path, self.project_root)
214
+ loader.validate_migration_file(file_path)
215
+ content = file_path.read_text(encoding="utf-8")
216
+ checksum = self._calculate_checksum(content)
217
+ version = self._extract_version(file_path.name)
218
+ description = file_path.stem.split("_", 1)[1] if "_" in file_path.stem else ""
219
+
220
+ has_upgrade, has_downgrade = True, False
221
+
222
+ if file_path.suffix == ".sql":
223
+ up_query, down_query = f"migrate-{version}-up", f"migrate-{version}-down"
224
+ self.loader.clear_cache()
225
+ self.loader.load_sql(file_path)
226
+ has_upgrade, has_downgrade = self.loader.has_query(up_query), self.loader.has_query(down_query)
227
+ else:
228
+ try:
229
+ has_downgrade = bool(run_(loader.get_down_sql)(file_path))
230
+ except Exception:
231
+ has_downgrade = False
232
+
233
+ return {
234
+ "version": version,
235
+ "description": description,
236
+ "file_path": file_path,
237
+ "checksum": checksum,
238
+ "has_upgrade": has_upgrade,
239
+ "has_downgrade": has_downgrade,
240
+ "loader": loader,
241
+ }
242
+
243
+ def _get_migration_sql(self, migration: "dict[str, Any]", direction: str) -> Optional[SQL]:
244
+ """Get migration SQL for given direction.
245
+
246
+ Args:
247
+ migration: Migration metadata.
248
+ direction: Either 'up' or 'down'.
249
+
250
+ Returns:
251
+ SQL object for the migration.
252
+ """
253
+ if not migration.get(f"has_{direction}grade"):
254
+ if direction == "down":
255
+ logger.warning("Migration %s has no downgrade query", migration["version"])
256
+ return None
257
+ msg = f"Migration {migration['version']} has no upgrade query"
258
+ raise ValueError(msg)
259
+
260
+ file_path, loader = migration["file_path"], migration["loader"]
261
+
262
+ try:
263
+ method = loader.get_up_sql if direction == "up" else loader.get_down_sql
264
+ sql_statements = run_(method)(file_path)
265
+
266
+ except Exception as e:
267
+ if direction == "down":
268
+ logger.warning("Failed to load downgrade for migration %s: %s", migration["version"], e)
269
+ return None
270
+ msg = f"Failed to load upgrade for migration {migration['version']}: {e}"
271
+ raise ValueError(msg) from e
272
+ else:
273
+ if sql_statements:
274
+ return SQL(sql_statements[0])
275
+ return None
276
+
277
+ @abstractmethod
278
+ def get_migration_files(self) -> Any:
279
+ """Get all migration files sorted by version."""
280
+ ...
281
+
282
+ @abstractmethod
283
+ def load_migration(self, file_path: Path) -> Any:
284
+ """Load a migration file and extract its components."""
285
+ ...
286
+
287
+ @abstractmethod
288
+ def execute_upgrade(self, driver: DriverT, migration: "dict[str, Any]") -> Any:
289
+ """Execute an upgrade migration."""
290
+ ...
291
+
292
+ @abstractmethod
293
+ def execute_downgrade(self, driver: DriverT, migration: "dict[str, Any]") -> Any:
294
+ """Execute a downgrade migration."""
295
+ ...
296
+
297
+ @abstractmethod
298
+ def load_all_migrations(self) -> Any:
299
+ """Load all migrations into a single namespace for bulk operations."""
300
+ ...
301
+
302
+
303
+ class BaseMigrationCommands(ABC, Generic[ConfigT, DriverT]):
304
+ """Base class for migration commands."""
305
+
306
+ def __init__(self, config: ConfigT) -> None:
307
+ """Initialize migration commands.
308
+
309
+ Args:
310
+ config: The SQLSpec configuration.
311
+ """
312
+ self.config = config
313
+ migration_config = getattr(self.config, "migration_config", {}) or {}
314
+
315
+ self.version_table = migration_config.get("version_table_name", "sqlspec_migrations")
316
+ self.migrations_path = Path(migration_config.get("script_location", "migrations"))
317
+ self.project_root = Path(migration_config["project_root"]) if "project_root" in migration_config else None
318
+
319
+ def _get_init_readme_content(self) -> str:
320
+ """Get README content for migration directory initialization.
321
+
322
+ Returns:
323
+ README markdown content.
324
+ """
325
+ return """# SQLSpec Migrations
326
+
327
+ This directory contains database migration files.
328
+
329
+ ## File Format
330
+
331
+ Migration files use SQLFileLoader's named query syntax with versioned names:
332
+
333
+ ```sql
334
+ -- name: migrate-0001-up
335
+ CREATE TABLE example (
336
+ id INTEGER PRIMARY KEY,
337
+ name TEXT NOT NULL
338
+ );
339
+
340
+ -- name: migrate-0001-down
341
+ DROP TABLE example;
342
+ ```
343
+
344
+ ## Naming Conventions
345
+
346
+ ### File Names
347
+
348
+ Format: `{version}_{description}.sql`
349
+
350
+ - Version: Zero-padded 4-digit number (0001, 0002, etc.)
351
+ - Description: Brief description using underscores
352
+ - Example: `0001_create_users_table.sql`
353
+
354
+ ### Query Names
355
+
356
+ - Upgrade: `migrate-{version}-up`
357
+ - Downgrade: `migrate-{version}-down`
358
+
359
+ This naming ensures proper sorting and avoids conflicts when loading multiple files.
360
+ """
361
+
362
+ def init_directory(self, directory: str, package: bool = True) -> None:
363
+ """Initialize migration directory structure.
364
+
365
+ Args:
366
+ directory: Directory to initialize migrations in.
367
+ package: Whether to create __init__.py file.
368
+ """
369
+ from rich.console import Console
370
+
371
+ console = Console()
372
+
373
+ migrations_dir = Path(directory)
374
+ migrations_dir.mkdir(parents=True, exist_ok=True)
375
+
376
+ if package:
377
+ (migrations_dir / "__init__.py").touch()
378
+
379
+ readme = migrations_dir / "README.md"
380
+ readme.write_text(self._get_init_readme_content())
381
+
382
+ (migrations_dir / ".gitkeep").touch()
383
+
384
+ console.print(f"[green]Initialized migrations in {directory}[/]")
385
+
386
+ @abstractmethod
387
+ def init(self, directory: str, package: bool = True) -> Any:
388
+ """Initialize migration directory structure."""
389
+ ...
390
+
391
+ @abstractmethod
392
+ def current(self, verbose: bool = False) -> Any:
393
+ """Show current migration version."""
394
+ ...
395
+
396
+ @abstractmethod
397
+ def upgrade(self, revision: str = "head") -> Any:
398
+ """Upgrade to a target revision."""
399
+ ...
400
+
401
+ @abstractmethod
402
+ def downgrade(self, revision: str = "-1") -> Any:
403
+ """Downgrade to a target revision."""
404
+ ...
405
+
406
+ @abstractmethod
407
+ def stamp(self, revision: str) -> Any:
408
+ """Mark database as being at a specific revision without running migrations."""
409
+ ...
410
+
411
+ @abstractmethod
412
+ def revision(self, message: str, file_type: str = "sql") -> Any:
413
+ """Create a new migration file."""
414
+ ...