kale

Finished
1import json
2from typing import Dict, Any, List, Optional
3
14class RestAPI:
25 def __init__(self, database: dict | None = None):
3 pass
6 if database is None:
7 self.database = {"users": []}
8 else:
9 self.database = database
10
11 def _get_user(self, name: str) -> Optional[Dict[str, Any]]:
12 """Helper method to get a user by name"""
13 for user in self.database["users"]:
14 if user["name"] == name:
15 return user
16 return None
17
18 def _create_user(self, name: str) -> Dict[str, Any]:
19 """Helper method to create a new user"""
20 user = {
21 "name": name,
22 "owes": {},
23 "owed_by": {},
24 "balance": 0.0
25 }
26 self.database["users"].append(user)
27 return user
28
29 def _calculate_balance(self, user: Dict[str, Any]) -> float:
30 """Helper method to calculate user's balance"""
31 total_owed_by_others = sum(user["owed_by"].values())
32 total_owed_to_others = sum(user["owes"].values())
33 return round(total_owed_by_others - total_owed_to_others, 2)
34
35 def _update_balances(self, lender_name: str, borrower_name: str) -> None:
36 """Helper method to update balances for lender and borrower"""
37 lender = self._get_user(lender_name)
38 borrower = self._get_user(borrower_name)
39
40 if lender:
41 lender["balance"] = self._calculate_balance(lender)
42 if borrower:
43 borrower["balance"] = self._calculate_balance(borrower)
444
545 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
46 # Edge Case: Invalid URL
47 if url != "/users":
48 return json.dumps({"error": "Invalid URL"})
49
50 # Edge Case: Malformed payload
51 if payload is not None:
52 try:
53 payload_data = json.loads(payload)
54 except json.JSONDecodeError:
55 return json.dumps({"error": "Invalid payload"})
56 else:
57 payload_data = None
58
59 users = self.database["users"]
60
61 # If no payload, return all users
62 if payload_data is None or "users" not in payload_data:
63 # Edge Case: No users in database
64 if not users:
65 return json.dumps({"users": []})
66 result_users = users
67 else:
68 # Edge Case: Empty users list in payload
69 if not payload_data["users"]:
70 return json.dumps({"users": []})
71
72 # Filter users by names in payload
73 result_users = []
74 for user_name in payload_data["users"]:
75 user = self._get_user(user_name)
76 # Edge Case: Requested user does not exist
77 if user is not None:
78 result_users.append(user)
79
80 # Edge Case: None of the requested users exist
81 if not result_users:
82 return json.dumps({"users": []})
83
84 # Sort users by name
85 result_users.sort(key=lambda x: x["name"])
86
87 # Create response with updated balances
88 response_users = []
89 for user in result_users:
90 response_user = user.copy()
91 response_user["balance"] = self._calculate_balance(user)
92 response_users.append(response_user)
93
94 return json.dumps({"users": response_users})
95
896 def post(self, url: str, payload: str | None = None) -> str:
9 pass
97 # Edge Case: Malformed payload
98 if payload is None:
99 return json.dumps({"error": "Payload required"})
100
101 try:
102 payload_data = json.loads(payload)
103 except json.JSONDecodeError:
104 return json.dumps({"error": "Invalid payload"})
105
106 if url == "/add":
107 # Edge Case: Missing user field
108 if "user" not in payload_data:
109 return json.dumps({"error": "Missing user field"})
110
111 user_name = payload_data["user"]
112
113 # Edge Case: User already exists
114 if self._get_user(user_name) is not None:
115 return json.dumps({"error": "User already exists"})
116
117 # Create new user
118 new_user = self._create_user(user_name)
119 return json.dumps(new_user)
120
121 elif url == "/iou":
122 # Edge Case: Missing required fields
123 required_fields = ["lender", "borrower", "amount"]
124 for field in required_fields:
125 if field not in payload_data:
126 return json.dumps({"error": f"Missing {field} field"})
127
128 lender_name = payload_data["lender"]
129 borrower_name = payload_data["borrower"]
130 amount = payload_data["amount"]
131
132 # Edge Case: Lender and borrower are the same person
133 if lender_name == borrower_name:
134 return json.dumps({"error": "Lender and borrower cannot be the same person"})
135
136 # Edge Case: Negative or zero amount
137 if amount <= 0:
138 return json.dumps({"error": "Amount must be positive"})
139
140 # Get or create lender
141 lender = self._get_user(lender_name)
142 if lender is None:
143 lender = self._create_user(lender_name)
144
145 # Get or create borrower
146 borrower = self._get_user(borrower_name)
147 if borrower is None:
148 borrower = self._create_user(borrower_name)
149
150 # Update IOUs
151 # When borrower borrows from lender:
152 # - borrower owes lender amount
153 # - lender is owed by borrower amount
154
155 # Update what borrower owes to lender
156 borrower["owes"][lender_name] = borrower["owes"].get(lender_name, 0) + amount
157
158 # Update what lender is owed by borrower
159 lender["owed_by"][borrower_name] = lender["owed_by"].get(borrower_name, 0) + amount
160
161 # Net reverse relationships if they exist
162 # Check if there are reverse relationships that should be netted
163 borrower_owes_lender = borrower["owes"].get(lender_name, 0)
164 borrower_is_owed_by_lender = borrower["owed_by"].get(lender_name, 0)
165
166 lender_owes_borrower = lender["owes"].get(borrower_name, 0)
167 lender_is_owed_by_borrower = lender["owed_by"].get(borrower_name, 0)
168
169 # Calculate net amounts
170 net_borrower_owes = borrower_owes_lender - borrower_is_owed_by_lender
171 net_lender_owes = lender_owes_borrower - lender_is_owed_by_borrower
172
173 # Update dictionaries based on net amounts
174 if net_borrower_owes > 0:
175 borrower["owes"][lender_name] = net_borrower_owes
176 if lender_name in borrower["owed_by"]:
177 del borrower["owed_by"][lender_name]
178 elif net_borrower_owes < 0:
179 if lender_name in borrower["owes"]:
180 del borrower["owes"][lender_name]
181 borrower["owed_by"][lender_name] = -net_borrower_owes
182 else:
183 # They owe each other nothing
184 if lender_name in borrower["owes"]:
185 del borrower["owes"][lender_name]
186 if lender_name in borrower["owed_by"]:
187 del borrower["owed_by"][lender_name]
188
189 if net_lender_owes > 0:
190 lender["owes"][borrower_name] = net_lender_owes
191 if borrower_name in lender["owed_by"]:
192 del lender["owed_by"][borrower_name]
193 elif net_lender_owes < 0:
194 if borrower_name in lender["owes"]:
195 del lender["owes"][borrower_name]
196 lender["owed_by"][borrower_name] = -net_lender_owes
197 else:
198 # They owe each other nothing
199 if borrower_name in lender["owes"]:
200 del lender["owes"][borrower_name]
201 if borrower_name in lender["owed_by"]:
202 del lender["owed_by"][borrower_name]
203
204 # Update balances
205 self._update_balances(lender_name, borrower_name)
206
207 # Return updated user information
208 updated_lender = self._get_user(lender_name)
209 updated_borrower = self._get_user(borrower_name)
210
211 result_users = [updated_lender, updated_borrower]
212 result_users.sort(key=lambda x: x["name"])
213
214 # Recalculate balances for response
215 response_users = []
216 for user in result_users:
217 response_user = user.copy()
218 response_user["balance"] = self._calculate_balance(user)
219 response_users.append(response_user)
220
221 return json.dumps({"users": response_users})
222 else:
223 # Edge Case: Invalid URL
224 return json.dumps({"error": "Invalid URL"})
225
226 # Handled Edge Cases: Invalid URL, Malformed payload, Missing user field, User already exists, Missing required fields,
227 # Lender and borrower are the same person, Negative or zero amount, Lender does not exist, Borrower does not exist,
228 # Empty users list in payload, None of the requested users exist, No users in database
Test NameStatus
test_add_user
Pass
test_borrower_has_negative_balance
Pass
test_both_users_have_0_balance
Pass
test_get_single_user
Pass
test_lender_has_negative_balance
Pass
test_lender_owes_borrower
Pass
test_lender_owes_borrower_less_than_new_loan
Pass
test_lender_owes_borrower_same_as_new_loan
Pass
test_no_users
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.