Database & Persistence¶
OSCAR stores persistent user data in a local SQLite database (default path: ./database/oscar.db).
The database layer serves two purposes:
- Persistence: Storing user preferences, semester plans, and feedback.
- Caching: Storing module metadata fetched from the Nextcloud API to reduce API calls and enable SQL joins.
Database Schema¶
OSCAR uses SQLite (Version 3) with the following main tables:
flowchart TD
%% Define entities with SQLite schema details
USER[("USERS<br/>--<br/>id {PK} INTEGER<br/>name TEXT")]
PREF[("PREFERENCES<br/>--<br/>user_id {PK,FK} INTEGER<br/>language VARCHAR2<br/>semester INTEGER<br/>major TEXT")]
MOD[("MODULES<br/>--<br/>id {PK} INTEGER<br/>language {PK} VARCHAR2<br/>title TEXT<br/>title_en TEXT")]
PLAN[("SEMESTER_PLANS<br/>--<br/>user_id {PK,FK} INTEGER<br/>module_id {PK,FK} INTEGER<br/>language {PK,FK} VARCHAR2<br/>UNIQUE(user_id, module_id)")]
FEED[("FEEDBACK<br/>--<br/>id {PK} INTEGER AI<br/>user_id {FK} INTEGER<br/>timestamp INTEGER<br/>intuitiveness INT 1-4<br/>discoverability INT 1-4<br/>usefulness INT 1-4<br/>improvements TEXT<br/>wishes TEXT<br/>bugs TEXT")]
%% Define relationships
REL_HAS{"has"}
REL_PLANS{"plans"}
REL_GIVES{"gives"}
REL_INCLUDES{"includes"}
%% Connections with min-max notation
%% User has Preference (0,1) to (1,1)
USER ---|"(0,1)"| REL_HAS
REL_HAS ---|"(1,1)"| PREF
%% User plans Semester_Plans (0,n) to (1,1)
USER ---|"(0,n)"| REL_PLANS
REL_PLANS ---|"(1,1)"| PLAN
%% Semester_Plans includes Module (0,n) to (0,m)
PLAN ---|"(0,n)"| REL_INCLUDES
REL_INCLUDES ---|"(0,m)"| MOD
%% User gives Feedback (0,n) to (1,1)
USER ---|"(0,n)"| REL_GIVES
REL_GIVES ---|"(1,1)"| FEED
%% Styling for EER appearance
classDef entity fill:#e1f5ff,stroke:#01579b,stroke-width:2px;
classDef relation fill:#fff3e0,stroke:#e65100,stroke-width:2px;
class USER,PREF,MOD,PLAN,FEED entity;
class REL_HAS,REL_PLANS,REL_GIVES,REL_INCLUDES relation;
Singleton Access¶
Do not instantiate Database directly. Use the singleton accessor to ensure thread safety and a single connection pool.
src.util.database.get_database ¶
Get or create the database singleton.
Data Schema (v6)¶
The database schema is versioned via PRAGMA user_version.
| Table | Description | Key Relationships |
|---|---|---|
users |
Stores Discord User IDs. | Primary Key (id) |
preferences |
User settings (Language, Major, Semester, SPO, Winter/Summer). | FK to users |
modules |
Cache of module definitions (Title, Language). | PK (id, language) |
semester_plans |
Link table for User ↔ Module assignments. | FK to users, FK to modules |
feedback |
Anonymous feedback submissions. | FK to users (for rate limiting/spam protection) |
study_buddies |
Opt-in module study group matchmaking. | FK to users |
module_ratings |
Student course evaluations & difficulty ratings. | FK to users |
Public API¶
The Database Class¶
The central interface for all SQL operations.
src.util.database.Database ¶
Class for handling database operations.
Version: 8
Initialize database connection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
db_path
|
str | None
|
Path to database file. Defaults to |
None
|
Source code in src/util/database.py
set_preferences ¶
set_preferences(user_id: int, language: LanguageCode | None = None, semester: int | None = None, major: str | None = None, spo: int | None = None, winter_semester: bool = True) -> None
Update the users preferences in the database.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
int
|
the users discord id. |
required |
language
|
LanguageCode | None
|
prefered language (e.g. |
None
|
semester
|
int | None
|
integer representing the current semester. |
None
|
major
|
str | None
|
the users course of study. |
None
|
spo
|
int | None
|
usually the users enrollment year or the next lower spo |
None
|
winter_semester
|
bool
|
weather the user has started to study in the winter semester |
True
|
Source code in src/util/database.py
get_preferences ¶
Retrieve a user's preferences as a dictionary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
int
|
the users discord id. |
required |
Returns:
| Type | Description |
|---|---|
PrefsDict | None
|
dictonary corresponding to the row for the users preferences |
Source code in src/util/database.py
get_users ¶
Fetches all users
Returns:
| Type | Description |
|---|---|
list[int] | None
|
List of user (discord) id's. |
Source code in src/util/database.py
get_module ¶
Fetches a module from the database.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
module_id
|
int
|
the modules id. |
required |
language
|
LanguageCode
|
the modules language. |
required |
Source code in src/util/database.py
add_to_semesterplan ¶
Adds a module to the users semester plan.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
int
|
the users discord id. |
required |
module_id
|
int
|
the modules id. |
required |
language
|
LanguageCode
|
the modules language. |
DE
|
Source code in src/util/database.py
get_semesterplan ¶
Fetches the semester plan for a user.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
int
|
the users discord id. |
required |
Returns:
| Type | Description |
|---|---|
list[Module]
|
List of modules in the users semester plan. |
Source code in src/util/database.py
send_feedback_dict ¶
Sends user feedback to the database.
Source code in src/util/database.py
send_feedback ¶
send_feedback(user_id: int, intuitiveness: int, discoverability: int, usefulness: int, improvements: str = '', wishes: str = '', bugs: str = '') -> None
Sends user feedback to the database.
Source code in src/util/database.py
get_feedback ¶
Fetches all feedback from the database, sorted by ccreation date.
Source code in src/util/database.py
delete_feedback ¶
Deletes feedback from the database by its id.
Source code in src/util/database.py
rate_module ¶
rate_module(user_id: int, module_id: int, rating: int, difficulty: int, comment: str | None = None) -> None
Stores or updates a student's rating and difficulty evaluation for a module.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
int
|
The student's discord id. |
required |
module_id
|
int
|
The module identifier. |
required |
rating
|
int
|
Overall rating (1-5 stars). |
required |
difficulty
|
int
|
Subjective difficulty (1-5, 1=easy, 5=hard). |
required |
comment
|
str | None
|
Optional review or advice for future students. |
None
|
Source code in src/util/database.py
get_module_ratings ¶
Returns aggregated ratings and difficulty statistics for a module.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
module_id
|
int
|
The module identifier. |
required |
Returns:
| Type | Description |
|---|---|
ModuleRatingDict
|
Dictionary with count, avg_rating, and avg_difficulty. |
Source code in src/util/database.py
get_user_module_rating ¶
Returns a student's own rating for a module if already submitted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
int
|
The student's discord id. |
required |
module_id
|
int
|
The module identifier. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
Rating dict or None if unrated. |
Source code in src/util/database.py
get_module_comments ¶
Returns recent student reviews/comments for a module.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
module_id
|
int
|
The module identifier. |
required |
limit
|
int
|
Maximum number of comments to return. |
5
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
List of dicts with rating, difficulty, comment, timestamp. |
Source code in src/util/database.py
Manual Documentation overrides¶
add_module¶
Hybrid Caching Logic: This method is polymorphic. If called with just an
int(ID), it attempts to fetch the module details from the Nextcloud Tables API (util.tables) and cache them locally before insertion.
Adds a module to the database.
- Overloads:
add_module(module: Module)add_module(module_id: int, language: LanguageCode = DE): Fetches data from API.add_module(module_id: int, language: LanguageCode, title: str, title_en: str)
- Parameters:
*args: Variable arguments based on usage above.
remove_from_semesterplan¶
Note: Documented manually due to docstring mismatch in source.
Removes a module from the user's semester plan.
- Parameters:
user_id(int): The user's Discord ID.module_id(int): The module's unique ID.
Helper Functions¶
get_user_language¶
A helper function used extensively in UI Views to determine the correct language string (DE or EN) for a user. Defaults to EN if no preference is saved.
src.util.database.get_user_language ¶
Liest die Sprache eines Benutzers aus der Datenbank.