Merry

Finished
1import json
2
13class RestAPI:
24 def __init__(self, database: dict | None = None):
3 pass
4
5 """
6 Initialize the REST API with a database.
7
8 Args:
9 database: A dictionary containing user data with keys 'users'.
10 """
11 self.database = database if database else {"users": []}
12
513 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
14 """
15 Handle GET requests to the API.
16
17 Args:
18 url: The endpoint URL.
19 payload: Optional JSON payload.
20
21 Returns:
22 A JSON string response.
23 """
24 if url == "/users":
25 if payload is None:
26 # Return all users sorted by name
27 users = self._get_all_users()
28 return json.dumps({"users": users})
29 else:
30 # Return specific users sorted by name
31 data = json.loads(payload)
32 user_names = data.get("users", [])
33
34 # Edge Case: Empty user list in payload
35 if not user_names:
36 return json.dumps({"users": []})
37
38 users = self._get_users_by_names(user_names)
39 return json.dumps({"users": users})
40
41 # Edge Case: Invalid URL
42 return json.dumps({"error": "Invalid URL"})
43
844 def post(self, url: str, payload: str | None = None) -> str:
9 pass
45 """
46 Handle POST requests to the API.
47
48 Args:
49 url: The endpoint URL.
50 payload: JSON payload.
51
52 Returns:
53 A JSON string response.
54 """
55 if payload is None:
56 # Edge Case: Missing payload
57 return json.dumps({"error": "Payload required"})
58
59 data = json.loads(payload)
60
61 if url == "/add":
62 user_name = data.get("user")
63
64 # Edge Case: Missing user name
65 if not user_name:
66 return json.dumps({"error": "User name required"})
67
68 # Edge Case: User already exists
69 if self._user_exists(user_name):
70 return json.dumps({"error": "User already exists"})
71
72 new_user = self._create_user(user_name)
73 self.database["users"].append(new_user)
74 return json.dumps(new_user)
75
76 elif url == "/iou":
77 lender_name = data.get("lender")
78 borrower_name = data.get("borrower")
79 amount = data.get("amount")
80
81 # Edge Case: Missing required fields
82 if not lender_name or not borrower_name or amount is None:
83 return json.dumps({"error": "Lender, borrower, and amount required"})
84
85 # Edge Case: Lender and borrower are the same
86 if lender_name == borrower_name:
87 return json.dumps({"error": "Lender and borrower cannot be the same"})
88
89 # Edge Case: Negative amount
90 if amount < 0:
91 return json.dumps({"error": "Amount must be non-negative"})
92
93 # Edge Case: User does not exist
94 if not self._user_exists(lender_name) or not self._user_exists(borrower_name):
95 return json.dumps({"error": "Both users must exist"})
96
97 # Update IOUs
98 self._update_iou(lender_name, borrower_name, amount)
99
100 # Return updated users
101 users = self._get_users_by_names([lender_name, borrower_name])
102 return json.dumps({"users": users})
103
104 # Edge Case: Invalid URL
105 return json.dumps({"error": "Invalid URL"})
106
107 def _get_all_users(self) -> list:
108 """
109 Get all users sorted by name.
110
111 Returns:
112 A list of user objects sorted by name.
113 """
114 users = [self._format_user(user) for user in self.database["users"]]
115 return sorted(users, key=lambda x: x["name"])
116
117 def _get_users_by_names(self, names: list) -> list:
118 """
119 Get specific users by their names, sorted by name.
120
121 Args:
122 names: A list of user names.
123
124 Returns:
125 A list of user objects sorted by name.
126 """
127 users = []
128 for user in self.database["users"]:
129 if user["name"] in names:
130 users.append(self._format_user(user))
131 return sorted(users, key=lambda x: x["name"])
132
133 def _user_exists(self, name: str) -> bool:
134 """
135 Check if a user exists in the database.
136
137 Args:
138 name: The name of the user.
139
140 Returns:
141 True if the user exists, False otherwise.
142 """
143 return any(user["name"] == name for user in self.database["users"])
144
145 def _create_user(self, name: str) -> dict:
146 """
147 Create a new user object.
148
149 Args:
150 name: The name of the user.
151
152 Returns:
153 A new user object.
154 """
155 return {
156 "name": name,
157 "owes": {},
158 "owed_by": {},
159 "balance": 0.0
160 }
161
162 def _format_user(self, user: dict) -> dict:
163 """
164 Format a user object, calculating the balance.
165
166 Args:
167 user: The user object.
168
169 Returns:
170 A formatted user object with calculated balance.
171 """
172 owes_total = sum(user.get("owes", {}).values())
173 owed_by_total = sum(user.get("owed_by", {}).values())
174 balance = round(owed_by_total - owes_total, 2)
175
176 # Ensure balance is properly formatted
177 return {
178 "name": user["name"],
179 "owes": user.get("owes", {}),
180 "owed_by": user.get("owed_by", {}),
181 "balance": balance
182 }
183
184 def _update_iou(self, lender_name: str, borrower_name: str, amount: float) -> None:
185 """
186 Update the IOU records between lender and borrower.
187
188 Args:
189 lender_name: The name of the lender.
190 borrower_name: The name of the borrower.
191 amount: The amount of the IOU.
192 """
193 lender = next(user for user in self.database["users"] if user["name"] == lender_name)
194 borrower = next(user for user in self.database["users"] if user["name"] == borrower_name)
195
196 # Update lender's owed_by
197 if "owed_by" not in lender:
198 lender["owed_by"] = {}
199 if borrower_name in lender["owed_by"]:
200 lender["owed_by"][borrower_name] += amount
201 else:
202 lender["owed_by"][borrower_name] = amount
203
204 # Update borrower's owes
205 if "owes" not in borrower:
206 borrower["owes"] = {}
207 if lender_name in borrower["owes"]:
208 borrower["owes"][lender_name] += amount
209 else:
210 borrower["owes"][lender_name] = amount
211
212 # Edge Case: Handle zero balances by removing entries
213 if lender["owed_by"][borrower_name] == 0:
214 del lender["owed_by"][borrower_name]
215 if not lender["owed_by"]:
216 del lender["owed_by"]
217
218 if borrower["owes"][lender_name] == 0:
219 del borrower["owes"][lender_name]
220 if not borrower["owes"]:
221 del borrower["owes"]
222
223 # Handled Edge Cases: Invalid URL, Missing payload, Missing user name, User already exists,
224 # Missing required fields, Lender and borrower are the same, Negative amount, User does not exist,
225 # Empty user list in payload, Zero balances
Test NameStatus
test_lender_owes_borrower
Fail
test_lender_owes_borrower_less_than_new_loan
Fail
test_lender_owes_borrower_same_as_new_loan
Fail
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_no_users
Pass

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