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 }