Skip to content

Commit e263e2f

Browse files
committed
✨ Add Salesforce custom plugin
1 parent 3d0fb0e commit e263e2f

File tree

9 files changed

+647
-0
lines changed

9 files changed

+647
-0
lines changed

plugins/salesforce_custom/.gitignore

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
# Go template downloaded with gut
3+
*.exe
4+
*.exe~
5+
*.dll
6+
*.so
7+
*.dylib
8+
*.test
9+
*.out
10+
go.work
11+
.gut
12+
13+
# Dev files
14+
*.log
15+
devManifest.*
16+
.init
17+
18+
dist/
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
version: 2
3+
4+
before:
5+
hooks:
6+
# You may remove this if you don't use go modules.
7+
- go mod tidy
8+
9+
builds:
10+
- env:
11+
- CGO_ENABLED=0
12+
goos:
13+
- linux
14+
- windows
15+
- darwin
16+
binary: salesforce_custom
17+
id: anyquery
18+
ldflags: "-s -w"
19+
flags: # To ensure reproducible builds
20+
- -trimpath
21+
22+
goarch:
23+
- amd64
24+
- arm64
25+
26+
archives:
27+
- format: binary
28+
29+
changelog:
30+
sort: asc
31+
filters:
32+
exclude:
33+
- "^docs:"
34+
- "^test:"

plugins/salesforce_custom/Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
files := $(wildcard *.go)
3+
4+
all: $(files)
5+
go build -o salesforce_custom.out $(files)
6+
7+
prod: $(files)
8+
go build -o salesforce_custom.out -ldflags "-s -w" $(files)
9+
10+
clean:
11+
rm -f salesforce_custom.out
12+
13+
.PHONY: all clean

