Connection Class

Extend this class to enable your Salesforce org to sync the external system’s schema and to handle queries, searches, and write operations (upsert and delete) of the external data. This class extends the DataSourceUtil class and inherits its methods.

Namespace

DataSource

Usage

Your DataSource.Connection and DataSource.Provider classes compose a custom adapter for Salesforce Connect.

Changing the sync method on the DataSource.Connection class doesn’t automatically resync any external objects.

Example

1global class SampleDataSourceConnection extends DataSource.Connection {
2    global SampleDataSourceConnection(DataSource.ConnectionParams connectionParams) {
3    }
4    
5    override global List<DataSource.Table> sync() {
6        List<DataSource.Table> tables = new List<DataSource.Table>();        
7        List<DataSource.Column> columns;
8        columns = new List<DataSource.Column>();
9        columns.add(DataSource.Column.text('Name', 255));
10        columns.add(DataSource.Column.text('ExternalId', 255));
11        columns.add(DataSource.Column.url('DisplayUrl'));
12        tables.add(DataSource.Table.get('Sample', 'Title', columns));
13        return tables;
14    }
15    
16    override global DataSource.TableResult query(DataSource.QueryContext c) {
17        return DataSource.TableResult.get(c, DataSource.QueryUtils.process(c, getRows()));
18    }
19    
20    override global List<DataSource.TableResult> search(DataSource.SearchContext c) {        
21        List<DataSource.TableResult> results = new List<DataSource.TableResult>();
22        for (DataSource.TableSelection tableSelection : c.tableSelections) {
23            results.add(DataSource.TableResult.get(tableSelection, getRows()));
24        }
25        return results;
26    }
27
28    // Helper method to get record values from the external system for the Sample table.
29    private List<Map<String, Object>> getRows () {
30        // Get row field values for the Sample table from the external system via a callout.
31        HttpResponse response = makeGetCallout();
32        // Parse the JSON response and populate the rows.
33        Map<String, Object> m = (Map<String, Object>)JSON.deserializeUntyped(
34                response.getBody());
35        Map<String, Object> error = (Map<String, Object>)m.get('error');
36        if (error != null) {
37            throwException(string.valueOf(error.get('message')));
38        }
39        List<Map<String,Object>> rows = new List<Map<String,Object>>();
40        List<Object> jsonRows = (List<Object>)m.get('value');
41        if (jsonRows == null) {
42            rows.add(foundRow(m));
43        } else {
44            for (Object jsonRow : jsonRows) {
45                Map<String,Object> row = (Map<String,Object>)jsonRow;
46                rows.add(foundRow(row));
47            }
48        }
49        return rows;
50    }
51    
52    global override List<DataSource.UpsertResult> upsertRows(DataSource.UpsertContext
53            context) {
54       if (context.tableSelected == 'Sample') {
55           List<DataSource.UpsertResult> results = new List<DataSource.UpsertResult>();
56           List<Map<String, Object>> rows = context.rows;
57           
58           for (Map<String, Object> row : rows){
59              // Make a callout to insert or update records in the external system.
60              HttpResponse response;
61              // Determine whether to insert or update a record.
62              if (row.get('ExternalId') == null){
63                 // Send a POST HTTP request to insert new external record.
64                 // Make an Apex callout and get HttpResponse.
65                 response = makePostCallout(
66                     '{"name":"' + row.get('Name') + '","ExternalId":"' + 
67                     row.get('ExternalId') + '"');
68              }
69              else {
70                 // Send a PUT HTTP request to update an existing external record.
71                 // Make an Apex callout and get HttpResponse.
72                 response = makePutCallout(
73                     '{"name":"' + row.get('Name') + '","ExternalId":"' + 
74                     row.get('ExternalId') + '"',
75                     String.valueOf(row.get('ExternalId')));
76              }
77         
78              // Check the returned response.
79              // First, deserialize it.
80              Map<String, Object> m = (Map<String, Object>)JSON.deserializeUntyped(
81                      response.getBody());
82              if (response.getStatusCode() == 200){
83                  results.add(DataSource.UpsertResult.success(
84                          String.valueOf(m.get('id'))));
85              } 
86              else {
87                 results.add(DataSource.UpsertResult.failure(
88                                 String.valueOf(m.get('id')), 
89                     'The callout resulted in an error: ' + 
90                     response.getStatusCode()));
91              }
92           } 
93           return results;
94       } 
95       return null;
96    }
97         
98    global override List<DataSource.DeleteResult> deleteRows(DataSource.DeleteContext 
99            context) {
100       if (context.tableSelected == 'Sample'){
101           List<DataSource.DeleteResult> results = new List<DataSource.DeleteResult>();
102           for (String externalId : context.externalIds){
103              HttpResponse response = makeDeleteCallout(externalId);
104              if (response.getStatusCode() == 200){
105                 results.add(DataSource.DeleteResult.success(externalId));
106              } 
107              else {
108                 results.add(DataSource.DeleteResult.failure(externalId, 
109                             'Callout delete error:' 
110                             + response.getBody()));
111              }
112           }
113           return results;
114       }
115       return null;
116     }
117     
118    // Helper methods
119        
120    // Make a GET callout
121     private static HttpResponse makeGetCallout() {
122         HttpResponse response;
123         // Make callout
124         // ...
125         return response;
126     }
127     
128     // Populate a row based on values from the external system.
129     private Map<String,Object> foundRow(Map<String,Object> foundRow) {
130        Map<String,Object> row = new Map<String,Object>();
131        row.put('ExternalId', string.valueOf(foundRow.get('Id')));
132        row.put('DisplayUrl', string.valueOf(foundRow.get('DisplayUrl')));
133        row.put('Name', string.valueOf(foundRow.get('Name')));        
134        return row;
135    }
136
137     // Make a POST callout
138     private static HttpResponse makePostCallout(String jsonBody) {
139         HttpResponse response;
140         // Make callout
141         // ...
142         return response;
143     }
144     
145     // Make a PUT callout
146     private static HttpResponse makePutCallout(String jsonBody, String externalID) {
147         HttpResponse response;
148         // Make callout
149         // ...
150         return response;
151     }
152     
153     // Make a DELETE callout
154     private static HttpResponse makeDeleteCallout(String externalID) {
155         HttpResponse response;
156         // Make callout
157         // ...
158         return response;
159     }
160}

