Skip to content

Commit ce44ded

Browse files
authored
feat: add filters for budget (#183)
1 parent ee1b90f commit ce44ded

File tree

7 files changed

+145
-6
lines changed

7 files changed

+145
-6
lines changed

api/docs.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,26 @@ const docTemplate = `{
594594
"Budgets"
595595
],
596596
"summary": "List all budgets",
597+
"parameters": [
598+
{
599+
"type": "string",
600+
"description": "Name of the budget",
601+
"name": "name",
602+
"in": "query"
603+
},
604+
{
605+
"type": "string",
606+
"description": "Note for the budget",
607+
"name": "note",
608+
"in": "query"
609+
},
610+
{
611+
"type": "string",
612+
"description": "Currency the budget is in",
613+
"name": "currency",
614+
"in": "query"
615+
}
616+
],
597617
"responses": {
598618
"200": {
599619
"description": "OK",
@@ -1785,7 +1805,7 @@ const docTemplate = `{
17851805
},
17861806
"transactions": {
17871807
"type": "string",
1788-
"example": "https://example.com/api/v1/transactions?=af892e10-7e0a-4fb8-b1bc-4b6d88401ed2"
1808+
"example": "https://example.com/api/v1/transactions?account♫=af892e10-7e0a-4fb8-b1bc-4b6d88401ed2"
17891809
}
17901810
}
17911811
},

api/swagger.json

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,26 @@
582582
"Budgets"
583583
],
584584
"summary": "List all budgets",
585+
"parameters": [
586+
{
587+
"type": "string",
588+
"description": "Name of the budget",
589+
"name": "name",
590+
"in": "query"
591+
},
592+
{
593+
"type": "string",
594+
"description": "Note for the budget",
595+
"name": "note",
596+
"in": "query"
597+
},
598+
{
599+
"type": "string",
600+
"description": "Currency the budget is in",
601+
"name": "currency",
602+
"in": "query"
603+
}
604+
],
585605
"responses": {
586606
"200": {
587607
"description": "OK",
@@ -1773,7 +1793,7 @@
17731793
},
17741794
"transactions": {
17751795
"type": "string",
1776-
"example": "https://example.com/api/v1/transactions?=af892e10-7e0a-4fb8-b1bc-4b6d88401ed2"
1796+
"example": "https://example.com/api/v1/transactions?account♫=af892e10-7e0a-4fb8-b1bc-4b6d88401ed2"
17771797
}
17781798
}
17791799
},

api/swagger.yaml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ definitions:
3636
example: https://example.com/api/v1/accounts/af892e10-7e0a-4fb8-b1bc-4b6d88401ed2
3737
type: string
3838
transactions:
39-
example: https://example.com/api/v1/transactions?=af892e10-7e0a-4fb8-b1bc-4b6d88401ed2
39+
example: https://example.com/api/v1/transactions?account♫=af892e10-7e0a-4fb8-b1bc-4b6d88401ed2
4040
type: string
4141
type: object
4242
controllers.AccountListResponse:
@@ -862,6 +862,19 @@ paths:
862862
/v1/budgets:
863863
get:
864864
description: Returns list of budgets
865+
parameters:
866+
- description: Name of the budget
867+
in: query
868+
name: name
869+
type: string
870+
- description: Note for the budget
871+
in: query
872+
name: note
873+
type: string
874+
- description: Currency the budget is in
875+
in: query
876+
name: currency
877+
type: string
865878
produces:
866879
- application/json
867880
responses:

