Skip to content

Commit

Permalink
Allow upsert query with external id
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandre Jaunasse <[email protected]>

Signed-off-by: Alexandre Jaunasse <[email protected]>
  • Loading branch information
Alexandre Jaunasse authored and malukenho committed Jun 22, 2022
1 parent d522680 commit d8fc46d
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 3 deletions.
53 changes: 50 additions & 3 deletions src/Soql/ConnectionWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use function array_map;
use function array_merge;
use function count;
use function in_array;
use function json_decode;
use function json_encode;
use function key;
Expand All @@ -34,9 +35,10 @@

class ConnectionWrapper extends Connection
{
private const SERVICE_OBJECT_URL = '/services/data/%s/sobjects/%s';
private const SERVICE_OBJECT_ID_URL = '/services/data/%s/sobjects/%s/%s';
private const SERVICE_COMPOSITE_URL = '/services/data/%s/composite';
private const SERVICE_OBJECT_URL = '/services/data/%s/sobjects/%s';
private const SERVICE_OBJECT_ID_URL = '/services/data/%s/sobjects/%s/%s';
private const SERVICE_OBJECT_EXTERNAL_ID_URL = '/services/data/%s/sobjects/%s/%s/%s';
private const SERVICE_COMPOSITE_URL = '/services/data/%s/composite';

private int $transactionalLevel = 0;

Expand Down Expand Up @@ -156,6 +158,51 @@ public function update(
return 1;
}

/**
* @param string $externalIdName Name of the external id of the object in Salesforce
* @param string $externalIdValue Value of the external id of the object in Salesforce
* @param array<string, string> $headers contains the headers that will be used when sending the request.
*
* @throws JsonException
*/
public function upsert(
string $tableExpression,
string $externalIdName,
string $externalIdValue,
array $data,
array $refs = [],
array $headers = []
): int {
$uri = sprintf(
self::SERVICE_OBJECT_EXTERNAL_ID_URL,
$this->apiVersion(),
$tableExpression,
$externalIdName,
$externalIdValue
);

$request = new Request(
'PATCH',
$uri,
$headers,
json_encode($data, JSON_THROW_ON_ERROR)
);

if ($this->isTransactionActive()) {
$this->addToBatchList($request, $refs);

return 1;
}

$response = $this->send($request);

if (! in_array($response->getStatusCode(), [200, 201, 204])) {
throw OperationFailed::upsertFailed($data);
}

return 1;
}

/**
* @param mixed[] $refs
*
Expand Down
6 changes: 6 additions & 0 deletions src/Soql/OperationFailed.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ public static function transactionFailed(array $errors): self
{
return new self(sprintf('Transaction failed with messages: %s', json_encode($errors, JSON_THROW_ON_ERROR)));
}

/** @param mixed[] $payload */
public static function upsertFailed(array $payload): self
{
return new self(sprintf('Upsert failed with payload %s', json_encode($payload)));
}
}
22 changes: 22 additions & 0 deletions tests/Soql/ConnectionWrapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,28 @@ public function transactional_should_throws_exception_when_error_occurs(): void
$this->connection->commit();
}

/** @test */
public function upsert_with_no_transaction(): void
{
$this->client->expects(self::once())->method('send')
->with(self::assertHttpHeaderIsPropagated())
->willReturn($this->response);

$this->response->expects(self::once())->method('getBody')->willReturn($this->stream);
$this->response->expects(self::once())->method('getStatusCode')->willReturn(201);

$this->stream->expects(self::once())->method('rewind');

$this->connection->upsert(
'User',
'ExternalId__c',
'12345',
['Name' => 'Pay as you go Opportunity'],
[],
['X-Unit-Testing' => 'Yes']
);
}

private static function assertHttpHeaderIsPropagated(): Callback
{
return self::callback(static function (Request $request) : bool {
Expand Down

0 comments on commit d8fc46d

Please sign in to comment.