Connection Methods

The following are methods for Connection.

deleteRows(deleteContext)

Invoked when external object records are deleted via the Salesforce user interface, APIs, or Apex.

Signature

public List<DataSource.DeleteResult> deleteRows(DataSource.DeleteContext deleteContext)

Parameters

deleteContext
Type: DataSource.DeleteContext
Contains context information about the delete request.

Return Value

Type: List<DataSource.DeleteResult>

The results of the delete operation.

query(queryContext)

Invoked by a SOQL query of an external object. A SOQL query is generated and executed when a user visits an external object’s list view or record detail page in Salesforce. Returns the results of the query.

Signature

public DataSource.TableResult query(DataSource.QueryContext queryContext)

Parameters

queryContext
Type: DataSource.QueryContext
Represents the query to run against a data table.

Return Value

Type: DataSource.TableResult

sync()

Invoked when an administrator clicks Validate and Sync on the external data source detail page. Returns a list of tables that describe the external system’s schema.

Signature

public List<DataSource.Table> sync()

Return Value

Type: List<DataSource.Table>

Each returned table can be used to create an external object in Salesforce. On the Validate External Data Source page, the administrator views the list of returned tables and selects which tables to sync. When the administrator clicks Sync, an external object is created for each selected table. Each column within the selected tables also becomes a field in the external object.

upsertRows(upsertContext)

Invoked when external object records are created or updated via the Salesforce user interface, APIs, or Apex.

Signature

public List<DataSource.UpsertResult> upsertRows(DataSource.UpsertContext upsertContext)

Parameters

upsertContext
Type: DataSource.UpsertContext
Contains context information about the upsert request.

Return Value

Type: List<DataSource.UpsertResult>

The results of the upsert operation.