From fe232533c367af5a764b249bc475e1c10b7419b0 Mon Sep 17 00:00:00 2001 From: valentinkolb Date: Wed, 13 Nov 2024 01:05:14 +0100 Subject: [PATCH] feat(analyticsApi): added better api for page counts --- analyticsApi/main.go | 108 ++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 37 deletions(-) diff --git a/analyticsApi/main.go b/analyticsApi/main.go index c1622ea..54d0e0f 100644 --- a/analyticsApi/main.go +++ b/analyticsApi/main.go @@ -14,44 +14,45 @@ import ( // initPageViewCount // -// This endpoint is used to retrieve page view counts for each unique path. +// This endpoint is used to retrieve paginated page view counts for each unique path. // It adds the following endpoint to the app: // GET /api/analytics/pageViewCount // -// The endpoint expects the following query parameters: +// Query parameters: // -// ?startDate=ISO 8601 formatted date (optional) -// ?page= -// ?perPage= -// ?sort= (default is ASC) +// ?startDate=ISO 8601 formatted date (optional) +// ?page= +// ?perPage= +// ?sort= (default is ASC) // -// - `startDate`: An optional start date in ISO 8601 format (e.g., "2024-11-12T15:04:05Z"). -// If provided, the global count reflects views from this date onward. -// If not provided, the global count includes all views. -// - `page`: Page number for pagination (default is 1). -// - `perPage`: Number of results per page for pagination (default is 10). -// - `sort`: Sorting order, either `ASC` or `DESC` for ascending or descending order. +// - `startDate`: Optional start date in ISO 8601 format (e.g., "2024-11-12T15:04:05Z"). +// - `page`: Page number for pagination (default is 1). +// - `perPage`: Number of results per page (default is 10). +// - `sort`: Sorting order, either `ASC` or `DESC` (default is ASC). // // Response format: -// [ // // { -// "id": , -// "data": "", -// "count": , -// "last_30_days_data": [ +// "page": , +// "perPage": , +// "totalItems": , +// "totalPages": , +// "items": [ // { -// "date": "YYYY-MM-DDTHH:MM:SSZ", -// "count": +// "id": , +// "path": "", +// "count": , +// "last_30_days_data": [ +// { +// "date": "YYYY-MM-DDTHH:MM:SSZ", +// "count": +// }, +// ... +// ] // }, // ... // ] -// }, -// ... -// -// ] -// -// `last_30_days_data` always provides daily counts for the most recent 30 days regardless of the `startDate` parameter. +// } func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) { e.Router.GET("/api/analytics/pageViewCount", func(c echo.Context) error { @@ -72,7 +73,7 @@ func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) { } } - // Get pagination and sorting parameters + // Pagination and sorting parameters page, _ := strconv.Atoi(c.QueryParam("page")) if page < 1 { page = 1 @@ -90,21 +91,45 @@ func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) { offset := (page - 1) * perPage - type PageViewData struct { - ID int `json:"id"` - Data string `json:"data"` - Count int `json:"count"` - Last30DaysData interface{} `json:"last_30_days_data"` + // Fetch total items for pagination + var totalItems int + err = app.Dao().DB(). + NewQuery(` + SELECT COUNT(DISTINCT path) as total + FROM analyticsPageViews + WHERE created >= {:startDate} + `). + Bind(dbx.Params{ + "startDate": startDate, + }). + Row(&totalItems) + + if err != nil { + return apis.NewApiError(500, "Failed to count total items", err) } - var result []PageViewData + totalPages := (totalItems + perPage - 1) / perPage // Calculate total pages - // Execute the query with nested JSON aggregation, pagination, and sorting + // Define the structure for items + type Last30DaysData struct { + Date string `json:"date"` + Count int `json:"count"` + } + + type Item struct { + ID int `json:"id"` + Path string `json:"path"` + Count int `json:"count"` + Last30DaysData []Last30DaysData `json:"last_30_days_data"` + } + + // Query paginated items + var items []Item err = app.Dao().DB(). NewQuery(` SELECT (ROW_NUMBER() OVER()) AS id, - view.path AS data, + view.path AS path, ( SELECT COUNT(id) FROM analyticsPageViews @@ -133,7 +158,7 @@ func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) { GROUP BY view.path ORDER BY - data ` + sort + ` + path ` + sort + ` LIMIT {:perPage} OFFSET {:offset} `). Bind(dbx.Params{ @@ -141,14 +166,23 @@ func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) { "perPage": perPage, "offset": offset, }). - All(&result) + All(&items) if err != nil { return apis.NewApiError(500, "Failed to query page view data", err) } + // Final response structure + response := map[string]interface{}{ + "page": page, + "perPage": perPage, + "totalItems": totalItems, + "totalPages": totalPages, + "items": items, + } + // Return the final JSON response - return c.JSON(200, result) + return c.JSON(200, response) }, apis.ActivityLogger(app)) }