Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ new_meeting = client.meeting.create(

# Delete a meeting
client.meeting.delete(meeting_id=123)

# Get multiple meetings by ID (batch read)
result = client.meeting.get_many([123, 456, 789])
for meeting in result.successful:
print(f"{meeting.name} - {meeting.meeting_date}")
# Handle any failed retrievals
for error in result.failed:
print(f"Failed to get meeting: {error.error}")
```

### Todos
Expand Down
11 changes: 11 additions & 0 deletions docs/api/operations/meetings.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ The async version `AsyncMeetingOperations` provides the same methods as above, b

# Get metrics for a meeting
metrics = client.meeting.metrics(meeting_id=123)

# Batch retrieve multiple meetings
result = client.meeting.get_many([123, 456, 789])
for meeting in result.successful:
print(f"{meeting.name}: {len(meeting.attendees)} attendees")
```

=== "Async"
Expand All @@ -72,6 +77,11 @@ The async version `AsyncMeetingOperations` provides the same methods as above, b

# Get metrics for a meeting
metrics = await client.meeting.metrics(meeting_id=123)

# Batch retrieve multiple meetings
result = await client.meeting.get_many([123, 456, 789])
for meeting in result.successful:
print(f"{meeting.name}: {len(meeting.attendees)} attendees")

asyncio.run(main())
```
Expand All @@ -82,6 +92,7 @@ The async version `AsyncMeetingOperations` provides the same methods as above, b
|--------|-------------|------------|
| `list()` | Get all meetings | `include_closed` |
| `details()` | Get detailed meeting information with attendees, issues, todos, and metrics | `meeting_id` |
| `get_many()` | Batch retrieve multiple meetings by ID | `meeting_ids` |
| `attendees()` | Get meeting attendees | `meeting_id` |
| `issues()` | Get issues from a meeting | `meeting_id` |
| `todos()` | Get todos from a meeting | `meeting_id` |
Expand Down
79 changes: 77 additions & 2 deletions docs/guide/bulk-operations.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
# Bulk Operations

The Bloomy SDK provides bulk creation methods for efficiently creating multiple resources at once. These methods use a best-effort approach, processing items sequentially to avoid rate limiting while capturing both successful and failed operations.
The Bloomy SDK provides bulk operations for efficiently working with multiple resources at once. These methods use a best-effort approach, processing items sequentially to avoid rate limiting while capturing both successful and failed operations.

## Overview

Bulk operations are available for:

**Creation:**
- Issues
- Todos
- Meetings
- Goals (Rocks)

**Reading:**
- Meetings (batch retrieve by ID)

Each bulk operation returns a `BulkCreateResult` containing:

- `successful`: List of successfully created items
- `successful`: List of successfully processed items (created or retrieved)
- `failed`: List of `BulkCreateError` objects with failure details

!!! note "Best-Effort Processing"
Expand Down Expand Up @@ -186,6 +190,77 @@ meeting_ids = [m['id'] for m in result.successful]
print(f"Created meetings with IDs: {meeting_ids}")
```

## Batch Reading Operations

### Retrieving Multiple Meetings

The SDK supports batch retrieval of meetings by ID, which is useful when you need details for multiple meetings:

```python
# Get details for multiple meetings
meeting_ids = [123, 456, 789, 999] # IDs to retrieve
result = client.meeting.get_many(meeting_ids)

# Process successful retrievals
print(f"Successfully retrieved {len(result.successful)} meetings:")
for meeting in result.successful:
print(f" - {meeting.name} on {meeting.meeting_date}")
print(f" Attendees: {len(meeting.attendees)}")
print(f" Todos: {len(meeting.todos)}")
print(f" Issues: {len(meeting.issues)}")

# Handle failed retrievals
if result.failed:
print(f"\nFailed to retrieve {len(result.failed)} meetings:")
for failure in result.failed:
meeting_id = failure.input_data.get('meeting_id')
print(f" - Meeting ID {meeting_id}: {failure.error}")
```

### Use Cases for Batch Reading

```python
# Example 1: Get details for all meetings from a list operation
meetings_list = client.meeting.list()
meeting_ids = [m.id for m in meetings_list[:10]] # First 10 meetings

result = client.meeting.get_many(meeting_ids)
meetings_with_details = result.successful

# Example 2: Aggregate data across multiple meetings
def get_all_open_issues(meeting_ids):
"""Get all open issues from multiple meetings."""
result = client.meeting.get_many(meeting_ids)

all_issues = []
for meeting in result.successful:
open_issues = [issue for issue in meeting.issues if not issue.closed]
all_issues.extend(open_issues)

return all_issues

# Example 3: Build a dashboard with meeting metrics
def build_meeting_dashboard(meeting_ids):
"""Build dashboard data for multiple meetings."""
result = client.meeting.get_many(meeting_ids)

dashboard = {
'total_meetings': len(result.successful),
'total_attendees': sum(len(m.attendees) for m in result.successful),
'total_todos': sum(len(m.todos) for m in result.successful),
'total_open_issues': sum(
len([i for i in m.issues if not i.closed])
for m in result.successful
),
'failed_retrievals': len(result.failed)
}

return dashboard
```

!!! note "Performance Considerations"
The `get_many()` method fetches full meeting details including attendees, issues, todos, and metrics for each meeting. For large batches, this can be data-intensive. Consider chunking if retrieving many meetings.

## Error Handling Strategies

### Retry Failed Operations
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "bloomy-python"
version = "0.16.0"
version = "0.17.0"
description = "Python SDK for Bloom Growth API"
readme = "README.md"
authors = [{ name = "Franccesco Orozco", email = "franccesco@codingdose.info" }]
Expand Down
43 changes: 43 additions & 0 deletions src/bloomy/operations/meetings.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,3 +380,46 @@ def create_many(
)

return BulkCreateResult(successful=successful, failed=failed)

def get_many(self, meeting_ids: list[int]) -> BulkCreateResult[MeetingDetails]:
"""Retrieve details for multiple meetings in a best-effort manner.

Processes each meeting ID sequentially to avoid rate limiting.
Failed operations are captured and returned alongside successful ones.

Args:
meeting_ids: List of meeting IDs to retrieve details for

Returns:
BulkCreateResult containing:
- successful: List of MeetingDetails instances for successfully
retrieved meetings
- failed: List of BulkCreateError instances for failed retrievals

Example:
```python
result = client.meeting.get_many([1, 2, 3])

print(f"Retrieved {len(result.successful)} meetings")
for error in result.failed:
print(f"Failed at index {error.index}: {error.error}")
```

"""
successful: builtins.list[MeetingDetails] = []
failed: builtins.list[BulkCreateError] = []

for index, meeting_id in enumerate(meeting_ids):
try:
# Use the existing details method to get meeting details
meeting_details = self.details(meeting_id)
successful.append(meeting_details)

except Exception as e:
failed.append(
BulkCreateError(
index=index, input_data={"meeting_id": meeting_id}, error=str(e)
)
)

return BulkCreateResult(successful=successful, failed=failed)
Loading