jameszokah commited on
Commit
d4255ec
·
1 Parent(s): 857bebe

Update Alembic configuration and migration scripts: change script location and version path in alembic.ini, add env.py for migration management, create initial migration script for audiobooks table, and implement migration execution in a new migrate.py script.

Browse files
alembic.ini CHANGED
@@ -1,9 +1,9 @@
1
  [alembic]
2
  # path to migration scripts
3
- script_location = migrations
4
 
5
  # template used to generate migration files
6
- file_template = %%(year)d%%(month).2d%%(day).2d_%%(hour).2d%%(minute).2d%%(second).2d_%%(slug)s
7
 
8
  # timezone to use when rendering the date
9
  # within the migration file as well as the filename.
@@ -24,16 +24,27 @@ revision_environment = false
24
  # versions/ directory
25
  sourceless = false
26
 
27
- # version location specification; this defaults
28
- # to migrations/versions. When using multiple version
29
- # directories, initial revisions must be specified with --version-path
30
- version_locations = %(here)s/migrations/versions
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  # the output encoding used when revision files
33
  # are written from script.py.mako
34
  output_encoding = utf-8
35
 
36
- sqlalchemy.url = driver://user:pass@localhost/dbname
37
 
38
  [post_write_hooks]
39
  # post_write_hooks defines scripts or Python functions that are run
 
1
  [alembic]
2
  # path to migration scripts
3
+ script_location = alembic
4
 
5
  # template used to generate migration files
6
+ file_template = %%(year)d%%(month).2d%%(day).2d_%%(hour).2d%%(minute).2d_%%(rev)s_%%(slug)s
7
 
8
  # timezone to use when rendering the date
9
  # within the migration file as well as the filename.
 
24
  # versions/ directory
25
  sourceless = false
26
 
27
+ # version location specification; This defaults
28
+ # to alembic/versions. When using multiple version
29
+ # directories, initial revisions must be specified with --version-path.
30
+ # The path separator used here should be the separator specified by "version_path_separator" below.
31
+ version_locations = %(here)s/alembic/versions
32
+
33
+ # version path separator; As mentioned above, this is the character used to split
34
+ # version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
35
+ # If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
36
+ # Valid values for version_path_separator are:
37
+ #
38
+ # version_path_separator = :
39
+ # version_path_separator = ;
40
+ # version_path_separator = space
41
+ version_path_separator = os
42
 
43
  # the output encoding used when revision files
44
  # are written from script.py.mako
45
  output_encoding = utf-8
46
 
47
+ sqlalchemy.url = sqlite:///app/storage/database.db
48
 
49
  [post_write_hooks]
50
  # post_write_hooks defines scripts or Python functions that are run
