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