diff --git a/internal/db/db.go b/internal/db/db.go index 756df1d..831654d 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -3,8 +3,11 @@ package db import ( "context" "fmt" + "net/http" + "strings" "time" + "github.com/H1K0/Kiraku/internal/models" "github.com/jackc/pgx/v5/pgxpool" ) @@ -44,3 +47,91 @@ func UserAuth(ctx context.Context, user_id string) (ok, editor bool) { } //#endregion Users + +//#region Persons + +func PersonsGet(ctx context.Context, user_id, filter, sort string, limit, offset int) (persons models.Persons, statusCode int, err error) { + if ok, _ := UserAuth(ctx, user_id); !ok { + err = fmt.Errorf("Unauthorized") + statusCode = http.StatusUnauthorized + return + } + queryGet := "SELECT id, name, coalesce(sort_name, '') FROM persons WHERE position($1 in lower(name))>0 OR position($1 in lower(sort_name))>0" + if sort != "" { + sort_options := strings.Split(sort, ",") + queryGet += " 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 "name": + case "sortName": + sort_field = "coalesce(sort_name, name)" + case "birthdate": + case "deathdate": + default: + err = fmt.Errorf("invalid sorting field: %q", sort_field) + statusCode = http.StatusBadRequest + return + } + if i > 0 { + queryGet += ", " + } + queryGet += fmt.Sprintf("%s %s NULLS LAST", sort_field, sort_order) + } + } + queryCount := queryGet + if limit >= 0 { + queryGet += fmt.Sprintf(" LIMIT %d", limit) + } + if offset > 0 { + queryGet += fmt.Sprintf(" OFFSET %d", offset) + } + filter = strings.ToLower(filter) + rows, err := connPool.Query(ctx, queryGet, filter) + if err != nil { + statusCode = http.StatusInternalServerError + return + } + count := 0 + for rows.Next() { + var person models.PersonBrief + err = rows.Scan(&person.ID, &person.Name, &person.SortName) + if err != nil { + err = fmt.Errorf("error while fetching persons: %w", err) + statusCode = http.StatusInternalServerError + return + } + persons.Persons = append(persons.Persons, person) + count++ + } + err = rows.Err() + if err != nil { + statusCode = http.StatusInternalServerError + return + } + persons.Pagination.Limit = limit + persons.Pagination.Offset = offset + persons.Pagination.Count = count + queryCount = fmt.Sprintf("SELECT count(*) FROM (%s) tmp", queryCount) + row := connPool.QueryRow(ctx, queryCount, filter) + err = row.Scan(&persons.Pagination.Total) + if err != nil { + statusCode = http.StatusInternalServerError + } else { + statusCode = http.StatusOK + } + return +} + +//#endregion Persons