Boost Azure Demo

This commit is contained in:
MangoPig
2026-05-25 17:05:06 +01:00
parent 675285e99d
commit 4f79137d89
230 changed files with 43275 additions and 2644 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,147 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: classrooms.sql
package sqlc
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const addStudentToClassroom = `-- name: AddStudentToClassroom :exec
INSERT INTO classroom_students (
classroom_id,
student_id
) VALUES (
$1,
$2
)
ON CONFLICT (classroom_id, student_id) DO NOTHING
`
type AddStudentToClassroomParams struct {
ClassroomID int64 `json:"classroom_id"`
StudentID int64 `json:"student_id"`
}
func (q *Queries) AddStudentToClassroom(ctx context.Context, arg AddStudentToClassroomParams) error {
_, err := q.db.Exec(ctx, addStudentToClassroom, arg.ClassroomID, arg.StudentID)
return err
}
const createClassroom = `-- name: CreateClassroom :one
INSERT INTO classrooms (
teacher_id,
name,
code,
description
) VALUES (
$1,
$2,
$3,
$4
)
RETURNING id, teacher_id, name, code, description, created_at, updated_at
`
type CreateClassroomParams struct {
TeacherID int64 `json:"teacher_id"`
Name string `json:"name"`
Code pgtype.Text `json:"code"`
Description pgtype.Text `json:"description"`
}
func (q *Queries) CreateClassroom(ctx context.Context, arg CreateClassroomParams) (Classroom, error) {
row := q.db.QueryRow(ctx, createClassroom,
arg.TeacherID,
arg.Name,
arg.Code,
arg.Description,
)
var i Classroom
err := row.Scan(
&i.ID,
&i.TeacherID,
&i.Name,
&i.Code,
&i.Description,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const listClassroomsByTeacher = `-- name: ListClassroomsByTeacher :many
SELECT id, teacher_id, name, code, description, created_at, updated_at
FROM classrooms
WHERE teacher_id = $1
ORDER BY created_at DESC
`
func (q *Queries) ListClassroomsByTeacher(ctx context.Context, teacherID int64) ([]Classroom, error) {
rows, err := q.db.Query(ctx, listClassroomsByTeacher, teacherID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Classroom{}
for rows.Next() {
var i Classroom
if err := rows.Scan(
&i.ID,
&i.TeacherID,
&i.Name,
&i.Code,
&i.Description,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listStudentsForClassroom = `-- name: ListStudentsForClassroom :many
SELECT u.id, u.email, u.password_hash, u.role, u.full_name, u.is_active, u.created_at, u.updated_at
FROM classroom_students cs
JOIN users u ON u.id = cs.student_id
WHERE cs.classroom_id = $1
ORDER BY u.full_name ASC
`
func (q *Queries) ListStudentsForClassroom(ctx context.Context, classroomID int64) ([]User, error) {
rows, err := q.db.Query(ctx, listStudentsForClassroom, classroomID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []User{}
for rows.Next() {
var i User
if err := rows.Scan(
&i.ID,
&i.Email,
&i.PasswordHash,
&i.Role,
&i.FullName,
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}

View File

@@ -0,0 +1,32 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
package sqlc
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
type DBTX interface {
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
QueryRow(context.Context, string, ...interface{}) pgx.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
return &Queries{
db: tx,
}
}

View File

@@ -0,0 +1,742 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: messages.sql
package sqlc
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const addMessageThreadParticipant = `-- name: AddMessageThreadParticipant :exec
INSERT INTO message_thread_participants (
thread_id,
user_id,
last_read_at
) VALUES (
$1,
$2,
$3
)
ON CONFLICT (thread_id, user_id) DO NOTHING
`
type AddMessageThreadParticipantParams struct {
ThreadID int64 `json:"thread_id"`
UserID int64 `json:"user_id"`
LastReadAt pgtype.Timestamptz `json:"last_read_at"`
}
func (q *Queries) AddMessageThreadParticipant(ctx context.Context, arg AddMessageThreadParticipantParams) error {
_, err := q.db.Exec(ctx, addMessageThreadParticipant, arg.ThreadID, arg.UserID, arg.LastReadAt)
return err
}
const createMessageThread = `-- name: CreateMessageThread :one
INSERT INTO message_threads (
created_by_user_id,
subject
) VALUES (
$1,
$2
)
RETURNING id, created_by_user_id, subject, created_at, updated_at
`
type CreateMessageThreadParams struct {
CreatedByUserID int64 `json:"created_by_user_id"`
Subject string `json:"subject"`
}
func (q *Queries) CreateMessageThread(ctx context.Context, arg CreateMessageThreadParams) (MessageThread, error) {
row := q.db.QueryRow(ctx, createMessageThread, arg.CreatedByUserID, arg.Subject)
var i MessageThread
err := row.Scan(
&i.ID,
&i.CreatedByUserID,
&i.Subject,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const createThreadMessage = `-- name: CreateThreadMessage :one
INSERT INTO messages (
thread_id,
sender_user_id,
body
) VALUES (
$1,
$2,
$3
)
RETURNING id, thread_id, sender_user_id, body, created_at, updated_at
`
type CreateThreadMessageParams struct {
ThreadID int64 `json:"thread_id"`
SenderUserID int64 `json:"sender_user_id"`
Body string `json:"body"`
}
func (q *Queries) CreateThreadMessage(ctx context.Context, arg CreateThreadMessageParams) (Message, error) {
row := q.db.QueryRow(ctx, createThreadMessage, arg.ThreadID, arg.SenderUserID, arg.Body)
var i Message
err := row.Scan(
&i.ID,
&i.ThreadID,
&i.SenderUserID,
&i.Body,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const deleteMessageThread = `-- name: DeleteMessageThread :one
DELETE FROM message_threads
WHERE id = $1
RETURNING id, created_by_user_id, subject, created_at, updated_at
`
func (q *Queries) DeleteMessageThread(ctx context.Context, threadID int64) (MessageThread, error) {
row := q.db.QueryRow(ctx, deleteMessageThread, threadID)
var i MessageThread
err := row.Scan(
&i.ID,
&i.CreatedByUserID,
&i.Subject,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const deleteThreadMessage = `-- name: DeleteThreadMessage :one
DELETE FROM messages
WHERE id = $1
AND thread_id = $2
AND sender_user_id = $3
RETURNING id, thread_id, sender_user_id, body, created_at, updated_at
`
type DeleteThreadMessageParams struct {
MessageID int64 `json:"message_id"`
ThreadID int64 `json:"thread_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) DeleteThreadMessage(ctx context.Context, arg DeleteThreadMessageParams) (Message, error) {
row := q.db.QueryRow(ctx, deleteThreadMessage, arg.MessageID, arg.ThreadID, arg.UserID)
var i Message
err := row.Scan(
&i.ID,
&i.ThreadID,
&i.SenderUserID,
&i.Body,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getMessageRecipientByIDForUser = `-- name: GetMessageRecipientByIDForUser :one
SELECT
u.id AS user_id,
u.email AS user_email,
u.role AS user_role,
u.full_name AS user_full_name,
p.preferred_name,
p.profile_icon_url,
p.headline
FROM users u
LEFT JOIN profiles p ON p.user_id = u.id
WHERE u.id = $2
AND u.id <> $1
AND u.is_active = TRUE
AND (
EXISTS (
SELECT 1
FROM classrooms c
JOIN classroom_students cs ON cs.classroom_id = c.id
WHERE c.teacher_id = u.id
AND cs.student_id = $1
)
OR EXISTS (
SELECT 1
FROM classrooms c
JOIN classroom_students cs ON cs.classroom_id = c.id
WHERE c.teacher_id = $1
AND cs.student_id = u.id
)
)
LIMIT 1
`
type GetMessageRecipientByIDForUserParams struct {
ID int64 `json:"id"`
ID_2 int64 `json:"id_2"`
}
type GetMessageRecipientByIDForUserRow struct {
UserID int64 `json:"user_id"`
UserEmail string `json:"user_email"`
UserRole UserRole `json:"user_role"`
UserFullName string `json:"user_full_name"`
PreferredName pgtype.Text `json:"preferred_name"`
ProfileIconUrl pgtype.Text `json:"profile_icon_url"`
Headline pgtype.Text `json:"headline"`
}
func (q *Queries) GetMessageRecipientByIDForUser(ctx context.Context, arg GetMessageRecipientByIDForUserParams) (GetMessageRecipientByIDForUserRow, error) {
row := q.db.QueryRow(ctx, getMessageRecipientByIDForUser, arg.ID, arg.ID_2)
var i GetMessageRecipientByIDForUserRow
err := row.Scan(
&i.UserID,
&i.UserEmail,
&i.UserRole,
&i.UserFullName,
&i.PreferredName,
&i.ProfileIconUrl,
&i.Headline,
)
return i, err
}
const getMessageThreadForUser = `-- name: GetMessageThreadForUser :one
SELECT
t.id,
t.subject,
t.created_by_user_id,
t.created_at,
t.updated_at,
participant.last_read_at,
COALESCE((
SELECT COUNT(*)::bigint
FROM messages unread
WHERE unread.thread_id = t.id
AND unread.sender_user_id <> $2
AND (participant.last_read_at IS NULL OR unread.created_at > participant.last_read_at)
), 0)::bigint AS unread_count
FROM message_threads t
JOIN message_thread_participants participant ON participant.thread_id = t.id
WHERE t.id = $1
AND participant.user_id = $2
AND participant.archived_at IS NULL
`
type GetMessageThreadForUserParams struct {
ID int64 `json:"id"`
SenderUserID int64 `json:"sender_user_id"`
}
type GetMessageThreadForUserRow struct {
ID int64 `json:"id"`
Subject string `json:"subject"`
CreatedByUserID int64 `json:"created_by_user_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
LastReadAt pgtype.Timestamptz `json:"last_read_at"`
UnreadCount int64 `json:"unread_count"`
}
func (q *Queries) GetMessageThreadForUser(ctx context.Context, arg GetMessageThreadForUserParams) (GetMessageThreadForUserRow, error) {
row := q.db.QueryRow(ctx, getMessageThreadForUser, arg.ID, arg.SenderUserID)
var i GetMessageThreadForUserRow
err := row.Scan(
&i.ID,
&i.Subject,
&i.CreatedByUserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.LastReadAt,
&i.UnreadCount,
)
return i, err
}
const listMessageRecipientsForUser = `-- name: ListMessageRecipientsForUser :many
SELECT
u.id AS user_id,
u.email AS user_email,
u.role AS user_role,
u.full_name AS user_full_name,
p.preferred_name,
p.profile_icon_url,
p.headline
FROM users u
LEFT JOIN profiles p ON p.user_id = u.id
WHERE u.id <> $1
AND u.is_active = TRUE
AND (
EXISTS (
SELECT 1
FROM classrooms c
JOIN classroom_students cs ON cs.classroom_id = c.id
WHERE c.teacher_id = u.id
AND cs.student_id = $1
)
OR EXISTS (
SELECT 1
FROM classrooms c
JOIN classroom_students cs ON cs.classroom_id = c.id
WHERE c.teacher_id = $1
AND cs.student_id = u.id
)
)
ORDER BY COALESCE(NULLIF(p.preferred_name, ''), u.full_name) ASC, u.id ASC
`
type ListMessageRecipientsForUserRow struct {
UserID int64 `json:"user_id"`
UserEmail string `json:"user_email"`
UserRole UserRole `json:"user_role"`
UserFullName string `json:"user_full_name"`
PreferredName pgtype.Text `json:"preferred_name"`
ProfileIconUrl pgtype.Text `json:"profile_icon_url"`
Headline pgtype.Text `json:"headline"`
}
func (q *Queries) ListMessageRecipientsForUser(ctx context.Context, id int64) ([]ListMessageRecipientsForUserRow, error) {
rows, err := q.db.Query(ctx, listMessageRecipientsForUser, id)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListMessageRecipientsForUserRow{}
for rows.Next() {
var i ListMessageRecipientsForUserRow
if err := rows.Scan(
&i.UserID,
&i.UserEmail,
&i.UserRole,
&i.UserFullName,
&i.PreferredName,
&i.ProfileIconUrl,
&i.Headline,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMessageThreadParticipantsForUser = `-- name: ListMessageThreadParticipantsForUser :many
SELECT
mtp.thread_id,
u.id AS user_id,
u.email AS user_email,
u.role AS user_role,
u.full_name AS user_full_name,
p.preferred_name,
p.profile_icon_url,
p.headline,
mtp.joined_at,
mtp.last_read_at,
mtp.archived_at
FROM message_thread_participants mtp
JOIN users u ON u.id = mtp.user_id
LEFT JOIN profiles p ON p.user_id = u.id
WHERE mtp.thread_id IN (
SELECT participant.thread_id
FROM message_thread_participants participant
WHERE participant.user_id = $1
AND participant.archived_at IS NULL
)
ORDER BY mtp.thread_id ASC, COALESCE(NULLIF(p.preferred_name, ''), u.full_name) ASC, u.id ASC
`
type ListMessageThreadParticipantsForUserRow struct {
ThreadID int64 `json:"thread_id"`
UserID int64 `json:"user_id"`
UserEmail string `json:"user_email"`
UserRole UserRole `json:"user_role"`
UserFullName string `json:"user_full_name"`
PreferredName pgtype.Text `json:"preferred_name"`
ProfileIconUrl pgtype.Text `json:"profile_icon_url"`
Headline pgtype.Text `json:"headline"`
JoinedAt pgtype.Timestamptz `json:"joined_at"`
LastReadAt pgtype.Timestamptz `json:"last_read_at"`
ArchivedAt pgtype.Timestamptz `json:"archived_at"`
}
func (q *Queries) ListMessageThreadParticipantsForUser(ctx context.Context, userID int64) ([]ListMessageThreadParticipantsForUserRow, error) {
rows, err := q.db.Query(ctx, listMessageThreadParticipantsForUser, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListMessageThreadParticipantsForUserRow{}
for rows.Next() {
var i ListMessageThreadParticipantsForUserRow
if err := rows.Scan(
&i.ThreadID,
&i.UserID,
&i.UserEmail,
&i.UserRole,
&i.UserFullName,
&i.PreferredName,
&i.ProfileIconUrl,
&i.Headline,
&i.JoinedAt,
&i.LastReadAt,
&i.ArchivedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMessageThreadsForUser = `-- name: ListMessageThreadsForUser :many
SELECT
t.id AS thread_id,
t.subject,
t.created_by_user_id,
t.created_at AS thread_created_at,
t.updated_at AS thread_updated_at,
COALESCE(last_message.id, 0)::bigint AS last_message_id,
COALESCE(last_message.body, '') AS last_message_body,
last_message.created_at AS last_message_created_at,
COALESCE(last_message.sender_user_id, 0)::bigint AS last_message_sender_user_id,
sender.full_name AS last_message_sender_full_name,
sender_profile.preferred_name AS last_message_sender_preferred_name,
sender_profile.profile_icon_url AS last_message_sender_profile_icon_url,
COALESCE((
SELECT COUNT(*)::bigint
FROM messages unread
WHERE unread.thread_id = t.id
AND unread.sender_user_id <> $1
AND (participant.last_read_at IS NULL OR unread.created_at > participant.last_read_at)
), 0)::bigint AS unread_count
FROM message_thread_participants participant
JOIN message_threads t ON t.id = participant.thread_id
LEFT JOIN LATERAL (
SELECT m.id, m.body, m.created_at, m.sender_user_id
FROM messages m
WHERE m.thread_id = t.id
ORDER BY m.created_at DESC, m.id DESC
LIMIT 1
) AS last_message ON TRUE
LEFT JOIN users sender ON sender.id = last_message.sender_user_id
LEFT JOIN profiles sender_profile ON sender_profile.user_id = sender.id
WHERE participant.user_id = $1
AND participant.archived_at IS NULL
ORDER BY COALESCE(last_message.created_at, t.updated_at) DESC, t.id DESC
`
type ListMessageThreadsForUserRow struct {
ThreadID int64 `json:"thread_id"`
Subject string `json:"subject"`
CreatedByUserID int64 `json:"created_by_user_id"`
ThreadCreatedAt pgtype.Timestamptz `json:"thread_created_at"`
ThreadUpdatedAt pgtype.Timestamptz `json:"thread_updated_at"`
LastMessageID int64 `json:"last_message_id"`
LastMessageBody string `json:"last_message_body"`
LastMessageCreatedAt pgtype.Timestamptz `json:"last_message_created_at"`
LastMessageSenderUserID int64 `json:"last_message_sender_user_id"`
LastMessageSenderFullName pgtype.Text `json:"last_message_sender_full_name"`
LastMessageSenderPreferredName pgtype.Text `json:"last_message_sender_preferred_name"`
LastMessageSenderProfileIconUrl pgtype.Text `json:"last_message_sender_profile_icon_url"`
UnreadCount int64 `json:"unread_count"`
}
func (q *Queries) ListMessageThreadsForUser(ctx context.Context, senderUserID int64) ([]ListMessageThreadsForUserRow, error) {
rows, err := q.db.Query(ctx, listMessageThreadsForUser, senderUserID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListMessageThreadsForUserRow{}
for rows.Next() {
var i ListMessageThreadsForUserRow
if err := rows.Scan(
&i.ThreadID,
&i.Subject,
&i.CreatedByUserID,
&i.ThreadCreatedAt,
&i.ThreadUpdatedAt,
&i.LastMessageID,
&i.LastMessageBody,
&i.LastMessageCreatedAt,
&i.LastMessageSenderUserID,
&i.LastMessageSenderFullName,
&i.LastMessageSenderPreferredName,
&i.LastMessageSenderProfileIconUrl,
&i.UnreadCount,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMessagesForThreadForUser = `-- name: ListMessagesForThreadForUser :many
SELECT
m.id,
m.thread_id,
m.sender_user_id,
m.body,
m.created_at,
m.updated_at,
sender.email AS sender_email,
sender.role AS sender_role,
sender.full_name AS sender_full_name,
sender_profile.preferred_name AS sender_preferred_name,
sender_profile.profile_icon_url AS sender_profile_icon_url,
sender_profile.headline AS sender_headline
FROM messages m
JOIN message_thread_participants participant ON participant.thread_id = m.thread_id
JOIN users sender ON sender.id = m.sender_user_id
LEFT JOIN profiles sender_profile ON sender_profile.user_id = sender.id
WHERE m.thread_id = $1
AND participant.user_id = $2
AND participant.archived_at IS NULL
ORDER BY m.created_at ASC, m.id ASC
`
type ListMessagesForThreadForUserParams struct {
ThreadID int64 `json:"thread_id"`
UserID int64 `json:"user_id"`
}
type ListMessagesForThreadForUserRow struct {
ID int64 `json:"id"`
ThreadID int64 `json:"thread_id"`
SenderUserID int64 `json:"sender_user_id"`
Body string `json:"body"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
SenderEmail string `json:"sender_email"`
SenderRole UserRole `json:"sender_role"`
SenderFullName string `json:"sender_full_name"`
SenderPreferredName pgtype.Text `json:"sender_preferred_name"`
SenderProfileIconUrl pgtype.Text `json:"sender_profile_icon_url"`
SenderHeadline pgtype.Text `json:"sender_headline"`
}
func (q *Queries) ListMessagesForThreadForUser(ctx context.Context, arg ListMessagesForThreadForUserParams) ([]ListMessagesForThreadForUserRow, error) {
rows, err := q.db.Query(ctx, listMessagesForThreadForUser, arg.ThreadID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListMessagesForThreadForUserRow{}
for rows.Next() {
var i ListMessagesForThreadForUserRow
if err := rows.Scan(
&i.ID,
&i.ThreadID,
&i.SenderUserID,
&i.Body,
&i.CreatedAt,
&i.UpdatedAt,
&i.SenderEmail,
&i.SenderRole,
&i.SenderFullName,
&i.SenderPreferredName,
&i.SenderProfileIconUrl,
&i.SenderHeadline,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listParticipantsForThreadForUser = `-- name: ListParticipantsForThreadForUser :many
SELECT
mtp.thread_id,
u.id AS user_id,
u.email AS user_email,
u.role AS user_role,
u.full_name AS user_full_name,
p.preferred_name,
p.profile_icon_url,
p.headline,
mtp.joined_at,
mtp.last_read_at,
mtp.archived_at
FROM message_thread_participants mtp
JOIN users u ON u.id = mtp.user_id
LEFT JOIN profiles p ON p.user_id = u.id
WHERE mtp.thread_id = $1
AND EXISTS (
SELECT 1
FROM message_thread_participants participant
WHERE participant.thread_id = mtp.thread_id
AND participant.user_id = $2
AND participant.archived_at IS NULL
)
ORDER BY COALESCE(NULLIF(p.preferred_name, ''), u.full_name) ASC, u.id ASC
`
type ListParticipantsForThreadForUserParams struct {
ThreadID int64 `json:"thread_id"`
UserID int64 `json:"user_id"`
}
type ListParticipantsForThreadForUserRow struct {
ThreadID int64 `json:"thread_id"`
UserID int64 `json:"user_id"`
UserEmail string `json:"user_email"`
UserRole UserRole `json:"user_role"`
UserFullName string `json:"user_full_name"`
PreferredName pgtype.Text `json:"preferred_name"`
ProfileIconUrl pgtype.Text `json:"profile_icon_url"`
Headline pgtype.Text `json:"headline"`
JoinedAt pgtype.Timestamptz `json:"joined_at"`
LastReadAt pgtype.Timestamptz `json:"last_read_at"`
ArchivedAt pgtype.Timestamptz `json:"archived_at"`
}
func (q *Queries) ListParticipantsForThreadForUser(ctx context.Context, arg ListParticipantsForThreadForUserParams) ([]ListParticipantsForThreadForUserRow, error) {
rows, err := q.db.Query(ctx, listParticipantsForThreadForUser, arg.ThreadID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListParticipantsForThreadForUserRow{}
for rows.Next() {
var i ListParticipantsForThreadForUserRow
if err := rows.Scan(
&i.ThreadID,
&i.UserID,
&i.UserEmail,
&i.UserRole,
&i.UserFullName,
&i.PreferredName,
&i.ProfileIconUrl,
&i.Headline,
&i.JoinedAt,
&i.LastReadAt,
&i.ArchivedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const markMessageThreadRead = `-- name: MarkMessageThreadRead :one
UPDATE message_thread_participants
SET last_read_at = COALESCE((SELECT MAX(m.created_at) FROM messages m WHERE m.thread_id = $1), NOW())
WHERE message_thread_participants.thread_id = $1
AND message_thread_participants.user_id = $2
RETURNING thread_id, user_id, joined_at, last_read_at, archived_at
`
type MarkMessageThreadReadParams struct {
ThreadID int64 `json:"thread_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) MarkMessageThreadRead(ctx context.Context, arg MarkMessageThreadReadParams) (MessageThreadParticipant, error) {
row := q.db.QueryRow(ctx, markMessageThreadRead, arg.ThreadID, arg.UserID)
var i MessageThreadParticipant
err := row.Scan(
&i.ThreadID,
&i.UserID,
&i.JoinedAt,
&i.LastReadAt,
&i.ArchivedAt,
)
return i, err
}
const touchMessageThread = `-- name: TouchMessageThread :exec
UPDATE message_threads
SET updated_at = NOW()
WHERE id = $1
`
func (q *Queries) TouchMessageThread(ctx context.Context, id int64) error {
_, err := q.db.Exec(ctx, touchMessageThread, id)
return err
}
const updateMessageThreadSubject = `-- name: UpdateMessageThreadSubject :one
UPDATE message_threads
SET subject = $1,
updated_at = NOW()
WHERE id = $2
RETURNING id, created_by_user_id, subject, created_at, updated_at
`
type UpdateMessageThreadSubjectParams struct {
Subject string `json:"subject"`
ThreadID int64 `json:"thread_id"`
}
func (q *Queries) UpdateMessageThreadSubject(ctx context.Context, arg UpdateMessageThreadSubjectParams) (MessageThread, error) {
row := q.db.QueryRow(ctx, updateMessageThreadSubject, arg.Subject, arg.ThreadID)
var i MessageThread
err := row.Scan(
&i.ID,
&i.CreatedByUserID,
&i.Subject,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const updateThreadMessageBody = `-- name: UpdateThreadMessageBody :one
UPDATE messages
SET body = $1,
updated_at = NOW()
WHERE id = $2
AND thread_id = $3
AND sender_user_id = $4
RETURNING id, thread_id, sender_user_id, body, created_at, updated_at
`
type UpdateThreadMessageBodyParams struct {
Body string `json:"body"`
MessageID int64 `json:"message_id"`
ThreadID int64 `json:"thread_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) UpdateThreadMessageBody(ctx context.Context, arg UpdateThreadMessageBodyParams) (Message, error) {
row := q.db.QueryRow(ctx, updateThreadMessageBody,
arg.Body,
arg.MessageID,
arg.ThreadID,
arg.UserID,
)
var i Message
err := row.Scan(
&i.ID,
&i.ThreadID,
&i.SenderUserID,
&i.Body,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}

View File

@@ -0,0 +1,526 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
package sqlc
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgx/v5/pgtype"
)
type AnswerStatus string
const (
AnswerStatusNotStarted AnswerStatus = "not_started"
AnswerStatusInProgress AnswerStatus = "in_progress"
AnswerStatusSubmitted AnswerStatus = "submitted"
AnswerStatusReviewed AnswerStatus = "reviewed"
)
func (e *AnswerStatus) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = AnswerStatus(s)
case string:
*e = AnswerStatus(s)
default:
return fmt.Errorf("unsupported scan type for AnswerStatus: %T", src)
}
return nil
}
type NullAnswerStatus struct {
AnswerStatus AnswerStatus `json:"answer_status"`
Valid bool `json:"valid"` // Valid is true if AnswerStatus is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullAnswerStatus) Scan(value interface{}) error {
if value == nil {
ns.AnswerStatus, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.AnswerStatus.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullAnswerStatus) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.AnswerStatus), nil
}
type AssignmentNextStepOutcome string
const (
AssignmentNextStepOutcomeRedo AssignmentNextStepOutcome = "redo"
AssignmentNextStepOutcomeAccept AssignmentNextStepOutcome = "accept"
AssignmentNextStepOutcomeSupport AssignmentNextStepOutcome = "support"
)
func (e *AssignmentNextStepOutcome) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = AssignmentNextStepOutcome(s)
case string:
*e = AssignmentNextStepOutcome(s)
default:
return fmt.Errorf("unsupported scan type for AssignmentNextStepOutcome: %T", src)
}
return nil
}
type NullAssignmentNextStepOutcome struct {
AssignmentNextStepOutcome AssignmentNextStepOutcome `json:"assignment_next_step_outcome"`
Valid bool `json:"valid"` // Valid is true if AssignmentNextStepOutcome is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullAssignmentNextStepOutcome) Scan(value interface{}) error {
if value == nil {
ns.AssignmentNextStepOutcome, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.AssignmentNextStepOutcome.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullAssignmentNextStepOutcome) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.AssignmentNextStepOutcome), nil
}
type AssignmentPassStatus string
const (
AssignmentPassStatusPending AssignmentPassStatus = "pending"
AssignmentPassStatusPass AssignmentPassStatus = "pass"
AssignmentPassStatusNoPass AssignmentPassStatus = "no_pass"
)
func (e *AssignmentPassStatus) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = AssignmentPassStatus(s)
case string:
*e = AssignmentPassStatus(s)
default:
return fmt.Errorf("unsupported scan type for AssignmentPassStatus: %T", src)
}
return nil
}
type NullAssignmentPassStatus struct {
AssignmentPassStatus AssignmentPassStatus `json:"assignment_pass_status"`
Valid bool `json:"valid"` // Valid is true if AssignmentPassStatus is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullAssignmentPassStatus) Scan(value interface{}) error {
if value == nil {
ns.AssignmentPassStatus, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.AssignmentPassStatus.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullAssignmentPassStatus) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.AssignmentPassStatus), nil
}
type AssignmentStatus string
const (
AssignmentStatusDraft AssignmentStatus = "draft"
AssignmentStatusAssigned AssignmentStatus = "assigned"
AssignmentStatusClosed AssignmentStatus = "closed"
)
func (e *AssignmentStatus) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = AssignmentStatus(s)
case string:
*e = AssignmentStatus(s)
default:
return fmt.Errorf("unsupported scan type for AssignmentStatus: %T", src)
}
return nil
}
type NullAssignmentStatus struct {
AssignmentStatus AssignmentStatus `json:"assignment_status"`
Valid bool `json:"valid"` // Valid is true if AssignmentStatus is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullAssignmentStatus) Scan(value interface{}) error {
if value == nil {
ns.AssignmentStatus, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.AssignmentStatus.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullAssignmentStatus) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.AssignmentStatus), nil
}
type QuestionDifficulty string
const (
QuestionDifficultyEasy QuestionDifficulty = "easy"
QuestionDifficultyMedium QuestionDifficulty = "medium"
QuestionDifficultyHard QuestionDifficulty = "hard"
)
func (e *QuestionDifficulty) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = QuestionDifficulty(s)
case string:
*e = QuestionDifficulty(s)
default:
return fmt.Errorf("unsupported scan type for QuestionDifficulty: %T", src)
}
return nil
}
type NullQuestionDifficulty struct {
QuestionDifficulty QuestionDifficulty `json:"question_difficulty"`
Valid bool `json:"valid"` // Valid is true if QuestionDifficulty is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullQuestionDifficulty) Scan(value interface{}) error {
if value == nil {
ns.QuestionDifficulty, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.QuestionDifficulty.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullQuestionDifficulty) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.QuestionDifficulty), nil
}
type QuestionStatus string
const (
QuestionStatusDraft QuestionStatus = "draft"
QuestionStatusPublished QuestionStatus = "published"
QuestionStatusArchived QuestionStatus = "archived"
)
func (e *QuestionStatus) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = QuestionStatus(s)
case string:
*e = QuestionStatus(s)
default:
return fmt.Errorf("unsupported scan type for QuestionStatus: %T", src)
}
return nil
}
type NullQuestionStatus struct {
QuestionStatus QuestionStatus `json:"question_status"`
Valid bool `json:"valid"` // Valid is true if QuestionStatus is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullQuestionStatus) Scan(value interface{}) error {
if value == nil {
ns.QuestionStatus, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.QuestionStatus.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullQuestionStatus) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.QuestionStatus), nil
}
type QuestionTopic string
const (
QuestionTopicPlaceValue QuestionTopic = "place_value"
QuestionTopicArithmetic QuestionTopic = "arithmetic"
QuestionTopicNegativeNumbers QuestionTopic = "negative_numbers"
QuestionTopicBidmas QuestionTopic = "bidmas"
QuestionTopicFractions QuestionTopic = "fractions"
QuestionTopicAlgebra QuestionTopic = "algebra"
QuestionTopicGeometry QuestionTopic = "geometry"
QuestionTopicData QuestionTopic = "data"
)
func (e *QuestionTopic) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = QuestionTopic(s)
case string:
*e = QuestionTopic(s)
default:
return fmt.Errorf("unsupported scan type for QuestionTopic: %T", src)
}
return nil
}
type NullQuestionTopic struct {
QuestionTopic QuestionTopic `json:"question_topic"`
Valid bool `json:"valid"` // Valid is true if QuestionTopic is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullQuestionTopic) Scan(value interface{}) error {
if value == nil {
ns.QuestionTopic, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.QuestionTopic.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullQuestionTopic) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.QuestionTopic), nil
}
type UserRole string
const (
UserRoleStudent UserRole = "student"
UserRoleTeacher UserRole = "teacher"
)
func (e *UserRole) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = UserRole(s)
case string:
*e = UserRole(s)
default:
return fmt.Errorf("unsupported scan type for UserRole: %T", src)
}
return nil
}
type NullUserRole struct {
UserRole UserRole `json:"user_role"`
Valid bool `json:"valid"` // Valid is true if UserRole is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullUserRole) Scan(value interface{}) error {
if value == nil {
ns.UserRole, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.UserRole.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullUserRole) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.UserRole), nil
}
type Assignment struct {
ID int64 `json:"id"`
ClassroomID int64 `json:"classroom_id"`
TeacherID int64 `json:"teacher_id"`
Title string `json:"title"`
Instructions pgtype.Text `json:"instructions"`
Status AssignmentStatus `json:"status"`
DueAt pgtype.Timestamptz `json:"due_at"`
PublishedAt pgtype.Timestamptz `json:"published_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
PassThreshold pgtype.Numeric `json:"pass_threshold"`
}
type AssignmentAssignee struct {
AssignmentID int64 `json:"assignment_id"`
StudentID int64 `json:"student_id"`
AssignedAt pgtype.Timestamptz `json:"assigned_at"`
AiFeedback pgtype.Text `json:"ai_feedback"`
TeacherFeedback pgtype.Text `json:"teacher_feedback"`
OverallScore pgtype.Numeric `json:"overall_score"`
PassThreshold pgtype.Numeric `json:"pass_threshold"`
PassStatus AssignmentPassStatus `json:"pass_status"`
PassStatusOverride NullAssignmentPassStatus `json:"pass_status_override"`
NextStepOutcome NullAssignmentNextStepOutcome `json:"next_step_outcome"`
RedoPlan pgtype.Text `json:"redo_plan"`
RedoPlanGeneratedAt pgtype.Timestamptz `json:"redo_plan_generated_at"`
}
type AssignmentQuestion struct {
AssignmentID int64 `json:"assignment_id"`
QuestionID int64 `json:"question_id"`
Position int32 `json:"position"`
}
type AssignmentStudentQuestion struct {
ID int64 `json:"id"`
AssignmentID int64 `json:"assignment_id"`
StudentID int64 `json:"student_id"`
QuestionID int64 `json:"question_id"`
Position int32 `json:"position"`
SourceBucket string `json:"source_bucket"`
SourceTopic NullQuestionTopic `json:"source_topic"`
SourceDifficulty NullQuestionDifficulty `json:"source_difficulty"`
GeneratorSeed pgtype.Int8 `json:"generator_seed"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type Classroom struct {
ID int64 `json:"id"`
TeacherID int64 `json:"teacher_id"`
Name string `json:"name"`
Code pgtype.Text `json:"code"`
Description pgtype.Text `json:"description"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type ClassroomStudent struct {
ClassroomID int64 `json:"classroom_id"`
StudentID int64 `json:"student_id"`
JoinedAt pgtype.Timestamptz `json:"joined_at"`
}
type Message struct {
ID int64 `json:"id"`
ThreadID int64 `json:"thread_id"`
SenderUserID int64 `json:"sender_user_id"`
Body string `json:"body"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type MessageThread struct {
ID int64 `json:"id"`
CreatedByUserID int64 `json:"created_by_user_id"`
Subject string `json:"subject"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type MessageThreadParticipant struct {
ThreadID int64 `json:"thread_id"`
UserID int64 `json:"user_id"`
JoinedAt pgtype.Timestamptz `json:"joined_at"`
LastReadAt pgtype.Timestamptz `json:"last_read_at"`
ArchivedAt pgtype.Timestamptz `json:"archived_at"`
}
type Profile struct {
UserID int64 `json:"user_id"`
PreferredName pgtype.Text `json:"preferred_name"`
ProfileIconUrl pgtype.Text `json:"profile_icon_url"`
Headline pgtype.Text `json:"headline"`
Bio pgtype.Text `json:"bio"`
Timezone pgtype.Text `json:"timezone"`
Locale pgtype.Text `json:"locale"`
GradeLevel pgtype.Text `json:"grade_level"`
LearningGoal pgtype.Text `json:"learning_goal"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type Question struct {
ID int64 `json:"id"`
AuthorTeacherID int64 `json:"author_teacher_id"`
Title string `json:"title"`
Prompt string `json:"prompt"`
Subject pgtype.Text `json:"subject"`
Source pgtype.Text `json:"source"`
Status QuestionStatus `json:"status"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
CorrectAnswer pgtype.Text `json:"correct_answer"`
Topic NullQuestionTopic `json:"topic"`
Difficulty NullQuestionDifficulty `json:"difficulty"`
}
type QuestionTag struct {
QuestionID int64 `json:"question_id"`
TagID int64 `json:"tag_id"`
}
type StudentAnswer struct {
ID int64 `json:"id"`
AssignmentID int64 `json:"assignment_id"`
QuestionID int64 `json:"question_id"`
StudentID int64 `json:"student_id"`
AnswerText pgtype.Text `json:"answer_text"`
AiFeedback pgtype.Text `json:"ai_feedback"`
TeacherFeedback pgtype.Text `json:"teacher_feedback"`
Status AnswerStatus `json:"status"`
SubmittedAt pgtype.Timestamptz `json:"submitted_at"`
ReviewedAt pgtype.Timestamptz `json:"reviewed_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
SolveMode string `json:"solve_mode"`
WorkingSteps pgtype.Text `json:"working_steps"`
IsCorrect pgtype.Bool `json:"is_correct"`
ReviewNeedsAttention bool `json:"review_needs_attention"`
ReviewIssueReason pgtype.Text `json:"review_issue_reason"`
ReviewCorrectnessScore pgtype.Numeric `json:"review_correctness_score"`
ReviewUnderstandingScore pgtype.Numeric `json:"review_understanding_score"`
ReviewQuestionScore pgtype.Numeric `json:"review_question_score"`
ReviewConfidence pgtype.Numeric `json:"review_confidence"`
ReviewTags []string `json:"review_tags"`
}
type Tag struct {
ID int64 `json:"id"`
Name string `json:"name"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type User struct {
ID int64 `json:"id"`
Email string `json:"email"`
PasswordHash pgtype.Text `json:"password_hash"`
Role UserRole `json:"role"`
FullName string `json:"full_name"`
IsActive bool `json:"is_active"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}

View File

@@ -0,0 +1,206 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: questions.sql
package sqlc
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const attachTagToQuestion = `-- name: AttachTagToQuestion :exec
INSERT INTO question_tags (
question_id,
tag_id
) VALUES (
$1,
$2
)
ON CONFLICT (question_id, tag_id) DO NOTHING
`
type AttachTagToQuestionParams struct {
QuestionID int64 `json:"question_id"`
TagID int64 `json:"tag_id"`
}
func (q *Queries) AttachTagToQuestion(ctx context.Context, arg AttachTagToQuestionParams) error {
_, err := q.db.Exec(ctx, attachTagToQuestion, arg.QuestionID, arg.TagID)
return err
}
const createQuestion = `-- name: CreateQuestion :one
INSERT INTO questions (
author_teacher_id,
title,
prompt,
topic,
subject,
difficulty,
source,
status,
correct_answer
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9
)
RETURNING id, author_teacher_id, title, prompt, subject, source, status, created_at, updated_at, correct_answer, topic, difficulty
`
type CreateQuestionParams struct {
AuthorTeacherID int64 `json:"author_teacher_id"`
Title string `json:"title"`
Prompt string `json:"prompt"`
Topic NullQuestionTopic `json:"topic"`
Subject pgtype.Text `json:"subject"`
Difficulty NullQuestionDifficulty `json:"difficulty"`
Source pgtype.Text `json:"source"`
Status QuestionStatus `json:"status"`
CorrectAnswer pgtype.Text `json:"correct_answer"`
}
func (q *Queries) CreateQuestion(ctx context.Context, arg CreateQuestionParams) (Question, error) {
row := q.db.QueryRow(ctx, createQuestion,
arg.AuthorTeacherID,
arg.Title,
arg.Prompt,
arg.Topic,
arg.Subject,
arg.Difficulty,
arg.Source,
arg.Status,
arg.CorrectAnswer,
)
var i Question
err := row.Scan(
&i.ID,
&i.AuthorTeacherID,
&i.Title,
&i.Prompt,
&i.Subject,
&i.Source,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.CorrectAnswer,
&i.Topic,
&i.Difficulty,
)
return i, err
}
const createTag = `-- name: CreateTag :one
INSERT INTO tags (name)
VALUES ($1)
ON CONFLICT (name) DO UPDATE SET name = EXCLUDED.name
RETURNING id, name, created_at
`
func (q *Queries) CreateTag(ctx context.Context, name string) (Tag, error) {
row := q.db.QueryRow(ctx, createTag, name)
var i Tag
err := row.Scan(&i.ID, &i.Name, &i.CreatedAt)
return i, err
}
const getQuestionByID = `-- name: GetQuestionByID :one
SELECT id, author_teacher_id, title, prompt, subject, source, status, created_at, updated_at, correct_answer, topic, difficulty
FROM questions
WHERE id = $1
`
func (q *Queries) GetQuestionByID(ctx context.Context, id int64) (Question, error) {
row := q.db.QueryRow(ctx, getQuestionByID, id)
var i Question
err := row.Scan(
&i.ID,
&i.AuthorTeacherID,
&i.Title,
&i.Prompt,
&i.Subject,
&i.Source,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.CorrectAnswer,
&i.Topic,
&i.Difficulty,
)
return i, err
}
const listQuestionsByTeacher = `-- name: ListQuestionsByTeacher :many
SELECT id, author_teacher_id, title, prompt, subject, source, status, created_at, updated_at, correct_answer, topic, difficulty
FROM questions
WHERE author_teacher_id = $1
ORDER BY created_at DESC
`
func (q *Queries) ListQuestionsByTeacher(ctx context.Context, authorTeacherID int64) ([]Question, error) {
rows, err := q.db.Query(ctx, listQuestionsByTeacher, authorTeacherID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Question{}
for rows.Next() {
var i Question
if err := rows.Scan(
&i.ID,
&i.AuthorTeacherID,
&i.Title,
&i.Prompt,
&i.Subject,
&i.Source,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.CorrectAnswer,
&i.Topic,
&i.Difficulty,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listTags = `-- name: ListTags :many
SELECT id, name, created_at
FROM tags
ORDER BY name ASC
`
func (q *Queries) ListTags(ctx context.Context) ([]Tag, error) {
rows, err := q.db.Query(ctx, listTags)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Tag{}
for rows.Next() {
var i Tag
if err := rows.Scan(&i.ID, &i.Name, &i.CreatedAt); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}

View File

@@ -0,0 +1,649 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: student_answers.sql
package sqlc
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const listAnswersForAssignment = `-- name: ListAnswersForAssignment :many
SELECT id, assignment_id, question_id, student_id, answer_text, ai_feedback, teacher_feedback, status, submitted_at, reviewed_at, created_at, updated_at, solve_mode, working_steps, is_correct, review_needs_attention, review_issue_reason, review_correctness_score, review_understanding_score, review_question_score, review_confidence, review_tags
FROM student_answers
WHERE assignment_id = $1
ORDER BY created_at ASC
`
func (q *Queries) ListAnswersForAssignment(ctx context.Context, assignmentID int64) ([]StudentAnswer, error) {
rows, err := q.db.Query(ctx, listAnswersForAssignment, assignmentID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []StudentAnswer{}
for rows.Next() {
var i StudentAnswer
if err := rows.Scan(
&i.ID,
&i.AssignmentID,
&i.QuestionID,
&i.StudentID,
&i.AnswerText,
&i.AiFeedback,
&i.TeacherFeedback,
&i.Status,
&i.SubmittedAt,
&i.ReviewedAt,
&i.CreatedAt,
&i.UpdatedAt,
&i.SolveMode,
&i.WorkingSteps,
&i.IsCorrect,
&i.ReviewNeedsAttention,
&i.ReviewIssueReason,
&i.ReviewCorrectnessScore,
&i.ReviewUnderstandingScore,
&i.ReviewQuestionScore,
&i.ReviewConfidence,
&i.ReviewTags,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listAnswersForStudent = `-- name: ListAnswersForStudent :many
SELECT id, assignment_id, question_id, student_id, answer_text, ai_feedback, teacher_feedback, status, submitted_at, reviewed_at, created_at, updated_at, solve_mode, working_steps, is_correct, review_needs_attention, review_issue_reason, review_correctness_score, review_understanding_score, review_question_score, review_confidence, review_tags
FROM student_answers
WHERE student_id = $1
ORDER BY created_at DESC
`
func (q *Queries) ListAnswersForStudent(ctx context.Context, studentID int64) ([]StudentAnswer, error) {
rows, err := q.db.Query(ctx, listAnswersForStudent, studentID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []StudentAnswer{}
for rows.Next() {
var i StudentAnswer
if err := rows.Scan(
&i.ID,
&i.AssignmentID,
&i.QuestionID,
&i.StudentID,
&i.AnswerText,
&i.AiFeedback,
&i.TeacherFeedback,
&i.Status,
&i.SubmittedAt,
&i.ReviewedAt,
&i.CreatedAt,
&i.UpdatedAt,
&i.SolveMode,
&i.WorkingSteps,
&i.IsCorrect,
&i.ReviewNeedsAttention,
&i.ReviewIssueReason,
&i.ReviewCorrectnessScore,
&i.ReviewUnderstandingScore,
&i.ReviewQuestionScore,
&i.ReviewConfidence,
&i.ReviewTags,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listQuestionDetailsForAssignmentStudent = `-- name: ListQuestionDetailsForAssignmentStudent :many
WITH student_question_set AS (
SELECT
asq.assignment_id,
asq.question_id,
asq.position
FROM assignment_student_questions asq
WHERE asq.assignment_id = $1
AND asq.student_id = $2
),
selected_questions AS (
SELECT
sq.assignment_id,
sq.question_id,
sq.position
FROM student_question_set sq
UNION ALL
SELECT
aq.assignment_id,
aq.question_id,
aq.position
FROM assignment_questions aq
WHERE aq.assignment_id = $1
AND NOT EXISTS (SELECT 1 FROM student_question_set)
)
SELECT
aq.assignment_id,
aq.question_id,
aq.position,
q.title,
q.prompt,
q.subject,
q.source,
COALESCE(
ARRAY(
SELECT t.name
FROM question_tags qt
JOIN tags t ON t.id = qt.tag_id
WHERE qt.question_id = aq.question_id
ORDER BY t.name ASC
),
ARRAY[]::TEXT[]
)::TEXT[] AS question_tags,
q.status AS question_status,
q.correct_answer,
aa.ai_feedback AS assignment_ai_feedback,
aa.teacher_feedback AS assignment_teacher_feedback,
review_summary.overall_score,
a.pass_threshold,
aa.next_step_outcome,
aa.pass_status_override,
COALESCE(
aa.pass_status_override,
CASE
WHEN review_summary.overall_score IS NULL THEN 'pending'::assignment_pass_status
WHEN review_summary.overall_score >= a.pass_threshold THEN 'pass'::assignment_pass_status
ELSE 'no_pass'::assignment_pass_status
END
) AS pass_status,
sa.id AS answer_id,
sa.student_id,
sa.answer_text,
sa.solve_mode,
sa.working_steps,
sa.is_correct,
sa.ai_feedback,
sa.teacher_feedback,
sa.status AS answer_status,
sa.review_needs_attention,
sa.review_issue_reason,
sa.review_correctness_score,
sa.review_understanding_score,
sa.review_question_score,
sa.review_confidence,
sa.review_tags,
sa.submitted_at,
sa.reviewed_at,
sa.created_at AS answer_created_at,
sa.updated_at AS answer_updated_at
FROM selected_questions aq
JOIN assignments a ON a.id = aq.assignment_id
JOIN questions q ON q.id = aq.question_id
LEFT JOIN assignment_assignees aa
ON aa.assignment_id = aq.assignment_id
AND aa.student_id = $2
LEFT JOIN LATERAL (
SELECT CASE
WHEN COUNT(sa2.id) = 0 THEN NULL::NUMERIC(5,2)
ELSE ROUND((AVG(
CASE
WHEN sa2.is_correct IS NULL THEN COALESCE(sa2.review_understanding_score, 0)::NUMERIC
ELSE (
((CASE WHEN sa2.is_correct THEN 1 ELSE 0 END)::NUMERIC) + COALESCE(sa2.review_understanding_score, 0)::NUMERIC
) / 2
END
) * 10)::NUMERIC, 2)::NUMERIC(5,2)
END AS overall_score
FROM selected_questions aq2
LEFT JOIN student_answers sa2
ON sa2.assignment_id = aq2.assignment_id
AND sa2.question_id = aq2.question_id
AND sa2.student_id = $2
WHERE aq2.assignment_id = aq.assignment_id
) review_summary ON TRUE
LEFT JOIN student_answers sa
ON sa.assignment_id = aq.assignment_id
AND sa.question_id = aq.question_id
AND sa.student_id = $2
WHERE aq.assignment_id = $1
ORDER BY aq.position ASC, aq.question_id ASC
`
type ListQuestionDetailsForAssignmentStudentParams struct {
AssignmentID int64 `json:"assignment_id"`
StudentID int64 `json:"student_id"`
}
type ListQuestionDetailsForAssignmentStudentRow struct {
AssignmentID int64 `json:"assignment_id"`
QuestionID int64 `json:"question_id"`
Position int32 `json:"position"`
Title string `json:"title"`
Prompt string `json:"prompt"`
Subject pgtype.Text `json:"subject"`
Source pgtype.Text `json:"source"`
QuestionTags []string `json:"question_tags"`
QuestionStatus QuestionStatus `json:"question_status"`
CorrectAnswer pgtype.Text `json:"correct_answer"`
AssignmentAiFeedback pgtype.Text `json:"assignment_ai_feedback"`
AssignmentTeacherFeedback pgtype.Text `json:"assignment_teacher_feedback"`
OverallScore pgtype.Numeric `json:"overall_score"`
PassThreshold pgtype.Numeric `json:"pass_threshold"`
NextStepOutcome NullAssignmentNextStepOutcome `json:"next_step_outcome"`
PassStatusOverride NullAssignmentPassStatus `json:"pass_status_override"`
PassStatus NullAssignmentPassStatus `json:"pass_status"`
AnswerID pgtype.Int8 `json:"answer_id"`
StudentID pgtype.Int8 `json:"student_id"`
AnswerText pgtype.Text `json:"answer_text"`
SolveMode pgtype.Text `json:"solve_mode"`
WorkingSteps pgtype.Text `json:"working_steps"`
IsCorrect pgtype.Bool `json:"is_correct"`
AiFeedback pgtype.Text `json:"ai_feedback"`
TeacherFeedback pgtype.Text `json:"teacher_feedback"`
AnswerStatus NullAnswerStatus `json:"answer_status"`
ReviewNeedsAttention pgtype.Bool `json:"review_needs_attention"`
ReviewIssueReason pgtype.Text `json:"review_issue_reason"`
ReviewCorrectnessScore pgtype.Numeric `json:"review_correctness_score"`
ReviewUnderstandingScore pgtype.Numeric `json:"review_understanding_score"`
ReviewQuestionScore pgtype.Numeric `json:"review_question_score"`
ReviewConfidence pgtype.Numeric `json:"review_confidence"`
ReviewTags []string `json:"review_tags"`
SubmittedAt pgtype.Timestamptz `json:"submitted_at"`
ReviewedAt pgtype.Timestamptz `json:"reviewed_at"`
AnswerCreatedAt pgtype.Timestamptz `json:"answer_created_at"`
AnswerUpdatedAt pgtype.Timestamptz `json:"answer_updated_at"`
}
func (q *Queries) ListQuestionDetailsForAssignmentStudent(ctx context.Context, arg ListQuestionDetailsForAssignmentStudentParams) ([]ListQuestionDetailsForAssignmentStudentRow, error) {
rows, err := q.db.Query(ctx, listQuestionDetailsForAssignmentStudent, arg.AssignmentID, arg.StudentID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListQuestionDetailsForAssignmentStudentRow{}
for rows.Next() {
var i ListQuestionDetailsForAssignmentStudentRow
if err := rows.Scan(
&i.AssignmentID,
&i.QuestionID,
&i.Position,
&i.Title,
&i.Prompt,
&i.Subject,
&i.Source,
&i.QuestionTags,
&i.QuestionStatus,
&i.CorrectAnswer,
&i.AssignmentAiFeedback,
&i.AssignmentTeacherFeedback,
&i.OverallScore,
&i.PassThreshold,
&i.NextStepOutcome,
&i.PassStatusOverride,
&i.PassStatus,
&i.AnswerID,
&i.StudentID,
&i.AnswerText,
&i.SolveMode,
&i.WorkingSteps,
&i.IsCorrect,
&i.AiFeedback,
&i.TeacherFeedback,
&i.AnswerStatus,
&i.ReviewNeedsAttention,
&i.ReviewIssueReason,
&i.ReviewCorrectnessScore,
&i.ReviewUnderstandingScore,
&i.ReviewQuestionScore,
&i.ReviewConfidence,
&i.ReviewTags,
&i.SubmittedAt,
&i.ReviewedAt,
&i.AnswerCreatedAt,
&i.AnswerUpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listStudentPlanningPerformance = `-- name: ListStudentPlanningPerformance :many
SELECT
sa.assignment_id,
sa.question_id,
q.topic,
q.subject,
q.difficulty,
COALESCE(
ARRAY(
SELECT t.name
FROM question_tags qt
JOIN tags t ON t.id = qt.tag_id
WHERE qt.question_id = sa.question_id
ORDER BY t.name ASC
),
ARRAY[]::TEXT[]
)::TEXT[] AS question_tags,
sa.is_correct,
sa.review_understanding_score,
sa.review_needs_attention,
sa.review_issue_reason,
sa.status,
sa.submitted_at,
sa.reviewed_at,
sa.updated_at
FROM student_answers sa
JOIN questions q ON q.id = sa.question_id
WHERE sa.student_id = $1
AND sa.status IN ('submitted'::answer_status, 'reviewed'::answer_status)
ORDER BY COALESCE(sa.reviewed_at, sa.submitted_at, sa.updated_at) DESC, sa.id DESC
`
type ListStudentPlanningPerformanceRow struct {
AssignmentID int64 `json:"assignment_id"`
QuestionID int64 `json:"question_id"`
Topic NullQuestionTopic `json:"topic"`
Subject pgtype.Text `json:"subject"`
Difficulty NullQuestionDifficulty `json:"difficulty"`
QuestionTags []string `json:"question_tags"`
IsCorrect pgtype.Bool `json:"is_correct"`
ReviewUnderstandingScore pgtype.Numeric `json:"review_understanding_score"`
ReviewNeedsAttention bool `json:"review_needs_attention"`
ReviewIssueReason pgtype.Text `json:"review_issue_reason"`
Status AnswerStatus `json:"status"`
SubmittedAt pgtype.Timestamptz `json:"submitted_at"`
ReviewedAt pgtype.Timestamptz `json:"reviewed_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
func (q *Queries) ListStudentPlanningPerformance(ctx context.Context, studentID int64) ([]ListStudentPlanningPerformanceRow, error) {
rows, err := q.db.Query(ctx, listStudentPlanningPerformance, studentID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListStudentPlanningPerformanceRow{}
for rows.Next() {
var i ListStudentPlanningPerformanceRow
if err := rows.Scan(
&i.AssignmentID,
&i.QuestionID,
&i.Topic,
&i.Subject,
&i.Difficulty,
&i.QuestionTags,
&i.IsCorrect,
&i.ReviewUnderstandingScore,
&i.ReviewNeedsAttention,
&i.ReviewIssueReason,
&i.Status,
&i.SubmittedAt,
&i.ReviewedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateAnswerAIReview = `-- name: UpdateAnswerAIReview :one
UPDATE student_answers
SET
ai_feedback = $2,
review_needs_attention = $3,
review_issue_reason = $4,
review_correctness_score = $5,
review_understanding_score = $6,
review_question_score = $7,
review_confidence = $8,
updated_at = NOW()
WHERE id = $1
RETURNING id, assignment_id, question_id, student_id, answer_text, ai_feedback, teacher_feedback, status, submitted_at, reviewed_at, created_at, updated_at, solve_mode, working_steps, is_correct, review_needs_attention, review_issue_reason, review_correctness_score, review_understanding_score, review_question_score, review_confidence, review_tags
`
type UpdateAnswerAIReviewParams struct {
ID int64 `json:"id"`
AiFeedback pgtype.Text `json:"ai_feedback"`
ReviewNeedsAttention bool `json:"review_needs_attention"`
ReviewIssueReason pgtype.Text `json:"review_issue_reason"`
ReviewCorrectnessScore pgtype.Numeric `json:"review_correctness_score"`
ReviewUnderstandingScore pgtype.Numeric `json:"review_understanding_score"`
ReviewQuestionScore pgtype.Numeric `json:"review_question_score"`
ReviewConfidence pgtype.Numeric `json:"review_confidence"`
}
func (q *Queries) UpdateAnswerAIReview(ctx context.Context, arg UpdateAnswerAIReviewParams) (StudentAnswer, error) {
row := q.db.QueryRow(ctx, updateAnswerAIReview,
arg.ID,
arg.AiFeedback,
arg.ReviewNeedsAttention,
arg.ReviewIssueReason,
arg.ReviewCorrectnessScore,
arg.ReviewUnderstandingScore,
arg.ReviewQuestionScore,
arg.ReviewConfidence,
)
var i StudentAnswer
err := row.Scan(
&i.ID,
&i.AssignmentID,
&i.QuestionID,
&i.StudentID,
&i.AnswerText,
&i.AiFeedback,
&i.TeacherFeedback,
&i.Status,
&i.SubmittedAt,
&i.ReviewedAt,
&i.CreatedAt,
&i.UpdatedAt,
&i.SolveMode,
&i.WorkingSteps,
&i.IsCorrect,
&i.ReviewNeedsAttention,
&i.ReviewIssueReason,
&i.ReviewCorrectnessScore,
&i.ReviewUnderstandingScore,
&i.ReviewQuestionScore,
&i.ReviewConfidence,
&i.ReviewTags,
)
return i, err
}
const updateAnswerReview = `-- name: UpdateAnswerReview :one
UPDATE student_answers
SET
status = $2,
review_needs_attention = $3,
review_issue_reason = $4,
review_correctness_score = $5,
review_understanding_score = $6,
review_question_score = $7,
review_confidence = $8,
review_tags = $9,
reviewed_at = CASE
WHEN $2::answer_status = 'reviewed' THEN NOW()
ELSE NULL
END,
updated_at = NOW()
WHERE id = $1
RETURNING id, assignment_id, question_id, student_id, answer_text, ai_feedback, teacher_feedback, status, submitted_at, reviewed_at, created_at, updated_at, solve_mode, working_steps, is_correct, review_needs_attention, review_issue_reason, review_correctness_score, review_understanding_score, review_question_score, review_confidence, review_tags
`
type UpdateAnswerReviewParams struct {
ID int64 `json:"id"`
Status AnswerStatus `json:"status"`
ReviewNeedsAttention bool `json:"review_needs_attention"`
ReviewIssueReason pgtype.Text `json:"review_issue_reason"`
ReviewCorrectnessScore pgtype.Numeric `json:"review_correctness_score"`
ReviewUnderstandingScore pgtype.Numeric `json:"review_understanding_score"`
ReviewQuestionScore pgtype.Numeric `json:"review_question_score"`
ReviewConfidence pgtype.Numeric `json:"review_confidence"`
ReviewTags []string `json:"review_tags"`
}
func (q *Queries) UpdateAnswerReview(ctx context.Context, arg UpdateAnswerReviewParams) (StudentAnswer, error) {
row := q.db.QueryRow(ctx, updateAnswerReview,
arg.ID,
arg.Status,
arg.ReviewNeedsAttention,
arg.ReviewIssueReason,
arg.ReviewCorrectnessScore,
arg.ReviewUnderstandingScore,
arg.ReviewQuestionScore,
arg.ReviewConfidence,
arg.ReviewTags,
)
var i StudentAnswer
err := row.Scan(
&i.ID,
&i.AssignmentID,
&i.QuestionID,
&i.StudentID,
&i.AnswerText,
&i.AiFeedback,
&i.TeacherFeedback,
&i.Status,
&i.SubmittedAt,
&i.ReviewedAt,
&i.CreatedAt,
&i.UpdatedAt,
&i.SolveMode,
&i.WorkingSteps,
&i.IsCorrect,
&i.ReviewNeedsAttention,
&i.ReviewIssueReason,
&i.ReviewCorrectnessScore,
&i.ReviewUnderstandingScore,
&i.ReviewQuestionScore,
&i.ReviewConfidence,
&i.ReviewTags,
)
return i, err
}
const upsertStudentAnswer = `-- name: UpsertStudentAnswer :one
INSERT INTO student_answers (
assignment_id,
question_id,
student_id,
answer_text,
solve_mode,
working_steps,
ai_feedback,
teacher_feedback,
status,
submitted_at,
reviewed_at,
is_correct
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12
)
ON CONFLICT (assignment_id, question_id, student_id) DO UPDATE
SET
answer_text = EXCLUDED.answer_text,
solve_mode = EXCLUDED.solve_mode,
working_steps = EXCLUDED.working_steps,
ai_feedback = EXCLUDED.ai_feedback,
teacher_feedback = EXCLUDED.teacher_feedback,
status = EXCLUDED.status,
submitted_at = EXCLUDED.submitted_at,
reviewed_at = EXCLUDED.reviewed_at,
is_correct = EXCLUDED.is_correct,
updated_at = NOW()
RETURNING id, assignment_id, question_id, student_id, answer_text, ai_feedback, teacher_feedback, status, submitted_at, reviewed_at, created_at, updated_at, solve_mode, working_steps, is_correct, review_needs_attention, review_issue_reason, review_correctness_score, review_understanding_score, review_question_score, review_confidence, review_tags
`
type UpsertStudentAnswerParams struct {
AssignmentID int64 `json:"assignment_id"`
QuestionID int64 `json:"question_id"`
StudentID int64 `json:"student_id"`
AnswerText pgtype.Text `json:"answer_text"`
SolveMode string `json:"solve_mode"`
WorkingSteps pgtype.Text `json:"working_steps"`
AiFeedback pgtype.Text `json:"ai_feedback"`
TeacherFeedback pgtype.Text `json:"teacher_feedback"`
Status AnswerStatus `json:"status"`
SubmittedAt pgtype.Timestamptz `json:"submitted_at"`
ReviewedAt pgtype.Timestamptz `json:"reviewed_at"`
IsCorrect pgtype.Bool `json:"is_correct"`
}
func (q *Queries) UpsertStudentAnswer(ctx context.Context, arg UpsertStudentAnswerParams) (StudentAnswer, error) {
row := q.db.QueryRow(ctx, upsertStudentAnswer,
arg.AssignmentID,
arg.QuestionID,
arg.StudentID,
arg.AnswerText,
arg.SolveMode,
arg.WorkingSteps,
arg.AiFeedback,
arg.TeacherFeedback,
arg.Status,
arg.SubmittedAt,
arg.ReviewedAt,
arg.IsCorrect,
)
var i StudentAnswer
err := row.Scan(
&i.ID,
&i.AssignmentID,
&i.QuestionID,
&i.StudentID,
&i.AnswerText,
&i.AiFeedback,
&i.TeacherFeedback,
&i.Status,
&i.SubmittedAt,
&i.ReviewedAt,
&i.CreatedAt,
&i.UpdatedAt,
&i.SolveMode,
&i.WorkingSteps,
&i.IsCorrect,
&i.ReviewNeedsAttention,
&i.ReviewIssueReason,
&i.ReviewCorrectnessScore,
&i.ReviewUnderstandingScore,
&i.ReviewQuestionScore,
&i.ReviewConfidence,
&i.ReviewTags,
)
return i, err
}

View File

@@ -0,0 +1,577 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: users.sql
package sqlc
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const createUser = `-- name: CreateUser :one
INSERT INTO users (
email,
password_hash,
role,
full_name
) VALUES (
$1,
$2,
$3,
$4
)
RETURNING id, email, password_hash, role, full_name, is_active, created_at, updated_at
`
type CreateUserParams struct {
Email string `json:"email"`
PasswordHash pgtype.Text `json:"password_hash"`
Role UserRole `json:"role"`
FullName string `json:"full_name"`
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
row := q.db.QueryRow(ctx, createUser,
arg.Email,
arg.PasswordHash,
arg.Role,
arg.FullName,
)
var i User
err := row.Scan(
&i.ID,
&i.Email,
&i.PasswordHash,
&i.Role,
&i.FullName,
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getAuthUserByEmail = `-- name: GetAuthUserByEmail :one
SELECT
u.id AS user_id,
u.email AS user_email,
u.role AS user_role,
u.full_name AS user_full_name,
u.is_active AS user_is_active,
u.password_hash AS user_password_hash,
u.created_at AS user_created_at,
u.updated_at AS user_updated_at,
p.user_id AS profile_user_id,
p.preferred_name,
p.profile_icon_url,
p.headline,
p.bio,
p.timezone,
p.locale,
p.grade_level,
p.learning_goal,
p.created_at AS profile_created_at,
p.updated_at AS profile_updated_at
FROM users u
LEFT JOIN profiles p ON p.user_id = u.id
WHERE u.email = $1
`
type GetAuthUserByEmailRow struct {
UserID int64 `json:"user_id"`
UserEmail string `json:"user_email"`
UserRole UserRole `json:"user_role"`
UserFullName string `json:"user_full_name"`
UserIsActive bool `json:"user_is_active"`
UserPasswordHash pgtype.Text `json:"user_password_hash"`
UserCreatedAt pgtype.Timestamptz `json:"user_created_at"`
UserUpdatedAt pgtype.Timestamptz `json:"user_updated_at"`
ProfileUserID pgtype.Int8 `json:"profile_user_id"`
PreferredName pgtype.Text `json:"preferred_name"`
ProfileIconUrl pgtype.Text `json:"profile_icon_url"`
Headline pgtype.Text `json:"headline"`
Bio pgtype.Text `json:"bio"`
Timezone pgtype.Text `json:"timezone"`
Locale pgtype.Text `json:"locale"`
GradeLevel pgtype.Text `json:"grade_level"`
LearningGoal pgtype.Text `json:"learning_goal"`
ProfileCreatedAt pgtype.Timestamptz `json:"profile_created_at"`
ProfileUpdatedAt pgtype.Timestamptz `json:"profile_updated_at"`
}
func (q *Queries) GetAuthUserByEmail(ctx context.Context, email string) (GetAuthUserByEmailRow, error) {
row := q.db.QueryRow(ctx, getAuthUserByEmail, email)
var i GetAuthUserByEmailRow
err := row.Scan(
&i.UserID,
&i.UserEmail,
&i.UserRole,
&i.UserFullName,
&i.UserIsActive,
&i.UserPasswordHash,
&i.UserCreatedAt,
&i.UserUpdatedAt,
&i.ProfileUserID,
&i.PreferredName,
&i.ProfileIconUrl,
&i.Headline,
&i.Bio,
&i.Timezone,
&i.Locale,
&i.GradeLevel,
&i.LearningGoal,
&i.ProfileCreatedAt,
&i.ProfileUpdatedAt,
)
return i, err
}
const getAuthUserByID = `-- name: GetAuthUserByID :one
SELECT
u.id AS user_id,
u.email AS user_email,
u.role AS user_role,
u.full_name AS user_full_name,
u.is_active AS user_is_active,
u.created_at AS user_created_at,
u.updated_at AS user_updated_at,
p.user_id AS profile_user_id,
p.preferred_name,
p.profile_icon_url,
p.headline,
p.bio,
p.timezone,
p.locale,
p.grade_level,
p.learning_goal,
p.created_at AS profile_created_at,
p.updated_at AS profile_updated_at
FROM users u
LEFT JOIN profiles p ON p.user_id = u.id
WHERE u.id = $1
`
type GetAuthUserByIDRow struct {
UserID int64 `json:"user_id"`
UserEmail string `json:"user_email"`
UserRole UserRole `json:"user_role"`
UserFullName string `json:"user_full_name"`
UserIsActive bool `json:"user_is_active"`
UserCreatedAt pgtype.Timestamptz `json:"user_created_at"`
UserUpdatedAt pgtype.Timestamptz `json:"user_updated_at"`
ProfileUserID pgtype.Int8 `json:"profile_user_id"`
PreferredName pgtype.Text `json:"preferred_name"`
ProfileIconUrl pgtype.Text `json:"profile_icon_url"`
Headline pgtype.Text `json:"headline"`
Bio pgtype.Text `json:"bio"`
Timezone pgtype.Text `json:"timezone"`
Locale pgtype.Text `json:"locale"`
GradeLevel pgtype.Text `json:"grade_level"`
LearningGoal pgtype.Text `json:"learning_goal"`
ProfileCreatedAt pgtype.Timestamptz `json:"profile_created_at"`
ProfileUpdatedAt pgtype.Timestamptz `json:"profile_updated_at"`
}
func (q *Queries) GetAuthUserByID(ctx context.Context, id int64) (GetAuthUserByIDRow, error) {
row := q.db.QueryRow(ctx, getAuthUserByID, id)
var i GetAuthUserByIDRow
err := row.Scan(
&i.UserID,
&i.UserEmail,
&i.UserRole,
&i.UserFullName,
&i.UserIsActive,
&i.UserCreatedAt,
&i.UserUpdatedAt,
&i.ProfileUserID,
&i.PreferredName,
&i.ProfileIconUrl,
&i.Headline,
&i.Bio,
&i.Timezone,
&i.Locale,
&i.GradeLevel,
&i.LearningGoal,
&i.ProfileCreatedAt,
&i.ProfileUpdatedAt,
)
return i, err
}
const getUserByEmail = `-- name: GetUserByEmail :one
SELECT id, email, password_hash, role, full_name, is_active, created_at, updated_at
FROM users
WHERE email = $1
`
func (q *Queries) GetUserByEmail(ctx context.Context, email string) (User, error) {
row := q.db.QueryRow(ctx, getUserByEmail, email)
var i User
err := row.Scan(
&i.ID,
&i.Email,
&i.PasswordHash,
&i.Role,
&i.FullName,
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getUserByID = `-- name: GetUserByID :one
SELECT id, email, password_hash, role, full_name, is_active, created_at, updated_at
FROM users
WHERE id = $1
`
func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
row := q.db.QueryRow(ctx, getUserByID, id)
var i User
err := row.Scan(
&i.ID,
&i.Email,
&i.PasswordHash,
&i.Role,
&i.FullName,
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getUserWithProfileByID = `-- name: GetUserWithProfileByID :one
SELECT
u.id AS user_id,
u.email AS user_email,
u.role AS user_role,
u.full_name AS user_full_name,
u.is_active AS user_is_active,
u.created_at AS user_created_at,
u.updated_at AS user_updated_at,
p.user_id AS profile_user_id,
p.preferred_name,
p.profile_icon_url,
p.headline,
p.bio,
p.timezone,
p.locale,
p.grade_level,
p.learning_goal,
p.created_at AS profile_created_at,
p.updated_at AS profile_updated_at
FROM users u
LEFT JOIN profiles p ON p.user_id = u.id
WHERE u.id = $1
`
type GetUserWithProfileByIDRow struct {
UserID int64 `json:"user_id"`
UserEmail string `json:"user_email"`
UserRole UserRole `json:"user_role"`
UserFullName string `json:"user_full_name"`
UserIsActive bool `json:"user_is_active"`
UserCreatedAt pgtype.Timestamptz `json:"user_created_at"`
UserUpdatedAt pgtype.Timestamptz `json:"user_updated_at"`
ProfileUserID pgtype.Int8 `json:"profile_user_id"`
PreferredName pgtype.Text `json:"preferred_name"`
ProfileIconUrl pgtype.Text `json:"profile_icon_url"`
Headline pgtype.Text `json:"headline"`
Bio pgtype.Text `json:"bio"`
Timezone pgtype.Text `json:"timezone"`
Locale pgtype.Text `json:"locale"`
GradeLevel pgtype.Text `json:"grade_level"`
LearningGoal pgtype.Text `json:"learning_goal"`
ProfileCreatedAt pgtype.Timestamptz `json:"profile_created_at"`
ProfileUpdatedAt pgtype.Timestamptz `json:"profile_updated_at"`
}
func (q *Queries) GetUserWithProfileByID(ctx context.Context, id int64) (GetUserWithProfileByIDRow, error) {
row := q.db.QueryRow(ctx, getUserWithProfileByID, id)
var i GetUserWithProfileByIDRow
err := row.Scan(
&i.UserID,
&i.UserEmail,
&i.UserRole,
&i.UserFullName,
&i.UserIsActive,
&i.UserCreatedAt,
&i.UserUpdatedAt,
&i.ProfileUserID,
&i.PreferredName,
&i.ProfileIconUrl,
&i.Headline,
&i.Bio,
&i.Timezone,
&i.Locale,
&i.GradeLevel,
&i.LearningGoal,
&i.ProfileCreatedAt,
&i.ProfileUpdatedAt,
)
return i, err
}
const listUsersByRole = `-- name: ListUsersByRole :many
SELECT id, email, password_hash, role, full_name, is_active, created_at, updated_at
FROM users
WHERE role = $1
ORDER BY full_name ASC
`
func (q *Queries) ListUsersByRole(ctx context.Context, role UserRole) ([]User, error) {
rows, err := q.db.Query(ctx, listUsersByRole, role)
if err != nil {
return nil, err
}
defer rows.Close()
items := []User{}
for rows.Next() {
var i User
if err := rows.Scan(
&i.ID,
&i.Email,
&i.PasswordHash,
&i.Role,
&i.FullName,
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listUsersWithProfileByRole = `-- name: ListUsersWithProfileByRole :many
SELECT
u.id AS user_id,
u.email AS user_email,
u.role AS user_role,
u.full_name AS user_full_name,
u.is_active AS user_is_active,
u.created_at AS user_created_at,
u.updated_at AS user_updated_at,
p.user_id AS profile_user_id,
p.preferred_name,
p.profile_icon_url,
p.headline,
p.bio,
p.timezone,
p.locale,
p.grade_level,
p.learning_goal,
p.created_at AS profile_created_at,
p.updated_at AS profile_updated_at
FROM users u
LEFT JOIN profiles p ON p.user_id = u.id
WHERE u.role = $1
ORDER BY u.full_name ASC
`
type ListUsersWithProfileByRoleRow struct {
UserID int64 `json:"user_id"`
UserEmail string `json:"user_email"`
UserRole UserRole `json:"user_role"`
UserFullName string `json:"user_full_name"`
UserIsActive bool `json:"user_is_active"`
UserCreatedAt pgtype.Timestamptz `json:"user_created_at"`
UserUpdatedAt pgtype.Timestamptz `json:"user_updated_at"`
ProfileUserID pgtype.Int8 `json:"profile_user_id"`
PreferredName pgtype.Text `json:"preferred_name"`
ProfileIconUrl pgtype.Text `json:"profile_icon_url"`
Headline pgtype.Text `json:"headline"`
Bio pgtype.Text `json:"bio"`
Timezone pgtype.Text `json:"timezone"`
Locale pgtype.Text `json:"locale"`
GradeLevel pgtype.Text `json:"grade_level"`
LearningGoal pgtype.Text `json:"learning_goal"`
ProfileCreatedAt pgtype.Timestamptz `json:"profile_created_at"`
ProfileUpdatedAt pgtype.Timestamptz `json:"profile_updated_at"`
}
func (q *Queries) ListUsersWithProfileByRole(ctx context.Context, role UserRole) ([]ListUsersWithProfileByRoleRow, error) {
rows, err := q.db.Query(ctx, listUsersWithProfileByRole, role)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListUsersWithProfileByRoleRow{}
for rows.Next() {
var i ListUsersWithProfileByRoleRow
if err := rows.Scan(
&i.UserID,
&i.UserEmail,
&i.UserRole,
&i.UserFullName,
&i.UserIsActive,
&i.UserCreatedAt,
&i.UserUpdatedAt,
&i.ProfileUserID,
&i.PreferredName,
&i.ProfileIconUrl,
&i.Headline,
&i.Bio,
&i.Timezone,
&i.Locale,
&i.GradeLevel,
&i.LearningGoal,
&i.ProfileCreatedAt,
&i.ProfileUpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateUserActiveStatus = `-- name: UpdateUserActiveStatus :one
UPDATE users
SET
is_active = $2,
updated_at = NOW()
WHERE id = $1
RETURNING id, email, password_hash, role, full_name, is_active, created_at, updated_at
`
type UpdateUserActiveStatusParams struct {
ID int64 `json:"id"`
IsActive bool `json:"is_active"`
}
func (q *Queries) UpdateUserActiveStatus(ctx context.Context, arg UpdateUserActiveStatusParams) (User, error) {
row := q.db.QueryRow(ctx, updateUserActiveStatus, arg.ID, arg.IsActive)
var i User
err := row.Scan(
&i.ID,
&i.Email,
&i.PasswordHash,
&i.Role,
&i.FullName,
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const updateUserFullName = `-- name: UpdateUserFullName :one
UPDATE users
SET
full_name = $2,
updated_at = NOW()
WHERE id = $1
RETURNING id, email, password_hash, role, full_name, is_active, created_at, updated_at
`
type UpdateUserFullNameParams struct {
ID int64 `json:"id"`
FullName string `json:"full_name"`
}
func (q *Queries) UpdateUserFullName(ctx context.Context, arg UpdateUserFullNameParams) (User, error) {
row := q.db.QueryRow(ctx, updateUserFullName, arg.ID, arg.FullName)
var i User
err := row.Scan(
&i.ID,
&i.Email,
&i.PasswordHash,
&i.Role,
&i.FullName,
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const upsertUserProfile = `-- name: UpsertUserProfile :one
INSERT INTO profiles (
user_id,
preferred_name,
profile_icon_url,
headline,
bio,
timezone,
locale,
grade_level,
learning_goal
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9
)
ON CONFLICT (user_id) DO UPDATE
SET
preferred_name = EXCLUDED.preferred_name,
profile_icon_url = EXCLUDED.profile_icon_url,
headline = EXCLUDED.headline,
bio = EXCLUDED.bio,
timezone = EXCLUDED.timezone,
locale = EXCLUDED.locale,
grade_level = EXCLUDED.grade_level,
learning_goal = EXCLUDED.learning_goal,
updated_at = NOW()
RETURNING user_id, preferred_name, profile_icon_url, headline, bio, timezone, locale, grade_level, learning_goal, created_at, updated_at
`
type UpsertUserProfileParams struct {
UserID int64 `json:"user_id"`
PreferredName pgtype.Text `json:"preferred_name"`
ProfileIconUrl pgtype.Text `json:"profile_icon_url"`
Headline pgtype.Text `json:"headline"`
Bio pgtype.Text `json:"bio"`
Timezone pgtype.Text `json:"timezone"`
Locale pgtype.Text `json:"locale"`
GradeLevel pgtype.Text `json:"grade_level"`
LearningGoal pgtype.Text `json:"learning_goal"`
}
func (q *Queries) UpsertUserProfile(ctx context.Context, arg UpsertUserProfileParams) (Profile, error) {
row := q.db.QueryRow(ctx, upsertUserProfile,
arg.UserID,
arg.PreferredName,
arg.ProfileIconUrl,
arg.Headline,
arg.Bio,
arg.Timezone,
arg.Locale,
arg.GradeLevel,
arg.LearningGoal,
)
var i Profile
err := row.Scan(
&i.UserID,
&i.PreferredName,
&i.ProfileIconUrl,
&i.Headline,
&i.Bio,
&i.Timezone,
&i.Locale,
&i.GradeLevel,
&i.LearningGoal,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}