alembic/env.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from logging.config import fileConfig
2
+
3
+ from sqlalchemy import engine_from_config
4
+ from sqlalchemy import pool
5
+
6
+ from alembic import context
7
+
8
+ from app.models import Base
9
+ from app.config import get_settings
10
+
11
+ # this is the Alembic Config object, which provides
12
+ # access to the values within the .ini file in use.
13
+ config = context.config
14
+
15
+ # Interpret the config file for Python logging.
16
+ # This line sets up loggers basically.
17
+ if config.config_file_name is not None:
18
+ fileConfig(config.config_file_name)
19
+
20
+ # add your model's MetaData object here
21
+ # for 'autogenerate' support
22
+ target_metadata = Base.metadata
23
+
24
+ # other values from the config, defined by the needs of env.py,
25
+ # can be acquired:
26
+ # my_important_option = config.get_main_option("my_important_option")
27
+ # ... etc.
28
+
29
+ def run_migrations_offline() -> None:
30
+ """Run migrations in 'offline' mode.
31
+
32
+ This configures the context with just a URL
33
+ and not an Engine, though an Engine is acceptable
34
+ here as well. By skipping the Engine creation
35
+ we don't even need a DBAPI to be available.
36
+
37
+ Calls to context.execute() here emit the given string to the
38
+ script output.
39
+
40
+ """
41
+ settings = get_settings()
42
+ url = settings.DATABASE_URL
43
+ context.configure(
44
+ url=url,
45
+ target_metadata=target_metadata,
46
+ literal_binds=True,
47
+ dialect_opts={"paramstyle": "named"},
48
+ )
49
+
50
+ with context.begin_transaction():
51
+ context.run_migrations()
52
+
53
+
54
+ def run_migrations_online() -> None:
55
+ """Run migrations in 'online' mode.
56
+
57
+ In this scenario we need to create an Engine
58
+ and associate a connection with the context.
59
+
60
+ """
61
+ settings = get_settings()
62
+ configuration = config.get_section(config.config_ini_section)
63
+ configuration["sqlalchemy.url"] = settings.DATABASE_URL
64
+ connectable = engine_from_config(
65
+ configuration,
66
+ prefix="sqlalchemy.",
67
+ poolclass=pool.NullPool,
68
+ )
69
+
70
+ with connectable.connect() as connection:
71
+ context.configure(
72
+ connection=connection, target_metadata=target_metadata
73
+ )
74
+
75
+ with context.begin_transaction():
76
+ context.run_migrations()
77
+
78
+
79
+ if context.is_offline_mode():
80
+ run_migrations_offline()
81
+ else:
82
+ run_migrations_online()
alembic/script.py.mako ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """${message}
2
+
3
+ Revision ID: ${up_revision}
4
+ Revises: ${down_revision | comma,n}
5
+ Create Date: ${create_date}
6
+
7
+ """
8
+ from alembic import op
9
+ import sqlalchemy as sa
10
+ ${imports if imports else ""}
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = ${repr(up_revision)}
14
+ down_revision = ${repr(down_revision)}
15
+ branch_labels = ${repr(branch_labels)}
16
+ depends_on = ${repr(depends_on)}
17
+
18
+
19
+ def upgrade() -> None:
20
+ ${upgrades if upgrades else "pass"}
21
+
22
+
23
+ def downgrade() -> None:
24
+ ${downgrades if downgrades else "pass"}
alembic/versions/001_initial_migration.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Initial migration
2
+
3
+ Revision ID: 001
4
+ Revises:
5
+ Create Date: 2024-03-27
6
+
7
+ """
8
+ from alembic import op
9
+ import sqlalchemy as sa
10
+
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = '001'
14
+ down_revision = None
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.create_table(
21
+ 'audiobooks',
22
+ sa.Column('id', sa.String(36), primary_key=True),
23
+ sa.Column('title', sa.String(255), nullable=False),
24
+ sa.Column('author', sa.String(255), nullable=False),
25
+ sa.Column('voice_id', sa.String(50), nullable=False),
26
+ sa.Column('status', sa.String(20), nullable=False),
27
+ sa.Column('text_file_path', sa.String(255), nullable=True),
28
+ sa.Column('audio_file_path', sa.String(255), nullable=True),
29
+ sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
30
+ sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
31
+ )
32
+
33
+
34
+ def downgrade() -> None:
35
+ op.drop_table('audiobooks')
app/db.py CHANGED
@@ -1,39 +1,29 @@
1
  """Database connection and session management."""
2
  import os
3
  from sqlalchemy import create_engine
4
- from sqlalchemy.orm import sessionmaker, Session
5
- from contextlib import contextmanager
6
  from app.models.database import Base
7
 
8
  # Get database URL from environment or use SQLite as default
9
- DATABASE_URL = os.environ.get(
10
  "DATABASE_URL",
11
- "sqlite:///app/audiobooks.db"
12
  )
13
 
14
  # Create engine
15
- engine = create_engine(
16
- DATABASE_URL,
17
- echo=False, # Set to True for SQL logging
18
- pool_pre_ping=True, # Enable connection health checks
19
- )
20
 
21
  # Create session factory
22
- SessionLocal = sessionmaker(
23
- bind=engine,
24
- autocommit=False,
25
- autoflush=False,
26
- )
27
 
28
- @contextmanager
29
- def get_db() -> Session:
30
- """Get database session."""
31
  db = SessionLocal()
32
  try:
33
  yield db
34
  finally:
35
- db.close()
36
-
37
- def init_db():
38
- """Initialize database."""
39
- Base.metadata.create_all(bind=engine)
 
1
  """Database connection and session management."""
2
  import os
3
  from sqlalchemy import create_engine
4
+ from sqlalchemy.orm import sessionmaker
 
5
  from app.models.database import Base
6
 
7
  # Get database URL from environment or use SQLite as default
8
+ DATABASE_URL = os.getenv(
9
  "DATABASE_URL",
10
+ "sqlite:///app/storage/audiobooks.db"
11
  )
12
 
13
  # Create engine
14
+ engine = create_engine(DATABASE_URL)
 
 
 
 
15
 
16
  # Create session factory
17
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
18
+
19
+ def init_db():
20
+ """Initialize the database, creating all tables."""
21
+ Base.metadata.create_all(bind=engine)
22
 
23
+ def get_db():
24
+ """Get a database session."""
 
25
  db = SessionLocal()
26
  try:
27
  yield db
28
  finally:
29
+ db.close()
 
 
 
 
scripts/migrate.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import logging
4
+ from alembic.config import Config
5
+ from alembic import command
6
+
7
+ # Configure logging
8
+ logging.basicConfig(
9
+ level=logging.INFO,
10
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
11
+ )
12
+ logger = logging.getLogger(__name__)
13
+
14
+ def run_migrations():
15
+ """Run database migrations using Alembic."""
16
+ try:
17
+ # Get the directory containing this script
18
+ current_dir = os.path.dirname(os.path.abspath(__file__))
19
+ # Get the project root directory (one level up)
20
+ project_root = os.path.dirname(current_dir)
21
+
22
+ # Create Alembic configuration
23
+ alembic_cfg = Config(os.path.join(project_root, "alembic.ini"))
24
+
25
+ # Set the script location
26
+ alembic_cfg.set_main_option("script_location", os.path.join(project_root, "alembic"))
27
+
28
+ # Run the migration
29
+ logger.info("Starting database migration...")
30
+ command.upgrade(alembic_cfg, "head")
31
+ logger.info("Database migration completed successfully.")
32
+
33
+ except Exception as e:
34
+ logger.error(f"Error during database migration: {str(e)}")
35
+ sys.exit(1)
36
+
37
+ if __name__ == "__main__":
38
+ run_migrations()
scripts/run.sh CHANGED
@@ -50,10 +50,7 @@ fi
50
 
51
  # Run database migrations
52
  echo "Running database migrations..."
53
- PYTHONPATH="/app:/app/app:${PYTHONPATH:-}" alembic upgrade head || {
54
- echo "Warning: Database migration failed. This might be expected for first run."
55
- echo "Continuing with application startup..."
56
- }
57
 
58
  echo "Starting CSM-1B TTS API server..."
59
  echo "Host: $HOST"
 
50
 
51
  # Run database migrations
52
  echo "Running database migrations..."
53
+ python scripts/migrate.py
 
 
 
54
 
55
  echo "Starting CSM-1B TTS API server..."
56
  echo "Host: $HOST"