go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/kana-server/pkg/model/manager.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package model 9 10 import ( 11 "context" 12 "fmt" 13 14 "go.charczuk.com/sdk/db" 15 "go.charczuk.com/sdk/db/dbutil" 16 "go.charczuk.com/sdk/uuid" 17 18 "go.charczuk.com/projects/kana-server/pkg/types" 19 ) 20 21 var ( 22 quizCols = db.TypeMetaFor(types.Quiz{}) 23 quizTableName = types.Quiz{}.TableName() 24 quizResultCols = db.TypeMetaFor(types.QuizResult{}) 25 quizResultTableName = types.QuizResult{}.TableName() 26 27 getQuizzesForUserQuery = fmt.Sprintf("SELECT %s FROM %s WHERE user_id = $1 ORDER BY created_utc desc", db.ColumnNamesCSV(quizCols.Columns()), quizTableName) 28 getQuizResultsForUserQuery = fmt.Sprintf("SELECT %s FROM %s WHERE user_id = $1 ORDER BY created_utc desc", db.ColumnNamesCSV(quizResultCols.Columns()), quizResultTableName) 29 getQuizResultsForQuizQuery = fmt.Sprintf("SELECT %s FROM %s WHERE quiz_id = $1 ORDER BY created_utc desc", db.ColumnNamesCSV(quizResultCols.Columns()), quizResultTableName) 30 ) 31 32 // New returns a new model manager. 33 func New(conn *db.Connection, opts ...db.InvocationOption) *Manager { 34 return &Manager{ 35 BaseManager: dbutil.NewBaseManager(conn, opts...), 36 } 37 } 38 39 // Manager implements database functions. 40 type Manager struct { 41 dbutil.BaseManager 42 } 43 44 // AllQuzzes returns all the quizzes. 45 func (m Manager) AllQuzzes(ctx context.Context, userID uuid.UUID) (output []*types.Quiz, err error) { 46 lookup := map[string]*types.Quiz{} 47 err = m.Invoke(ctx, db.OptLabel("all_quizzes")).Query(getQuizzesForUserQuery, userID).Each(func(r db.Rows) error { 48 var q types.Quiz 49 if populateErr := db.PopulateInOrder(&q, r, quizCols.Columns()); populateErr != nil { 50 return populateErr 51 } 52 output = append(output, &q) 53 lookup[q.ID.String()] = &q 54 return nil 55 }) 56 if err != nil { 57 return 58 } 59 err = m.Invoke(ctx, db.OptLabel("all_quizzes_results")).Query(getQuizResultsForUserQuery, userID).Each(func(r db.Rows) error { 60 var qr types.QuizResult 61 if populateErr := db.PopulateInOrder(&qr, r, quizResultCols.Columns()); populateErr != nil { 62 return populateErr 63 } 64 if quiz, ok := lookup[qr.QuizID.String()]; ok { 65 quiz.Results = append(quiz.Results, qr) 66 } else { 67 return fmt.Errorf("quiz for quiz result not found: %s", qr.QuizID.String()) 68 } 69 return nil 70 }) 71 return 72 } 73 74 // AllQuizResults returns all the quiz results for a given user. 75 func (m Manager) AllQuizResults(ctx context.Context, userID uuid.UUID) (output []types.QuizResult, err error) { 76 err = m.Invoke(ctx, db.OptLabel("all_quiz_results")).Query(getQuizResultsForUserQuery, userID).OutMany(&output) 77 return 78 } 79 80 // CreateQuiz creates a quiz. 81 func (m Manager) CreateQuiz(ctx context.Context, q types.Quiz) error { 82 return m.Invoke(ctx).Create(&q) 83 } 84 85 // GetQuiz gets a quiz and associated results. 86 func (m Manager) GetQuiz(ctx context.Context, id uuid.UUID) (output types.Quiz, found bool, err error) { 87 found, err = m.Invoke(ctx).Get(&output, id) 88 if err != nil || !found { 89 return 90 } 91 err = m.Invoke(ctx, db.OptLabel("get_quiz_results_for_quiz")).Query(getQuizResultsForQuizQuery, id).Each(func(r db.Rows) error { 92 var qr types.QuizResult 93 if populateErr := db.PopulateInOrder(&qr, r, quizResultCols.Columns()); populateErr != nil { 94 return populateErr 95 } 96 output.Results = append(output.Results, qr) 97 return nil 98 }) 99 return 100 } 101 102 // UpdateQuiz updates a quiz. 103 func (m Manager) UpdateQuiz(ctx context.Context, q types.Quiz) error { 104 _, err := m.Invoke(ctx).Update(&q) 105 return err 106 } 107 108 // AddQuizResult creates a new quiz result. 109 func (m Manager) AddQuizResult(ctx context.Context, qr types.QuizResult) error { 110 return m.Invoke(ctx).Create(&qr) 111 }