From 35f8fafddcc1915a44d1d854c2322d9ba885aba3 Mon Sep 17 00:00:00 2001 From: Lucas dos Santos Abreu Date: Sat, 25 May 2024 09:55:55 -0300 Subject: [PATCH] chg: paginate with generics --- api/client.go | 141 +++++++++++++------------------------------------- 1 file changed, 35 insertions(+), 106 deletions(-) diff --git a/api/client.go b/api/client.go index a16a0fbb..dadfd457 100644 --- a/api/client.go +++ b/api/client.go @@ -6,7 +6,6 @@ import ( "fmt" "net/http" "net/url" - "reflect" "regexp" "strings" "time" @@ -347,27 +346,18 @@ func (c *client) WorkspaceUsers(p WorkspaceUsersParam) (users []dto.User, err er return users, err } - err = c.paginate( + users, err = paginate[dto.User]( + c, "GET", fmt.Sprintf("v1/workspaces/%s/users", p.Workspace), p.PaginationParam, dto.WorkspaceUsersRequest{ Email: p.Email, }, - &users, - func(res interface{}) (int, error) { - if res == nil { - return 0, nil - } - ls := *res.(*[]dto.User) - - users = append(users, ls...) - return len(ls), nil - }, "WorkspaceUsers", ) - return users, err + return } // PaginationParam parameters about pagination @@ -449,36 +439,15 @@ type GetUserTimeEntriesParam struct { // GetUserTimeEntries will list the time entries of a user on a workspace, can be paginated func (c *client) GetUserTimeEntries(p GetUserTimeEntriesParam) ([]dto.TimeEntryImpl, error) { - var timeEntries []dto.TimeEntryImpl var tes []dto.TimeEntryImpl + return getUserTimeEntriesImpl(c, p, false, &tes) - err := c.getUserTimeEntriesImpl(p, false, &tes, func(res interface{}) (int, error) { - if res == nil { - return 0, nil - } - - tes := res.(*[]dto.TimeEntryImpl) - timeEntries = append(timeEntries, *tes...) - return len(*tes), nil - }) - - return timeEntries, err } // GetUsersHydratedTimeEntries will list hydrated time entries of a user on a workspace, can be paginated func (c *client) GetUsersHydratedTimeEntries(p GetUserTimeEntriesParam) ([]dto.TimeEntry, error) { var timeEntries []dto.TimeEntry - var tes []dto.TimeEntry - - err := c.getUserTimeEntriesImpl(p, true, &tes, func(res interface{}) (int, error) { - if res == nil { - return 0, nil - } - - tes := res.(*[]dto.TimeEntry) - timeEntries = append(timeEntries, *tes...) - return len(*tes), nil - }) + timeEntries, err := getUserTimeEntriesImpl(c, p, true, &timeEntries) if err != nil { return timeEntries, err @@ -496,12 +465,12 @@ func (c *client) GetUsersHydratedTimeEntries(p GetUserTimeEntriesParam) ([]dto.T return timeEntries, err } -func (c *client) getUserTimeEntriesImpl( +func getUserTimeEntriesImpl[K dto.TimeEntry | dto.TimeEntryImpl]( + c *client, p GetUserTimeEntriesParam, hydrated bool, - tmpl interface{}, - reducer func(interface{}) (int, error), -) (err error) { + tmpl *[]K, +) (tes []K, err error) { defer wrapError(&err, "get time entries from user \"%s\"", p.UserID) ids := map[field]string{ @@ -510,11 +479,11 @@ func (c *client) getUserTimeEntriesImpl( } if err := required(ids); err != nil { - return err + return tes, err } if err := checkIDs(ids); err != nil { - return err + return tes, err } inProgressFilter := "nil" @@ -552,7 +521,8 @@ func (c *client) getUserTimeEntriesImpl( r.End = &dto.DateTime{Time: *p.End} } - err = c.paginate( + tes, err = paginate[K]( + c, "GET", fmt.Sprintf( "v1/workspaces/%s/user/%s/time-entries", @@ -561,22 +531,19 @@ func (c *client) getUserTimeEntriesImpl( ), p.PaginationParam, r, - tmpl, - reducer, "GetUserTimeEntries", ) - return err + return } -func (c *client) paginate( +func paginate[K any]( + c *client, method, uri string, p PaginationParam, request dto.PaginatedRequest, - bodyTempl interface{}, - reducer func(interface{}) (int, error), name string, -) error { +) ([]K, error) { page := p.Page if p.AllPages { page = 1 @@ -586,6 +553,7 @@ func (c *client) paginate( p.PageSize = 50 } + ls := make([]K, 0) stop := false for !stop { r, err := c.NewRequest( @@ -594,24 +562,24 @@ func (c *client) paginate( request.WithPagination(page, p.PageSize), ) if err != nil { - return err + return ls, err } - response := reflect.New(reflect.TypeOf(bodyTempl).Elem()).Interface() + var response []K _, err = c.Do(r, &response, name) if err != nil { - return err + return ls, err } - count, err := reducer(response) - if err != nil { - return err + count := len(response) + if count > 0 { + ls = append(ls, response...) } stop = count < p.PageSize || !p.AllPages page++ } - return nil + return ls, nil } // GetTimeEntryInProgressParam params to query entries @@ -878,8 +846,6 @@ type GetTasksParam struct { // GetTasks get tasks of a project func (c *client) GetTasks(p GetTasksParam) (ps []dto.Task, err error) { - var tmpl []dto.Task - defer wrapError(&err, "get tasks from project \"%s\"", p.ProjectID) ids := map[field]string{ @@ -895,7 +861,8 @@ func (c *client) GetTasks(p GetTasksParam) (ps []dto.Task, err error) { return ps, err } - err = c.paginate( + ps, err = paginate[dto.Task]( + c, "GET", fmt.Sprintf( "v1/workspaces/%s/projects/%s/tasks", @@ -907,16 +874,6 @@ func (c *client) GetTasks(p GetTasksParam) (ps []dto.Task, err error) { Name: p.Name, Active: p.Active, }, - &tmpl, - func(res interface{}) (int, error) { - if res == nil { - return 0, nil - } - ls := *res.(*[]dto.Task) - - ps = append(ps, ls...) - return len(ls), nil - }, "GetTasks", ) return ps, err @@ -1210,12 +1167,12 @@ type GetTagsParam struct { // GetTags get all tags of a workspace func (c *client) GetTags(p GetTagsParam) (ps []dto.Tag, err error) { defer wrapError(&err, "get tags") - var tmpl []dto.Tag if err = checkWorkspace(p.Workspace); err != nil { return ps, err } - err = c.paginate( + ps, err = paginate[dto.Tag]( + c, "GET", fmt.Sprintf( "v1/workspaces/%s/tags", @@ -1226,16 +1183,6 @@ func (c *client) GetTags(p GetTagsParam) (ps []dto.Tag, err error) { Name: p.Name, Archived: p.Archived, }, - &tmpl, - func(res interface{}) (int, error) { - if res == nil { - return 0, nil - } - ls := *res.(*[]dto.Tag) - - ps = append(ps, ls...) - return len(ls), nil - }, "GetTags", ) return ps, err @@ -1255,12 +1202,12 @@ func (c *client) GetClients(p GetClientsParam) ( clients []dto.Client, err error) { defer wrapError(&err, "get clients") - var tmpl []dto.Client if err = checkWorkspace(p.Workspace); err != nil { return clients, err } - err = c.paginate( + clients, err = paginate[dto.Client]( + c, "GET", fmt.Sprintf( "v1/workspaces/%s/clients", @@ -1271,19 +1218,11 @@ func (c *client) GetClients(p GetClientsParam) ( Name: p.Name, Archived: p.Archived, }, - &tmpl, - func(res interface{}) (int, error) { - if res == nil { - return 0, nil - } - ls := *res.(*[]dto.Client) - clients = append(clients, ls...) - return len(ls), nil - }, "GetClients", ) - return clients, err + + return } type AddClientParam struct { @@ -1342,12 +1281,12 @@ type GetProjectsParam struct { func (c *client) GetProjects(p GetProjectsParam) (ps []dto.Project, err error) { defer wrapError(&err, "get projects") - var tmpl []dto.Project if err = checkWorkspace(p.Workspace); err != nil { return ps, err } - err = c.paginate( + ps, err = paginate[dto.Project]( + c, "GET", fmt.Sprintf( "v1/workspaces/%s/projects", @@ -1360,16 +1299,6 @@ func (c *client) GetProjects(p GetProjectsParam) (ps []dto.Project, err error) { Clients: p.Clients, Hydrated: p.Hydrate, }, - &tmpl, - func(res interface{}) (int, error) { - if res == nil { - return 0, nil - } - ls := *res.(*[]dto.Project) - - ps = append(ps, ls...) - return len(ls), nil - }, "GetProjects", )