Delta Synchronization
Delta sync enables efficient incremental data synchronization by fetching only records modified since your last sync. HTTP calls use intapp-rest-client; see Error handling for API errors.
Overview
| Method | Purpose |
|---|---|
get_modified_entries() | Get IDs modified since a datetime |
aget_modified_entries() | Async version |
sync_delta() | Convenience helper for common pattern |
Quick Start
from dealcloud_sdk import DealCloud, DealCloudConfig
from datetime import datetime, timedelta
config = DealCloudConfig(
siteUrl="yoursite.dealcloud.com",
clientId=12345,
clientSecret="your-secret",
)
dc = DealCloud.from_config_object(config)
# Get changes from last hour
last_sync = datetime.now() - timedelta(hours=1)
result = dc.sync_delta("Company", last_sync)
print(f"Modified: {len(result.modified_ids)}")
print(f"Deleted: {len(result.deleted_ids)}")
# Process changes
for row in result.modified_data:
your_db.upsert(row)
for entry_id in result.deleted_ids:
your_db.delete(entry_id)get_modified_entries()
Returns Entry IDs modified since a specific datetime:
from datetime import datetime, timedelta
# Get modified entries
last_sync = datetime.now() - timedelta(days=1)
changes = dc.get_modified_entries("Company", last_sync)
for change in changes:
print(f"Entry {change.entry_id}: deleted={change.is_deleted}")Return Value
@dataclass
class ModifiedEntry:
entry_id: int
modified_date: datetime
is_deleted: boolParameters
| Parameter | Type | Description |
|---|---|---|
object_id | str | int | Object API name or ID |
modified_since | datetime | str | Cutoff datetime |
include_deleted | bool | Include deleted entries (default: True) |
đź’ˇ
get_modified_entries() returns ALL modified IDs in a single response - no pagination. The response is lightweight (just IDs and metadata).
sync_delta()
The sync_delta() helper implements the most common delta sync pattern:
from datetime import datetime, timedelta
last_sync = datetime.now() - timedelta(hours=1)
# All-in-one delta sync
result = dc.sync_delta(
"Company",
last_sync,
fields=["CompanyName", "Revenue", "Status"], # Optional
output="list" # or "pandas"
)
# Result contains everything you need
print(f"Sync timestamp: {result.sync_timestamp}")
print(f"Modified IDs: {result.modified_ids}")
print(f"Deleted IDs: {result.deleted_ids}")
print(f"Modified data: {len(result.modified_data)} records")Return Value
@dataclass
class DeltaSyncResult:
sync_timestamp: datetime # Timestamp for next sync
modified_ids: List[int] # IDs that were modified
deleted_ids: List[int] # IDs that were deleted
modified_data: List[dict] # Full data for modified recordsParameters
| Parameter | Type | Description |
|---|---|---|
object_id | str | int | Object API name or ID |
modified_since | datetime | str | Cutoff datetime |
fields | List[str] | Fields to fetch (default: all) |
output | str | "list", "pandas", "polars", or "polars_lazy" |
include_deleted | bool | Include deleted entries |
Output Formats
from datetime import datetime, timedelta
last_sync = datetime.now() - timedelta(hours=1)
# List (default)
result = dc.sync_delta("Company", last_sync)
for row in result.modified_data:
print(row)
# Pandas DataFrame
result = dc.sync_delta("Company", last_sync, output="pandas")
df = result.modified_data # pandas.DataFrame
# Polars DataFrame
result = dc.sync_delta("Company", last_sync, output="polars")
df = result.modified_data # polars.DataFrame
# Polars LazyFrame (for optimization)
result = dc.sync_delta("Company", last_sync, output="polars_lazy")
lf = result.modified_data # polars.LazyFrame
df = lf.collect() # Execute lazy operationsBuilding Your Own Pattern
For custom requirements, use get_modified_entries() directly:
from datetime import datetime, timedelta
from dealcloud_sdk import DealCloud, DealCloudConfig
config = DealCloudConfig(
siteUrl="yoursite.dealcloud.com",
clientId=12345,
clientSecret="your-secret",
)
dc = DealCloud.from_config_object(config)
# 1. Get modified entry IDs
last_sync = datetime.now() - timedelta(hours=6)
changes = dc.get_modified_entries("Company", last_sync)
# 2. Separate modifications from deletions
modified_ids = [c.entry_id for c in changes if not c.is_deleted]
deleted_ids = [c.entry_id for c in changes if c.is_deleted]
print(f"Modified: {len(modified_ids)}, Deleted: {len(deleted_ids)}")
# 3. Fetch data for modifications
if modified_ids:
# Choose method based on volume
if len(modified_ids) < 500:
# Small batch: direct query
# Option 1: DealCloud query string format (simpler)
ids_str = ",".join(map(str, modified_ids))
data = dc.read_data(
"Company",
output="list",
query=f"EntryId in ({ids_str})"
)
# Option 2: MongoDB-style format (also works)
# data = dc.read_data(
# "Company",
# output="list",
# query=f"{{EntryId: {{$in: [{ids_str}]}}}}"
# )
else:
# Large batch: streaming
ids_str = ",".join(map(str, modified_ids))
for row in dc.read_data_streaming(
"Company",
query=f"EntryId in ({ids_str})"
):
process_row(row)
# 4. Handle deletions
for entry_id in deleted_ids:
your_db.delete(entry_id)
# 5. Save sync timestamp
save_last_sync(datetime.now())Async Version
import asyncio
from datetime import datetime, timedelta
from dealcloud_sdk import DealCloud, DealCloudConfig
async def delta_sync_async():
config = DealCloudConfig(
siteUrl="yoursite.dealcloud.com",
clientId=12345,
clientSecret="your-secret",
)
dc = DealCloud.from_config_object(config)
last_sync = datetime.now() - timedelta(hours=1)
changes = await dc.aget_modified_entries("Company", last_sync)
modified_ids = [c.entry_id for c in changes if not c.is_deleted]
# Process asynchronously
ids_str = ",".join(map(str, modified_ids))
async for row in dc.aread_data_streaming(
"Company",
query=f"EntryId in ({ids_str})"
):
await process_async(row)
asyncio.run(delta_sync_async())Complete Sync Pipeline
from dealcloud_sdk import DealCloud, DealCloudConfig
from datetime import datetime
import json
from pathlib import Path
config = DealCloudConfig(
siteUrl="yoursite.dealcloud.com",
clientId=12345,
clientSecret="your-secret",
)
dc = DealCloud.from_config_object(config)
class SyncState:
"""Persist sync state between runs."""
def __init__(self, filepath="sync_state.json"):
self.filepath = Path(filepath)
def get_last_sync(self, object_id: str) -> datetime:
if self.filepath.exists():
with open(self.filepath) as f:
state = json.load(f)
ts = state.get(object_id)
if ts:
return datetime.fromisoformat(ts)
return datetime.min # First sync: get everything
def save_sync(self, object_id: str, timestamp: datetime):
state = {}
if self.filepath.exists():
with open(self.filepath) as f:
state = json.load(f)
state[object_id] = timestamp.isoformat()
with open(self.filepath, "w") as f:
json.dump(state, f)
def sync_object(object_id: str, process_record, delete_record):
"""
Sync a DealCloud object incrementally.
Args:
object_id: Object to sync
process_record: Function to handle modified records
delete_record: Function to handle deletions
"""
state = SyncState()
last_sync = state.get_last_sync(object_id)
print(f"Syncing {object_id} since {last_sync}")
result = dc.sync_delta(object_id, last_sync)
# Process modifications
for record in result.modified_data:
process_record(record)
# Process deletions
for entry_id in result.deleted_ids:
delete_record(entry_id)
# Save state
state.save_sync(object_id, result.sync_timestamp)
print(f" Modified: {len(result.modified_ids)}")
print(f" Deleted: {len(result.deleted_ids)}")
# Usage
def upsert_to_warehouse(record):
# Your logic here
pass
def delete_from_warehouse(entry_id):
# Your logic here
pass
sync_object("Company", upsert_to_warehouse, delete_from_warehouse)
sync_object("Contact", upsert_to_warehouse, delete_from_warehouse)
sync_object("Deal", upsert_to_warehouse, delete_from_warehouse)Performance Considerations
Small Deltas (< 500 records)
# Simple approach for small deltas
result = dc.sync_delta("Company", last_sync, output="list")
process_all(result.modified_data)Large Deltas (> 500 records)
# Streaming for large deltas
changes = dc.get_modified_entries("Company", last_sync)
modified_ids = [c.entry_id for c in changes if not c.is_deleted]
if modified_ids:
ids_str = ",".join(map(str, modified_ids))
ids_query = f"EntryId in ({ids_str})"
for row in dc.read_data_streaming("Company", query=ids_query):
process_one(row) # Memory-efficientFull Sync vs Delta
| Scenario | Approach |
|---|---|
| First sync | Full read with read_data() |
| Regular intervals | Delta with sync_delta() |
| Large changes | Delta with streaming |
| Very old last_sync | Consider full sync |
Related
- Streaming Reads - Memory-efficient reads
- History API - Detailed change history
- ID Mapping - External ID management