airbyte-agent-salesforce 0.1.17__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- airbyte_agent_salesforce/__init__.py +87 -0
- airbyte_agent_salesforce/_vendored/__init__.py +1 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/__init__.py +82 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/auth_strategies.py +1123 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/auth_template.py +135 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/cloud_utils/__init__.py +5 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/cloud_utils/client.py +213 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/connector_model_loader.py +957 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/constants.py +78 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/exceptions.py +23 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/executor/__init__.py +31 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/executor/hosted_executor.py +197 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/executor/local_executor.py +1504 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/executor/models.py +190 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/extensions.py +655 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/http/__init__.py +37 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/http/adapters/__init__.py +9 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/http/adapters/httpx_adapter.py +251 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/http/config.py +98 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/http/exceptions.py +119 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/http/protocols.py +114 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/http/response.py +102 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/http_client.py +686 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/logging/__init__.py +11 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/logging/logger.py +264 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/logging/types.py +92 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/observability/__init__.py +11 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/observability/models.py +19 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/observability/redactor.py +81 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/observability/session.py +94 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/performance/__init__.py +6 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/performance/instrumentation.py +57 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/performance/metrics.py +93 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/schema/__init__.py +75 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/schema/base.py +161 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/schema/components.py +238 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/schema/connector.py +131 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/schema/extensions.py +109 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/schema/operations.py +146 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/schema/security.py +213 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/secrets.py +182 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/telemetry/__init__.py +10 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/telemetry/config.py +32 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/telemetry/events.py +58 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/telemetry/tracker.py +151 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/types.py +241 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/utils.py +60 -0
- airbyte_agent_salesforce/_vendored/connector_sdk/validation.py +822 -0
- airbyte_agent_salesforce/connector.py +1862 -0
- airbyte_agent_salesforce/connector_model.py +1597 -0
- airbyte_agent_salesforce/models.py +365 -0
- airbyte_agent_salesforce/types.py +166 -0
- airbyte_agent_salesforce-0.1.17.dist-info/METADATA +113 -0
- airbyte_agent_salesforce-0.1.17.dist-info/RECORD +55 -0
- airbyte_agent_salesforce-0.1.17.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,1862 @@
|
|
|
1
|
+
"""
|
|
2
|
+
salesforce connector.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING, Any, AsyncIterator, overload
|
|
8
|
+
try:
|
|
9
|
+
from typing import Literal
|
|
10
|
+
except ImportError:
|
|
11
|
+
from typing_extensions import Literal
|
|
12
|
+
|
|
13
|
+
from .connector_model import SalesforceConnectorModel
|
|
14
|
+
|
|
15
|
+
from .types import (
|
|
16
|
+
AccountsGetParams,
|
|
17
|
+
AccountsListParams,
|
|
18
|
+
AccountsSearchParams,
|
|
19
|
+
AttachmentsDownloadParams,
|
|
20
|
+
AttachmentsGetParams,
|
|
21
|
+
AttachmentsListParams,
|
|
22
|
+
CampaignsGetParams,
|
|
23
|
+
CampaignsListParams,
|
|
24
|
+
CampaignsSearchParams,
|
|
25
|
+
CasesGetParams,
|
|
26
|
+
CasesListParams,
|
|
27
|
+
CasesSearchParams,
|
|
28
|
+
ContactsGetParams,
|
|
29
|
+
ContactsListParams,
|
|
30
|
+
ContactsSearchParams,
|
|
31
|
+
ContentVersionsDownloadParams,
|
|
32
|
+
ContentVersionsGetParams,
|
|
33
|
+
ContentVersionsListParams,
|
|
34
|
+
EventsGetParams,
|
|
35
|
+
EventsListParams,
|
|
36
|
+
EventsSearchParams,
|
|
37
|
+
LeadsGetParams,
|
|
38
|
+
LeadsListParams,
|
|
39
|
+
LeadsSearchParams,
|
|
40
|
+
NotesGetParams,
|
|
41
|
+
NotesListParams,
|
|
42
|
+
NotesSearchParams,
|
|
43
|
+
OpportunitiesGetParams,
|
|
44
|
+
OpportunitiesListParams,
|
|
45
|
+
OpportunitiesSearchParams,
|
|
46
|
+
QueryListParams,
|
|
47
|
+
TasksGetParams,
|
|
48
|
+
TasksListParams,
|
|
49
|
+
TasksSearchParams,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if TYPE_CHECKING:
|
|
53
|
+
from .models import SalesforceAuthConfig
|
|
54
|
+
# Import response models and envelope models at runtime
|
|
55
|
+
from .models import (
|
|
56
|
+
SalesforceExecuteResult,
|
|
57
|
+
SalesforceExecuteResultWithMeta,
|
|
58
|
+
Account,
|
|
59
|
+
AccountQueryResult,
|
|
60
|
+
Attachment,
|
|
61
|
+
AttachmentQueryResult,
|
|
62
|
+
Campaign,
|
|
63
|
+
CampaignQueryResult,
|
|
64
|
+
Case,
|
|
65
|
+
CaseQueryResult,
|
|
66
|
+
Contact,
|
|
67
|
+
ContactQueryResult,
|
|
68
|
+
ContentVersion,
|
|
69
|
+
ContentVersionQueryResult,
|
|
70
|
+
Event,
|
|
71
|
+
EventQueryResult,
|
|
72
|
+
Lead,
|
|
73
|
+
LeadQueryResult,
|
|
74
|
+
Note,
|
|
75
|
+
NoteQueryResult,
|
|
76
|
+
Opportunity,
|
|
77
|
+
OpportunityQueryResult,
|
|
78
|
+
QueryResult,
|
|
79
|
+
SearchResult,
|
|
80
|
+
Task,
|
|
81
|
+
TaskQueryResult,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class SalesforceConnector:
|
|
86
|
+
"""
|
|
87
|
+
Type-safe Salesforce API connector.
|
|
88
|
+
|
|
89
|
+
Auto-generated from OpenAPI specification with full type safety.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
connector_name = "salesforce"
|
|
93
|
+
connector_version = "1.0.3"
|
|
94
|
+
vendored_sdk_version = "0.1.0" # Version of vendored connector-sdk
|
|
95
|
+
|
|
96
|
+
# Map of (entity, action) -> has_extractors for envelope wrapping decision
|
|
97
|
+
_EXTRACTOR_MAP = {
|
|
98
|
+
("accounts", "list"): False,
|
|
99
|
+
("accounts", "get"): False,
|
|
100
|
+
("accounts", "search"): False,
|
|
101
|
+
("contacts", "list"): False,
|
|
102
|
+
("contacts", "get"): False,
|
|
103
|
+
("contacts", "search"): False,
|
|
104
|
+
("leads", "list"): False,
|
|
105
|
+
("leads", "get"): False,
|
|
106
|
+
("leads", "search"): False,
|
|
107
|
+
("opportunities", "list"): False,
|
|
108
|
+
("opportunities", "get"): False,
|
|
109
|
+
("opportunities", "search"): False,
|
|
110
|
+
("tasks", "list"): False,
|
|
111
|
+
("tasks", "get"): False,
|
|
112
|
+
("tasks", "search"): False,
|
|
113
|
+
("events", "list"): False,
|
|
114
|
+
("events", "get"): False,
|
|
115
|
+
("events", "search"): False,
|
|
116
|
+
("campaigns", "list"): False,
|
|
117
|
+
("campaigns", "get"): False,
|
|
118
|
+
("campaigns", "search"): False,
|
|
119
|
+
("cases", "list"): False,
|
|
120
|
+
("cases", "get"): False,
|
|
121
|
+
("cases", "search"): False,
|
|
122
|
+
("notes", "list"): False,
|
|
123
|
+
("notes", "get"): False,
|
|
124
|
+
("notes", "search"): False,
|
|
125
|
+
("content_versions", "list"): False,
|
|
126
|
+
("content_versions", "get"): False,
|
|
127
|
+
("content_versions", "download"): False,
|
|
128
|
+
("attachments", "list"): False,
|
|
129
|
+
("attachments", "get"): False,
|
|
130
|
+
("attachments", "download"): False,
|
|
131
|
+
("query", "list"): False,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# Map of (entity, action) -> {python_param_name: api_param_name}
|
|
135
|
+
# Used to convert snake_case TypedDict keys to API parameter names in execute()
|
|
136
|
+
_PARAM_MAP = {
|
|
137
|
+
('accounts', 'list'): {'q': 'q'},
|
|
138
|
+
('accounts', 'get'): {'id': 'id', 'fields': 'fields'},
|
|
139
|
+
('accounts', 'search'): {'q': 'q'},
|
|
140
|
+
('contacts', 'list'): {'q': 'q'},
|
|
141
|
+
('contacts', 'get'): {'id': 'id', 'fields': 'fields'},
|
|
142
|
+
('contacts', 'search'): {'q': 'q'},
|
|
143
|
+
('leads', 'list'): {'q': 'q'},
|
|
144
|
+
('leads', 'get'): {'id': 'id', 'fields': 'fields'},
|
|
145
|
+
('leads', 'search'): {'q': 'q'},
|
|
146
|
+
('opportunities', 'list'): {'q': 'q'},
|
|
147
|
+
('opportunities', 'get'): {'id': 'id', 'fields': 'fields'},
|
|
148
|
+
('opportunities', 'search'): {'q': 'q'},
|
|
149
|
+
('tasks', 'list'): {'q': 'q'},
|
|
150
|
+
('tasks', 'get'): {'id': 'id', 'fields': 'fields'},
|
|
151
|
+
('tasks', 'search'): {'q': 'q'},
|
|
152
|
+
('events', 'list'): {'q': 'q'},
|
|
153
|
+
('events', 'get'): {'id': 'id', 'fields': 'fields'},
|
|
154
|
+
('events', 'search'): {'q': 'q'},
|
|
155
|
+
('campaigns', 'list'): {'q': 'q'},
|
|
156
|
+
('campaigns', 'get'): {'id': 'id', 'fields': 'fields'},
|
|
157
|
+
('campaigns', 'search'): {'q': 'q'},
|
|
158
|
+
('cases', 'list'): {'q': 'q'},
|
|
159
|
+
('cases', 'get'): {'id': 'id', 'fields': 'fields'},
|
|
160
|
+
('cases', 'search'): {'q': 'q'},
|
|
161
|
+
('notes', 'list'): {'q': 'q'},
|
|
162
|
+
('notes', 'get'): {'id': 'id', 'fields': 'fields'},
|
|
163
|
+
('notes', 'search'): {'q': 'q'},
|
|
164
|
+
('content_versions', 'list'): {'q': 'q'},
|
|
165
|
+
('content_versions', 'get'): {'id': 'id', 'fields': 'fields'},
|
|
166
|
+
('content_versions', 'download'): {'id': 'id', 'range_header': 'range_header'},
|
|
167
|
+
('attachments', 'list'): {'q': 'q'},
|
|
168
|
+
('attachments', 'get'): {'id': 'id', 'fields': 'fields'},
|
|
169
|
+
('attachments', 'download'): {'id': 'id', 'range_header': 'range_header'},
|
|
170
|
+
('query', 'list'): {'q': 'q'},
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
def __init__(
|
|
174
|
+
self,
|
|
175
|
+
auth_config: SalesforceAuthConfig | None = None,
|
|
176
|
+
external_user_id: str | None = None,
|
|
177
|
+
airbyte_client_id: str | None = None,
|
|
178
|
+
airbyte_client_secret: str | None = None,
|
|
179
|
+
on_token_refresh: Any | None = None,
|
|
180
|
+
instance_url: str | None = None ):
|
|
181
|
+
"""
|
|
182
|
+
Initialize a new salesforce connector instance.
|
|
183
|
+
|
|
184
|
+
Supports both local and hosted execution modes:
|
|
185
|
+
- Local mode: Provide `auth_config` for direct API calls
|
|
186
|
+
- Hosted mode: Provide `external_user_id`, `airbyte_client_id`, and `airbyte_client_secret` for hosted execution
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
auth_config: Typed authentication configuration (required for local mode)
|
|
190
|
+
external_user_id: External user ID (required for hosted mode)
|
|
191
|
+
airbyte_client_id: Airbyte OAuth client ID (required for hosted mode)
|
|
192
|
+
airbyte_client_secret: Airbyte OAuth client secret (required for hosted mode)
|
|
193
|
+
on_token_refresh: Optional callback for OAuth2 token refresh persistence.
|
|
194
|
+
Called with new_tokens dict when tokens are refreshed. Can be sync or async.
|
|
195
|
+
Example: lambda tokens: save_to_database(tokens) instance_url: Your Salesforce instance URL (e.g., https://na1.salesforce.com)
|
|
196
|
+
Examples:
|
|
197
|
+
# Local mode (direct API calls)
|
|
198
|
+
connector = SalesforceConnector(auth_config=SalesforceAuthConfig(refresh_token="...", client_id="...", client_secret="..."))
|
|
199
|
+
# Hosted mode (executed on Airbyte cloud)
|
|
200
|
+
connector = SalesforceConnector(
|
|
201
|
+
external_user_id="user-123",
|
|
202
|
+
airbyte_client_id="client_abc123",
|
|
203
|
+
airbyte_client_secret="secret_xyz789"
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# Local mode with OAuth2 token refresh callback
|
|
207
|
+
def save_tokens(new_tokens: dict) -> None:
|
|
208
|
+
# Persist updated tokens to your storage (file, database, etc.)
|
|
209
|
+
with open("tokens.json", "w") as f:
|
|
210
|
+
json.dump(new_tokens, f)
|
|
211
|
+
|
|
212
|
+
connector = SalesforceConnector(
|
|
213
|
+
auth_config=SalesforceAuthConfig(access_token="...", refresh_token="..."),
|
|
214
|
+
on_token_refresh=save_tokens
|
|
215
|
+
)
|
|
216
|
+
"""
|
|
217
|
+
# Hosted mode: external_user_id, airbyte_client_id, and airbyte_client_secret provided
|
|
218
|
+
if external_user_id and airbyte_client_id and airbyte_client_secret:
|
|
219
|
+
from ._vendored.connector_sdk.executor import HostedExecutor
|
|
220
|
+
self._executor = HostedExecutor(
|
|
221
|
+
external_user_id=external_user_id,
|
|
222
|
+
airbyte_client_id=airbyte_client_id,
|
|
223
|
+
airbyte_client_secret=airbyte_client_secret,
|
|
224
|
+
connector_definition_id=str(SalesforceConnectorModel.id),
|
|
225
|
+
)
|
|
226
|
+
else:
|
|
227
|
+
# Local mode: auth_config required
|
|
228
|
+
if not auth_config:
|
|
229
|
+
raise ValueError(
|
|
230
|
+
"Either provide (external_user_id, airbyte_client_id, airbyte_client_secret) for hosted mode "
|
|
231
|
+
"or auth_config for local mode"
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
from ._vendored.connector_sdk.executor import LocalExecutor
|
|
235
|
+
|
|
236
|
+
# Build config_values dict from server variables
|
|
237
|
+
config_values: dict[str, str] = {}
|
|
238
|
+
if instance_url:
|
|
239
|
+
config_values["instance_url"] = instance_url
|
|
240
|
+
|
|
241
|
+
self._executor = LocalExecutor(
|
|
242
|
+
model=SalesforceConnectorModel,
|
|
243
|
+
auth_config=auth_config.model_dump() if auth_config else None,
|
|
244
|
+
config_values=config_values,
|
|
245
|
+
on_token_refresh=on_token_refresh
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
# Update base_url with server variables if provided
|
|
249
|
+
base_url = self._executor.http_client.base_url
|
|
250
|
+
if instance_url:
|
|
251
|
+
base_url = base_url.replace("{instance_url}", instance_url)
|
|
252
|
+
self._executor.http_client.base_url = base_url
|
|
253
|
+
|
|
254
|
+
# Initialize entity query objects
|
|
255
|
+
self.accounts = AccountsQuery(self)
|
|
256
|
+
self.contacts = ContactsQuery(self)
|
|
257
|
+
self.leads = LeadsQuery(self)
|
|
258
|
+
self.opportunities = OpportunitiesQuery(self)
|
|
259
|
+
self.tasks = TasksQuery(self)
|
|
260
|
+
self.events = EventsQuery(self)
|
|
261
|
+
self.campaigns = CampaignsQuery(self)
|
|
262
|
+
self.cases = CasesQuery(self)
|
|
263
|
+
self.notes = NotesQuery(self)
|
|
264
|
+
self.content_versions = ContentVersionsQuery(self)
|
|
265
|
+
self.attachments = AttachmentsQuery(self)
|
|
266
|
+
self.query = QueryQuery(self)
|
|
267
|
+
|
|
268
|
+
# ===== TYPED EXECUTE METHOD (Recommended Interface) =====
|
|
269
|
+
|
|
270
|
+
@overload
|
|
271
|
+
async def execute(
|
|
272
|
+
self,
|
|
273
|
+
entity: Literal["accounts"],
|
|
274
|
+
action: Literal["list"],
|
|
275
|
+
params: "AccountsListParams"
|
|
276
|
+
) -> "AccountQueryResult": ...
|
|
277
|
+
|
|
278
|
+
@overload
|
|
279
|
+
async def execute(
|
|
280
|
+
self,
|
|
281
|
+
entity: Literal["accounts"],
|
|
282
|
+
action: Literal["get"],
|
|
283
|
+
params: "AccountsGetParams"
|
|
284
|
+
) -> "Account": ...
|
|
285
|
+
|
|
286
|
+
@overload
|
|
287
|
+
async def execute(
|
|
288
|
+
self,
|
|
289
|
+
entity: Literal["accounts"],
|
|
290
|
+
action: Literal["search"],
|
|
291
|
+
params: "AccountsSearchParams"
|
|
292
|
+
) -> "SearchResult": ...
|
|
293
|
+
|
|
294
|
+
@overload
|
|
295
|
+
async def execute(
|
|
296
|
+
self,
|
|
297
|
+
entity: Literal["contacts"],
|
|
298
|
+
action: Literal["list"],
|
|
299
|
+
params: "ContactsListParams"
|
|
300
|
+
) -> "ContactQueryResult": ...
|
|
301
|
+
|
|
302
|
+
@overload
|
|
303
|
+
async def execute(
|
|
304
|
+
self,
|
|
305
|
+
entity: Literal["contacts"],
|
|
306
|
+
action: Literal["get"],
|
|
307
|
+
params: "ContactsGetParams"
|
|
308
|
+
) -> "Contact": ...
|
|
309
|
+
|
|
310
|
+
@overload
|
|
311
|
+
async def execute(
|
|
312
|
+
self,
|
|
313
|
+
entity: Literal["contacts"],
|
|
314
|
+
action: Literal["search"],
|
|
315
|
+
params: "ContactsSearchParams"
|
|
316
|
+
) -> "SearchResult": ...
|
|
317
|
+
|
|
318
|
+
@overload
|
|
319
|
+
async def execute(
|
|
320
|
+
self,
|
|
321
|
+
entity: Literal["leads"],
|
|
322
|
+
action: Literal["list"],
|
|
323
|
+
params: "LeadsListParams"
|
|
324
|
+
) -> "LeadQueryResult": ...
|
|
325
|
+
|
|
326
|
+
@overload
|
|
327
|
+
async def execute(
|
|
328
|
+
self,
|
|
329
|
+
entity: Literal["leads"],
|
|
330
|
+
action: Literal["get"],
|
|
331
|
+
params: "LeadsGetParams"
|
|
332
|
+
) -> "Lead": ...
|
|
333
|
+
|
|
334
|
+
@overload
|
|
335
|
+
async def execute(
|
|
336
|
+
self,
|
|
337
|
+
entity: Literal["leads"],
|
|
338
|
+
action: Literal["search"],
|
|
339
|
+
params: "LeadsSearchParams"
|
|
340
|
+
) -> "SearchResult": ...
|
|
341
|
+
|
|
342
|
+
@overload
|
|
343
|
+
async def execute(
|
|
344
|
+
self,
|
|
345
|
+
entity: Literal["opportunities"],
|
|
346
|
+
action: Literal["list"],
|
|
347
|
+
params: "OpportunitiesListParams"
|
|
348
|
+
) -> "OpportunityQueryResult": ...
|
|
349
|
+
|
|
350
|
+
@overload
|
|
351
|
+
async def execute(
|
|
352
|
+
self,
|
|
353
|
+
entity: Literal["opportunities"],
|
|
354
|
+
action: Literal["get"],
|
|
355
|
+
params: "OpportunitiesGetParams"
|
|
356
|
+
) -> "Opportunity": ...
|
|
357
|
+
|
|
358
|
+
@overload
|
|
359
|
+
async def execute(
|
|
360
|
+
self,
|
|
361
|
+
entity: Literal["opportunities"],
|
|
362
|
+
action: Literal["search"],
|
|
363
|
+
params: "OpportunitiesSearchParams"
|
|
364
|
+
) -> "SearchResult": ...
|
|
365
|
+
|
|
366
|
+
@overload
|
|
367
|
+
async def execute(
|
|
368
|
+
self,
|
|
369
|
+
entity: Literal["tasks"],
|
|
370
|
+
action: Literal["list"],
|
|
371
|
+
params: "TasksListParams"
|
|
372
|
+
) -> "TaskQueryResult": ...
|
|
373
|
+
|
|
374
|
+
@overload
|
|
375
|
+
async def execute(
|
|
376
|
+
self,
|
|
377
|
+
entity: Literal["tasks"],
|
|
378
|
+
action: Literal["get"],
|
|
379
|
+
params: "TasksGetParams"
|
|
380
|
+
) -> "Task": ...
|
|
381
|
+
|
|
382
|
+
@overload
|
|
383
|
+
async def execute(
|
|
384
|
+
self,
|
|
385
|
+
entity: Literal["tasks"],
|
|
386
|
+
action: Literal["search"],
|
|
387
|
+
params: "TasksSearchParams"
|
|
388
|
+
) -> "SearchResult": ...
|
|
389
|
+
|
|
390
|
+
@overload
|
|
391
|
+
async def execute(
|
|
392
|
+
self,
|
|
393
|
+
entity: Literal["events"],
|
|
394
|
+
action: Literal["list"],
|
|
395
|
+
params: "EventsListParams"
|
|
396
|
+
) -> "EventQueryResult": ...
|
|
397
|
+
|
|
398
|
+
@overload
|
|
399
|
+
async def execute(
|
|
400
|
+
self,
|
|
401
|
+
entity: Literal["events"],
|
|
402
|
+
action: Literal["get"],
|
|
403
|
+
params: "EventsGetParams"
|
|
404
|
+
) -> "Event": ...
|
|
405
|
+
|
|
406
|
+
@overload
|
|
407
|
+
async def execute(
|
|
408
|
+
self,
|
|
409
|
+
entity: Literal["events"],
|
|
410
|
+
action: Literal["search"],
|
|
411
|
+
params: "EventsSearchParams"
|
|
412
|
+
) -> "SearchResult": ...
|
|
413
|
+
|
|
414
|
+
@overload
|
|
415
|
+
async def execute(
|
|
416
|
+
self,
|
|
417
|
+
entity: Literal["campaigns"],
|
|
418
|
+
action: Literal["list"],
|
|
419
|
+
params: "CampaignsListParams"
|
|
420
|
+
) -> "CampaignQueryResult": ...
|
|
421
|
+
|
|
422
|
+
@overload
|
|
423
|
+
async def execute(
|
|
424
|
+
self,
|
|
425
|
+
entity: Literal["campaigns"],
|
|
426
|
+
action: Literal["get"],
|
|
427
|
+
params: "CampaignsGetParams"
|
|
428
|
+
) -> "Campaign": ...
|
|
429
|
+
|
|
430
|
+
@overload
|
|
431
|
+
async def execute(
|
|
432
|
+
self,
|
|
433
|
+
entity: Literal["campaigns"],
|
|
434
|
+
action: Literal["search"],
|
|
435
|
+
params: "CampaignsSearchParams"
|
|
436
|
+
) -> "SearchResult": ...
|
|
437
|
+
|
|
438
|
+
@overload
|
|
439
|
+
async def execute(
|
|
440
|
+
self,
|
|
441
|
+
entity: Literal["cases"],
|
|
442
|
+
action: Literal["list"],
|
|
443
|
+
params: "CasesListParams"
|
|
444
|
+
) -> "CaseQueryResult": ...
|
|
445
|
+
|
|
446
|
+
@overload
|
|
447
|
+
async def execute(
|
|
448
|
+
self,
|
|
449
|
+
entity: Literal["cases"],
|
|
450
|
+
action: Literal["get"],
|
|
451
|
+
params: "CasesGetParams"
|
|
452
|
+
) -> "Case": ...
|
|
453
|
+
|
|
454
|
+
@overload
|
|
455
|
+
async def execute(
|
|
456
|
+
self,
|
|
457
|
+
entity: Literal["cases"],
|
|
458
|
+
action: Literal["search"],
|
|
459
|
+
params: "CasesSearchParams"
|
|
460
|
+
) -> "SearchResult": ...
|
|
461
|
+
|
|
462
|
+
@overload
|
|
463
|
+
async def execute(
|
|
464
|
+
self,
|
|
465
|
+
entity: Literal["notes"],
|
|
466
|
+
action: Literal["list"],
|
|
467
|
+
params: "NotesListParams"
|
|
468
|
+
) -> "NoteQueryResult": ...
|
|
469
|
+
|
|
470
|
+
@overload
|
|
471
|
+
async def execute(
|
|
472
|
+
self,
|
|
473
|
+
entity: Literal["notes"],
|
|
474
|
+
action: Literal["get"],
|
|
475
|
+
params: "NotesGetParams"
|
|
476
|
+
) -> "Note": ...
|
|
477
|
+
|
|
478
|
+
@overload
|
|
479
|
+
async def execute(
|
|
480
|
+
self,
|
|
481
|
+
entity: Literal["notes"],
|
|
482
|
+
action: Literal["search"],
|
|
483
|
+
params: "NotesSearchParams"
|
|
484
|
+
) -> "SearchResult": ...
|
|
485
|
+
|
|
486
|
+
@overload
|
|
487
|
+
async def execute(
|
|
488
|
+
self,
|
|
489
|
+
entity: Literal["content_versions"],
|
|
490
|
+
action: Literal["list"],
|
|
491
|
+
params: "ContentVersionsListParams"
|
|
492
|
+
) -> "ContentVersionQueryResult": ...
|
|
493
|
+
|
|
494
|
+
@overload
|
|
495
|
+
async def execute(
|
|
496
|
+
self,
|
|
497
|
+
entity: Literal["content_versions"],
|
|
498
|
+
action: Literal["get"],
|
|
499
|
+
params: "ContentVersionsGetParams"
|
|
500
|
+
) -> "ContentVersion": ...
|
|
501
|
+
|
|
502
|
+
@overload
|
|
503
|
+
async def execute(
|
|
504
|
+
self,
|
|
505
|
+
entity: Literal["content_versions"],
|
|
506
|
+
action: Literal["download"],
|
|
507
|
+
params: "ContentVersionsDownloadParams"
|
|
508
|
+
) -> "AsyncIterator[bytes]": ...
|
|
509
|
+
|
|
510
|
+
@overload
|
|
511
|
+
async def execute(
|
|
512
|
+
self,
|
|
513
|
+
entity: Literal["attachments"],
|
|
514
|
+
action: Literal["list"],
|
|
515
|
+
params: "AttachmentsListParams"
|
|
516
|
+
) -> "AttachmentQueryResult": ...
|
|
517
|
+
|
|
518
|
+
@overload
|
|
519
|
+
async def execute(
|
|
520
|
+
self,
|
|
521
|
+
entity: Literal["attachments"],
|
|
522
|
+
action: Literal["get"],
|
|
523
|
+
params: "AttachmentsGetParams"
|
|
524
|
+
) -> "Attachment": ...
|
|
525
|
+
|
|
526
|
+
@overload
|
|
527
|
+
async def execute(
|
|
528
|
+
self,
|
|
529
|
+
entity: Literal["attachments"],
|
|
530
|
+
action: Literal["download"],
|
|
531
|
+
params: "AttachmentsDownloadParams"
|
|
532
|
+
) -> "AsyncIterator[bytes]": ...
|
|
533
|
+
|
|
534
|
+
@overload
|
|
535
|
+
async def execute(
|
|
536
|
+
self,
|
|
537
|
+
entity: Literal["query"],
|
|
538
|
+
action: Literal["list"],
|
|
539
|
+
params: "QueryListParams"
|
|
540
|
+
) -> "QueryResult": ...
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
@overload
|
|
544
|
+
async def execute(
|
|
545
|
+
self,
|
|
546
|
+
entity: str,
|
|
547
|
+
action: str,
|
|
548
|
+
params: dict[str, Any]
|
|
549
|
+
) -> SalesforceExecuteResult[Any] | SalesforceExecuteResultWithMeta[Any, Any] | Any: ...
|
|
550
|
+
|
|
551
|
+
async def execute(
|
|
552
|
+
self,
|
|
553
|
+
entity: str,
|
|
554
|
+
action: str,
|
|
555
|
+
params: dict[str, Any] | None = None
|
|
556
|
+
) -> Any:
|
|
557
|
+
"""
|
|
558
|
+
Execute an entity operation with full type safety.
|
|
559
|
+
|
|
560
|
+
This is the recommended interface for blessed connectors as it:
|
|
561
|
+
- Uses the same signature as non-blessed connectors
|
|
562
|
+
- Provides full IDE autocomplete for entity/action/params
|
|
563
|
+
- Makes migration from generic to blessed connectors seamless
|
|
564
|
+
|
|
565
|
+
Args:
|
|
566
|
+
entity: Entity name (e.g., "customers")
|
|
567
|
+
action: Operation action (e.g., "create", "get", "list")
|
|
568
|
+
params: Operation parameters (typed based on entity+action)
|
|
569
|
+
|
|
570
|
+
Returns:
|
|
571
|
+
Typed response based on the operation
|
|
572
|
+
|
|
573
|
+
Example:
|
|
574
|
+
customer = await connector.execute(
|
|
575
|
+
entity="customers",
|
|
576
|
+
action="get",
|
|
577
|
+
params={"id": "cus_123"}
|
|
578
|
+
)
|
|
579
|
+
"""
|
|
580
|
+
from ._vendored.connector_sdk.executor import ExecutionConfig
|
|
581
|
+
|
|
582
|
+
# Remap parameter names from snake_case (TypedDict keys) to API parameter names
|
|
583
|
+
if params:
|
|
584
|
+
param_map = self._PARAM_MAP.get((entity, action), {})
|
|
585
|
+
if param_map:
|
|
586
|
+
params = {param_map.get(k, k): v for k, v in params.items()}
|
|
587
|
+
|
|
588
|
+
# Use ExecutionConfig for both local and hosted executors
|
|
589
|
+
config = ExecutionConfig(
|
|
590
|
+
entity=entity,
|
|
591
|
+
action=action,
|
|
592
|
+
params=params
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
result = await self._executor.execute(config)
|
|
596
|
+
|
|
597
|
+
if not result.success:
|
|
598
|
+
raise RuntimeError(f"Execution failed: {result.error}")
|
|
599
|
+
|
|
600
|
+
# Check if this operation has extractors configured
|
|
601
|
+
has_extractors = self._EXTRACTOR_MAP.get((entity, action), False)
|
|
602
|
+
|
|
603
|
+
if has_extractors:
|
|
604
|
+
# With extractors - return Pydantic envelope with data and meta
|
|
605
|
+
if result.meta is not None:
|
|
606
|
+
return SalesforceExecuteResultWithMeta[Any, Any](
|
|
607
|
+
data=result.data,
|
|
608
|
+
meta=result.meta
|
|
609
|
+
)
|
|
610
|
+
else:
|
|
611
|
+
return SalesforceExecuteResult[Any](data=result.data)
|
|
612
|
+
else:
|
|
613
|
+
# No extractors - return raw response data
|
|
614
|
+
return result.data
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
class AccountsQuery:
|
|
619
|
+
"""
|
|
620
|
+
Query class for Accounts entity operations.
|
|
621
|
+
"""
|
|
622
|
+
|
|
623
|
+
def __init__(self, connector: SalesforceConnector):
|
|
624
|
+
"""Initialize query with connector reference."""
|
|
625
|
+
self._connector = connector
|
|
626
|
+
|
|
627
|
+
async def list(
|
|
628
|
+
self,
|
|
629
|
+
q: str,
|
|
630
|
+
**kwargs
|
|
631
|
+
) -> AccountQueryResult:
|
|
632
|
+
"""
|
|
633
|
+
Returns a list of accounts via SOQL query. Default returns up to 200 records.
|
|
634
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
Args:
|
|
638
|
+
q: SOQL query for accounts. Default returns up to 200 records.
|
|
639
|
+
To change the limit, provide your own query with a LIMIT clause.
|
|
640
|
+
Example: "SELECT FIELDS(STANDARD) FROM Account ORDER BY LastModifiedDate DESC LIMIT 50"
|
|
641
|
+
|
|
642
|
+
**kwargs: Additional parameters
|
|
643
|
+
|
|
644
|
+
Returns:
|
|
645
|
+
AccountQueryResult
|
|
646
|
+
"""
|
|
647
|
+
params = {k: v for k, v in {
|
|
648
|
+
"q": q,
|
|
649
|
+
**kwargs
|
|
650
|
+
}.items() if v is not None}
|
|
651
|
+
|
|
652
|
+
result = await self._connector.execute("accounts", "list", params)
|
|
653
|
+
return result
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
async def get(
|
|
658
|
+
self,
|
|
659
|
+
id: str | None = None,
|
|
660
|
+
fields: str | None = None,
|
|
661
|
+
**kwargs
|
|
662
|
+
) -> Account:
|
|
663
|
+
"""
|
|
664
|
+
Get a single account by ID. Returns all accessible fields by default.
|
|
665
|
+
Use the `fields` parameter to retrieve only specific fields for better performance.
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
Args:
|
|
669
|
+
id: Salesforce Account ID (18-character ID starting with '001')
|
|
670
|
+
fields: Comma-separated list of fields to retrieve. If omitted, returns all accessible fields.
|
|
671
|
+
Example: "Id,Name,Industry,AnnualRevenue,Website"
|
|
672
|
+
|
|
673
|
+
**kwargs: Additional parameters
|
|
674
|
+
|
|
675
|
+
Returns:
|
|
676
|
+
Account
|
|
677
|
+
"""
|
|
678
|
+
params = {k: v for k, v in {
|
|
679
|
+
"id": id,
|
|
680
|
+
"fields": fields,
|
|
681
|
+
**kwargs
|
|
682
|
+
}.items() if v is not None}
|
|
683
|
+
|
|
684
|
+
result = await self._connector.execute("accounts", "get", params)
|
|
685
|
+
return result
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
async def search(
|
|
690
|
+
self,
|
|
691
|
+
q: str,
|
|
692
|
+
**kwargs
|
|
693
|
+
) -> SearchResult:
|
|
694
|
+
"""
|
|
695
|
+
Search for accounts using SOSL (Salesforce Object Search Language).
|
|
696
|
+
SOSL is optimized for text-based searches across multiple fields and objects.
|
|
697
|
+
Use SOQL (list action) for structured queries with specific field conditions.
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
Args:
|
|
701
|
+
q: SOSL search query. Format: FIND {searchTerm} IN scope RETURNING Object(fields) [LIMIT n]
|
|
702
|
+
Examples:
|
|
703
|
+
- "FIND {Acme} IN ALL FIELDS RETURNING Account(Id,Name)"
|
|
704
|
+
- "FIND {tech*} IN NAME FIELDS RETURNING Account(Id,Name,Industry) LIMIT 50"
|
|
705
|
+
- "FIND {\"exact phrase\"} RETURNING Account(Id,Name,Website)"
|
|
706
|
+
|
|
707
|
+
**kwargs: Additional parameters
|
|
708
|
+
|
|
709
|
+
Returns:
|
|
710
|
+
SearchResult
|
|
711
|
+
"""
|
|
712
|
+
params = {k: v for k, v in {
|
|
713
|
+
"q": q,
|
|
714
|
+
**kwargs
|
|
715
|
+
}.items() if v is not None}
|
|
716
|
+
|
|
717
|
+
result = await self._connector.execute("accounts", "search", params)
|
|
718
|
+
return result
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
class ContactsQuery:
|
|
723
|
+
"""
|
|
724
|
+
Query class for Contacts entity operations.
|
|
725
|
+
"""
|
|
726
|
+
|
|
727
|
+
def __init__(self, connector: SalesforceConnector):
|
|
728
|
+
"""Initialize query with connector reference."""
|
|
729
|
+
self._connector = connector
|
|
730
|
+
|
|
731
|
+
async def list(
|
|
732
|
+
self,
|
|
733
|
+
q: str,
|
|
734
|
+
**kwargs
|
|
735
|
+
) -> ContactQueryResult:
|
|
736
|
+
"""
|
|
737
|
+
Returns a list of contacts via SOQL query. Default returns up to 200 records.
|
|
738
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
Args:
|
|
742
|
+
q: SOQL query for contacts. Default returns up to 200 records.
|
|
743
|
+
To change the limit, provide your own query with a LIMIT clause.
|
|
744
|
+
Example: "SELECT FIELDS(STANDARD) FROM Contact WHERE AccountId = '001xx...' LIMIT 50"
|
|
745
|
+
|
|
746
|
+
**kwargs: Additional parameters
|
|
747
|
+
|
|
748
|
+
Returns:
|
|
749
|
+
ContactQueryResult
|
|
750
|
+
"""
|
|
751
|
+
params = {k: v for k, v in {
|
|
752
|
+
"q": q,
|
|
753
|
+
**kwargs
|
|
754
|
+
}.items() if v is not None}
|
|
755
|
+
|
|
756
|
+
result = await self._connector.execute("contacts", "list", params)
|
|
757
|
+
return result
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
async def get(
|
|
762
|
+
self,
|
|
763
|
+
id: str | None = None,
|
|
764
|
+
fields: str | None = None,
|
|
765
|
+
**kwargs
|
|
766
|
+
) -> Contact:
|
|
767
|
+
"""
|
|
768
|
+
Get a single contact by ID. Returns all accessible fields by default.
|
|
769
|
+
Use the `fields` parameter to retrieve only specific fields for better performance.
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
Args:
|
|
773
|
+
id: Salesforce Contact ID (18-character ID starting with '003')
|
|
774
|
+
fields: Comma-separated list of fields to retrieve. If omitted, returns all accessible fields.
|
|
775
|
+
Example: "Id,FirstName,LastName,Email,Phone,AccountId"
|
|
776
|
+
|
|
777
|
+
**kwargs: Additional parameters
|
|
778
|
+
|
|
779
|
+
Returns:
|
|
780
|
+
Contact
|
|
781
|
+
"""
|
|
782
|
+
params = {k: v for k, v in {
|
|
783
|
+
"id": id,
|
|
784
|
+
"fields": fields,
|
|
785
|
+
**kwargs
|
|
786
|
+
}.items() if v is not None}
|
|
787
|
+
|
|
788
|
+
result = await self._connector.execute("contacts", "get", params)
|
|
789
|
+
return result
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
async def search(
|
|
794
|
+
self,
|
|
795
|
+
q: str,
|
|
796
|
+
**kwargs
|
|
797
|
+
) -> SearchResult:
|
|
798
|
+
"""
|
|
799
|
+
Search for contacts using SOSL (Salesforce Object Search Language).
|
|
800
|
+
SOSL is optimized for text-based searches across multiple fields.
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
Args:
|
|
804
|
+
q: SOSL search query. Format: FIND {searchTerm} RETURNING Contact(fields) [LIMIT n]
|
|
805
|
+
Examples:
|
|
806
|
+
- "FIND {John} IN NAME FIELDS RETURNING Contact(Id,FirstName,LastName,Email)"
|
|
807
|
+
- "FIND {*@example.com} IN EMAIL FIELDS RETURNING Contact(Id,Name,Email) LIMIT 25"
|
|
808
|
+
|
|
809
|
+
**kwargs: Additional parameters
|
|
810
|
+
|
|
811
|
+
Returns:
|
|
812
|
+
SearchResult
|
|
813
|
+
"""
|
|
814
|
+
params = {k: v for k, v in {
|
|
815
|
+
"q": q,
|
|
816
|
+
**kwargs
|
|
817
|
+
}.items() if v is not None}
|
|
818
|
+
|
|
819
|
+
result = await self._connector.execute("contacts", "search", params)
|
|
820
|
+
return result
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
class LeadsQuery:
|
|
825
|
+
"""
|
|
826
|
+
Query class for Leads entity operations.
|
|
827
|
+
"""
|
|
828
|
+
|
|
829
|
+
def __init__(self, connector: SalesforceConnector):
|
|
830
|
+
"""Initialize query with connector reference."""
|
|
831
|
+
self._connector = connector
|
|
832
|
+
|
|
833
|
+
async def list(
|
|
834
|
+
self,
|
|
835
|
+
q: str,
|
|
836
|
+
**kwargs
|
|
837
|
+
) -> LeadQueryResult:
|
|
838
|
+
"""
|
|
839
|
+
Returns a list of leads via SOQL query. Default returns up to 200 records.
|
|
840
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
Args:
|
|
844
|
+
q: SOQL query for leads. Default returns up to 200 records.
|
|
845
|
+
To change the limit, provide your own query with a LIMIT clause.
|
|
846
|
+
Example: "SELECT FIELDS(STANDARD) FROM Lead WHERE Status = 'Open' LIMIT 100"
|
|
847
|
+
|
|
848
|
+
**kwargs: Additional parameters
|
|
849
|
+
|
|
850
|
+
Returns:
|
|
851
|
+
LeadQueryResult
|
|
852
|
+
"""
|
|
853
|
+
params = {k: v for k, v in {
|
|
854
|
+
"q": q,
|
|
855
|
+
**kwargs
|
|
856
|
+
}.items() if v is not None}
|
|
857
|
+
|
|
858
|
+
result = await self._connector.execute("leads", "list", params)
|
|
859
|
+
return result
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
async def get(
|
|
864
|
+
self,
|
|
865
|
+
id: str | None = None,
|
|
866
|
+
fields: str | None = None,
|
|
867
|
+
**kwargs
|
|
868
|
+
) -> Lead:
|
|
869
|
+
"""
|
|
870
|
+
Get a single lead by ID. Returns all accessible fields by default.
|
|
871
|
+
Use the `fields` parameter to retrieve only specific fields for better performance.
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
Args:
|
|
875
|
+
id: Salesforce Lead ID (18-character ID starting with '00Q')
|
|
876
|
+
fields: Comma-separated list of fields to retrieve. If omitted, returns all accessible fields.
|
|
877
|
+
Example: "Id,FirstName,LastName,Email,Company,Status,LeadSource"
|
|
878
|
+
|
|
879
|
+
**kwargs: Additional parameters
|
|
880
|
+
|
|
881
|
+
Returns:
|
|
882
|
+
Lead
|
|
883
|
+
"""
|
|
884
|
+
params = {k: v for k, v in {
|
|
885
|
+
"id": id,
|
|
886
|
+
"fields": fields,
|
|
887
|
+
**kwargs
|
|
888
|
+
}.items() if v is not None}
|
|
889
|
+
|
|
890
|
+
result = await self._connector.execute("leads", "get", params)
|
|
891
|
+
return result
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
async def search(
|
|
896
|
+
self,
|
|
897
|
+
q: str,
|
|
898
|
+
**kwargs
|
|
899
|
+
) -> SearchResult:
|
|
900
|
+
"""
|
|
901
|
+
Search for leads using SOSL (Salesforce Object Search Language).
|
|
902
|
+
SOSL is optimized for text-based searches across multiple fields.
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
Args:
|
|
906
|
+
q: SOSL search query. Format: FIND {searchTerm} RETURNING Lead(fields) [LIMIT n]
|
|
907
|
+
Examples:
|
|
908
|
+
- "FIND {Smith} IN NAME FIELDS RETURNING Lead(Id,FirstName,LastName,Company,Status)"
|
|
909
|
+
- "FIND {marketing} IN ALL FIELDS RETURNING Lead(Id,Name,LeadSource) LIMIT 50"
|
|
910
|
+
|
|
911
|
+
**kwargs: Additional parameters
|
|
912
|
+
|
|
913
|
+
Returns:
|
|
914
|
+
SearchResult
|
|
915
|
+
"""
|
|
916
|
+
params = {k: v for k, v in {
|
|
917
|
+
"q": q,
|
|
918
|
+
**kwargs
|
|
919
|
+
}.items() if v is not None}
|
|
920
|
+
|
|
921
|
+
result = await self._connector.execute("leads", "search", params)
|
|
922
|
+
return result
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
class OpportunitiesQuery:
|
|
927
|
+
"""
|
|
928
|
+
Query class for Opportunities entity operations.
|
|
929
|
+
"""
|
|
930
|
+
|
|
931
|
+
def __init__(self, connector: SalesforceConnector):
|
|
932
|
+
"""Initialize query with connector reference."""
|
|
933
|
+
self._connector = connector
|
|
934
|
+
|
|
935
|
+
async def list(
|
|
936
|
+
self,
|
|
937
|
+
q: str,
|
|
938
|
+
**kwargs
|
|
939
|
+
) -> OpportunityQueryResult:
|
|
940
|
+
"""
|
|
941
|
+
Returns a list of opportunities via SOQL query. Default returns up to 200 records.
|
|
942
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
Args:
|
|
946
|
+
q: SOQL query for opportunities. Default returns up to 200 records.
|
|
947
|
+
To change the limit, provide your own query with a LIMIT clause.
|
|
948
|
+
Example: "SELECT FIELDS(STANDARD) FROM Opportunity WHERE StageName = 'Closed Won' LIMIT 50"
|
|
949
|
+
|
|
950
|
+
**kwargs: Additional parameters
|
|
951
|
+
|
|
952
|
+
Returns:
|
|
953
|
+
OpportunityQueryResult
|
|
954
|
+
"""
|
|
955
|
+
params = {k: v for k, v in {
|
|
956
|
+
"q": q,
|
|
957
|
+
**kwargs
|
|
958
|
+
}.items() if v is not None}
|
|
959
|
+
|
|
960
|
+
result = await self._connector.execute("opportunities", "list", params)
|
|
961
|
+
return result
|
|
962
|
+
|
|
963
|
+
|
|
964
|
+
|
|
965
|
+
async def get(
|
|
966
|
+
self,
|
|
967
|
+
id: str | None = None,
|
|
968
|
+
fields: str | None = None,
|
|
969
|
+
**kwargs
|
|
970
|
+
) -> Opportunity:
|
|
971
|
+
"""
|
|
972
|
+
Get a single opportunity by ID. Returns all accessible fields by default.
|
|
973
|
+
Use the `fields` parameter to retrieve only specific fields for better performance.
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
Args:
|
|
977
|
+
id: Salesforce Opportunity ID (18-character ID starting with '006')
|
|
978
|
+
fields: Comma-separated list of fields to retrieve. If omitted, returns all accessible fields.
|
|
979
|
+
Example: "Id,Name,Amount,StageName,CloseDate,AccountId"
|
|
980
|
+
|
|
981
|
+
**kwargs: Additional parameters
|
|
982
|
+
|
|
983
|
+
Returns:
|
|
984
|
+
Opportunity
|
|
985
|
+
"""
|
|
986
|
+
params = {k: v for k, v in {
|
|
987
|
+
"id": id,
|
|
988
|
+
"fields": fields,
|
|
989
|
+
**kwargs
|
|
990
|
+
}.items() if v is not None}
|
|
991
|
+
|
|
992
|
+
result = await self._connector.execute("opportunities", "get", params)
|
|
993
|
+
return result
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
|
|
997
|
+
async def search(
|
|
998
|
+
self,
|
|
999
|
+
q: str,
|
|
1000
|
+
**kwargs
|
|
1001
|
+
) -> SearchResult:
|
|
1002
|
+
"""
|
|
1003
|
+
Search for opportunities using SOSL (Salesforce Object Search Language).
|
|
1004
|
+
SOSL is optimized for text-based searches across multiple fields.
|
|
1005
|
+
|
|
1006
|
+
|
|
1007
|
+
Args:
|
|
1008
|
+
q: SOSL search query. Format: FIND {searchTerm} RETURNING Opportunity(fields) [LIMIT n]
|
|
1009
|
+
Examples:
|
|
1010
|
+
- "FIND {Enterprise} IN NAME FIELDS RETURNING Opportunity(Id,Name,Amount,StageName)"
|
|
1011
|
+
- "FIND {renewal} IN ALL FIELDS RETURNING Opportunity(Id,Name,CloseDate) LIMIT 25"
|
|
1012
|
+
|
|
1013
|
+
**kwargs: Additional parameters
|
|
1014
|
+
|
|
1015
|
+
Returns:
|
|
1016
|
+
SearchResult
|
|
1017
|
+
"""
|
|
1018
|
+
params = {k: v for k, v in {
|
|
1019
|
+
"q": q,
|
|
1020
|
+
**kwargs
|
|
1021
|
+
}.items() if v is not None}
|
|
1022
|
+
|
|
1023
|
+
result = await self._connector.execute("opportunities", "search", params)
|
|
1024
|
+
return result
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
class TasksQuery:
|
|
1029
|
+
"""
|
|
1030
|
+
Query class for Tasks entity operations.
|
|
1031
|
+
"""
|
|
1032
|
+
|
|
1033
|
+
def __init__(self, connector: SalesforceConnector):
|
|
1034
|
+
"""Initialize query with connector reference."""
|
|
1035
|
+
self._connector = connector
|
|
1036
|
+
|
|
1037
|
+
async def list(
|
|
1038
|
+
self,
|
|
1039
|
+
q: str,
|
|
1040
|
+
**kwargs
|
|
1041
|
+
) -> TaskQueryResult:
|
|
1042
|
+
"""
|
|
1043
|
+
Returns a list of tasks via SOQL query. Default returns up to 200 records.
|
|
1044
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
Args:
|
|
1048
|
+
q: SOQL query for tasks. Default returns up to 200 records.
|
|
1049
|
+
To change the limit, provide your own query with a LIMIT clause.
|
|
1050
|
+
Example: "SELECT FIELDS(STANDARD) FROM Task WHERE Status = 'Not Started' LIMIT 100"
|
|
1051
|
+
|
|
1052
|
+
**kwargs: Additional parameters
|
|
1053
|
+
|
|
1054
|
+
Returns:
|
|
1055
|
+
TaskQueryResult
|
|
1056
|
+
"""
|
|
1057
|
+
params = {k: v for k, v in {
|
|
1058
|
+
"q": q,
|
|
1059
|
+
**kwargs
|
|
1060
|
+
}.items() if v is not None}
|
|
1061
|
+
|
|
1062
|
+
result = await self._connector.execute("tasks", "list", params)
|
|
1063
|
+
return result
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
async def get(
|
|
1068
|
+
self,
|
|
1069
|
+
id: str | None = None,
|
|
1070
|
+
fields: str | None = None,
|
|
1071
|
+
**kwargs
|
|
1072
|
+
) -> Task:
|
|
1073
|
+
"""
|
|
1074
|
+
Get a single task by ID. Returns all accessible fields by default.
|
|
1075
|
+
Use the `fields` parameter to retrieve only specific fields for better performance.
|
|
1076
|
+
|
|
1077
|
+
|
|
1078
|
+
Args:
|
|
1079
|
+
id: Salesforce Task ID (18-character ID starting with '00T')
|
|
1080
|
+
fields: Comma-separated list of fields to retrieve. If omitted, returns all accessible fields.
|
|
1081
|
+
Example: "Id,Subject,Status,Priority,ActivityDate,WhoId,WhatId"
|
|
1082
|
+
|
|
1083
|
+
**kwargs: Additional parameters
|
|
1084
|
+
|
|
1085
|
+
Returns:
|
|
1086
|
+
Task
|
|
1087
|
+
"""
|
|
1088
|
+
params = {k: v for k, v in {
|
|
1089
|
+
"id": id,
|
|
1090
|
+
"fields": fields,
|
|
1091
|
+
**kwargs
|
|
1092
|
+
}.items() if v is not None}
|
|
1093
|
+
|
|
1094
|
+
result = await self._connector.execute("tasks", "get", params)
|
|
1095
|
+
return result
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
async def search(
|
|
1100
|
+
self,
|
|
1101
|
+
q: str,
|
|
1102
|
+
**kwargs
|
|
1103
|
+
) -> SearchResult:
|
|
1104
|
+
"""
|
|
1105
|
+
Search for tasks using SOSL (Salesforce Object Search Language).
|
|
1106
|
+
SOSL is optimized for text-based searches across multiple fields.
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
Args:
|
|
1110
|
+
q: SOSL search query. Format: FIND {searchTerm} RETURNING Task(fields) [LIMIT n]
|
|
1111
|
+
Examples:
|
|
1112
|
+
- "FIND {follow up} IN ALL FIELDS RETURNING Task(Id,Subject,Status,Priority)"
|
|
1113
|
+
- "FIND {call} IN NAME FIELDS RETURNING Task(Id,Subject,ActivityDate) LIMIT 50"
|
|
1114
|
+
|
|
1115
|
+
**kwargs: Additional parameters
|
|
1116
|
+
|
|
1117
|
+
Returns:
|
|
1118
|
+
SearchResult
|
|
1119
|
+
"""
|
|
1120
|
+
params = {k: v for k, v in {
|
|
1121
|
+
"q": q,
|
|
1122
|
+
**kwargs
|
|
1123
|
+
}.items() if v is not None}
|
|
1124
|
+
|
|
1125
|
+
result = await self._connector.execute("tasks", "search", params)
|
|
1126
|
+
return result
|
|
1127
|
+
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
class EventsQuery:
|
|
1131
|
+
"""
|
|
1132
|
+
Query class for Events entity operations.
|
|
1133
|
+
"""
|
|
1134
|
+
|
|
1135
|
+
def __init__(self, connector: SalesforceConnector):
|
|
1136
|
+
"""Initialize query with connector reference."""
|
|
1137
|
+
self._connector = connector
|
|
1138
|
+
|
|
1139
|
+
async def list(
|
|
1140
|
+
self,
|
|
1141
|
+
q: str,
|
|
1142
|
+
**kwargs
|
|
1143
|
+
) -> EventQueryResult:
|
|
1144
|
+
"""
|
|
1145
|
+
Returns a list of events via SOQL query. Default returns up to 200 records.
|
|
1146
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
1147
|
+
|
|
1148
|
+
|
|
1149
|
+
Args:
|
|
1150
|
+
q: SOQL query for events. Default returns up to 200 records.
|
|
1151
|
+
To change the limit, provide your own query with a LIMIT clause.
|
|
1152
|
+
Example: "SELECT FIELDS(STANDARD) FROM Event WHERE StartDateTime > TODAY LIMIT 50"
|
|
1153
|
+
|
|
1154
|
+
**kwargs: Additional parameters
|
|
1155
|
+
|
|
1156
|
+
Returns:
|
|
1157
|
+
EventQueryResult
|
|
1158
|
+
"""
|
|
1159
|
+
params = {k: v for k, v in {
|
|
1160
|
+
"q": q,
|
|
1161
|
+
**kwargs
|
|
1162
|
+
}.items() if v is not None}
|
|
1163
|
+
|
|
1164
|
+
result = await self._connector.execute("events", "list", params)
|
|
1165
|
+
return result
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
|
|
1169
|
+
async def get(
|
|
1170
|
+
self,
|
|
1171
|
+
id: str | None = None,
|
|
1172
|
+
fields: str | None = None,
|
|
1173
|
+
**kwargs
|
|
1174
|
+
) -> Event:
|
|
1175
|
+
"""
|
|
1176
|
+
Get a single event by ID. Returns all accessible fields by default.
|
|
1177
|
+
Use the `fields` parameter to retrieve only specific fields for better performance.
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
Args:
|
|
1181
|
+
id: Salesforce Event ID (18-character ID starting with '00U')
|
|
1182
|
+
fields: Comma-separated list of fields to retrieve. If omitted, returns all accessible fields.
|
|
1183
|
+
Example: "Id,Subject,StartDateTime,EndDateTime,Location,WhoId,WhatId"
|
|
1184
|
+
|
|
1185
|
+
**kwargs: Additional parameters
|
|
1186
|
+
|
|
1187
|
+
Returns:
|
|
1188
|
+
Event
|
|
1189
|
+
"""
|
|
1190
|
+
params = {k: v for k, v in {
|
|
1191
|
+
"id": id,
|
|
1192
|
+
"fields": fields,
|
|
1193
|
+
**kwargs
|
|
1194
|
+
}.items() if v is not None}
|
|
1195
|
+
|
|
1196
|
+
result = await self._connector.execute("events", "get", params)
|
|
1197
|
+
return result
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
|
|
1201
|
+
async def search(
|
|
1202
|
+
self,
|
|
1203
|
+
q: str,
|
|
1204
|
+
**kwargs
|
|
1205
|
+
) -> SearchResult:
|
|
1206
|
+
"""
|
|
1207
|
+
Search for events using SOSL (Salesforce Object Search Language).
|
|
1208
|
+
SOSL is optimized for text-based searches across multiple fields.
|
|
1209
|
+
|
|
1210
|
+
|
|
1211
|
+
Args:
|
|
1212
|
+
q: SOSL search query. Format: FIND {searchTerm} RETURNING Event(fields) [LIMIT n]
|
|
1213
|
+
Examples:
|
|
1214
|
+
- "FIND {meeting} IN ALL FIELDS RETURNING Event(Id,Subject,StartDateTime,Location)"
|
|
1215
|
+
- "FIND {demo} IN NAME FIELDS RETURNING Event(Id,Subject,EndDateTime) LIMIT 25"
|
|
1216
|
+
|
|
1217
|
+
**kwargs: Additional parameters
|
|
1218
|
+
|
|
1219
|
+
Returns:
|
|
1220
|
+
SearchResult
|
|
1221
|
+
"""
|
|
1222
|
+
params = {k: v for k, v in {
|
|
1223
|
+
"q": q,
|
|
1224
|
+
**kwargs
|
|
1225
|
+
}.items() if v is not None}
|
|
1226
|
+
|
|
1227
|
+
result = await self._connector.execute("events", "search", params)
|
|
1228
|
+
return result
|
|
1229
|
+
|
|
1230
|
+
|
|
1231
|
+
|
|
1232
|
+
class CampaignsQuery:
|
|
1233
|
+
"""
|
|
1234
|
+
Query class for Campaigns entity operations.
|
|
1235
|
+
"""
|
|
1236
|
+
|
|
1237
|
+
def __init__(self, connector: SalesforceConnector):
|
|
1238
|
+
"""Initialize query with connector reference."""
|
|
1239
|
+
self._connector = connector
|
|
1240
|
+
|
|
1241
|
+
async def list(
|
|
1242
|
+
self,
|
|
1243
|
+
q: str,
|
|
1244
|
+
**kwargs
|
|
1245
|
+
) -> CampaignQueryResult:
|
|
1246
|
+
"""
|
|
1247
|
+
Returns a list of campaigns via SOQL query. Default returns up to 200 records.
|
|
1248
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
1249
|
+
|
|
1250
|
+
|
|
1251
|
+
Args:
|
|
1252
|
+
q: SOQL query for campaigns. Default returns up to 200 records.
|
|
1253
|
+
To change the limit, provide your own query with a LIMIT clause.
|
|
1254
|
+
Example: "SELECT FIELDS(STANDARD) FROM Campaign WHERE IsActive = true LIMIT 50"
|
|
1255
|
+
|
|
1256
|
+
**kwargs: Additional parameters
|
|
1257
|
+
|
|
1258
|
+
Returns:
|
|
1259
|
+
CampaignQueryResult
|
|
1260
|
+
"""
|
|
1261
|
+
params = {k: v for k, v in {
|
|
1262
|
+
"q": q,
|
|
1263
|
+
**kwargs
|
|
1264
|
+
}.items() if v is not None}
|
|
1265
|
+
|
|
1266
|
+
result = await self._connector.execute("campaigns", "list", params)
|
|
1267
|
+
return result
|
|
1268
|
+
|
|
1269
|
+
|
|
1270
|
+
|
|
1271
|
+
async def get(
|
|
1272
|
+
self,
|
|
1273
|
+
id: str | None = None,
|
|
1274
|
+
fields: str | None = None,
|
|
1275
|
+
**kwargs
|
|
1276
|
+
) -> Campaign:
|
|
1277
|
+
"""
|
|
1278
|
+
Get a single campaign by ID. Returns all accessible fields by default.
|
|
1279
|
+
Use the `fields` parameter to retrieve only specific fields for better performance.
|
|
1280
|
+
|
|
1281
|
+
|
|
1282
|
+
Args:
|
|
1283
|
+
id: Salesforce Campaign ID (18-character ID starting with '701')
|
|
1284
|
+
fields: Comma-separated list of fields to retrieve. If omitted, returns all accessible fields.
|
|
1285
|
+
Example: "Id,Name,Type,Status,StartDate,EndDate,IsActive"
|
|
1286
|
+
|
|
1287
|
+
**kwargs: Additional parameters
|
|
1288
|
+
|
|
1289
|
+
Returns:
|
|
1290
|
+
Campaign
|
|
1291
|
+
"""
|
|
1292
|
+
params = {k: v for k, v in {
|
|
1293
|
+
"id": id,
|
|
1294
|
+
"fields": fields,
|
|
1295
|
+
**kwargs
|
|
1296
|
+
}.items() if v is not None}
|
|
1297
|
+
|
|
1298
|
+
result = await self._connector.execute("campaigns", "get", params)
|
|
1299
|
+
return result
|
|
1300
|
+
|
|
1301
|
+
|
|
1302
|
+
|
|
1303
|
+
async def search(
|
|
1304
|
+
self,
|
|
1305
|
+
q: str,
|
|
1306
|
+
**kwargs
|
|
1307
|
+
) -> SearchResult:
|
|
1308
|
+
"""
|
|
1309
|
+
Search for campaigns using SOSL (Salesforce Object Search Language).
|
|
1310
|
+
SOSL is optimized for text-based searches across multiple fields.
|
|
1311
|
+
|
|
1312
|
+
|
|
1313
|
+
Args:
|
|
1314
|
+
q: SOSL search query. Format: FIND {searchTerm} RETURNING Campaign(fields) [LIMIT n]
|
|
1315
|
+
Examples:
|
|
1316
|
+
- "FIND {webinar} IN ALL FIELDS RETURNING Campaign(Id,Name,Type,Status)"
|
|
1317
|
+
- "FIND {2024} IN NAME FIELDS RETURNING Campaign(Id,Name,StartDate,IsActive) LIMIT 50"
|
|
1318
|
+
|
|
1319
|
+
**kwargs: Additional parameters
|
|
1320
|
+
|
|
1321
|
+
Returns:
|
|
1322
|
+
SearchResult
|
|
1323
|
+
"""
|
|
1324
|
+
params = {k: v for k, v in {
|
|
1325
|
+
"q": q,
|
|
1326
|
+
**kwargs
|
|
1327
|
+
}.items() if v is not None}
|
|
1328
|
+
|
|
1329
|
+
result = await self._connector.execute("campaigns", "search", params)
|
|
1330
|
+
return result
|
|
1331
|
+
|
|
1332
|
+
|
|
1333
|
+
|
|
1334
|
+
class CasesQuery:
|
|
1335
|
+
"""
|
|
1336
|
+
Query class for Cases entity operations.
|
|
1337
|
+
"""
|
|
1338
|
+
|
|
1339
|
+
def __init__(self, connector: SalesforceConnector):
|
|
1340
|
+
"""Initialize query with connector reference."""
|
|
1341
|
+
self._connector = connector
|
|
1342
|
+
|
|
1343
|
+
async def list(
|
|
1344
|
+
self,
|
|
1345
|
+
q: str,
|
|
1346
|
+
**kwargs
|
|
1347
|
+
) -> CaseQueryResult:
|
|
1348
|
+
"""
|
|
1349
|
+
Returns a list of cases via SOQL query. Default returns up to 200 records.
|
|
1350
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
Args:
|
|
1354
|
+
q: SOQL query for cases. Default returns up to 200 records.
|
|
1355
|
+
To change the limit, provide your own query with a LIMIT clause.
|
|
1356
|
+
Example: "SELECT FIELDS(STANDARD) FROM Case WHERE Status = 'New' LIMIT 100"
|
|
1357
|
+
|
|
1358
|
+
**kwargs: Additional parameters
|
|
1359
|
+
|
|
1360
|
+
Returns:
|
|
1361
|
+
CaseQueryResult
|
|
1362
|
+
"""
|
|
1363
|
+
params = {k: v for k, v in {
|
|
1364
|
+
"q": q,
|
|
1365
|
+
**kwargs
|
|
1366
|
+
}.items() if v is not None}
|
|
1367
|
+
|
|
1368
|
+
result = await self._connector.execute("cases", "list", params)
|
|
1369
|
+
return result
|
|
1370
|
+
|
|
1371
|
+
|
|
1372
|
+
|
|
1373
|
+
async def get(
|
|
1374
|
+
self,
|
|
1375
|
+
id: str | None = None,
|
|
1376
|
+
fields: str | None = None,
|
|
1377
|
+
**kwargs
|
|
1378
|
+
) -> Case:
|
|
1379
|
+
"""
|
|
1380
|
+
Get a single case by ID. Returns all accessible fields by default.
|
|
1381
|
+
Use the `fields` parameter to retrieve only specific fields for better performance.
|
|
1382
|
+
|
|
1383
|
+
|
|
1384
|
+
Args:
|
|
1385
|
+
id: Salesforce Case ID (18-character ID starting with '500')
|
|
1386
|
+
fields: Comma-separated list of fields to retrieve. If omitted, returns all accessible fields.
|
|
1387
|
+
Example: "Id,CaseNumber,Subject,Status,Priority,ContactId,AccountId"
|
|
1388
|
+
|
|
1389
|
+
**kwargs: Additional parameters
|
|
1390
|
+
|
|
1391
|
+
Returns:
|
|
1392
|
+
Case
|
|
1393
|
+
"""
|
|
1394
|
+
params = {k: v for k, v in {
|
|
1395
|
+
"id": id,
|
|
1396
|
+
"fields": fields,
|
|
1397
|
+
**kwargs
|
|
1398
|
+
}.items() if v is not None}
|
|
1399
|
+
|
|
1400
|
+
result = await self._connector.execute("cases", "get", params)
|
|
1401
|
+
return result
|
|
1402
|
+
|
|
1403
|
+
|
|
1404
|
+
|
|
1405
|
+
async def search(
|
|
1406
|
+
self,
|
|
1407
|
+
q: str,
|
|
1408
|
+
**kwargs
|
|
1409
|
+
) -> SearchResult:
|
|
1410
|
+
"""
|
|
1411
|
+
Search for cases using SOSL (Salesforce Object Search Language).
|
|
1412
|
+
SOSL is optimized for text-based searches across multiple fields.
|
|
1413
|
+
|
|
1414
|
+
|
|
1415
|
+
Args:
|
|
1416
|
+
q: SOSL search query. Format: FIND {searchTerm} RETURNING Case(fields) [LIMIT n]
|
|
1417
|
+
Examples:
|
|
1418
|
+
- "FIND {login issue} IN ALL FIELDS RETURNING Case(Id,CaseNumber,Subject,Status)"
|
|
1419
|
+
- "FIND {urgent} IN NAME FIELDS RETURNING Case(Id,Subject,Priority) LIMIT 25"
|
|
1420
|
+
|
|
1421
|
+
**kwargs: Additional parameters
|
|
1422
|
+
|
|
1423
|
+
Returns:
|
|
1424
|
+
SearchResult
|
|
1425
|
+
"""
|
|
1426
|
+
params = {k: v for k, v in {
|
|
1427
|
+
"q": q,
|
|
1428
|
+
**kwargs
|
|
1429
|
+
}.items() if v is not None}
|
|
1430
|
+
|
|
1431
|
+
result = await self._connector.execute("cases", "search", params)
|
|
1432
|
+
return result
|
|
1433
|
+
|
|
1434
|
+
|
|
1435
|
+
|
|
1436
|
+
class NotesQuery:
|
|
1437
|
+
"""
|
|
1438
|
+
Query class for Notes entity operations.
|
|
1439
|
+
"""
|
|
1440
|
+
|
|
1441
|
+
def __init__(self, connector: SalesforceConnector):
|
|
1442
|
+
"""Initialize query with connector reference."""
|
|
1443
|
+
self._connector = connector
|
|
1444
|
+
|
|
1445
|
+
async def list(
|
|
1446
|
+
self,
|
|
1447
|
+
q: str,
|
|
1448
|
+
**kwargs
|
|
1449
|
+
) -> NoteQueryResult:
|
|
1450
|
+
"""
|
|
1451
|
+
Returns a list of notes via SOQL query. Default returns up to 200 records.
|
|
1452
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
1453
|
+
|
|
1454
|
+
|
|
1455
|
+
Args:
|
|
1456
|
+
q: SOQL query for notes. Default returns up to 200 records.
|
|
1457
|
+
To change the limit, provide your own query with a LIMIT clause.
|
|
1458
|
+
Example: "SELECT FIELDS(STANDARD) FROM Note WHERE ParentId = '001xx...' LIMIT 50"
|
|
1459
|
+
|
|
1460
|
+
**kwargs: Additional parameters
|
|
1461
|
+
|
|
1462
|
+
Returns:
|
|
1463
|
+
NoteQueryResult
|
|
1464
|
+
"""
|
|
1465
|
+
params = {k: v for k, v in {
|
|
1466
|
+
"q": q,
|
|
1467
|
+
**kwargs
|
|
1468
|
+
}.items() if v is not None}
|
|
1469
|
+
|
|
1470
|
+
result = await self._connector.execute("notes", "list", params)
|
|
1471
|
+
return result
|
|
1472
|
+
|
|
1473
|
+
|
|
1474
|
+
|
|
1475
|
+
async def get(
|
|
1476
|
+
self,
|
|
1477
|
+
id: str | None = None,
|
|
1478
|
+
fields: str | None = None,
|
|
1479
|
+
**kwargs
|
|
1480
|
+
) -> Note:
|
|
1481
|
+
"""
|
|
1482
|
+
Get a single note by ID. Returns all accessible fields by default.
|
|
1483
|
+
Use the `fields` parameter to retrieve only specific fields for better performance.
|
|
1484
|
+
|
|
1485
|
+
|
|
1486
|
+
Args:
|
|
1487
|
+
id: Salesforce Note ID (18-character ID starting with '002')
|
|
1488
|
+
fields: Comma-separated list of fields to retrieve. If omitted, returns all accessible fields.
|
|
1489
|
+
Example: "Id,Title,Body,ParentId,OwnerId"
|
|
1490
|
+
|
|
1491
|
+
**kwargs: Additional parameters
|
|
1492
|
+
|
|
1493
|
+
Returns:
|
|
1494
|
+
Note
|
|
1495
|
+
"""
|
|
1496
|
+
params = {k: v for k, v in {
|
|
1497
|
+
"id": id,
|
|
1498
|
+
"fields": fields,
|
|
1499
|
+
**kwargs
|
|
1500
|
+
}.items() if v is not None}
|
|
1501
|
+
|
|
1502
|
+
result = await self._connector.execute("notes", "get", params)
|
|
1503
|
+
return result
|
|
1504
|
+
|
|
1505
|
+
|
|
1506
|
+
|
|
1507
|
+
async def search(
|
|
1508
|
+
self,
|
|
1509
|
+
q: str,
|
|
1510
|
+
**kwargs
|
|
1511
|
+
) -> SearchResult:
|
|
1512
|
+
"""
|
|
1513
|
+
Search for notes using SOSL (Salesforce Object Search Language).
|
|
1514
|
+
SOSL is optimized for text-based searches across multiple fields.
|
|
1515
|
+
|
|
1516
|
+
|
|
1517
|
+
Args:
|
|
1518
|
+
q: SOSL search query. Format: FIND {searchTerm} RETURNING Note(fields) [LIMIT n]
|
|
1519
|
+
Examples:
|
|
1520
|
+
- "FIND {important} IN ALL FIELDS RETURNING Note(Id,Title,ParentId)"
|
|
1521
|
+
- "FIND {action items} IN NAME FIELDS RETURNING Note(Id,Title,Body) LIMIT 50"
|
|
1522
|
+
|
|
1523
|
+
**kwargs: Additional parameters
|
|
1524
|
+
|
|
1525
|
+
Returns:
|
|
1526
|
+
SearchResult
|
|
1527
|
+
"""
|
|
1528
|
+
params = {k: v for k, v in {
|
|
1529
|
+
"q": q,
|
|
1530
|
+
**kwargs
|
|
1531
|
+
}.items() if v is not None}
|
|
1532
|
+
|
|
1533
|
+
result = await self._connector.execute("notes", "search", params)
|
|
1534
|
+
return result
|
|
1535
|
+
|
|
1536
|
+
|
|
1537
|
+
|
|
1538
|
+
class ContentVersionsQuery:
|
|
1539
|
+
"""
|
|
1540
|
+
Query class for ContentVersions entity operations.
|
|
1541
|
+
"""
|
|
1542
|
+
|
|
1543
|
+
def __init__(self, connector: SalesforceConnector):
|
|
1544
|
+
"""Initialize query with connector reference."""
|
|
1545
|
+
self._connector = connector
|
|
1546
|
+
|
|
1547
|
+
async def list(
|
|
1548
|
+
self,
|
|
1549
|
+
q: str,
|
|
1550
|
+
**kwargs
|
|
1551
|
+
) -> ContentVersionQueryResult:
|
|
1552
|
+
"""
|
|
1553
|
+
Returns a list of content versions (file metadata) via SOQL query. Default returns up to 200 records.
|
|
1554
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
1555
|
+
Note: ContentVersion does not support FIELDS(STANDARD), so specific fields must be listed.
|
|
1556
|
+
|
|
1557
|
+
|
|
1558
|
+
Args:
|
|
1559
|
+
q: SOQL query for content versions. Default returns up to 200 records.
|
|
1560
|
+
To change the limit, provide your own query with a LIMIT clause.
|
|
1561
|
+
Example: "SELECT Id, Title, FileExtension, ContentSize FROM ContentVersion WHERE IsLatest = true LIMIT 50"
|
|
1562
|
+
|
|
1563
|
+
**kwargs: Additional parameters
|
|
1564
|
+
|
|
1565
|
+
Returns:
|
|
1566
|
+
ContentVersionQueryResult
|
|
1567
|
+
"""
|
|
1568
|
+
params = {k: v for k, v in {
|
|
1569
|
+
"q": q,
|
|
1570
|
+
**kwargs
|
|
1571
|
+
}.items() if v is not None}
|
|
1572
|
+
|
|
1573
|
+
result = await self._connector.execute("content_versions", "list", params)
|
|
1574
|
+
return result
|
|
1575
|
+
|
|
1576
|
+
|
|
1577
|
+
|
|
1578
|
+
async def get(
|
|
1579
|
+
self,
|
|
1580
|
+
id: str | None = None,
|
|
1581
|
+
fields: str | None = None,
|
|
1582
|
+
**kwargs
|
|
1583
|
+
) -> ContentVersion:
|
|
1584
|
+
"""
|
|
1585
|
+
Get a single content version's metadata by ID. Returns file metadata, not the file content.
|
|
1586
|
+
Use the download action to retrieve the actual file binary.
|
|
1587
|
+
|
|
1588
|
+
|
|
1589
|
+
Args:
|
|
1590
|
+
id: Salesforce ContentVersion ID (18-character ID starting with '068')
|
|
1591
|
+
fields: Comma-separated list of fields to retrieve. If omitted, returns all accessible fields.
|
|
1592
|
+
Example: "Id,Title,FileExtension,ContentSize,ContentDocumentId,IsLatest"
|
|
1593
|
+
|
|
1594
|
+
**kwargs: Additional parameters
|
|
1595
|
+
|
|
1596
|
+
Returns:
|
|
1597
|
+
ContentVersion
|
|
1598
|
+
"""
|
|
1599
|
+
params = {k: v for k, v in {
|
|
1600
|
+
"id": id,
|
|
1601
|
+
"fields": fields,
|
|
1602
|
+
**kwargs
|
|
1603
|
+
}.items() if v is not None}
|
|
1604
|
+
|
|
1605
|
+
result = await self._connector.execute("content_versions", "get", params)
|
|
1606
|
+
return result
|
|
1607
|
+
|
|
1608
|
+
|
|
1609
|
+
|
|
1610
|
+
async def download(
|
|
1611
|
+
self,
|
|
1612
|
+
id: str | None = None,
|
|
1613
|
+
range_header: str | None = None,
|
|
1614
|
+
**kwargs
|
|
1615
|
+
) -> AsyncIterator[bytes]:
|
|
1616
|
+
"""
|
|
1617
|
+
Downloads the binary file content of a content version.
|
|
1618
|
+
First use the list or get action to retrieve the ContentVersion ID and file metadata (size, type, etc.),
|
|
1619
|
+
then use this action to download the actual file content.
|
|
1620
|
+
The response is the raw binary file data.
|
|
1621
|
+
|
|
1622
|
+
|
|
1623
|
+
Args:
|
|
1624
|
+
id: Salesforce ContentVersion ID (18-character ID starting with '068').
|
|
1625
|
+
Obtain this ID from the list or get action.
|
|
1626
|
+
|
|
1627
|
+
range_header: Optional Range header for partial downloads (e.g., 'bytes=0-99')
|
|
1628
|
+
**kwargs: Additional parameters
|
|
1629
|
+
|
|
1630
|
+
Returns:
|
|
1631
|
+
AsyncIterator[bytes]
|
|
1632
|
+
"""
|
|
1633
|
+
params = {k: v for k, v in {
|
|
1634
|
+
"id": id,
|
|
1635
|
+
"range_header": range_header,
|
|
1636
|
+
**kwargs
|
|
1637
|
+
}.items() if v is not None}
|
|
1638
|
+
|
|
1639
|
+
result = await self._connector.execute("content_versions", "download", params)
|
|
1640
|
+
return result
|
|
1641
|
+
|
|
1642
|
+
|
|
1643
|
+
async def download_local(
|
|
1644
|
+
self,
|
|
1645
|
+
path: str,
|
|
1646
|
+
id: str | None = None,
|
|
1647
|
+
range_header: str | None = None,
|
|
1648
|
+
**kwargs
|
|
1649
|
+
) -> Path:
|
|
1650
|
+
"""
|
|
1651
|
+
Downloads the binary file content of a content version.
|
|
1652
|
+
First use the list or get action to retrieve the ContentVersion ID and file metadata (size, type, etc.),
|
|
1653
|
+
then use this action to download the actual file content.
|
|
1654
|
+
The response is the raw binary file data.
|
|
1655
|
+
and save to file.
|
|
1656
|
+
|
|
1657
|
+
Args:
|
|
1658
|
+
id: Salesforce ContentVersion ID (18-character ID starting with '068').
|
|
1659
|
+
Obtain this ID from the list or get action.
|
|
1660
|
+
|
|
1661
|
+
range_header: Optional Range header for partial downloads (e.g., 'bytes=0-99')
|
|
1662
|
+
path: File path to save downloaded content
|
|
1663
|
+
**kwargs: Additional parameters
|
|
1664
|
+
|
|
1665
|
+
Returns:
|
|
1666
|
+
str: Path to the downloaded file
|
|
1667
|
+
"""
|
|
1668
|
+
from ._vendored.connector_sdk import save_download
|
|
1669
|
+
|
|
1670
|
+
# Get the async iterator
|
|
1671
|
+
content_iterator = await self.download(
|
|
1672
|
+
id=id,
|
|
1673
|
+
range_header=range_header,
|
|
1674
|
+
**kwargs
|
|
1675
|
+
)
|
|
1676
|
+
|
|
1677
|
+
return await save_download(content_iterator, path)
|
|
1678
|
+
|
|
1679
|
+
|
|
1680
|
+
class AttachmentsQuery:
|
|
1681
|
+
"""
|
|
1682
|
+
Query class for Attachments entity operations.
|
|
1683
|
+
"""
|
|
1684
|
+
|
|
1685
|
+
def __init__(self, connector: SalesforceConnector):
|
|
1686
|
+
"""Initialize query with connector reference."""
|
|
1687
|
+
self._connector = connector
|
|
1688
|
+
|
|
1689
|
+
async def list(
|
|
1690
|
+
self,
|
|
1691
|
+
q: str,
|
|
1692
|
+
**kwargs
|
|
1693
|
+
) -> AttachmentQueryResult:
|
|
1694
|
+
"""
|
|
1695
|
+
Returns a list of attachments (legacy) via SOQL query. Default returns up to 200 records.
|
|
1696
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
1697
|
+
Note: Attachments are a legacy feature; consider using ContentVersion (Salesforce Files) for new implementations.
|
|
1698
|
+
|
|
1699
|
+
|
|
1700
|
+
Args:
|
|
1701
|
+
q: SOQL query for attachments. Default returns up to 200 records.
|
|
1702
|
+
To change the limit, provide your own query with a LIMIT clause.
|
|
1703
|
+
Example: "SELECT Id, Name, ContentType, BodyLength, ParentId FROM Attachment WHERE ParentId = '001xx...' LIMIT 50"
|
|
1704
|
+
|
|
1705
|
+
**kwargs: Additional parameters
|
|
1706
|
+
|
|
1707
|
+
Returns:
|
|
1708
|
+
AttachmentQueryResult
|
|
1709
|
+
"""
|
|
1710
|
+
params = {k: v for k, v in {
|
|
1711
|
+
"q": q,
|
|
1712
|
+
**kwargs
|
|
1713
|
+
}.items() if v is not None}
|
|
1714
|
+
|
|
1715
|
+
result = await self._connector.execute("attachments", "list", params)
|
|
1716
|
+
return result
|
|
1717
|
+
|
|
1718
|
+
|
|
1719
|
+
|
|
1720
|
+
async def get(
|
|
1721
|
+
self,
|
|
1722
|
+
id: str | None = None,
|
|
1723
|
+
fields: str | None = None,
|
|
1724
|
+
**kwargs
|
|
1725
|
+
) -> Attachment:
|
|
1726
|
+
"""
|
|
1727
|
+
Get a single attachment's metadata by ID. Returns file metadata, not the file content.
|
|
1728
|
+
Use the download action to retrieve the actual file binary.
|
|
1729
|
+
Note: Attachments are a legacy feature; consider using ContentVersion for new implementations.
|
|
1730
|
+
|
|
1731
|
+
|
|
1732
|
+
Args:
|
|
1733
|
+
id: Salesforce Attachment ID (18-character ID starting with '00P')
|
|
1734
|
+
fields: Comma-separated list of fields to retrieve. If omitted, returns all accessible fields.
|
|
1735
|
+
Example: "Id,Name,ContentType,BodyLength,ParentId"
|
|
1736
|
+
|
|
1737
|
+
**kwargs: Additional parameters
|
|
1738
|
+
|
|
1739
|
+
Returns:
|
|
1740
|
+
Attachment
|
|
1741
|
+
"""
|
|
1742
|
+
params = {k: v for k, v in {
|
|
1743
|
+
"id": id,
|
|
1744
|
+
"fields": fields,
|
|
1745
|
+
**kwargs
|
|
1746
|
+
}.items() if v is not None}
|
|
1747
|
+
|
|
1748
|
+
result = await self._connector.execute("attachments", "get", params)
|
|
1749
|
+
return result
|
|
1750
|
+
|
|
1751
|
+
|
|
1752
|
+
|
|
1753
|
+
async def download(
|
|
1754
|
+
self,
|
|
1755
|
+
id: str | None = None,
|
|
1756
|
+
range_header: str | None = None,
|
|
1757
|
+
**kwargs
|
|
1758
|
+
) -> AsyncIterator[bytes]:
|
|
1759
|
+
"""
|
|
1760
|
+
Downloads the binary file content of an attachment (legacy).
|
|
1761
|
+
First use the list or get action to retrieve the Attachment ID and file metadata,
|
|
1762
|
+
then use this action to download the actual file content.
|
|
1763
|
+
Note: Attachments are a legacy feature; consider using ContentVersion for new implementations.
|
|
1764
|
+
|
|
1765
|
+
|
|
1766
|
+
Args:
|
|
1767
|
+
id: Salesforce Attachment ID (18-character ID starting with '00P').
|
|
1768
|
+
Obtain this ID from the list or get action.
|
|
1769
|
+
|
|
1770
|
+
range_header: Optional Range header for partial downloads (e.g., 'bytes=0-99')
|
|
1771
|
+
**kwargs: Additional parameters
|
|
1772
|
+
|
|
1773
|
+
Returns:
|
|
1774
|
+
AsyncIterator[bytes]
|
|
1775
|
+
"""
|
|
1776
|
+
params = {k: v for k, v in {
|
|
1777
|
+
"id": id,
|
|
1778
|
+
"range_header": range_header,
|
|
1779
|
+
**kwargs
|
|
1780
|
+
}.items() if v is not None}
|
|
1781
|
+
|
|
1782
|
+
result = await self._connector.execute("attachments", "download", params)
|
|
1783
|
+
return result
|
|
1784
|
+
|
|
1785
|
+
|
|
1786
|
+
async def download_local(
|
|
1787
|
+
self,
|
|
1788
|
+
path: str,
|
|
1789
|
+
id: str | None = None,
|
|
1790
|
+
range_header: str | None = None,
|
|
1791
|
+
**kwargs
|
|
1792
|
+
) -> Path:
|
|
1793
|
+
"""
|
|
1794
|
+
Downloads the binary file content of an attachment (legacy).
|
|
1795
|
+
First use the list or get action to retrieve the Attachment ID and file metadata,
|
|
1796
|
+
then use this action to download the actual file content.
|
|
1797
|
+
Note: Attachments are a legacy feature; consider using ContentVersion for new implementations.
|
|
1798
|
+
and save to file.
|
|
1799
|
+
|
|
1800
|
+
Args:
|
|
1801
|
+
id: Salesforce Attachment ID (18-character ID starting with '00P').
|
|
1802
|
+
Obtain this ID from the list or get action.
|
|
1803
|
+
|
|
1804
|
+
range_header: Optional Range header for partial downloads (e.g., 'bytes=0-99')
|
|
1805
|
+
path: File path to save downloaded content
|
|
1806
|
+
**kwargs: Additional parameters
|
|
1807
|
+
|
|
1808
|
+
Returns:
|
|
1809
|
+
str: Path to the downloaded file
|
|
1810
|
+
"""
|
|
1811
|
+
from ._vendored.connector_sdk import save_download
|
|
1812
|
+
|
|
1813
|
+
# Get the async iterator
|
|
1814
|
+
content_iterator = await self.download(
|
|
1815
|
+
id=id,
|
|
1816
|
+
range_header=range_header,
|
|
1817
|
+
**kwargs
|
|
1818
|
+
)
|
|
1819
|
+
|
|
1820
|
+
return await save_download(content_iterator, path)
|
|
1821
|
+
|
|
1822
|
+
|
|
1823
|
+
class QueryQuery:
|
|
1824
|
+
"""
|
|
1825
|
+
Query class for Query entity operations.
|
|
1826
|
+
"""
|
|
1827
|
+
|
|
1828
|
+
def __init__(self, connector: SalesforceConnector):
|
|
1829
|
+
"""Initialize query with connector reference."""
|
|
1830
|
+
self._connector = connector
|
|
1831
|
+
|
|
1832
|
+
async def list(
|
|
1833
|
+
self,
|
|
1834
|
+
q: str,
|
|
1835
|
+
**kwargs
|
|
1836
|
+
) -> QueryResult:
|
|
1837
|
+
"""
|
|
1838
|
+
Execute a custom SOQL query and return results. Use this for querying any Salesforce object.
|
|
1839
|
+
For pagination, check the response: if `done` is false, use `nextRecordsUrl` to fetch the next page.
|
|
1840
|
+
|
|
1841
|
+
|
|
1842
|
+
Args:
|
|
1843
|
+
q: SOQL query string. Include LIMIT clause to control the number of records returned.
|
|
1844
|
+
Examples:
|
|
1845
|
+
- "SELECT Id, Name FROM Account LIMIT 100"
|
|
1846
|
+
- "SELECT FIELDS(STANDARD) FROM Contact WHERE AccountId = '001xx...' LIMIT 50"
|
|
1847
|
+
- "SELECT Id, Subject, Status FROM Case WHERE CreatedDate = TODAY"
|
|
1848
|
+
|
|
1849
|
+
**kwargs: Additional parameters
|
|
1850
|
+
|
|
1851
|
+
Returns:
|
|
1852
|
+
QueryResult
|
|
1853
|
+
"""
|
|
1854
|
+
params = {k: v for k, v in {
|
|
1855
|
+
"q": q,
|
|
1856
|
+
**kwargs
|
|
1857
|
+
}.items() if v is not None}
|
|
1858
|
+
|
|
1859
|
+
result = await self._connector.execute("query", "list", params)
|
|
1860
|
+
return result
|
|
1861
|
+
|
|
1862
|
+
|