Skip to content

Instantly share code, notes, and snippets.

@zblanco
Last active May 13, 2019 20:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zblanco/dc514be204cbed6c3c99abd9d583492b to your computer and use it in GitHub Desktop.
Save zblanco/dc514be204cbed6c3c99abd9d583492b to your computer and use it in GitHub Desktop.

Salesforks

A theoretical Salesforce API wrapper to bring higher level abstractions and functional design techniques to Salesforce.

Code samples are in Elixir, but the techniques can be applied elsewhere.

The Operation Protocol

An Operation is a datastructure that represents a set of actions that can be applied against a given Salesforce Org. The Operation is protocol or contract which enforces that consuming datastructures can be converted into a valid Operation against a Salesforce API. An Operation could represent a batch or composite API request. Any valid Operation can be converted into a raw HTTP Request that can be executed against an HTTP Client.

The Org

The Org is a run-time dependency injected resource that holds the credentials needed to authenticate requests. Runtime dependency injection here is important as the Salesforce User credentials may change frequently.

In-Memory Org Model/Schema generation

A Salesforce Org is a quickly moving target. While it is best practice to be pushing new changes from a Sandbox or scratch Org before deploying to a production instance - that's not worth relying on. In addition to returning errors from an executed Operation you may want validation prior to side effects like upserts on a Production org. One way to do that is to maintain an in-memory representation of a given Salesforce org. There are Metadata resources, so building an internal schema of fields, types, and things like picklist options are all possible. Metadata change subscriptions via CometD/Streaming API allows us to maintain this in-memory representation without polling the REST API.

Examples

# New Account
acc_params = %{name: "Test Account", company: "Test Co"}
new_account_operation = SObject.new('Account', acc_params)
> %Operation{
	valid: true,
	errors: [],
	type: :sobject,
	schema: %{
		sobject: "Account",
		fields: %{
			name: "Test Account",
			company: "Test Co",
		}
	}
}

# Query
all_accounts_query = Query.new("SELECT Id FROM Account")
> %Operation{
	valid: true,
	errors: [],
	type: :query,
	query: "SELECT Id FROM Account"
}

# Executing a Query

result = Org.execute(all_accounts_query)
> {:ok, %QueryResult{
	query: 'SELECT Id FROM Account',
	size: 2,
	records: [
		%Record{
			type: "Account",
			url: "/services/data/v20.0/sobjects/Account/001D000000IRFmaIAH",
			data: %{
				id: "001D000000IRFmaIAH",
				name: "Test Account",
				company: "Test Co",
			}
		},
		%Record{
			type: "Account",
			url: "/services/data/v20.0/sobjects/Account/001D000000IRFmaIAB",
			data: %{
				id: "001D000000IRFmaIAB",
				name: "Test Account2",
				company: "Test Co2",
			}
		},
	]

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