Skip to content

Commit def0803

Browse files
authored
Merge pull request #121 from halorrr/complete-all_categories-call
complete all_categories call
2 parents 4508b7f + c039a20 commit def0803

File tree

6 files changed

+177
-17
lines changed

6 files changed

+177
-17
lines changed

lib/lunchmoney/categories/category.rb

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,48 +12,53 @@ class Category < LunchMoney::DataObject
1212
sig { returns(T.nilable(String)) }
1313
attr_accessor :description, :archived_on, :updated_at, :created_at
1414

15+
sig { returns(T.nilable(T::Boolean)) }
16+
attr_accessor :archived
17+
1518
sig { returns(T::Boolean) }
16-
attr_accessor :is_income, :exclude_from_budget, :exclude_from_totals, :archived, :is_group
19+
attr_accessor :is_income, :exclude_from_budget, :exclude_from_totals, :is_group
1720

1821
sig { returns(T.nilable(Integer)) }
19-
attr_accessor :group_id
22+
attr_accessor :group_id, :order
2023

21-
sig { returns(T::Array[LunchMoney::Category]) }
24+
sig { returns(T.nilable(T::Array[LunchMoney::Category])) }
2225
attr_accessor :children
2326

2427
sig do
2528
params(
26-
name: String,
2729
id: Integer,
28-
children: T::Array[LunchMoney::Category],
30+
name: String,
2931
is_income: T::Boolean,
3032
exclude_from_budget: T::Boolean,
3133
exclude_from_totals: T::Boolean,
32-
archived: T::Boolean,
3334
is_group: T::Boolean,
35+
archived: T.nilable(T::Boolean),
3436
archived_on: T.nilable(String),
3537
updated_at: T.nilable(String),
3638
created_at: T.nilable(String),
3739
group_id: T.nilable(Integer),
40+
order: T.nilable(Integer),
3841
description: T.nilable(String),
42+
children: T.nilable(T::Array[LunchMoney::Category]),
3943
).void
4044
end
41-
def initialize(name:, id:, children:, is_income:, exclude_from_budget:, exclude_from_totals:, archived:, is_group:,
42-
archived_on: nil, updated_at: nil, created_at: nil, group_id: nil, description: nil)
45+
def initialize(id:, name:, is_income:, exclude_from_budget:, exclude_from_totals:, is_group:, archived: nil,
46+
archived_on: nil, updated_at: nil, created_at: nil, group_id: nil, order: nil, description: nil, children: nil)
4347
super()
44-
@name = name
4548
@id = id
46-
@children = children
49+
@name = name
4750
@is_income = is_income
4851
@exclude_from_budget = exclude_from_budget
4952
@exclude_from_totals = exclude_from_totals
50-
@archived = archived
5153
@is_group = is_group
54+
@archived = archived
5255
@archived_on = archived_on
5356
@updated_at = updated_at
5457
@created_at = created_at
5558
@group_id = group_id
59+
@order = order
5660
@description = description
61+
@children = children
5762
end
5863
end
5964
end

lib/lunchmoney/categories/category_calls.rb

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,24 @@
22
# frozen_string_literal: true
33

44
require_relative "category"
5-
require "pry"
65

76
module LunchMoney
87
class CategoryCalls < ApiCall
9-
sig { returns(T.any(T::Array[LunchMoney::Category], LunchMoney::Errors)) }
10-
def all_categories
11-
response = get("categories")
8+
VALID_FORMATS = T.let(
9+
[
10+
"flattened",
11+
"nested",
12+
],
13+
T::Array[String],
14+
)
15+
16+
sig do
17+
params(
18+
format: T.nilable(T.any(String, Symbol)),
19+
).returns(T.any(T::Array[LunchMoney::Category], LunchMoney::Errors))
20+
end
21+
def all_categories(format: nil)
22+
response = get("categories", query_params: all_categories_params(format:))
1223

1324
api_errors = errors(response)
1425
return api_errors if api_errors.present?
@@ -171,5 +182,16 @@ def force_delete_category(category_id)
171182

172183
response.body
173184
end
185+
186+
private
187+
188+
sig { params(format: T.nilable(T.any(String, Symbol))).returns(T.nilable(T::Hash[String, String])) }
189+
def all_categories_params(format:)
190+
return unless format
191+
192+
raise(InvalidQueryParameter, "format must be either flattened or nested") if VALID_FORMATS.exclude?(format.to_s)
193+
194+
{ format: format.to_s }
195+
end
174196
end
175197
end

lib/lunchmoney/data_object.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
module LunchMoney
55
class DataObject
6-
require "pry"
7-
86
sig { params(symbolize_keys: T::Boolean).returns(T::Hash[String, T.untyped]) }
97
def serialize(symbolize_keys: false)
108
ivars = instance_variables

lib/lunchmoney/exceptions.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ class Exception < StandardError; end
77
class InvalidApiKey < Exception; end
88

