Class-Corder / database / bigquery_operations.py
bigquery_operations.py
Raw
from google.cloud import bigquery
from datetime import datetime
import uuid
import streamlit as st
from utils import generate_uuid


client = bigquery.Client()

def get_quizzes(lecture_id):
    query = """
        SELECT Quiz_name, Quiz_id, Lecture_id, Created_at
        FROM `{project}.{dataset}.Quizzes`
        WHERE Lecture_id = @lecture_id
        ORDER BY Created_at DESC
    """.format(project=st.secrets.project, dataset=st.secrets.dataset)
    job_config = bigquery.QueryJobConfig(
        query_parameters=[
            bigquery.ScalarQueryParameter("lecture_id", "STRING", lecture_id)
        ]
    )
    query_job = client.query(query, job_config=job_config)
    
    results = query_job.result()  # Waits for the query to finish

    quizzes = []
    for row in results:
        quizzes.append({
            "Quiz_id": row.Quiz_id,
            "Quiz_name": row.Quiz_name,
            "Lecture_id": row.Lecture_id,
            "Created_at": row.Created_at.isoformat()
        })
    
    return quizzes

def check_quiz_completion(quiz_id):
    client = bigquery.Client()
    query = """
        SELECT Quiz_completed
        FROM `{project}.{dataset}.Quizzes`
        WHERE Quiz_id = @quiz_id
    """.format(project=st.secrets.project, dataset=st.secrets.dataset)
    job_config = bigquery.QueryJobConfig(
        query_parameters=[
            bigquery.ScalarQueryParameter("quiz_id", "STRING", quiz_id)
        ]
    )
    query_job = client.query(query, job_config=job_config)
    results = query_job.result()
    for row in results:
        return row.Quiz_completed

def get_quiz_data(quiz_id):
    client = bigquery.Client()
    # Simplified query to only fetch question and all related answers without identifying the correct answer
    quiz_query = """
        SELECT
            q.Question_id,
            q.Text AS Question_Text,
            a.Answer_id,
            a.Text AS Answer_Text
        FROM `{project}.{dataset}.Questions` q
        JOIN `{project}.{dataset}.Answers` a ON q.Question_id = a.Question_id
        WHERE q.Quiz_id = @quiz_id
        ORDER BY q.Question_id, a.Answer_id
    """.format(project=st.secrets.project, dataset=st.secrets.dataset)

    job_config = bigquery.QueryJobConfig(
        query_parameters=[
            bigquery.ScalarQueryParameter("quiz_id", "STRING", quiz_id)
        ]
    )

    query_job = client.query(quiz_query, job_config=job_config)
    results = query_job.result()

    # Initialize a dictionary to organize the quiz data
    organized_quiz = {}
    for row in results:
        question_id = row.Question_id
        if question_id not in organized_quiz:
            organized_quiz[question_id] = {
                "question_text": row.Question_Text,
                "answers": []
            }
        # Append each answer to the respective question
        organized_quiz[question_id]["answers"].append({
            "answer_id": row.Answer_id,
            "answer_text": row.Answer_Text
        })

    return organized_quiz

def insert_quiz_data(quiz_data, lecture_id, quiz_name):
    """
    Quiz data is in json format, lecture_id is passed from session state.
    """

    existing_quizzes = get_quizzes(lecture_id)
    if any(quiz['Quiz_name'] == quiz_name for quiz in existing_quizzes):
        return False  # Indicates that a quiz with this name already exists

    # Generate a new quiz ID and current timestamp
    quiz_id = generate_uuid()
    created_at = datetime.utcnow()
    # Insert into the Quizzes table
    quiz_query = """
        INSERT INTO `{project}.{dataset}.Quizzes` (Quiz_id, Quiz_name, Quiz_completed, Lecture_id, Created_at)
        VALUES (@quiz_id, @quiz_name, @quiz_completed, @lecture_id, @created_at)
    """.format(project=st.secrets.project, dataset=st.secrets.dataset)
    client.query(quiz_query, job_config=bigquery.QueryJobConfig(
        query_parameters=[
            bigquery.ScalarQueryParameter("quiz_id", "STRING", quiz_id),
            bigquery.ScalarQueryParameter("quiz_name", "STRING", quiz_name),
            bigquery.ScalarQueryParameter("lecture_id", "STRING", lecture_id),
            bigquery.ScalarQueryParameter("quiz_completed", "BOOL", False),
            bigquery.ScalarQueryParameter("created_at", "TIMESTAMP", created_at)
        ]
    ))

    # Loop through each question in the data
    for question in quiz_data:
        question_id = generate_uuid()
        correct_answer_id = generate_uuid()
        
        # Insert into the Questions table
        question_query = """
            INSERT INTO `{project}.{dataset}.Questions` (Question_id, Quiz_id, Text, Correct_answer_id)
            VALUES (@question_id, @quiz_id, @text, @correct_answer_id)
        """.format(project=st.secrets.project, dataset=st.secrets.dataset)
        client.query(question_query, job_config=bigquery.QueryJobConfig(
            query_parameters=[
                bigquery.ScalarQueryParameter("question_id", "STRING", question_id),
                bigquery.ScalarQueryParameter("quiz_id", "STRING", quiz_id),
                bigquery.ScalarQueryParameter("text", "STRING", question['question']),
                bigquery.ScalarQueryParameter("correct_answer_id", "STRING", correct_answer_id),
            ]
        ))

        # Insert answers for each question
        for choice in question['choices']:
            is_correct = (choice == question['answer'])
            answer_id = correct_answer_id if is_correct else generate_uuid()
            answer_query = """
                INSERT INTO `{project}.{dataset}.Answers` (Answer_id, Question_id, Text)
                VALUES (@answer_id, @question_id, @text)
            """.format(project=st.secrets.project, dataset=st.secrets.dataset)
            client.query(answer_query, job_config=bigquery.QueryJobConfig(
                query_parameters=[
                    bigquery.ScalarQueryParameter("answer_id", "STRING", answer_id),
                    bigquery.ScalarQueryParameter("question_id", "STRING", question_id),
                    bigquery.ScalarQueryParameter("text", "STRING", choice),
                ]
            ))

    print("Quiz data insertion complete.")
    return quiz_id

