1+ from abc import ABC , abstractmethod
2+ from sqlite3 import OperationalError
3+ from sqlalchemy import create_engine
4+ from sqlalchemy .orm import sessionmaker
5+
6+ from jupyter_scheduler .orm import Base as DefaultBase , update_db_schema
7+
8+
9+ class DatabaseManager (ABC ):
10+ """Base class for database managers.
11+
12+ Database managers handle database operations for jupyter-scheduler.
13+ Subclasses can implement custom storage backends (K8s, Redis, etc.)
14+ while maintaining compatibility with the scheduler's session interface.
15+ """
16+
17+ @abstractmethod
18+ def create_session (self , db_url : str ):
19+ """Create a database session.
20+
21+ Args:
22+ db_url: Database URL (e.g., "k8s://namespace", "redis://localhost")
23+
24+ Returns:
25+ Session object compatible with SQLAlchemy session interface
26+ """
27+ pass
28+
29+ @abstractmethod
30+ def create_tables (self , db_url : str , drop_tables : bool = False , Base = None ):
31+ """Create database tables/schema.
32+
33+ Args:
34+ db_url: Database URL
35+ drop_tables: Whether to drop existing tables first
36+ Base: SQLAlchemy Base for custom schemas (tests)
37+ """
38+ pass
39+
40+
41+ class SQLAlchemyDatabaseManager (DatabaseManager ):
42+ """Default database manager using SQLAlchemy."""
43+
44+ def create_session (self , db_url : str ):
45+ """Create SQLAlchemy session factory."""
46+ engine = create_engine (db_url , echo = False )
47+ Session = sessionmaker (bind = engine )
48+ return Session
49+
50+ def create_tables (self , db_url : str , drop_tables : bool = False , Base = None ):
51+ """Create database tables using SQLAlchemy."""
52+ if Base is None :
53+ Base = DefaultBase
54+
55+ engine = create_engine (db_url )
56+ update_db_schema (engine , Base )
57+
58+ try :
59+ if drop_tables :
60+ Base .metadata .drop_all (engine )
61+ except OperationalError :
62+ pass
63+ finally :
64+ Base .metadata .create_all (engine )
0 commit comments