Yimaru-BackEnd/internal/repository/lms_personas.go
Yared Yemane 873be1b482 Add LMS personas catalog and CRUD API.
Introduce lms_personas table, repoint practice persona_id FKs off users, validate persona refs on LMS and exam-prep practice flows, personas.* RBAC permissions, and OpenAPI docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-20 06:06:42 -07:00

116 lines
2.9 KiB
Go

package repository
import (
"context"
"errors"
dbgen "Yimaru-Backend/gen/db"
"Yimaru-Backend/internal/domain"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
)
func lmsPersonaToDomain(p dbgen.LmsPersona) domain.LmsPersona {
out := domain.LmsPersona{
ID: p.ID,
Name: p.Name,
IsActive: p.IsActive,
}
out.Description = fromPgText(p.Description)
out.AvatarURL = fromPgText(p.AvatarUrl)
out.CreatedAt = p.CreatedAt.Time
if p.UpdatedAt.Valid {
t := p.UpdatedAt.Time
out.UpdatedAt = &t
}
return out
}
func optionalBoolUpdatePB(v *bool) pgtype.Bool {
if v == nil {
return pgtype.Bool{Valid: false}
}
return pgtype.Bool{Bool: *v, Valid: true}
}
func (s *Store) CreateLmsPersona(ctx context.Context, in domain.CreateLmsPersonaInput) (domain.LmsPersona, error) {
active := true
if in.IsActive != nil {
active = *in.IsActive
}
p, err := s.queries.CreateLmsPersona(ctx, dbgen.CreateLmsPersonaParams{
Name: in.Name,
Description: toPgText(in.Description),
AvatarUrl: toPgText(in.AvatarURL),
IsActive: active,
})
if err != nil {
return domain.LmsPersona{}, err
}
return lmsPersonaToDomain(p), nil
}
func (s *Store) GetLmsPersonaByID(ctx context.Context, id int64) (domain.LmsPersona, error) {
p, err := s.queries.GetLmsPersonaByID(ctx, id)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.LmsPersona{}, pgx.ErrNoRows
}
return domain.LmsPersona{}, err
}
return lmsPersonaToDomain(p), nil
}
func (s *Store) UpdateLmsPersona(ctx context.Context, id int64, in domain.UpdateLmsPersonaInput) (domain.LmsPersona, error) {
p, err := s.queries.UpdateLmsPersona(ctx, dbgen.UpdateLmsPersonaParams{
ID: id,
Name: optionalTextUpdate(in.Name),
Description: optionalTextUpdate(in.Description),
AvatarUrl: optionalTextUpdate(in.AvatarURL),
IsActive: optionalBoolUpdatePB(in.IsActive),
})
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.LmsPersona{}, pgx.ErrNoRows
}
return domain.LmsPersona{}, err
}
return lmsPersonaToDomain(p), nil
}
func (s *Store) DeleteLmsPersona(ctx context.Context, id int64) error {
return s.queries.DeleteLmsPersona(ctx, id)
}
func (s *Store) ListLmsPersonas(ctx context.Context, activeOnly bool, limit, offset int32) ([]domain.LmsPersona, int64, error) {
rows, err := s.queries.ListLmsPersonas(ctx, dbgen.ListLmsPersonasParams{
Limit: limit,
Offset: offset,
FilterActive: activeOnly,
})
if err != nil {
return nil, 0, err
}
if len(rows) == 0 {
return []domain.LmsPersona{}, 0, nil
}
var total int64
out := make([]domain.LmsPersona, 0, len(rows))
for i, r := range rows {
if i == 0 {
total = r.TotalCount
}
out = append(out, lmsPersonaToDomain(dbgen.LmsPersona{
ID: r.ID,
Name: r.Name,
Description: r.Description,
AvatarUrl: r.AvatarUrl,
IsActive: r.IsActive,
CreatedAt: r.CreatedAt,
UpdatedAt: r.UpdatedAt,
}))
}
return out, total, nil
}