rdune71 commited on
Commit
f6d2b4a
·
1 Parent(s): 2665582

Implement Goal Tracker services with Redis-backed CRUD operations

Browse files
Files changed (1) hide show
  1. modules/goal_tracker/services.py +107 -0
modules/goal_tracker/services.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import uuid
2
+ from datetime import datetime
3
+ from typing import List, Optional
4
+ from core.memory import get_redis_client
5
+ from .models import GoalCreate, GoalUpdate, GoalInDB
6
+
7
+ def _get_redis_key(user_id: str, goal_id: str) -> str:
8
+ return f"user:{user_id}:goals:{goal_id}"
9
+
10
+ def _get_index_key(user_id: str) -> str:
11
+ return f"user:{user_id}:goals:index"
12
+
13
+ def create_goal(user_id: str, goal_data: GoalCreate) -> GoalInDB:
14
+ redis_client = get_redis_client()
15
+ if not redis_client:
16
+ raise RuntimeError("Redis connection unavailable.")
17
+
18
+ goal_id = str(uuid.uuid4())
19
+ now = datetime.utcnow()
20
+ goal_dict = {
21
+ "id": goal_id,
22
+ "user_id": user_id,
23
+ "title": goal_data.title,
24
+ "description": goal_data.description or "",
25
+ "target_date": goal_data.target_date.isoformat() if goal_data.target_date else "",
26
+ "created_at": now.isoformat(),
27
+ "updated_at": now.isoformat()
28
+ }
29
+
30
+ redis_client.hset(_get_redis_key(user_id, goal_id), mapping=goal_dict)
31
+ redis_client.zadd(_get_index_key(user_id), {goal_id: now.timestamp()})
32
+
33
+ return GoalInDB(**goal_dict)
34
+
35
+ def get_goals(user_id: str) -> List[GoalInDB]:
36
+ redis_client = get_redis_client()
37
+ if not redis_client:
38
+ return []
39
+
40
+ goal_ids = redis_client.zrange(_get_index_key(user_id), 0, -1)
41
+ goals = []
42
+
43
+ for gid in goal_ids:
44
+ raw_goal = redis_client.hgetall(_get_redis_key(user_id, gid))
45
+ if raw_goal:
46
+ # Parse dates back to datetime objects
47
+ raw_goal["target_date"] = datetime.fromisoformat(raw_goal["target_date"]) if raw_goal["target_date"] else None
48
+ raw_goal["created_at"] = datetime.fromisoformat(raw_goal["created_at"])
49
+ raw_goal["updated_at"] = datetime.fromisoformat(raw_goal["updated_at"])
50
+ goals.append(GoalInDB(**raw_goal))
51
+
52
+ return goals
53
+
54
+ def get_goal_by_id(user_id: str, goal_id: str) -> Optional[GoalInDB]:
55
+ redis_client = get_redis_client()
56
+ if not redis_client:
57
+ return None
58
+
59
+ raw_goal = redis_client.hgetall(_get_redis_key(user_id, goal_id))
60
+ if not raw_goal:
61
+ return None
62
+
63
+ raw_goal["target_date"] = datetime.fromisoformat(raw_goal["target_date"]) if raw_goal["target_date"] else None
64
+ raw_goal["created_at"] = datetime.fromisoformat(raw_goal["created_at"])
65
+ raw_goal["updated_at"] = datetime.fromisoformat(raw_goal["updated_at"])
66
+
67
+ return GoalInDB(**raw_goal)
68
+
69
+ def update_goal(user_id: str, goal_id: str, updates: GoalUpdate) -> Optional[GoalInDB]:
70
+ redis_client = get_redis_client()
71
+ if not redis_client:
72
+ return None
73
+
74
+ raw_goal = redis_client.hgetall(_get_redis_key(user_id, goal_id))
75
+ if not raw_goal:
76
+ return None
77
+
78
+ # Apply updates
79
+ update_data = updates.dict(exclude_unset=True)
80
+ for field, value in update_data.items():
81
+ if isinstance(value, datetime):
82
+ raw_goal[field] = value.isoformat()
83
+ else:
84
+ raw_goal[field] = value
85
+
86
+ raw_goal["updated_at"] = datetime.utcnow().isoformat()
87
+
88
+ redis_client.hset(_get_redis_key(user_id, goal_id), mapping=raw_goal)
89
+
90
+ parsed_goal = raw_goal.copy()
91
+ parsed_goal["target_date"] = datetime.fromisoformat(parsed_goal["target_date"]) if parsed_goal["target_date"] else None
92
+ parsed_goal["created_at"] = datetime.fromisoformat(parsed_goal["created_at"])
93
+ parsed_goal["updated_at"] = datetime.fromisoformat(parsed_goal["updated_at"])
94
+
95
+ return GoalInDB(**parsed_goal)
96
+
97
+ def delete_goal(user_id: str, goal_id: str) -> bool:
98
+ redis_client = get_redis_client()
99
+ if not redis_client:
100
+ return False
101
+
102
+ pipe = redis_client.pipeline()
103
+ pipe.delete(_get_redis_key(user_id, goal_id))
104
+ pipe.zrem(_get_index_key(user_id), goal_id)
105
+ results = pipe.execute()
106
+
107
+ return results[0] > 0 # True if deleted