def mark_quiz_as_completed(quiz_id):
    query = """
        UPDATE `{project}.{dataset}.Quizzes`
        SET Quiz_completed = TRUE
        WHERE Quiz_id = @quiz_id
    """.format(project=st.secrets.project, dataset=st.secrets.dataset)
    params = [bigquery.ScalarQueryParameter("quiz_id", "STRING", quiz_id)]
    job_config = bigquery.QueryJobConfig(query_parameters=params)
    client.query(query, job_config=job_config)

def insert_user_response(question_id, selected_answer_id):
    response_id = generate_uuid()
    query = """
        INSERT INTO `{project}.{dataset}.UserResponses` (Response_id, Question_id, Selected_answer_id)
        VALUES (@response_id, @question_id, @selected_answer_id)
    """.format(project=st.secrets.project, dataset=st.secrets.dataset)
    params = [
        bigquery.ScalarQueryParameter("response_id", "STRING", response_id),
        bigquery.ScalarQueryParameter("question_id", "STRING", question_id),
        bigquery.ScalarQueryParameter("selected_answer_id", "STRING", selected_answer_id),
    ]
    job_config = bigquery.QueryJobConfig(query_parameters=params)
    try:
        client.query(query, job_config=job_config)
    except Exception as e:
        print(f"Failed to insert due to: {e}")
        raise


def get_quiz_results(quiz_id):
    client = bigquery.Client()
    # Corrected query to fetch question details along with the correct and user-selected answers
    query = """
        SELECT 
            q.Question_id,
            q.Text AS Question_text,
            q.Correct_answer_id,
            a_correct.Text AS Correct_answer_text,
            a_user.Answer_id AS User_answer_id,
            a_user.Text AS User_answer_text
        FROM `{project}.{dataset}.Questions` q
        JOIN `{project}.{dataset}.Answers` a_correct ON q.Correct_answer_id = a_correct.Answer_id
        LEFT JOIN `{project}.{dataset}.UserResponses` ur ON q.Question_id = ur.Question_id
        LEFT JOIN `{project}.{dataset}.Answers` a_user ON ur.Selected_answer_id = a_user.Answer_id
        WHERE q.Quiz_id = @quiz_id
    """.format(project=st.secrets.project, dataset=st.secrets.dataset)
    job_config = bigquery.QueryJobConfig(
        query_parameters=[
            bigquery.ScalarQueryParameter("quiz_id", "STRING", quiz_id)
        ]
    )
    query_job = client.query(query, job_config=job_config)
    results = query_job.result()
    
    feedback_data = []
    for row in results:
        feedback_data.append({
            "question_text": row.Question_text,
            "correct_answer_text": row.Correct_answer_text,
            "user_answer_text": row.User_answer_text
        })
    print(feedback_data)
    return feedback_data


def insert_feedback(quiz_id, feedback_text):
    print("Inserting feedback...")
    client = bigquery.Client()
    feedback_id = generate_uuid()
    query = """
        INSERT INTO `{project}.{dataset}..Feedback` (Feedback_id, Quiz_id, Text)
        VALUES (@feedback_id, @quiz_id, @feedback_text)
    """.format(project=st.secrets.project, dataset=st.secrets.dataset)
    job_config = bigquery.QueryJobConfig(
        query_parameters=[
            bigquery.ScalarQueryParameter("feedback_id", "STRING", feedback_id),
            bigquery.ScalarQueryParameter("quiz_id", "STRING", quiz_id),
            bigquery.ScalarQueryParameter("feedback_text", "STRING", feedback_text),
        ]
    )
    client.query(query, job_config=job_config)

def get_feedback(quiz_id):
    client = bigquery.Client()
    query = """
        SELECT Text FROM `{project}.{dataset}.Feedback` WHERE Quiz_id = @quiz_id LIMIT 1
    """.format(project=st.secrets.project, dataset=st.secrets.dataset)
    job_config = bigquery.QueryJobConfig(
        query_parameters=[
            bigquery.ScalarQueryParameter("quiz_id", "STRING", quiz_id)
        ]
    )
    query_job = client.query(query, job_config=job_config)
    results = query_job.result()
    feedback_text = ''
    for row in results:
        feedback_text = row.Text
    return feedback_text