From 8b417dc623a15029ff38bbf029adf324c5f05237 Mon Sep 17 00:00:00 2001 From: Masahiko AMANO Date: Tue, 7 Jan 2025 04:04:06 +0300 Subject: [PATCH] perf(web): add pagination and remove getting total quotes count --- web/api/handlers.go | 11 ---------- web/api/routes.go | 1 - web/db/db.go | 41 +++++++++++++++++++++--------------- web/models/models.go | 12 +++++++++++ web/static/js/quotes.js | 46 ++++++++++++++--------------------------- 5 files changed, 51 insertions(+), 60 deletions(-) diff --git a/web/api/handlers.go b/web/api/handlers.go index b45ce98..9cfa814 100644 --- a/web/api/handlers.go +++ b/web/api/handlers.go @@ -162,17 +162,6 @@ func quotesGet(c *gin.Context) { c.JSON(http.StatusOK, quotes) } -func quotesCount(c *gin.Context) { - user_id := c.GetString("user_id") - count, err := db.QuotesCount(context.Background(), user_id) - if err != nil { - status, message := handleDBError(err) - c.JSON(status, gin.H{"error": message}) - return - } - c.JSON(http.StatusOK, gin.H{"count": count}) -} - func quoteGet(c *gin.Context) { user_id := c.GetString("user_id") quote_id := c.Param("id") diff --git a/web/api/routes.go b/web/api/routes.go index fde2ef2..19bac28 100644 --- a/web/api/routes.go +++ b/web/api/routes.go @@ -26,7 +26,6 @@ func RegisterRoutes(r *gin.Engine) { api.DELETE("/auth", userLogout) api.GET("/quotes", MiddlewareAuth, quotesGet) - api.GET("/quotes/count", MiddlewareAuth, quotesCount) api.POST("/quotes", MiddlewareAuth, quoteAdd) api.GET("/quotes/:id", MiddlewareAuth, quoteGet) api.PATCH("/quotes/:id", MiddlewareAuth, quoteUpdate) diff --git a/web/db/db.go b/web/db/db.go index fb45cf2..a9e6ca5 100644 --- a/web/db/db.go +++ b/web/db/db.go @@ -72,13 +72,13 @@ func UserUpdatePassword(ctx context.Context, user_id string, new_password string //#region Quotes -func QuotesGet(ctx context.Context, user_id string, filter string, sort string, limit int, offset int) (quotes []models.Quote, err error) { - query := "SELECT * FROM quotes_get($1) WHERE position($2 in lower(text))>0 OR position($2 in lower(author))>0" +func QuotesGet(ctx context.Context, user_id string, filter string, sort string, limit int, offset int) (quotes models.Quotes, err error) { + queryGet := "SELECT * FROM quotes_get($1) WHERE position($2 in lower(text))>0 OR position($2 in lower(author))>0" if sort == "random" { - query += " ORDER BY random()" + queryGet += " ORDER BY random()" } else if sort != "" { sort_options := strings.Split(sort, ",") - query += " ORDER BY " + queryGet += " ORDER BY " for i, sort_option := range sort_options { sort_order := sort_option[:1] sort_field := sort_option[1:] @@ -105,23 +105,26 @@ func QuotesGet(ctx context.Context, user_id string, filter string, sort string, return } if i > 0 { - query += ", " + queryGet += ", " } - query += fmt.Sprintf("%s %s", sort_field, sort_order) + queryGet += fmt.Sprintf("%s %s", sort_field, sort_order) } } + queryCount := queryGet if limit >= 0 { - query += fmt.Sprintf(" LIMIT %d", limit) + queryGet += fmt.Sprintf(" LIMIT %d", limit) } if offset > 0 { - query += fmt.Sprintf(" OFFSET %d", offset) + queryGet += fmt.Sprintf(" OFFSET %d", offset) } - rows, err := ConnPool.Query(ctx, query, user_id, strings.ToLower(filter)) + filter = strings.ToLower(filter) + rows, err := ConnPool.Query(ctx, queryGet, user_id, filter) if err != nil { err = fmt.Errorf("error while getting quotes: %w", err) return } - quotes = []models.Quote{} + quotes.Quotes = []models.Quote{} + count := 0 for rows.Next() { var quote models.Quote err = rows.Scan("e.ID, "e.Text, "e.Author, "e.Datetime, "e.Creator.ID, "e.Creator.Name, "e.Creator.Login, "e.Creator.Role, "e.Creator.TelegramID) @@ -129,15 +132,19 @@ func QuotesGet(ctx context.Context, user_id string, filter string, sort string, err = fmt.Errorf("error while fetching quotes: %w", err) return } - quotes = append(quotes, quote) + quotes.Quotes = append(quotes.Quotes, quote) + count++ } err = rows.Err() - return -} - -func QuotesCount(ctx context.Context, user_id string) (count int, err error) { - row := ConnPool.QueryRow(ctx, "SELECT count(*) FROM quotes_get($1)", user_id) - err = row.Scan(&count) + if err != nil { + return + } + quotes.Pagination.Limit = limit + quotes.Pagination.Offset = offset + quotes.Pagination.Count = count + queryCount = fmt.Sprintf("SELECT count(*) FROM (%s) q", queryCount) + row := ConnPool.QueryRow(ctx, queryCount, user_id, filter) + err = row.Scan("es.Pagination.TotalCount) return } diff --git a/web/models/models.go b/web/models/models.go index 7026261..eea3dca 100644 --- a/web/models/models.go +++ b/web/models/models.go @@ -27,3 +27,15 @@ type Quote struct { Datetime time.Time `json:"datetime"` Creator User `json:"creator"` } + +type Pagination struct { + TotalCount int `json:"totalCount"` + Offset int `json:"offset"` + Limit int `json:"limit"` + Count int `json:"count"` +} + +type Quotes struct { + Pagination Pagination `json:"pagination"` + Quotes []Quote `json:"quotes"` +} diff --git a/web/static/js/quotes.js b/web/static/js/quotes.js index 57b3fae..369c58d 100644 --- a/web/static/js/quotes.js +++ b/web/static/js/quotes.js @@ -45,28 +45,33 @@ function renderBlockQuote(quote) { function load() { var quotesCount; - failed = false; + $("#input-search").val(search); + $("#input-sorting").val(sorting); + container = $("#block-quotes"); $.ajax({ async: false, - url: "/api/quotes/count", + url: `/api/quotes?filter=${encodeURIComponent(search)}&sort=${encodeURIComponent(sorting)}&limit=${PAGE_SIZE}&offset=${(currPage - 1)*PAGE_SIZE}`, type: "GET", dataType: "json", success: function (resp) { - quotesCount = resp.count; + quotesCount = resp.pagination.totalCount + if (resp.pagination.count == 0) { + container.html("

Чёт нету ничего...

"); + return; + } + resp.quotes.forEach((quote) => { + container.append(renderBlockQuote(quote)); + }); }, error: function (err) { $("#error-message").text(err.responseJSON.error); $("#error").removeClass("hidden"); - failed = true; + }, + complete: function () { $("#block-quotes-loader").addClass("hidden"); }, }); - if (failed) { - return; - } totalPages = Math.ceil(quotesCount / PAGE_SIZE); - $("#input-search").val(search); - $("#input-sorting").val(sorting); $("#btn-page-curr").text(currPage); if (currPage > 1) { $("#btn-page-first").removeClass("hidden"); @@ -89,28 +94,6 @@ function load() { } } } - container = $("#block-quotes"); - $.ajax({ - url: `/api/quotes?filter=${encodeURIComponent(search)}&sort=${encodeURIComponent(sorting)}&limit=${PAGE_SIZE}&offset=${(currPage - 1)*PAGE_SIZE}`, - type: "GET", - dataType: "json", - success: function (resp) { - if (resp.length == 0) { - container.html("

Чёт нету ничего...

"); - return; - } - resp.forEach((quote) => { - container.append(renderBlockQuote(quote)); - }); - }, - error: function (err) { - $("#error-message").text(err.responseJSON.error); - $("#error").removeClass("hidden"); - }, - complete: function () { - $("#block-quotes-loader").addClass("hidden"); - }, - }); } function reload() { @@ -122,6 +105,7 @@ function reload() { $("#btn-page-first").addClass("hidden"); $("#pages-prev").addClass("hidden"); $("#btn-page-prev").addClass("hidden"); + $("#btn-page-curr").text(1); $("#btn-page-next").addClass("hidden"); $("#pages-next").addClass("hidden"); $("#btn-page-last").addClass("hidden");