plugins/salesforce_custom/README.md

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Salesforce
2+
3+
The Salesforce custom plugin provides a way to interact with a Salesforce sObject using SQL queries. It allows you to query, insert, update, and delete records from Salesforce objects.
4+
5+
Compared to the [Salesforce plugin](https://anyquery.dev/integrations/salesforce), the Salesforce custom plugin doesn't have a predefined list of tables. Instead, you input the sobject you want to query, and the plugin will make the sObject available as a table in the query.
6+
7+
## Usage
8+
9+
In the plugin configuration, you will provide the sobject you want to query. Then, the plugin will make the sObject available as a table in the query.
10+
11+
```sql
12+
-- Let's say you chose the account sobject
13+
SELECT Id, Name FROM salesforce_custom_object
14+
15+
-- Now you have a second profile named contact with the contact sobject configured
16+
SELECT Id, LastName FROM contact_salesforce_custom_object
17+
```
18+
19+
If you want to query across multiple organizations, you can [create multiple profiles](https://anyquery.dev/docs/usage/managing-profiles) and configure each profile with the credentials of a different organization.
20+
21+
```bash
22+
anyquery profile new default salesforce_custom mysobject
23+
```
24+
25+
## Configuration
26+
27+
To get started, install the plugin:
28+
29+
```bash
30+
anyquery install salesforce_custom
31+
```
32+
33+
To use this plugin, you will need a Salesforce organization with the REST API enabled. Currently, there are four ways to authenticate with the Salesforce plugin:
34+
35+
- Username and Password
36+
- Access Token using the `sf` CLI
37+
- OAuth 2.0 Web Server Flow
38+
- OAuth 2.0 Client Credentials Flow
39+
40+
All flows require the following configuration:
41+
42+
- `domain`: The domain of your Salesforce organization. For example, `mydomain.my.salesforce.com`. You need to left out the `https://` part. You can find this in the URL of the login page. <br> In `https://mycompany.lightning.force.com/lightning/setup`, your domain is `mycompany.my.salesforce.com`. For more information, see [Finding Your Salesforce Domain](https://help.salesforce.com/s/articleView?id=sf.faq_domain_name_what.htm&type=5).
43+
- `cache_ttl`: The time-to-live (TTL) for the cache in seconds. The default is 0, which means no cache.
44+
- `encryption_key`: The encryption key used to encrypt the cache for sensitive data. The key must either be 16, 24, or 32 bytes long. Make sure you are using ascii characters only. If you don't provide an encryption key, the plugin will not be able to start.
45+
46+
### Access Token using the `sf` CLI
47+
48+
1. Install the `sf` CLI by [following the instructions](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm)
49+
2. Run `sf org login web` to authenticate with Salesforce
50+
3. Run `sf org display --target-org <username>` and replace `<username>` with your username
51+
4. Copy the Access Token from the output
52+
53+
When anyquery will ask for the access token, paste the token you copied. Fill in the `domain`, `encryption_key`, and `cache_ttl` in the configuration, and leave the other fields empty.
54+
55+
Note that the access token expires after a certain amount of time (usually 1 hour). You can refresh the access token by running again `sf org login web` and copying the new access token. Then run `anyquery profiles update default salesforce_custom <profile name>` (*default* is the main profile name) and paste the new access token in the access token field. Leave the other fields empty.
56+
57+
### OAuth 2.0 Web Server Flow
58+
59+
#### Step 1: Create a Connected App
60+
61+
1. Go to `Setup` > `App Manager` > `New Connected App`
62+
2. Fill in the required fields
63+
3. In the `API (Enable OAuth Settings)` section, check `Enable OAuth Settings`
64+
4. In the `Callback URL` field, enter `http://localhost:8080/callback`
65+
5. In the `Selected OAuth Scopes` section, add the required scopes
66+
- Access and manage your data (api)
67+
- Perform requests on your behalf at any time (refresh_token, offline_access)
68+
6. Click `Save`
69+
70+
#### Step 2: Get the Consumer Key and Consumer Secret
71+
72+
1. Go to `Setup` > `App Manager` > `Manage Connected Apps`
73+
2. Click on the app you created
74+
3. Open OAuth Settings accordion
75+
4. Click on `Consumer Key`, pass the security check, and copy the consumer key and consumer secret
76+
77+
#### Step 3: Authenticate with Salesforce
78+
79+
Open in your browser the following URL and replace the placeholders with your values:
80+
81+
```url
82+
https://<domain>/services/oauth2/authorize?response_type=code&client_id=<consumer_key>&redirect_uri=http://localhost:8080/callback
83+
```
84+
85+
After you authenticate, you will be redirected to `http://localhost:8080/callback?code=<code>`. Copy the code from the URL.
86+
87+
#### Step 4: Get the refresh token
88+
89+
Run the following command in your terminal and replace the placeholders with your values:
90+
91+
```bash
92+
curl -X "POST" "https://<domain>/services/oauth2/token" \
93+
-H 'Content-Type: application/x-www-form-urlencoded; charset=utf-8' \
94+
--data-urlencode "grant_type=authorization_code" \
95+
--data-urlencode "code=<the code you copied from the URL>" \
96+
--data-urlencode "client_id=<consumer_key>" \
97+
--data-urlencode "client_secret=<consumer_secret>" \
98+
--data-urlencode "redirect_uri=http://localhost:8080/callback"
99+
```
100+
101+
Copy the `refresh_token` from the response. When anyquery will ask for the refresh token, paste the token you copied. Fill in the `domain`, `consumer_key`, `consumer_secret`, `encryption_key`, and `cache_ttl` in the configuration, and leave the other fields empty.
102+
103+
### OAuth 2.0 Client Credentials Flow
104+
105+
#### Step 1: Create a Connected App
106+
107+
1. Go to `Setup` > `App Manager` > `New Connected App`
108+
2. Fill in the required fields
109+
3. In the `API (Enable OAuth Settings)` section, check `Enable OAuth Settings`
110+
4. In the `Callback URL` field, enter whatever you want
111+
5. In the `Selected OAuth Scopes` section, add the required scopes
112+
- Access and manage your data (api)
113+
- Perform requests on your behalf at any time (refresh_token, offline_access)
114+
6. Click `Save`
115+
116+
Now you need to enable the `Client Credentials OAuth Flow` for the connected app:
117+
118+
1. Go to `Setup` > `App Manager` > `Manage Connected Apps`
119+
2. Click on the app you created
120+
3. Click on `Edit Policies`
121+
4. Under OAuth Policies, select "Enable Client Credentials OAuth Flow"
122+
5. In the input field just below, enter the email adress of the user you want to impersonate for Anyquery
123+
6. Click `Save`
124+
125+
#### Step 2: Get the Consumer Key and Consumer Secret
126+
127+
1. Go to `Setup` > `App Manager` > `Manage Connected Apps`
128+
2. Click on the app you created
129+
3. Open OAuth Settings accordion
130+
4. Click on `Consumer Key`, pass the security check, and copy the consumer key and consumer secret
131+
132+
When asked by Anyquery, paste the consumer key and consumer secret. Fill in the `domain`, `encryption_key`, and `cache_ttl` in the configuration, and leave the other fields empty.
133+
134+
### Username and Password
135+
136+
This flow is not recommended for security reasons. If you can, prefer the Client Credentials Flow.
137+
138+
#### Step 1: Create a Connected App
139+
140+
1. Go to `Setup` > `App Manager` > `New Connected App`
141+
2. Fill in the required fields
142+
3. In the `API (Enable OAuth Settings)` section, check `Enable OAuth Settings`
143+
4. In the `Callback URL` field, enter `http://localhost:8080/callback`
144+
5. In the `Selected OAuth Scopes` section, add the required scopes
145+
- Access and manage your data (api)
146+
- Perform requests on your behalf at any time (refresh_token, offline_access)
147+
6. Click `Save`
148+
149+
#### Step 2: Enable the Username and Password OAuth Flow
150+
151+
1. Go to `Setup` > `Identity` > `OAuth and OpenID Connect Settings`
152+
2. Check `Allow users to use the username/password OAuth flow` and click `Save`
153+
154+
Once done, when asked by Anyquery, paste the consumer key (client_id) and consumer secret (client_secret). Fill in the `domain`, `encryption_key`, and `cache_ttl` in the configuration.
155+
You'll need to enter your username and password when Anyquery asks for them. Your password is the concatenation of your password and your security token. Learn how to get your security token [here](https://help.salesforce.com/s/articleView?id=xcloud.user_security_token.htm&type=5).
156+
157+
## Additional Information
158+
159+
- The plugin uses the Salesforce REST API to interact with Salesforce. As a rule of thumb, querying 2000 records costs 1 API request. And 200 Insert, Update, or Delete operations cost 1 API request. Refer to the [Salesforce documentation](https://help.salesforce.com/s/articleView?id=000389027&type=1) to find your monthly API request limit.
160+
- Queries using `sum`, `count` or other aggregate functions may result in a lot of API requests because Anyquery has to fetch all the records to calculate the result. Avoid them on `sobject` that have a lot of records.
161+
- The plugin uses the v61.0 version (Summer '24) of the Salesforce API.
162+
- The plugin caches the results of the queries to reduce the number of API requests. The cache is encrypted using the encryption key provided in the configuration. You can change the cache TTL in the configuration.
163+
- Internally, the plugin transforms the SQL queries into SOQL queries to interact with Salesforce.
164+
- Any insert or update on fields that are not updatable will be ignored.
165+
- The plugin doesn't support the Bulk API. If it's a requirement for you, feel free to [open an issue](https://github.com/julien040/anyquery/issues/new)
166+
167+
## Schema
168+
169+
The schema will depend of the object you are querying.

plugins/salesforce_custom/go.mod

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
module github.com/julien040/anyquery/plugins/salesforce_custom
2+
3+
go 1.23.2
4+
5+
require (
6+
github.com/julien040/anyquery v0.1.3
7+
github.com/julien040/anyquery/plugins/salesforce v0.0.0-20241017131231-c2247a7f1db1
8+
)
9+
10+
require (
11+
github.com/adrg/xdg v0.4.0 // indirect
12+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
13+
github.com/dgraph-io/badger/v4 v4.3.0 // indirect
14+
github.com/dgraph-io/ristretto v0.1.2-0.20240116140435-c67e07994f91 // indirect
15+
github.com/dustin/go-humanize v1.0.1 // indirect
16+
github.com/fatih/color v1.17.0 // indirect
17+
github.com/go-resty/resty/v2 v2.15.3 // indirect
18+
github.com/gogo/protobuf v1.3.2 // indirect
19+
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
20+
github.com/golang/protobuf v1.5.4 // indirect
21+
github.com/google/flatbuffers v1.12.1 // indirect
22+
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
23+
github.com/hashicorp/go-hclog v1.6.3 // indirect
24+
github.com/hashicorp/go-plugin v1.6.1 // indirect
25+
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
26+
github.com/hashicorp/yamux v0.1.2 // indirect
27+
github.com/huandu/go-sqlbuilder v1.30.1 // indirect
28+
github.com/huandu/xstrings v1.4.0 // indirect
29+
github.com/klauspost/compress v1.17.9 // indirect
30+
github.com/mattn/go-colorable v0.1.13 // indirect
31+
github.com/mattn/go-isatty v0.0.20 // indirect
32+
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
33+
github.com/oklog/run v1.1.0 // indirect
34+
github.com/pkg/errors v0.9.1 // indirect
35+
go.opencensus.io v0.24.0 // indirect
36+
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
37+
golang.org/x/net v0.30.0 // indirect
38+
golang.org/x/oauth2 v0.23.0 // indirect
39+
golang.org/x/sys v0.26.0 // indirect
40+
golang.org/x/text v0.19.0 // indirect
41+
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
42+
google.golang.org/grpc v1.67.1 // indirect
43+
google.golang.org/protobuf v1.35.1 // indirect
44+
)

0 commit comments

Comments
 (0)