Skip to content

Issue #2838 : Add experimental Salesforce Bulk API 2.0 transforms - #9410

Open
mattcasters wants to merge 1 commit into
apache:mainfrom
mattcasters:issue-2838
Open

mattcasters wants to merge 1 commit into
apache:mainfrom
mattcasters:issue-2838

Conversation

@mattcasters

Copy link
Copy Markdown
Contributor

Summary

Adds two experimental transforms to the existing Salesforce plugin for Bulk API 2.0. The SOAP Input, Insert, Update, Upsert, and Delete transforms are unchanged.

  • Salesforce bulk load (experimental) (SalesforceBulkLoad) inserts, updates, upserts, deletes, or hard-deletes one object through an ingest job.
  • Salesforce bulk input (experimental) (SalesforceBulkInput) runs query or queryAll and reads the CSV result pages.

Bulk API 2.0 is a different lifecycle from the partner API: create a job, upload one CSV, close it, poll, then download result files that are not in input order. A flag on the existing transforms would mix that with the synchronous SaveResult path, so these are separate transforms. Both reuse the salesforce-connection metadata. An OAuth token is sent as a bearer token. A username/password connection uses the SOAP session id the same way. There is no new Salesforce SDK.

The transforms are local-engine only. Beam and Spark refuse them by plugin id.

Fixes #2838.

Testing

  • plugins/tech/salesforce unit tests, including CSV rules, reversed result matching, the session id used as a bearer token, and the REST job flow against WireMock.
  • Beam BeamPipelineEngineSupportsTest and Spark HopPipelineMetaToSparkConverterTest for the engine bans.
  • The Bulk API stub in docker/integration-tests/salesforce-mock/bulk_api.py was exercised directly: insert with a failed row, reversed success rows, two query pages, and HTTP 401.

The integration-tests/salesforce project runs those same cases through Hop against the stub (docker/integration-tests/integration-tests-salesforce.yaml). That compose project was not executed inside the Hop integration image.

The SOAP transforms stay synchronous. Bulk load and bulk input use the job API, and the integration test talks to a local stub instead of a Salesforce org.
@bamaer

bamaer commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

Thanks @mattcasters, nice to have Bulk API 2.0 without pulling in another SDK. The reversed-results matching test is a good touch.

What I ran: built the PR and ran the 15 SalesforceBulk*Test unit tests, which all pass. I did not run the integration-tests/salesforce project or anything against a real org.

Blocker

Date values move by a day depending on the JVM time zone.

  • Load (SalesforceBulkValues.formatDate): on a Europe/Brussels JVM, a Hop date of 2026-03-15 goes into the CSV as 2026-03-14T23:00:00.000Z. Salesforce Insert sends the same row as 2026-03-15T00:00:00Z (SalesforceTransform.normalizeValue).
  • Input (SalesforceBulkValues.parseDate): a Date field holding 2026-03-15 is parsed as UTC midnight. On an America/New_York JVM that is 2026-03-14 20:00, so it shows and is written out as 2026-03-14.

Suggested fix: on load, keep the wall-clock time the way normalizeValue does. On input, parse the yyyy-MM-dd pattern in the local zone. With that change, Brussels, New York and Tokyo all give 2026-03-15T00:00:00.000Z on load and 2026-03-15 on input. A test in SalesforceBulkValuesTest that sets a non-UTC default zone would keep it fixed.

Question

Has this been run against a real Salesforce org at least once, for example a free Developer Edition org? The ITs and WireMock tests use a stub built from the docs. Row matching depends on Salesforce echoing the uploaded values unchanged in the result files, which a stub can't confirm. A short note in the PR on what was run against a real org (operations and field types) would be enough.

@mattcasters

Copy link
Copy Markdown
Contributor Author

I can't test it myself against SalesForce hence:

  1. The experimental status of the transforms. I would keep them until we get more usage data
  2. The mock tests against the published SalesForce REST API

At the risk of stating the obvious: this was done to de-block the issue from being stuck for another 3 years ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request]: Implement bulk apis in Salesforce transforms

2 participants