99
class InvalidObjectAttribute < Exception; end
10+
11+
class InvalidQueryParameter < Exception; end
1012
end

test/helpers/fake_response_data_helper.rb

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,70 @@ def fake_budget_summary_response
112112
},
113113
]
114114
end
115+
116+
sig { returns(T::Hash[String, T.untyped]) }
117+
def fake_all_categories_response
118+
{
119+
"categories": [
120+
{
121+
"id": 83,
122+
"name": "Test 1",
123+
"description": "Test description",
124+
"is_income": false,
125+
"exclude_from_budget": true,
126+
"exclude_from_totals": false,
127+
"updated_at": "2020-01-28T09:49:03.225Z",
128+
"created_at": "2020-01-28T09:49:03.225Z",
129+
"is_group": false,
130+
"group_id": nil,
131+
"order": 0,
132+
},
133+
{
134+
"id": 84,
135+
"name": "Test 2",
136+
"description": nil,
137+
"is_income": true,
138+
"exclude_from_budget": false,
139+
"exclude_from_totals": true,
140+
"updated_at": "2020-01-28T09:49:03.238Z",
141+
"created_at": "2020-01-28T09:49:03.238Z",
142+
"is_group": true,
143+
"group_id": 83,
144+
"order": 1,
145+
"children": [
146+
{
147+
"id": 315162,
148+
"name": "Alcohol, Bars",
149+
"description": nil,
150+
"is_income": false,
151+
"exclude_from_budget": false,
152+
"exclude_from_totals": false,
153+
"created_at": "2022-03-06T20:11:36.066Z",
154+
"is_group": false,
155+
},
156+
{
157+
"id": 315169,
158+
"name": "Groceries",
159+
"description": nil,
160+
"is_income": false,
161+
"exclude_from_budget": false,
162+
"exclude_from_totals": false,
163+
"created_at": "2022-03-06T20:11:36.120Z",
164+
"is_group": false,
165+
},
166+
{
167+
"id": 315172,
168+
"name": "Restaurants",
169+
"description": nil,
170+
"is_income": false,
171+
"exclude_from_budget": false,
172+
"exclude_from_totals": false,
173+
"created_at": "2022-03-06T20:11:36.146Z",
174+
"is_group": false,
175+
},
176+
],
177+
},
178+
],
179+
}
180+
end
115181
end
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
require "test_helper"
5+
6+
class CategoryCallsTest < ActiveSupport::TestCase
7+
include MockResponseHelper
8+
include FakeResponseDataHelper
9+
10+
test "all_categories returns an array of Category objects on success response" do
11+
response = mock_faraday_response(fake_all_categories_response)
12+
13+
LunchMoney::CategoryCalls.any_instance.stubs(:get).returns(response)
14+
15+
api_call = LunchMoney::CategoryCalls.new.all_categories
16+
17+
assert_kind_of(LunchMoney::Category, api_call.first)
18+
end
19+
20+
test "all_categories returns an array of Error objects on error response" do
21+
response = mock_faraday_response(fake_general_error)
22+
23+
LunchMoney::CategoryCalls.any_instance.stubs(:get).returns(response)
24+
25+
api_call = LunchMoney::CategoryCalls.new.all_categories(format: "flattened")
26+
27+
assert_kind_of(LunchMoney::Error, api_call.first)
28+
end
29+
30+
test "all_categories does not raise an error when called with flattened format" do
31+
response = mock_faraday_response(fake_all_categories_response)
32+
33+
query_params = { format: "flattened" }
34+
35+
LunchMoney::CategoryCalls.any_instance.stubs(:get).with("categories", query_params:).returns(response)
36+
37+
assert_nothing_raised do
38+
LunchMoney::CategoryCalls.new.all_categories(**query_params)
39+
end
40+
end
41+
42+
test "all_categories does not raise an error when called with nested format" do
43+
response = mock_faraday_response(fake_all_categories_response)
44+
45+
query_params = { format: "nested" }
46+
47+
LunchMoney::CategoryCalls.any_instance.stubs(:get).with("categories", query_params:).returns(response)
48+
49+
assert_nothing_raised do
50+
LunchMoney::CategoryCalls.new.all_categories(**query_params)
51+
end
52+
end
53+
54+
test "all_categories raises an exception when called with invalid format" do
55+
response = mock_faraday_response(fake_all_categories_response)
56+
57+
query_params = { format: "not_a_valid_format" }
58+
59+
LunchMoney::CategoryCalls.any_instance.stubs(:get).with("categories", query_params:).returns(response)
60+
61+
error = assert_raises(LunchMoney::InvalidQueryParameter) do
62+
LunchMoney::CategoryCalls.new.all_categories(**query_params)
63+
end
64+
65+
assert_equal("format must be either flattened or nested", error.message)
66+
end
67+
end

0 commit comments

Comments
 (0)