From db213bd559f242e9f839331650adf47b3be745f2 Mon Sep 17 00:00:00 2001 From: Masahiko AMANO Date: Sat, 18 Jan 2025 20:29:09 +0300 Subject: [PATCH] init(db): add credits get functions --- internal/db/credits.go | 202 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 internal/db/credits.go diff --git a/internal/db/credits.go b/internal/db/credits.go new file mode 100644 index 0000000..037c921 --- /dev/null +++ b/internal/db/credits.go @@ -0,0 +1,202 @@ +package db + +import ( + "context" + "fmt" + "net/http" + "strings" + + "github.com/H1K0/Kiraku/internal/models" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +func CreditsGetByPerson(ctx context.Context, user_id, person_id, sort string) (credits []models.PersonCredit, statusCode int, err error) { + ok, _ := UserAuth(ctx, user_id) + if !ok { + err = fmt.Errorf("unauthorized") + statusCode = http.StatusUnauthorized + return + } + query := "SELECT t.id AS track_id, t.name AS track_name, t.duration AS track_duration, COALESCE(t.release_date::text, '') AS track_releaseDate, t.acquire_datetime AS track_acquireDatetime, r.id AS role_id, r.name AS role_name, COALESCE(c.alias, '') AS alias " + + "FROM credits c " + + "JOIN tracks t ON t.id=c.track_id " + + "JOIN roles r ON r.id=c.role_id " + + "WHERE c.person_id=$1" + if sort != "" { + sort_options := strings.Split(sort, ",") + query += " ORDER BY " + for i, sort_option := range sort_options { + sort_order := sort_option[:1] + sort_field := sort_option[1:] + switch sort_order { + case "+": + sort_order = "ASC" + case "-": + sort_order = "DESC" + default: + err = fmt.Errorf("invalid sorting order mark: %q", sort) + statusCode = http.StatusBadRequest + return + } + switch sort_field { + case "track.name": + fallthrough + case "track.releaseDate": + fallthrough + case "track.acquireDatetime": + fallthrough + case "track.duration": + fallthrough + case "role.name": + sort_field = strings.ReplaceAll(sort_field, ".", "_") + case "track.sortName": + sort_field = "COALESCE(t.sort_name, t.name)" + case "alias": + default: + err = fmt.Errorf("invalid sorting field: %q", sort_field) + statusCode = http.StatusBadRequest + return + } + if i > 0 { + query += ", " + } + query += fmt.Sprintf("%s %s NULLS LAST", sort_field, sort_order) + } + } + row := connPool.QueryRow(ctx, "SELECT 1 FROM persons WHERE id=$1", person_id) + err = row.Scan(nil) + if err != nil { + if err == pgx.ErrNoRows { + err = fmt.Errorf("not found") + statusCode = http.StatusNotFound + return + } + pgErr := err.(*pgconn.PgError) + if pgErr.Code == "22P02" { + err = fmt.Errorf("%s", pgErr.Message) + statusCode = http.StatusBadRequest + } else { + statusCode = http.StatusInternalServerError + } + return + } + rows, err := connPool.Query(ctx, query, person_id) + if err != nil { + statusCode = http.StatusInternalServerError + return + } + count := 0 + for rows.Next() { + var credit models.PersonCredit + err = rows.Scan( + &credit.Track.ID, &credit.Track.Name, &credit.Track.Duration, &credit.Track.ReleaseDate, &credit.Track.AcquireDatetime, + &credit.Role.ID, &credit.Role.Name, &credit.Alias, + ) + if err != nil { + statusCode = http.StatusInternalServerError + return + } + credits = append(credits, credit) + count++ + } + err = rows.Err() + if err != nil { + statusCode = http.StatusInternalServerError + return + } + statusCode = http.StatusOK + return +} + +func CreditsGetByTrack(ctx context.Context, user_id, track_id, sort string) (credits []models.TrackCredit, statusCode int, err error) { + ok, _ := UserAuth(ctx, user_id) + if !ok { + err = fmt.Errorf("unauthorized") + statusCode = http.StatusUnauthorized + return + } + query := "SELECT p.id AS person_id, p.name AS person_name, COALESCE(p.sort_name, '') AS person_sortName, r.id AS role_id, r.name AS role_name, COALESCE(c.alias, '') AS alias " + + "FROM credits c " + + "JOIN persons p ON p.id=c.person_id " + + "JOIN roles r ON r.id=c.role_id " + + "WHERE c.track_id=$1" + if sort != "" { + sort_options := strings.Split(sort, ",") + query += " ORDER BY " + for i, sort_option := range sort_options { + sort_order := sort_option[:1] + sort_field := sort_option[1:] + switch sort_order { + case "+": + sort_order = "ASC" + case "-": + sort_order = "DESC" + default: + err = fmt.Errorf("invalid sorting order mark: %q", sort) + statusCode = http.StatusBadRequest + return + } + switch sort_field { + case "person.name": + fallthrough + case "role.name": + sort_field = strings.ReplaceAll(sort_field, ".", "_") + case "person.sortName": + sort_field = "COALESCE(p.sort_name, p.name)" + case "alias": + default: + err = fmt.Errorf("invalid sorting field: %q", sort_field) + statusCode = http.StatusBadRequest + return + } + if i > 0 { + query += ", " + } + query += fmt.Sprintf("%s %s NULLS LAST", sort_field, sort_order) + } + } + row := connPool.QueryRow(ctx, "SELECT 1 FROM tracks WHERE id=$1", track_id) + err = row.Scan(nil) + if err != nil { + if err == pgx.ErrNoRows { + err = fmt.Errorf("not found") + statusCode = http.StatusNotFound + return + } + pgErr := err.(*pgconn.PgError) + if pgErr.Code == "22P02" { + err = fmt.Errorf("%s", pgErr.Message) + statusCode = http.StatusBadRequest + } else { + statusCode = http.StatusInternalServerError + } + return + } + rows, err := connPool.Query(ctx, query, track_id) + if err != nil { + statusCode = http.StatusInternalServerError + return + } + count := 0 + for rows.Next() { + var credit models.TrackCredit + err = rows.Scan( + &credit.Person.ID, &credit.Person.Name, &credit.Person.SortName, + &credit.Role.ID, &credit.Role.Name, &credit.Alias, + ) + if err != nil { + statusCode = http.StatusInternalServerError + return + } + credits = append(credits, credit) + count++ + } + err = rows.Err() + if err != nil { + statusCode = http.StatusInternalServerError + return + } + statusCode = http.StatusOK + return +}