Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding request_sobject_by_external_id function #63

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions lib/ex_force.ex
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ defmodule ExForce do
@type soql :: String.t()
@type query_id :: String.t()
@type sobject :: %{id: String.t(), attributes: %{type: String.t()}}
@type method :: Atom.t()

defdelegate build_client(instance_url), to: Client
defdelegate build_client(instance_url, opts), to: Client
Expand Down Expand Up @@ -160,6 +161,30 @@ defmodule ExForce do
do:
do_get_sobject(client, "sobjects/#{sobject_name}/#{field_name}/#{URI.encode(field_value)}")

@doc """
Makes a request to a SObject based on the value of a specified extneral ID field. Works similarly to get_sobject_by_external_id, but accepts methods other than GET.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please make following small changes?

  1. Keep single line at the first paragraph, as it will be shown in the function list doc
  2. Quote the function name with arity, (e.g. get_sobject_by_external_id/4) so that the generated doc has the proper link


See [SObject Rows by External ID](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_sobject_upsert.htm)
Also [Insert or Update (Upsert) a Record Using an External ID](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_upsert.htm)
"""
@spec request_sobject_by_external_id(client, method, any, field_name, sobject_name, map) ::
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm.. so request_sobject_by_external_id(client, :get, fv, fn, sn, attrs) would be same with get_sobject_by_external_id(client, fv, fn, sn, attrs) - right?

Hm.. I'm slightly more inclined to have separate functions instead of one function taking request as an argument - e.g.

get_sobject_by_external_id # GET
create_sobject_by_external_id # POST
create_or_update_sobject_by_external_id # PATCH
delete_sobject_by_external_id # DELETE

and they share the same function.

Because choosing the HTTP request (:get, :post, ..) is implementation details - not the high-level behavior.

Any thought?

{:ok, map} | {:error, any}
def request_sobject_by_external_id(
client,
method,
field_value,
field_name,
sobject_name,
attrs
),
do:
do_request_sobject(
client,
method,
"sobjects/#{sobject_name}/#{field_name}/#{URI.encode(field_value)}",
attrs
)

@doc """
Retrieves a SObject by relationship field.

Expand Down Expand Up @@ -206,6 +231,19 @@ defmodule ExForce do
end
end

defp do_request_sobject(client, method, path, attrs) do
case ExForce.Client.request(client, %ExForce.Request{
method: method,
url: path,
body: attrs
}) do
{:ok, %ExForce.Response{status: 200, body: body}} -> {:ok, body}
{:ok, %ExForce.Response{status: 201, body: body}} -> {:ok, body}
{:ok, %ExForce.Response{body: body}} -> {:error, body}
{:error, _} = other -> other
end
end

defp build_fields_query([]), do: []
defp build_fields_query(fields), do: [fields: Enum.join(fields, ",")]

Expand Down
41 changes: 41 additions & 0 deletions test/ex_force_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,47 @@ defmodule ExForceTest do
) == {:error, :econnrefused}
end

test "request_sobject_by_external_id/4", %{bypass: bypass, client: client} do
Bypass.expect_once(
bypass,
"PATCH",
"/services/data/v53.0/sobjects/Account/Foo__c/foo%20bar",
fn conn ->
conn
|> Conn.put_resp_content_type("application/json")
|> Conn.resp(201, """
{
"created": true,
"errors": [],
"id": "foo",
"success": true
}
""")
end
)

assert ExForce.request_sobject_by_external_id(
client,
:patch,
"foo bar",
"Foo__c",
"Account",
%{Name: "name"}
) ==
{:ok, %{"created" => true, "errors" => [], "id" => "foo", "success" => true}}
end

test "request_sobject_by_external_id/4 - network error" do
assert ExForce.request_sobject_by_external_id(
client_with_econnrefused(),
:patch,
"foo bar",
"Foo__c",
"Account",
%{Name: "name"}
) == {:error, :econnrefused}
end

test "get_sobject_by_relationship/5 - success", %{bypass: bypass, client: client} do
Bypass.expect_once(
bypass,
Expand Down