2020def get_url () -> str :
2121 """
2222 Database URL for migrations. Uses DB_PATH from app config so we migrate the same DB the app uses.
23- Tests can override with config.set_main_option("sqlalchemy.url", "sqlite:///:memory:").
23+ Tests can override with config.set_main_option("sqlalchemy.url", "sqlite:///path" or "sqlite:/// :memory:").
2424 """
2525 url_from_config = config .get_main_option ("sqlalchemy.url" )
26- if url_from_config and ":memory:" in url_from_config :
26+ if url_from_config :
2727 return url_from_config
2828 db_path = Path (DB_PATH ).resolve ()
2929 return f"sqlite:///{ db_path .as_posix ()} "
@@ -43,11 +43,37 @@ def run_migrations_offline() -> None:
4343
4444def run_migrations_online () -> None :
4545 url_from_config = config .get_main_option ("sqlalchemy.url" )
46- # Prefer app DB_PATH so we migrate the same DB the app uses (alembic.ini may have a different path)
47- use_app_path = True
48- if url_from_config and ":memory:" in url_from_config :
49- use_app_path = False # tests override with in-memory DB
50- if use_app_path :
46+ # Use url_from_config when set (tests or explicit override); otherwise use app DB_PATH
47+ if url_from_config :
48+ url_str : str = url_from_config
49+ if ":memory:" in url_str :
50+ configuration = config .get_section (config .config_ini_section ) or {}
51+ configuration ["sqlalchemy.url" ] = url_str
52+ connectable = engine_from_config (
53+ configuration ,
54+ prefix = "sqlalchemy." ,
55+ poolclass = pool .NullPool ,
56+ )
57+ else :
58+ # File path: extract path and use creator so SQLite creates the file
59+ path_str = url_str .replace ("sqlite:///" , "" ).replace ("sqlite://" , "" )
60+ path_obj = Path (path_str )
61+ if not path_obj .is_absolute ():
62+ # Resolve relative to the directory containing alembic.ini so
63+ # "data.sqlite" in backend/alembic.ini -> backend/data.sqlite
64+ config_dir = Path (config .config_file_name or "" ).resolve ().parent
65+ path_obj = (config_dir / path_str ).resolve ()
66+ path_obj .parent .mkdir (parents = True , exist_ok = True )
67+
68+ def _sqlite_creator ():
69+ return sqlite3 .connect (str (path_obj ))
70+
71+ connectable = create_engine (
72+ "sqlite://" ,
73+ creator = _sqlite_creator ,
74+ poolclass = pool .NullPool ,
75+ )
76+ else :
5177 db_path = Path (DB_PATH ).resolve ()
5278 db_path .parent .mkdir (parents = True , exist_ok = True )
5379 path_str = str (db_path )
@@ -60,14 +86,6 @@ def _sqlite_creator():
6086 creator = _sqlite_creator ,
6187 poolclass = pool .NullPool ,
6288 )
63- else :
64- configuration = config .get_section (config .config_ini_section ) or {}
65- configuration ["sqlalchemy.url" ] = url_from_config
66- connectable = engine_from_config (
67- configuration ,
68- prefix = "sqlalchemy." ,
69- poolclass = pool .NullPool ,
70- )
7189
7290 with connectable .connect () as connection :
7391 context .configure (
0 commit comments