Coverage for src/local_deep_research/database/models/settings.py: 95%

56 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-03 23:15 +0000

1""" 

2Settings and configuration models. 

3Stores user preferences and API keys in encrypted database. 

4""" 

5 

6import enum 

7 

8from sqlalchemy import ( 

9 JSON, 

10 Boolean, 

11 Column, 

12 Enum, 

13 Float, 

14 Integer, 

15 String, 

16 Text, 

17) 

18from sqlalchemy_utc import UtcDateTime, utcnow 

19 

20from .base import Base 

21 

22 

23class UserSettings(Base): 

24 """ 

25 User-specific settings stored in their encrypted database. 

26 Replaces the need for config files or unencrypted storage. 

27 """ 

28 

29 __tablename__ = "user_settings" 

30 

31 id = Column(Integer, primary_key=True) 

32 key = Column(String(255), unique=True, nullable=False, index=True) 

33 value = Column(JSON) 

34 category = Column(String(100)) 

35 description = Column(Text) 

36 created_at = Column(UtcDateTime, default=utcnow()) 

37 updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow()) 

38 

39 def __repr__(self): 

40 return f"<UserSettings(key='{self.key}', category='{self.category}')>" 

41 

42 

43class APIKey(Base): 

44 """ 

45 Encrypted storage for API keys. 

46 These are especially sensitive and benefit from database encryption. 

47 """ 

48 

49 __tablename__ = "api_keys" 

50 

51 id = Column(Integer, primary_key=True) 

52 provider = Column(String(100), unique=True, nullable=False, index=True) 

53 key = Column(Text, nullable=False) # Encrypted by SQLCipher 

54 description = Column(Text) 

55 is_active = Column(Boolean, default=True) 

56 created_at = Column(UtcDateTime, default=utcnow()) 

57 updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow()) 

58 last_used = Column(UtcDateTime) 

59 usage_count = Column(Integer, default=0) 

60 

61 def __repr__(self): 

62 # Never show the actual key in repr 

63 return f"<APIKey(provider='{self.provider}', active={self.is_active})>" 

64 

65 

66class SettingType(str, enum.Enum): 

67 """Types of settings. 

68 

69 Inherits from ``str`` so that instances are JSON-serializable and work 

70 seamlessly with both SQLAlchemy columns and Pydantic models. 

71 """ 

72 

73 APP = "app" 

74 CHAT = "chat" 

75 LLM = "llm" 

76 SEARCH = "search" 

77 REPORT = "report" 

78 DATABASE = "database" 

79 

80 

81class Setting(Base): 

82 """ 

83 Global application settings (shared across users). 

84 For user-specific settings, use UserSettings. 

85 """ 

86 

87 __tablename__ = "settings" 

88 

89 id = Column(Integer, primary_key=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 ) 

108 

109 # unique=True on the key column already creates a unique constraint; 

110 # the separate UniqueConstraint was removed to avoid Alembic autogenerate drift. 

111 

112 def __repr__(self): 

113 return f"<Setting(key='{self.key}', type={self.type.value})>"