pkg/controllers/account.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type Account struct {
2525

2626
type AccountLinks struct {
2727
Self string `json:"self" example:"https://example.com/api/v1/accounts/af892e10-7e0a-4fb8-b1bc-4b6d88401ed2"`
28-
Transactions string `json:"transactions" example:"https://example.com/api/v1/transactions?=af892e10-7e0a-4fb8-b1bc-4b6d88401ed2"`
28+
Transactions string `json:"transactions" example:"https://example.com/api/v1/transactions?account♫=af892e10-7e0a-4fb8-b1bc-4b6d88401ed2"`
2929
}
3030

3131
// RegisterAccountRoutes registers the routes for accounts with

pkg/controllers/budget.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ type BudgetMonthResponse struct {
3737
Data models.BudgetMonth `json:"data"`
3838
}
3939

40+
type BudgetQueryFilter struct {
41+
QueryFilter
42+
Currency string `form:"currency"`
43+
}
44+
4045
// RegisterBudgetRoutes registers the routes for budgets with
4146
// the RouterGroup that is passed.
4247
func RegisterBudgetRoutes(r *gin.RouterGroup) {
@@ -110,9 +115,26 @@ func CreateBudget(c *gin.Context) {
110115
// @Success 200 {object} BudgetListResponse
111116
// @Failure 500 {object} httputil.HTTPError
112117
// @Router /v1/budgets [get]
118+
// @Router /v1/budgets [get]
119+
// @Param name query string false "Name of the budget"
120+
// @Param note query string false "Note for the budget"
121+
// @Param currency query string false "Currency the budget is in"
113122
func GetBudgets(c *gin.Context) {
123+
var f BudgetQueryFilter
124+
125+
// We should find something that is not parseable and test this line
126+
if err := c.Bind(&f); err != nil {
127+
return
128+
}
129+
114130
var budgets []models.Budget
115-
models.DB.Find(&budgets)
131+
models.DB.Where(&models.Budget{
132+
BudgetCreate: models.BudgetCreate{
133+
Name: f.Name,
134+
Note: f.Note,
135+
Currency: f.Currency,
136+
},
137+
}).Find(&budgets)
116138

117139
// When there are no budgets, we want an empty list, not null
118140
// Therefore, we use make to create a slice with zero elements

pkg/controllers/budget_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ import (
1313
"github.com/stretchr/testify/assert"
1414
)
1515

16+
func createTestBudget(t *testing.T, c models.BudgetCreate) controllers.BudgetResponse {
17+
r := test.Request(t, http.MethodPost, "/v1/budgets", c)
18+
test.AssertHTTPStatus(t, http.StatusCreated, &r)
19+
20+
var a controllers.BudgetResponse
21+
test.DecodeResponse(t, &r, &a)
22+
23+
return a
24+
}
25+
1626
func TestGetBudgets(t *testing.T) {
1727
recorder := test.Request(t, "GET", "/v1/budgets", "")
1828

@@ -34,6 +44,53 @@ func TestGetBudgets(t *testing.T) {
3444
assert.LessOrEqual(t, diff, test.TOLERANCE)
3545
}
3646

47+
func TestGetBudgetsFilter(t *testing.T) {
48+
_ = createTestBudget(t, models.BudgetCreate{
49+
Name: "Exact String Match",
50+
Note: "This is a specific note",
51+
Currency: "€",
52+
})
53+
54+
_ = createTestBudget(t, models.BudgetCreate{
55+
Name: "Another String",
56+
Note: "This is a specific note",
57+
Currency: "$",
58+
})
59+
60+
_ = createTestBudget(t, models.BudgetCreate{
61+
Name: "Another String",
62+
Note: "A different note",
63+
Currency: "€",
64+
})
65+
66+
var re controllers.BudgetListResponse
67+
68+
r := test.Request(t, http.MethodGet, "/v1/budgets?currency=€", "")
69+
test.AssertHTTPStatus(t, http.StatusOK, &r)
70+
test.DecodeResponse(t, &r, &re)
71+
assert.Equal(t, 2, len(re.Data))
72+
73+
r = test.Request(t, http.MethodGet, "/v1/budgets?currency=$", "")
74+
test.AssertHTTPStatus(t, http.StatusOK, &r)
75+
test.DecodeResponse(t, &r, &re)
76+
assert.Equal(t, 1, len(re.Data))
77+
78+
r = test.Request(t, http.MethodGet, "/v1/budgets?currency=€&name=Another String", "")
79+
test.AssertHTTPStatus(t, http.StatusOK, &r)
80+
test.DecodeResponse(t, &r, &re)
81+
assert.Equal(t, 1, len(re.Data))
82+
83+
r = test.Request(t, http.MethodGet, "/v1/budgets?note=This is a specific note", "")
84+
test.AssertHTTPStatus(t, http.StatusOK, &r)
85+
test.DecodeResponse(t, &r, &re)
86+
assert.Equal(t, 2, len(re.Data))
87+
88+
r = test.Request(t, http.MethodGet, "/v1/budgets?name=Exact String Match", "")
89+
test.AssertHTTPStatus(t, http.StatusOK, &r)
90+
test.DecodeResponse(t, &r, &re)
91+
assert.Equal(t, 1, len(re.Data))
92+
}
93+
3794
func TestNoBudgetNotFound(t *testing.T) {
3895
recorder := test.Request(t, "GET", "/v1/budgets/65064e6f-04b4-46e0-8bbc-88c96c6b21bd", "")
3996

pkg/controllers/types.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
package controllers
22

3-
import "time"
3+
import (
4+
"time"
5+
)
46

57
// This file holds types that are used over multiple files.
68

79
// Month is used to parse requests for data about a specific month.
810
type URIMonth struct {
911
Month time.Time `uri:"month" time_format:"2006-01" time_utc:"1"`
1012
}
13+
14+
type QueryFilter struct {
15+
Name string `form:"name"`
16+
Note string `form:"note"`
17+
}

0 commit comments

Comments
 (0)