Coverage for src / local_deep_research / database / models / settings.py: 95%
56 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-25 01:07 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-25 01:07 +0000
1"""
2Settings and configuration models.
3Stores user preferences and API keys in encrypted database.
4"""
6import enum
8from sqlalchemy import (
9 JSON,
10 Boolean,
11 Column,
12 Enum,
13 Float,
14 Integer,
15 String,
16 Text,
17 UniqueConstraint,
18)
19from sqlalchemy_utc import UtcDateTime, utcnow
21from .base import Base
24class UserSettings(Base):
25 """
26 User-specific settings stored in their encrypted database.
27 Replaces the need for config files or unencrypted storage.
28 """
30 __tablename__ = "user_settings"
32 id = Column(Integer, primary_key=True)
33 key = Column(String(255), unique=True, nullable=False, index=True)
34 value = Column(JSON)
35 category = Column(String(100))
36 description = Column(Text)
37 created_at = Column(UtcDateTime, default=utcnow())
38 updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow())
40 def __repr__(self):
41 return f"<UserSettings(key='{self.key}', category='{self.category}')>"
44class APIKey(Base):
45 """
46 Encrypted storage for API keys.
47 These are especially sensitive and benefit from database encryption.
48 """
50 __tablename__ = "api_keys"
52 id = Column(Integer, primary_key=True)
53 provider = Column(String(100), unique=True, nullable=False, index=True)
54 key = Column(Text, nullable=False) # Encrypted by SQLCipher
55 description = Column(Text)
56 is_active = Column(Boolean, default=True)
57 created_at = Column(UtcDateTime, default=utcnow())
58 updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow())
59 last_used = Column(UtcDateTime)
60 usage_count = Column(Integer, default=0)
62 def __repr__(self):
63 # Never show the actual key in repr
64 return f"<APIKey(provider='{self.provider}', active={self.is_active})>"
67class SettingType(str, enum.Enum):
68 """Types of settings.
70 Inherits from ``str`` so that instances are JSON-serializable and work
71 seamlessly with both SQLAlchemy columns and Pydantic models.
72 """
74 APP = "app"
75 LLM = "llm"
76 SEARCH = "search"
77 REPORT = "report"
78 DATABASE = "database"
81class Setting(Base):
82 """
83 Global application settings (shared across users).
84 For user-specific settings, use UserSettings.
85 """
87 __tablename__ = "settings"
89 id = Column(Integer, primary_key=True, index=True)
90 key = Column(String(255), nullable=False, unique=True, index=True)
91 value = Column(JSON, nullable=True)
92 type = Column(Enum(SettingType), nullable=False, index=True)
93 name = Column(String(255), nullable=False)
94 description = Column(Text, nullable=True)
95 category = Column(String(100), nullable=True, index=True)
96 ui_element = Column(String(50), default="text", nullable=False)
97 options = Column(JSON, nullable=True) # For select elements
98 min_value = Column(Float, nullable=True) # For numeric inputs
99 max_value = Column(Float, nullable=True) # For numeric inputs
100 step = Column(Float, nullable=True) # For sliders
101 visible = Column(Boolean, default=True, nullable=False)
102 editable = Column(Boolean, default=True, nullable=False)
103 env_var = Column(String(255), nullable=True) # Environment variable name
104 created_at = Column(UtcDateTime, server_default=utcnow(), nullable=False)
105 updated_at = Column(
106 UtcDateTime, server_default=utcnow(), onupdate=utcnow(), nullable=False
107 )
109 __table_args__ = (UniqueConstraint("key", name="uix_settings_key"),)
111 def __repr__(self):
112 return f"<Setting(key='{self.key}', type={self.type.value})>"