From d1fba6a44e2b5ed42effc5c2565f77a961f3e44f Mon Sep 17 00:00:00 2001 From: Tommy McNeely Date: Sun, 1 Nov 2020 16:41:49 -0700 Subject: [PATCH 1/4] Use type.setClient(c) for consistency and ... There are several Type(s) that have sub-types, and it was inconsistent. The goal here is to use type.setClient(c) every time, and if there are sub-types, loop through them and use their subType.setClient(c). Additionally, when possible, set the parent object. (i.e.) Board <-> List <-> Card <-> CheckList <-> CheckItem Used the `_, item` for range, as the code is much cleaner. (and maybe easier to understand). Also, minor "lint" change on board_test.go --- action.go | 6 ++++++ attachment.go | 7 +++++++ board.go | 27 ++++++++++++++++----------- board_test.go | 4 ++-- card.go | 45 +++++++++++++++++++++++++++++++++++++-------- checklist.go | 36 ++++++++++++++++++++++++++++-------- checklist_test.go | 4 ++-- label.go | 7 +++++++ list.go | 26 ++++++++++++++++---------- member.go | 19 ++++++++++++------- notification.go | 9 +++++++-- organization.go | 7 ++++++- search.go | 7 +++++-- webhook.go | 11 ++++++++--- 14 files changed, 159 insertions(+), 56 deletions(-) diff --git a/action.go b/action.go index 39ff2aa..63e3cf6 100644 --- a/action.go +++ b/action.go @@ -14,6 +14,7 @@ import ( // Actions are immutable event traces generated whenever an action occurs in Trello. // See https://developers.trello.com/reference/#actions. type Action struct { + client *Client ID string `json:"id"` IDMemberCreator string `json:"idMemberCreator"` Type string `json:"type"` @@ -194,3 +195,8 @@ func ListAfterAction(a *Action) *List { } return nil } + +// setClient on Action for interface consistency +func (a *Action) setClient(client *Client) { + a.client = client +} diff --git a/attachment.go b/attachment.go index 62a68d6..a4ff55f 100644 --- a/attachment.go +++ b/attachment.go @@ -8,6 +8,8 @@ package trello // Attachment represent the attachments of cards. This is a nested resource of Card. // https://developers.trello.com/reference/#attachments type Attachment struct { + client *Client + Card *Card ID string `json:"id"` Name string `json:"name"` Pos float32 `json:"pos"` @@ -30,3 +32,8 @@ type AttachmentPreview struct { Bytes int `json:"bytes"` Scaled bool `json:"scaled"` } + +// setClient on Attachment for interface consistency +func (a *Attachment) setClient(client *Client) { + a.client = client +} diff --git a/board.go b/board.go index 0e0a2d6..295eec1 100644 --- a/board.go +++ b/board.go @@ -124,7 +124,7 @@ func (c *Client) CreateBoard(board *Board, extraArgs ...Arguments) error { err := c.Post(path, args, &board) if err == nil { - board.client = c + board.setClient(c) } return err } @@ -170,7 +170,7 @@ func (c *Client) GetBoard(boardID string, extraArgs ...Arguments) (board *Board, path := fmt.Sprintf("boards/%s", boardID) err = c.Get(path, args, &board) if board != nil { - board.client = c + board.setClient(c) } return } @@ -180,8 +180,8 @@ func (c *Client) GetMyBoards(extraArgs ...Arguments) (boards []*Board, err error args := flattenArguments(extraArgs) path := "members/me/boards" err = c.Get(path, args, &boards) - for i := range boards { - boards[i].client = c + for _, board := range boards { + board.setClient(c) } return } @@ -191,12 +191,8 @@ func (m *Member) GetBoards(extraArgs ...Arguments) (boards []*Board, err error) args := flattenArguments(extraArgs) path := fmt.Sprintf("members/%s/boards", m.ID) err = m.client.Get(path, args, &boards) - for i := range boards { - boards[i].client = m.client - - for j := range boards[i].Lists { - boards[i].Lists[j].client = m.client - } + for _, board := range boards { + board.setClient(m.client) } return } @@ -237,7 +233,16 @@ func (c *Client) PutBoard(board *Board, extraArgs ...Arguments) error { err := c.Put(path, args, &board) if err == nil { - board.client = c + board.setClient(c) } return err } + +// setclient on board and any sub-objects +func (b *Board) setClient(client *Client) { + b.client = client + for _, list := range b.Lists { + list.setClient(client) + list.Board = b // Set Parent + } +} diff --git a/board_test.go b/board_test.go index 02a8679..816ef55 100644 --- a/board_test.go +++ b/board_test.go @@ -165,13 +165,13 @@ func testBoard(t *testing.T) *Board { func TestBoardUpdate(t *testing.T) { expected := map[string]map[string]string{ - "created": map[string]string{ + "created": { "id": "5d2ccd3015468d3df508f10d", "name": "test-board-for-update", "description": "Some description", "cardAging": "regular", }, - "updated": map[string]string{ + "updated": { "id": "5d2ccd3015468d3df508f10d", "name": "test-board-for-update plus", "description": "Some other description", diff --git a/card.go b/card.go index a61b298..16de465 100644 --- a/card.go +++ b/card.go @@ -237,7 +237,7 @@ func (c *Client) CreateCard(card *Card, extraArgs ...Arguments) error { args.flatten(extraArgs) err := c.Post(path, args, &card) if err == nil { - card.client = c + card.setClient(c) } return err } @@ -259,7 +259,8 @@ func (l *List) AddCard(card *Card, extraArgs ...Arguments) error { err := l.client.Post(path, args, &card) if err == nil { - card.client = l.client + card.setClient(l.client) + card.List = l } else { err = errors.Wrapf(err, "Error adding card to list %s", l.ID) } @@ -282,7 +283,8 @@ func (c *Card) CopyToList(listID string, extraArgs ...Arguments) (*Card, error) args.flatten(extraArgs) err := c.client.Post(path, args, &newCard) if err == nil { - newCard.client = c.client + newCard.setClient(c.client) + //newCard.List = } else { err = errors.Wrapf(err, "Error copying card '%s' to list '%s'.", c.ID, listID) } @@ -460,7 +462,8 @@ func (c *Client) GetCard(cardID string, extraArgs ...Arguments) (card *Card, err path := fmt.Sprintf("cards/%s", cardID) err = c.Get(path, args, &card) if card != nil { - card.client = c + card.setClient(c) + //card.List = getListById(card.IDList)? // Set Parent } return card, err } @@ -488,8 +491,9 @@ func (b *Board) GetCards(extraArgs ...Arguments) (cards []*Card, err error) { } } - for i := range cards { - cards[i].client = b.client + for _, card := range cards { + card.setClient(b.client) + //card.List = getListById(card.IDList)? // Set Parent } return @@ -500,8 +504,9 @@ func (l *List) GetCards(extraArgs ...Arguments) (cards []*Card, err error) { args := flattenArguments(extraArgs) path := fmt.Sprintf("lists/%s/cards", l.ID) err = l.client.Get(path, args, &cards) - for i := range cards { - cards[i].client = l.client + for _, card := range cards { + card.setClient(l.client) + card.List = l // Set Parent } return } @@ -518,3 +523,27 @@ func earliestCardID(cards []*Card) string { } return earliest } + +// setClient on card and sub-objects +func (c *Card) setClient(client *Client) { + c.client = client + for _, action := range c.Actions { + action.setClient(client) + } + for _, attachment := range c.Attachments { + attachment.setClient(client) + attachment.Card = c // Set Parent + } + for _, checklist := range c.Checklists { + checklist.setClient(client) + checklist.Card = c // Set Parent + } + for _, label := range c.Labels { + label.setClient(client) + label.Board = c.Board // Set Parent + } + for _, member := range c.Members { + member.setClient(client) + } + +} diff --git a/checklist.go b/checklist.go index 1fbc0cc..cf6652b 100644 --- a/checklist.go +++ b/checklist.go @@ -11,17 +11,20 @@ import "fmt" // A card can have one zero or more checklists. // https://developers.trello.com/reference/#checklist-object type Checklist struct { - ID string `json:"id"` - Name string `json:"name"` - IDBoard string `json:"idBoard,omitempty"` - IDCard string `json:"idCard,omitempty"` - Pos float64 `json:"pos,omitempty"` - CheckItems []CheckItem `json:"checkItems,omitempty"` client *Client + Card *Card + ID string `json:"id"` + Name string `json:"name"` + IDBoard string `json:"idBoard,omitempty"` + IDCard string `json:"idCard,omitempty"` + Pos float64 `json:"pos,omitempty"` + CheckItems []*CheckItem `json:"checkItems,omitempty"` } // CheckItem is a nested resource representing an item in Checklist. type CheckItem struct { + client *Client + Checklist *Checklist ID string `json:"id"` Name string `json:"name"` State string `json:"state"` @@ -52,7 +55,8 @@ func (c *Client) CreateChecklist(card *Card, name string, extraArgs ...Arguments checklist = &Checklist{} err = c.Post(path, args, &checklist) if err == nil { - checklist.client = c + checklist.setClient(c) + checklist.Card = card checklist.IDCard = card.ID card.Checklists = append(card.Checklists, checklist) } @@ -87,7 +91,9 @@ func (c *Client) CreateCheckItem(checklist *Checklist, name string, extraArgs .. item = &CheckItem{} err = c.Post(path, args, item) if err == nil { - checklist.CheckItems = append(checklist.CheckItems, *item) + checklist.CheckItems = append(checklist.CheckItems, item) + item.setClient(c) + item.Checklist = checklist } return } @@ -103,3 +109,17 @@ func (c *Client) GetChecklist(checklistID string, args Arguments) (checklist *Ch } return checklist, err } + +// setClient on checkList and sub-objects +func (cl *Checklist) setClient(client *Client) { + cl.client = client + for _, checkitem := range cl.CheckItems { + checkitem.setClient(client) + checkitem.Checklist = cl // Set Parent + } +} + +// setClient on checkItem (for interface consistency) +func (ci *CheckItem) setClient(client *Client) { + ci.client = client +} diff --git a/checklist_test.go b/checklist_test.go index 160c5a0..4faebac 100644 --- a/checklist_test.go +++ b/checklist_test.go @@ -81,8 +81,8 @@ func TestCreateCheckItem(t *testing.T) { t.Errorf("Expected checklist to pick up the created checkitem. Instead got '%v'.", len(cl.CheckItems)) } - if cl.CheckItems[0] != *item { - t.Errorf("Expected the returned item and the checkitem inside the checklist to be equal.\n got: %#v\nwant: %#v", cl.CheckItems[0], *item) + if cl.CheckItems[0] != item { + t.Errorf("Expected the returned item and the checkitem inside the checklist to be equal.\n got: %#v\nwant: %#v", cl.CheckItems[0], item) } if item.Pos != 35 { t.Errorf("Expected the returned item to pick up a position. Instead got '%v'.", item.Pos) diff --git a/label.go b/label.go index d413ab8..b67c400 100644 --- a/label.go +++ b/label.go @@ -11,6 +11,8 @@ import "fmt" // Labels are defined per board, and can be applied to the cards on that board. // https://developers.trello.com/reference/#label-object type Label struct { + client *Client + Board *Board ID string `json:"id"` IDBoard string `json:"idBoard"` Name string `json:"name"` @@ -34,3 +36,8 @@ func (b *Board) GetLabels(extraArgs ...Arguments) (labels []*Label, err error) { err = b.client.Get(path, args, &labels) return } + +// setClient on Label (for interface consistency) +func (l *Label) setClient(client *Client) { + l.client = client +} diff --git a/list.go b/list.go index 83aadc4..1bc02eb 100644 --- a/list.go +++ b/list.go @@ -36,10 +36,8 @@ func (c *Client) GetList(listID string, extraArgs ...Arguments) (list *List, err path := fmt.Sprintf("lists/%s", listID) err = c.Get(path, args, &list) if list != nil { - list.client = c - for i := range list.Cards { - list.Cards[i].client = c - } + list.setClient(c) + // list.Board, err = c.GetBoard(list.IDBoard, Defaults()) // Set Parent } return } @@ -49,11 +47,9 @@ func (b *Board) GetLists(extraArgs ...Arguments) (lists []*List, err error) { args := flattenArguments(extraArgs) path := fmt.Sprintf("boards/%s/lists", b.ID) err = b.client.Get(path, args, &lists) - for i := range lists { - lists[i].client = b.client - for j := range lists[i].Cards { - lists[i].Cards[j].client = b.client - } + for _, list := range lists { + list.setClient(b.client) + list.Board = b // Set Parent } return } @@ -76,7 +72,8 @@ func (c *Client) CreateList(onBoard *Board, name string, extraArgs ...Arguments) list = &List{} err = c.Post(path, args, &list) if err == nil { - list.client = c + list.setClient(c) + list.Board = onBoard } return } @@ -98,3 +95,12 @@ func (l *List) Update(extraArgs ...Arguments) error { path := fmt.Sprintf("lists/%s", l.ID) return l.client.Put(path, args, l) } + +// setClient on List and sub-objects +func (l *List) setClient(client *Client) { + l.client = client + for _, card := range l.Cards { + card.setClient(client) + card.List = l // Set Parent + } +} diff --git a/member.go b/member.go index 57e40ef..e696fdf 100644 --- a/member.go +++ b/member.go @@ -29,7 +29,7 @@ func (c *Client) GetMember(memberID string, extraArgs ...Arguments) (member *Mem path := fmt.Sprintf("members/%s", memberID) err = c.Get(path, args, &member) if err == nil { - member.client = c + member.setClient(c) } return } @@ -49,8 +49,8 @@ func (o *Organization) GetMembers(extraArgs ...Arguments) (members []*Member, er args := flattenArguments(extraArgs) path := fmt.Sprintf("organizations/%s/members", o.ID) err = o.client.Get(path, args, &members) - for i := range members { - members[i].client = o.client + for _, member := range members { + member.setClient(o.client) } return } @@ -60,8 +60,8 @@ func (b *Board) GetMembers(extraArgs ...Arguments) (members []*Member, err error args := flattenArguments(extraArgs) path := fmt.Sprintf("boards/%s/members", b.ID) err = b.client.Get(path, args, &members) - for i := range members { - members[i].client = b.client + for _, member := range members { + member.setClient(b.client) } return } @@ -71,8 +71,13 @@ func (c *Card) GetMembers(extraArgs ...Arguments) (members []*Member, err error) args := flattenArguments(extraArgs) path := fmt.Sprintf("cards/%s/members", c.ID) err = c.client.Get(path, args, &members) - for i := range members { - members[i].client = c.client + for _, member := range members { + member.setClient(c.client) } return } + +//setClient on member (for interface consistency) +func (m *Member) setClient(client *Client) { + m.client = client +} diff --git a/notification.go b/notification.go index 641583d..b3971c7 100644 --- a/notification.go +++ b/notification.go @@ -47,8 +47,13 @@ func (c *Client) GetMyNotifications(extraArgs ...Arguments) (notifications []*No args := flattenArguments(extraArgs) path := "members/me/notifications" err = c.Get(path, args, ¬ifications) - for i := range notifications { - notifications[i].client = c + for _, notification := range notifications { + notification.setClient(c) } return } + +// setClient on Notification for interface consistency +func (n *Notification) setClient(client *Client) { + n.client = client +} diff --git a/organization.go b/organization.go index 12669a9..1029f57 100644 --- a/organization.go +++ b/organization.go @@ -30,7 +30,12 @@ func (c *Client) GetOrganization(orgID string, extraArgs ...Arguments) (organiza path := fmt.Sprintf("organizations/%s", orgID) err = c.Get(path, args, &organization) if organization != nil { - organization.client = c + organization.setClient(c) } return } + +// setClient on Organization for interface consistency +func (o *Organization) setClient(client *Client) { + o.client = client +} diff --git a/search.go b/search.go index bc98a03..01690a6 100644 --- a/search.go +++ b/search.go @@ -45,7 +45,7 @@ func (c *Client) SearchCards(query string, extraArgs ...Arguments) (cards []*Car err = c.Get("search", args, &res) cards = res.Cards for _, card := range cards { - card.client = c + card.setClient(c) } return } @@ -61,7 +61,7 @@ func (c *Client) SearchBoards(query string, extraArgs ...Arguments) (boards []*B err = c.Get("search", args, &res) boards = res.Boards for _, board := range boards { - board.client = c + board.setClient(c) } return } @@ -73,5 +73,8 @@ func (c *Client) SearchMembers(query string, extraArgs ...Arguments) (members [] } args.flatten(extraArgs) err = c.Get("search/members", args, &members) + for _, member := range members { + member.setClient(c) + } return } diff --git a/webhook.go b/webhook.go index 182a670..2664276 100644 --- a/webhook.go +++ b/webhook.go @@ -56,7 +56,7 @@ func (c *Client) CreateWebhook(webhook *Webhook) error { args := Arguments{"idModel": webhook.IDModel, "description": webhook.Description, "callbackURL": webhook.CallbackURL} err := c.Post(path, args, webhook) if err == nil { - webhook.client = c + webhook.setClient(c) } return err } @@ -73,7 +73,7 @@ func (c *Client) GetWebhook(webhookID string, extraArgs ...Arguments) (webhook * path := fmt.Sprintf("webhooks/%s", webhookID) err = c.Get(path, args, &webhook) if webhook != nil { - webhook.client = c + webhook.setClient(c) } return } @@ -85,7 +85,7 @@ func (t *Token) GetWebhooks(extraArgs ...Arguments) (webhooks []*Webhook, err er err = t.client.Get(path, args, &webhooks) if err == nil { for _, webhook := range webhooks { - webhook.client = t.client + webhook.setClient(t.client) } } return @@ -129,3 +129,8 @@ func GetCardWebhookRequest(r *http.Request) (whr *CardWebhookRequest, err error) } return } + +// setClient on Organization for interface consistency +func (w *Webhook) setClient(client *Client) { + w.client = client +} From ee122a19c2c0dc712bed776a1e24137c617245f3 Mon Sep 17 00:00:00 2001 From: Tommy McNeely Date: Mon, 2 Nov 2020 10:29:52 -0700 Subject: [PATCH 2/4] fix: Card.setClient should set List and Board --- card.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/card.go b/card.go index 16de465..62fed2f 100644 --- a/card.go +++ b/card.go @@ -284,7 +284,6 @@ func (c *Card) CopyToList(listID string, extraArgs ...Arguments) (*Card, error) err := c.client.Post(path, args, &newCard) if err == nil { newCard.setClient(c.client) - //newCard.List = } else { err = errors.Wrapf(err, "Error copying card '%s' to list '%s'.", c.ID, listID) } @@ -344,6 +343,7 @@ func (c *Card) GetParentCard(extraArgs ...Arguments) (*Card, error) { if action != nil && action.Data != nil && action.Data.CardSource != nil { card, err := c.client.GetCard(action.Data.CardSource.ID, args) + card.setClient(c.client) return card, err } @@ -463,7 +463,6 @@ func (c *Client) GetCard(cardID string, extraArgs ...Arguments) (card *Card, err err = c.Get(path, args, &card) if card != nil { card.setClient(c) - //card.List = getListById(card.IDList)? // Set Parent } return card, err } @@ -492,8 +491,8 @@ func (b *Board) GetCards(extraArgs ...Arguments) (cards []*Card, err error) { } for _, card := range cards { + card.Board = b // Set this hear to avoid the lookup card.setClient(b.client) - //card.List = getListById(card.IDList)? // Set Parent } return @@ -505,8 +504,10 @@ func (l *List) GetCards(extraArgs ...Arguments) (cards []*Card, err error) { path := fmt.Sprintf("lists/%s/cards", l.ID) err = l.client.Get(path, args, &cards) for _, card := range cards { + // Set these here before setClient to avoid lookup + card.Board = l.Board + card.List = l card.setClient(l.client) - card.List = l // Set Parent } return } @@ -527,6 +528,19 @@ func earliestCardID(cards []*Card) string { // setClient on card and sub-objects func (c *Card) setClient(client *Client) { c.client = client + if c.Board == nil { // Retrieve and Set Board + board, err := c.client.GetBoard(c.IDBoard, Defaults()) + if err == nil { + c.Board = board + } + } + if c.List == nil { // Retrieve and Set List + // NOTE: Board.GetCards will destroy this, need some sort of "cache.GetList" capability + list, err := c.client.GetList(c.IDList, Defaults()) + if err == nil { + c.List = list + } + } for _, action := range c.Actions { action.setClient(client) } From a9163e2c1e813010dad793341b5fd88624811182 Mon Sep 17 00:00:00 2001 From: Tommy McNeely Date: Mon, 2 Nov 2020 15:27:38 -0700 Subject: [PATCH 3/4] feat: add queryCache for GetBoard and GetList --- arguments.go | 16 ++++++++++++++++ board.go | 29 +++++++++++++++++++++++------ card.go | 5 ++--- client.go | 2 ++ list.go | 31 ++++++++++++++++++++++++++----- querycache.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 querycache.go diff --git a/arguments.go b/arguments.go index 02b7d3c..6d99683 100644 --- a/arguments.go +++ b/arguments.go @@ -7,6 +7,7 @@ package trello import ( "net/url" + "strconv" ) // Arguments are used for passing URL parameters to the client for making API calls. @@ -17,6 +18,21 @@ func Defaults() Arguments { return make(Arguments) } +// DefaultsWithCache is just like Defaults() but with cache enabled +func DefaultsWithCache() (args Arguments) { + args = make(Arguments) + args["EnableCache"] = "true" + return +} + +// IsCacheEnabled returns a boolean true if EnableCache is set to something truthy +func (args Arguments) IsCacheEnabled() (cacheEnabled bool) { + if arg, ok := args["EnableCache"]; ok { // if "EnableCache" arg is not present cacheEnabled will be false anyhow + cacheEnabled, _ = strconv.ParseBool(arg) // if parsing err's cacheEnabled will be false anyhow + } + return +} + // ToURLValues returns the argument's URL value representation. func (args Arguments) ToURLValues() url.Values { v := url.Values{} diff --git a/board.go b/board.go index 295eec1..6e0b53f 100644 --- a/board.go +++ b/board.go @@ -131,16 +131,24 @@ func (c *Client) CreateBoard(board *Board, extraArgs ...Arguments) error { // Update PUTs the supported board attributes remote and updates // the struct from the returned values. -func (b *Board) Update(extraArgs ...Arguments) error { +func (b *Board) Update(extraArgs ...Arguments) (err error) { args := flattenArguments(extraArgs) - return b.client.PutBoard(b, args) + err = b.client.PutBoard(b, args) + if args.IsCacheEnabled() { + b.client.cache.SetBoard(b.ID, b) + } + return } // Delete makes a DELETE call for the receiver Board. -func (b *Board) Delete(extraArgs ...Arguments) error { +func (b *Board) Delete(extraArgs ...Arguments) (err error) { args := flattenArguments(extraArgs) path := fmt.Sprintf("boards/%s", b.ID) - return b.client.Delete(path, args, b) + err = b.client.Delete(path, Arguments{}, b) + if args.IsCacheEnabled() { + b.client.cache.RemoveBoard(b.ID) + } + return } // AddedMembersResponse represents a response after adding a new member. @@ -167,8 +175,17 @@ func (b *Board) AddMember(member *Member, extraArgs ...Arguments) (response *Add // GetBoard retrieves a Trello board by its ID. func (c *Client) GetBoard(boardID string, extraArgs ...Arguments) (board *Board, err error) { args := flattenArguments(extraArgs) - path := fmt.Sprintf("boards/%s", boardID) - err = c.Get(path, args, &board) + if args.IsCacheEnabled() { + var found bool + if board, found = c.cache.GetBoard(boardID); !found { // Not Found, Query without cache + args["CacheEnabled"] = "false" + board, err = c.GetBoard(boardID, args) + c.cache.SetBoard(boardID, board) + } + } else { + path := fmt.Sprintf("boards/%s", boardID) + err = c.Get(path, args, &board) + } if board != nil { board.setClient(c) } diff --git a/card.go b/card.go index 62fed2f..d9237c9 100644 --- a/card.go +++ b/card.go @@ -529,14 +529,13 @@ func earliestCardID(cards []*Card) string { func (c *Card) setClient(client *Client) { c.client = client if c.Board == nil { // Retrieve and Set Board - board, err := c.client.GetBoard(c.IDBoard, Defaults()) + board, err := c.client.GetBoard(c.IDBoard, DefaultsWithCache()) if err == nil { c.Board = board } } if c.List == nil { // Retrieve and Set List - // NOTE: Board.GetCards will destroy this, need some sort of "cache.GetList" capability - list, err := c.client.GetList(c.IDList, Defaults()) + list, err := c.client.GetList(c.IDList, DefaultsWithCache()) if err == nil { c.List = list } diff --git a/client.go b/client.go index 02a8b9b..02f0126 100644 --- a/client.go +++ b/client.go @@ -31,6 +31,7 @@ type Client struct { throttle *rate.Limiter testMode bool ctx context.Context + cache *queryCache } type logger interface { @@ -50,6 +51,7 @@ func NewClient(key, token string) *Client { throttle: rate.NewLimiter(limit, 1), testMode: false, ctx: context.Background(), + cache: &queryCache{}, } } diff --git a/list.go b/list.go index 1bc02eb..2dd8b06 100644 --- a/list.go +++ b/list.go @@ -33,8 +33,17 @@ func (l *List) CreatedAt() time.Time { // GetList takes a list's id and Arguments and returns the matching list. func (c *Client) GetList(listID string, extraArgs ...Arguments) (list *List, err error) { args := flattenArguments(extraArgs) - path := fmt.Sprintf("lists/%s", listID) - err = c.Get(path, args, &list) + if args.IsCacheEnabled() { + var found bool + if list, found = c.cache.GetList(listID); !found { // Not Found, Query without cache + args["CacheEnabled"] = "false" + list, err = c.GetList(listID, args) + c.cache.SetList(listID, list) + } + } else { + path := fmt.Sprintf("lists/%s", listID) + err = c.Get(path, args, &list) + } if list != nil { list.setClient(c) // list.Board, err = c.GetBoard(list.IDBoard, Defaults()) // Set Parent @@ -50,6 +59,9 @@ func (b *Board) GetLists(extraArgs ...Arguments) (lists []*List, err error) { for _, list := range lists { list.setClient(b.client) list.Board = b // Set Parent + if args.IsCacheEnabled() { + b.client.cache.SetList(list.ID, list) + } } return } @@ -85,15 +97,24 @@ func (c *Client) CreateList(onBoard *Board, name string, extraArgs ...Arguments) // API Docs: https://developers.trello.com/reference/#lists-1 func (b *Board) CreateList(name string, extraArgs ...Arguments) (list *List, err error) { args := flattenArguments(extraArgs) - return b.client.CreateList(b, name, args) + list, err = b.client.CreateList(b, name, args) + list.setClient(b.client) + if args.IsCacheEnabled() { + b.client.cache.SetList(list.ID, list) + } + return } // Update UPDATEs the list's attributes. // API Docs: https://developers.trello.com/reference/#listsid-1 -func (l *List) Update(extraArgs ...Arguments) error { +func (l *List) Update(extraArgs ...Arguments) (err error) { args := flattenArguments(extraArgs) path := fmt.Sprintf("lists/%s", l.ID) - return l.client.Put(path, args, l) + err = l.client.Put(path, args, l) + if args.IsCacheEnabled() { + l.client.cache.SetList(l.ID, l) + } + return } // setClient on List and sub-objects diff --git a/querycache.go b/querycache.go new file mode 100644 index 0000000..876dde3 --- /dev/null +++ b/querycache.go @@ -0,0 +1,51 @@ +// Copyright © 2016 Aaron Longwell +// +// Use of this source code is governed by an MIT license. +// Details in the LICENSE file. + +package trello + +// queryCache struct to hold maps +// Type map[IDType]*Type +type queryCache struct { + Boards map[string]*Board + Lists map[string]*List +} + +// GetBoard returns *List if found, else nil +func (qc *queryCache) GetBoard(id string) (board *Board, found bool) { + + board, found = qc.Boards[id] + + return +} + +// SetBoard adds board by id +func (qc *queryCache) SetBoard(id string, board *Board) { + qc.Boards[id] = board + return +} + +// RemoveBoard adds board by id +func (qc *queryCache) RemoveBoard(id string) { + delete(qc.Boards, id) + return +} + +// GetList returns *List if found, else nil +func (qc *queryCache) GetList(id string) (list *List, found bool) { + list, found = qc.Lists[id] + return +} + +// SetList adds board by id +func (qc *queryCache) SetList(id string, list *List) { + qc.Lists[id] = list + return +} + +// RemoveList adds board by id +func (qc *queryCache) RemoveList(id string) { + delete(qc.Lists, id) + return +} From 7ae07adf61a01a553cab131ea56725afdee620a0 Mon Sep 17 00:00:00 2001 From: Tommy McNeely Date: Wed, 4 Nov 2020 08:11:01 -0700 Subject: [PATCH 4/4] Lets not pass EnableCache to Trello :) --- client.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client.go b/client.go index 02f0126..f07b389 100644 --- a/client.go +++ b/client.go @@ -79,6 +79,7 @@ func (c *Client) Get(path string, args Arguments, target interface{}) error { // Trello prohibits more than 10 seconds/second per token c.Throttle() + delete(args, "EnableCache") params := args.ToURLValues() c.log("[trello] GET %s?%s", path, params.Encode()) @@ -111,6 +112,7 @@ func (c *Client) Put(path string, args Arguments, target interface{}) error { // Trello prohibits more than 10 seconds/second per token c.Throttle() + delete(args, "EnableCache") params := args.ToURLValues() c.log("[trello] PUT %s?%s", path, params.Encode()) @@ -142,6 +144,7 @@ func (c *Client) Post(path string, args Arguments, target interface{}) error { // Trello prohibits more than 10 seconds/second per token c.Throttle() + delete(args, "EnableCache") params := args.ToURLValues() c.log("[trello] POST %s?%s", path, params.Encode()) @@ -172,6 +175,7 @@ func (c *Client) Delete(path string, args Arguments, target interface{}) error { c.Throttle() + delete(args, "EnableCache") params := args.ToURLValues() c.log("[trello] DELETE %s?%s", path, params.Encode())