Skip to content

Commit e06dde1

Browse files
committed
Refactor team deletion and partition key handling
Simplifies team deletion logic in CosmosDBClient by removing redundant methods and partition key strategies. Adds session_id as a required field in TeamConfiguration and ensures session_id is generated and used consistently in team creation and deletion. Updates TeamService to use the new deletion method.
1 parent 8464f3b commit e06dde1

File tree

4 files changed

+11
-251
lines changed

4 files changed

+11
-251
lines changed

src/backend/common/database/cosmosdb.py

Lines changed: 7 additions & 235 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,9 @@ async def update_item(self, item: BaseDataModel) -> None:
129129
try:
130130
# Convert to dictionary and handle datetime serialization
131131
document = item.model_dump()
132-
document = json.loads(json.dumps(document, cls=DateTimeEncoder))
133-
132+
for key, value in list(document.items()):
133+
if isinstance(value, datetime.datetime):
134+
document[key] = value.isoformat()
134135
await self.container.upsert_item(body=document)
135136
except Exception as e:
136137
self.logger.error("Failed to update item in CosmosDB: %s", str(e))
@@ -164,7 +165,7 @@ async def query_items(
164165
items = self.container.query_items(query=query, parameters=parameters)
165166
result_list = []
166167
async for item in items:
167-
item["ts"] = item["_ts"]
168+
# item["ts"] = item["_ts"]
168169
try:
169170
result_list.append(model_class.model_validate(item))
170171
except Exception as validation_error:
@@ -352,88 +353,10 @@ async def delete_team(self, team_id: str) -> bool:
352353
try:
353354
# First find the team to get its document id and partition key
354355
team = await self.get_team(team_id)
356+
print(team)
355357
if team:
356-
# Use the session_id as partition key, or fall back to user_id if no session_id
357-
partition_key = (
358-
team.session_id
359-
if hasattr(team, "session_id") and team.session_id
360-
else team.user_id
361-
)
362-
await self.container.delete_item(
363-
item=team.id, partition_key=partition_key
364-
)
365-
return True
366-
return False
367-
except Exception as e:
368-
logging.exception(f"Failed to delete team from Cosmos DB: {e}")
369-
return False
370-
371-
async def delete_team_by_id(self, id: str) -> bool:
372-
"""Delete a team configuration by its document id.
373-
374-
Args:
375-
id: The document id of the team configuration to delete
376-
377-
Returns:
378-
True if team was found and deleted, False otherwise
379-
"""
380-
await self._ensure_initialized()
381-
382-
try:
383-
# First find the team to get its partition key
384-
team = await self.get_team_by_id(id)
385-
if team:
386-
# Debug logging
387-
logging.info(f"Attempting to delete team {id}")
388-
logging.info(f"Team user_id: {team.user_id}")
389-
logging.info(
390-
f"Team session_id: {getattr(team, 'session_id', 'NOT_SET')}"
391-
)
392-
393-
# Try different partition key strategies
394-
partition_keys_to_try = []
395-
396-
# Strategy 1: Use session_id if it exists
397-
if hasattr(team, "session_id") and team.session_id:
398-
partition_keys_to_try.append(team.session_id)
399-
logging.info(f"Will try session_id: {team.session_id}")
400-
401-
# Strategy 2: Use user_id as fallback
402-
if team.user_id:
403-
partition_keys_to_try.append(team.user_id)
404-
logging.info(f"Will try user_id: {team.user_id}")
405-
406-
# Strategy 3: Use current context session_id
407-
if self.session_id:
408-
partition_keys_to_try.append(self.session_id)
409-
logging.info(f"Will try context session_id: {self.session_id}")
410-
411-
# Strategy 4: Try null/empty partition key (for documents created without session_id)
412-
partition_keys_to_try.extend([None, ""])
413-
logging.info("Will try null and empty partition keys")
414-
415-
# Try each partition key until one works
416-
for partition_key in partition_keys_to_try:
417-
try:
418-
logging.info(
419-
f"Attempting delete with partition key: {partition_key}"
420-
)
421-
await self.container.delete_item(
422-
item=id, partition_key=partition_key
423-
)
424-
logging.info(
425-
f"Successfully deleted team {id} with partition key: {partition_key}"
426-
)
427-
return True
428-
except Exception as e:
429-
logging.warning(
430-
f"Delete failed with partition key {partition_key}: {str(e)}"
431-
)
432-
continue
433-
434-
logging.error(f"All partition key strategies failed for team {id}")
435-
return False
436-
return False
358+
await self.delete_item(item_id=team.id, partition_key=team.session_id)
359+
return True
437360
except Exception as e:
438361
logging.exception(f"Failed to delete team from Cosmos DB: {e}")
439362
return False
@@ -487,154 +410,3 @@ async def update_team(self, team: TeamConfiguration) -> None:
487410
team: The TeamConfiguration to update
488411
"""
489412
await self.update_item(team)
490-
491-
async def get_team(self, team_id: str) -> Optional[TeamConfiguration]:
492-
"""Retrieve a specific team configuration by team_id.
493-
494-
Args:
495-
team_id: The team_id of the team configuration to retrieve
496-
497-
Returns:
498-
TeamConfiguration object or None if not found
499-
"""
500-
query = "SELECT * FROM c WHERE c.team_id=@team_id AND c.data_type=@data_type"
501-
parameters = [
502-
{"name": "@team_id", "value": team_id},
503-
{"name": "@data_type", "value": "team_config"},
504-
]
505-
teams = await self.query_items(query, parameters, TeamConfiguration)
506-
return teams[0] if teams else None
507-
508-
async def get_team_by_id(self, id: str) -> Optional[TeamConfiguration]:
509-
"""Retrieve a specific team configuration by its document id.
510-
511-
Args:
512-
id: The document id of the team configuration to retrieve
513-
514-
Returns:
515-
TeamConfiguration object or None if not found
516-
"""
517-
query = "SELECT * FROM c WHERE c.id=@id AND c.data_type=@data_type"
518-
parameters = [
519-
{"name": "@id", "value": id},
520-
{"name": "@data_type", "value": "team_config"},
521-
]
522-
teams = await self.query_items(query, parameters, TeamConfiguration)
523-
return teams[0] if teams else None
524-
525-
async def get_all_teams_by_user(self, user_id: str) -> List[TeamConfiguration]:
526-
"""Retrieve all team configurations for a specific user.
527-
528-
Args:
529-
user_id: The user_id to get team configurations for
530-
531-
Returns:
532-
List of TeamConfiguration objects
533-
"""
534-
query = "SELECT * FROM c WHERE c.user_id=@user_id AND c.data_type=@data_type ORDER BY c.created DESC"
535-
parameters = [
536-
{"name": "@user_id", "value": user_id},
537-
{"name": "@data_type", "value": "team_config"},
538-
]
539-
teams = await self.query_items(query, parameters, TeamConfiguration)
540-
return teams
541-
542-
async def delete_team(self, team_id: str) -> bool:
543-
"""Delete a team configuration by team_id.
544-
545-
Args:
546-
team_id: The team_id of the team configuration to delete
547-
548-
Returns:
549-
True if team was found and deleted, False otherwise
550-
"""
551-
await self.ensure_initialized()
552-
553-
try:
554-
# First find the team to get its document id and partition key
555-
team = await self.get_team(team_id)
556-
if team:
557-
# Use the session_id as partition key, or fall back to user_id if no session_id
558-
partition_key = (
559-
team.session_id
560-
if hasattr(team, "session_id") and team.session_id
561-
else team.user_id
562-
)
563-
await self._container.delete_item(
564-
item=team.id, partition_key=partition_key
565-
)
566-
return True
567-
return False
568-
except Exception as e:
569-
logging.exception(f"Failed to delete team from Cosmos DB: {e}")
570-
return False
571-
572-
async def delete_team_by_id(self, id: str) -> bool:
573-
"""Delete a team configuration by its document id.
574-
575-
Args:
576-
id: The document id of the team configuration to delete
577-
578-
Returns:
579-
True if team was found and deleted, False otherwise
580-
"""
581-
await self.ensure_initialized()
582-
583-
try:
584-
# First find the team to get its partition key
585-
team = await self.get_team_by_id(id)
586-
if team:
587-
# Debug logging
588-
logging.info(f"Attempting to delete team {id}")
589-
logging.info(f"Team user_id: {team.user_id}")
590-
logging.info(
591-
f"Team session_id: {getattr(team, 'session_id', 'NOT_SET')}"
592-
)
593-
594-
# Try different partition key strategies
595-
partition_keys_to_try = []
596-
597-
# Strategy 1: Use session_id if it exists
598-
if hasattr(team, "session_id") and team.session_id:
599-
partition_keys_to_try.append(team.session_id)
600-
logging.info(f"Will try session_id: {team.session_id}")
601-
602-
# Strategy 2: Use user_id as fallback
603-
if team.user_id:
604-
partition_keys_to_try.append(team.user_id)
605-
logging.info(f"Will try user_id: {team.user_id}")
606-
607-
# Strategy 3: Use current context session_id
608-
if self.session_id:
609-
partition_keys_to_try.append(self.session_id)
610-
logging.info(f"Will try context session_id: {self.session_id}")
611-
612-
# Strategy 4: Try null/empty partition key (for documents created without session_id)
613-
partition_keys_to_try.extend([None, ""])
614-
logging.info("Will try null and empty partition keys")
615-
616-
# Try each partition key until one works
617-
for partition_key in partition_keys_to_try:
618-
try:
619-
logging.info(
620-
f"Attempting delete with partition key: {partition_key}"
621-
)
622-
await self._container.delete_item(
623-
item=id, partition_key=partition_key
624-
)
625-
logging.info(
626-
f"Successfully deleted team {id} with partition key: {partition_key}"
627-
)
628-
return True
629-
except Exception as e:
630-
logging.warning(
631-
f"Delete failed with partition key {partition_key}: {str(e)}"
632-
)
633-
continue
634-
635-
logging.error(f"All partition key strategies failed for team {id}")
636-
return False
637-
return False
638-
except Exception as e:
639-
logging.exception(f"Failed to delete team from Cosmos DB: {e}")
640-
return False

src/backend/common/database/database_base.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,6 @@ async def delete_team(self, team_id: str) -> bool:
157157
"""Delete a team configuration by team_id and return True if deleted."""
158158
pass
159159

160-
@abstractmethod
161-
async def delete_team_by_id(self, id: str) -> bool:
162-
"""Delete a team configuration by internal id and return True if deleted."""
163-
pass
164-
165160
# Data Management Operations
166161
@abstractmethod
167162
async def get_data_by_type(self, data_type: str) -> List[BaseDataModel]:

src/backend/common/models/messages_kernel.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ class TeamConfiguration(BaseDataModel):
178178

179179
team_id: str
180180
data_type: Literal["team_config"] = Field("team_config", Literal=True)
181+
session_id: str # Partition key
181182
name: str
182183
status: str
183184
created: str

src/backend/v3/common/services/team_service.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ async def validate_and_parse_team_config(
6767

6868
# Generate unique IDs and timestamps
6969
unique_team_id = str(uuid.uuid4())
70+
session_id = str(uuid.uuid4())
7071
current_timestamp = datetime.now(timezone.utc).isoformat()
7172

7273
# Validate agents array exists and is not empty
@@ -104,6 +105,7 @@ async def validate_and_parse_team_config(
104105
# Create team configuration
105106
team_config = TeamConfiguration(
106107
id=unique_team_id, # Use generated GUID
108+
session_id=session_id,
107109
team_id=unique_team_id, # Use generated GUID
108110
name=json_data["name"],
109111
status=json_data["status"],
@@ -253,17 +255,7 @@ async def delete_team_configuration(self, team_id: str, user_id: str) -> bool:
253255
"""
254256
try:
255257
# First, verify the configuration exists and belongs to the user
256-
team_config = await self.memory_context.get_team_by_id(team_id)
257-
258-
if team_config is None:
259-
self.logger.warning(
260-
"Team configuration not found for deletion: %s", team_id
261-
)
262-
return False
263-
264-
# Delete the configuration using the specific delete_team_by_id method
265-
success = await self.memory_context.delete_team_by_id(team_id)
266-
258+
success = await self.memory_context.delete_team(team_id)
267259
if success:
268260
self.logger.info("Successfully deleted team configuration: %s", team_id)
269261

0 commit comments

Comments
 (0)