Skip to content

Conversation

@tpellissier-msft
Copy link
Collaborator

Summary

This PR implements Phase 1 of the SDK restructure plan, introducing the fluent .with_detail_response() API pattern for accessing telemetry while maintaining full backward compatibility.

  • PR 1.1: Add core result types (RequestMetadata, DataverseResponse, FluentResult)
  • PR 1.2: Add internal metadata capture to _odata.py and _http.py
  • PR 1.3: Integrate FluentResult into client.py with backward compatibility

Backward Compatibility

Existing code continues to work unchanged:

# Old code still works
ids = client.create("account", {"name": "Contoso"})
print(ids[0])  # Works via __getitem__
for id in ids:  # Works via __iter__
    print(id)

New Telemetry Access

# New code can access telemetry
response = client.create("account", {"name": "A"}).with_detail_response()
print(response.telemetry['timing_ms'])      # Request duration
print(response.telemetry['client_request_id'])  # For tracing
print(response.telemetry['batch_info'])     # For bulk operations

Key Changes

New Types in core/results.py:

  • RequestMetadata - HTTP request/response metadata dataclass
  • DataverseResponse[T] - Generic response with result + telemetry dict
  • FluentResult[T] - Wrapper enabling .with_detail_response() pattern

Updated Methods in client.py:

  • create()FluentResult[List[str]]
  • update()FluentResult[None]
  • delete()FluentResult[Optional[str]]
  • get() (single record) → FluentResult[Dict]

Test plan

  • All 81 existing unit tests pass
  • New tests for RequestMetadata, DataverseResponse, FluentResult (44 tests)
  • Updated test_client.py tests for new _with_metadata methods
  • Backward compatibility tests for iteration, indexing, equality

🤖 Generated with Claude Code

tpellissier and others added 3 commits January 25, 2026 22:34
Introduces foundational types that enable the `.with_detail_response()` fluent API pattern:

- RequestMetadata: HTTP request/response metadata for diagnostics (client_request_id, correlation_id, service_request_id, http_status_code, timing_ms)
- DataverseResponse[T]: Generic response object with result and telemetry dict
- FluentResult[T]: Wrapper enabling fluent pattern - acts like result by default, returns DataverseResponse via .with_detail_response()

FluentResult implements magic methods (__iter__, __getitem__, __len__, __eq__, __bool__, __contains__, __hash__) for transparent backward compatibility.

Existing OperationResult, CreateResult, UpdateResult, DeleteResult, GetResult, PagedResult types remain unchanged for backward compatibility.

Includes comprehensive unit tests (44 tests) covering:
- RequestMetadata dataclass behavior
- DataverseResponse structure
- FluentResult wrapper with all magic methods
- Legacy type backward compatibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds infrastructure for capturing request/response metadata to enable
the fluent .with_detail_response() API pattern.

Changes to _http.py:
- Add _HttpTiming dataclass for request timing info (elapsed_ms, attempts)
- Add _request_with_timing() method that returns (response, timing)

Changes to _odata.py:
- Import RequestMetadata from core.results
- Add _request_with_metadata() that returns (response, RequestMetadata)
- Add _create_with_metadata() returning (record_id, RequestMetadata)
- Add _create_multiple_with_metadata() returning (ids, metadata, batch_info)
- Add _update_with_metadata() returning (None, RequestMetadata)
- Add _delete_with_metadata() returning (None, RequestMetadata)
- Add _get_with_metadata() returning (record, RequestMetadata)

These internal methods capture:
- client_request_id from request headers
- correlation_id from request headers
- service_request_id from response headers
- http_status_code from response
- timing_ms from HTTP timing

The original methods remain unchanged for backward compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updates DataverseClient methods to return FluentResult wrappers that:
- Act like the original return types by default (backward compatible)
- Support .with_detail_response() for accessing telemetry

Changes to client.py:
- Import FluentResult and RequestMetadata from core.results
- create() now returns FluentResult[List[str]] with batch_info
- update() now returns FluentResult[None] with metadata
- delete() now returns FluentResult[Optional[str]] with metadata
- get() for single record returns FluentResult[Dict] with metadata
- get() for multiple records unchanged (returns iterator)

Backward compatibility maintained:
- ids = client.create("account", {"name": "A"})  # Works as before
- ids[0]  # Works via __getitem__
- for id in ids:  # Works via __iter__
- len(ids)  # Works via __len__

New telemetry access:
- response = client.create(...).with_detail_response()
- response.telemetry['timing_ms']  # Request duration
- response.telemetry['client_request_id']  # For tracing
- response.telemetry['batch_info']  # For bulk operations

Updates test_client.py:
- Tests now use _with_metadata mock methods
- Added tests for .with_detail_response() pattern
- All 10 client tests pass

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants