サンプルの DataSource.Connection クラスの作成
1global class SampleDataSourceConnection
2 extends DataSource.Connection {
3 global SampleDataSourceConnection(DataSource.ConnectionParams
4 connectionParams) {
5 }
6// ...sync
sync() メソッドは、システム管理者が外部データソースの詳細ページで [検証して同期] ボタンをクリックしたときに呼び出されます。このメソッドは、外部システムの構造的なメタデータを説明する情報を返します。
1// ...
2 override global List<DataSource.Table> sync() {
3 List<DataSource.Table> tables =
4 new List<DataSource.Table>();
5 List<DataSource.Column> columns;
6 columns = new List<DataSource.Column>();
7 columns.add(DataSource.Column.text('Name', 255));
8 columns.add(DataSource.Column.text('ExternalId', 255));
9 columns.add(DataSource.Column.url('DisplayUrl'));
10 tables.add(DataSource.Table.get('Sample', 'Title',
11 columns));
12 return tables;
13 }
14// ...query
query メソッドは、外部オブジェクトで SOQL クエリが実行されたときに呼び出されます。SOQL クエリは、Salesforce でユーザが外部オブジェクトのリストビューまたは詳細ページを開いたときに自動的に生成され実行されます。DataSource.QueryContext は常に 1 つのテーブルのみを対象とします。
このサンプルのカスタムアダプタは、DataSource.QueryUtils クラスでヘルパーメソッドを使用して、SOQL クエリの WHERE および ORDER BY 句を基に結果の絞り込みや並び替えを行います。
DataSource.QueryUtils クラスとそのヘルパーメソッドは、Salesforce 組織内でローカルにクエリ結果を処理できます。このクラスは、初期テスト用の Salesforce Connect カスタムアダプタの開発を簡略化し、利便性を向上することを目的として提供されます。ただし、DataSource.QueryUtils クラスとそのメソッドは、コールアウトを使用して外部システムからデータを取得する本番環境での使用はサポートされていません。クエリ結果を Salesforce に送信する前に、外部システムで絞り込みと並び替えを完了してください。可能であれば、サーバ駆動ページングを使用するか、別の技法を使用してクエリの LIMIT および OFFSET 句に従って外部システムに適切なデータサブセットを判定させてください。
1// ...
2 override global DataSource.TableResult query(
3 DataSource.QueryContext context) {
4 if (context.tableSelection.columnsSelected.size() == 1 &&
5 context.tableSelection.columnsSelected.get(0).aggregation ==
6 DataSource.QueryAggregation.COUNT) {
7 List<Map<String,Object>> rows = getRows(context);
8 List<Map<String,Object>> response =
9 DataSource.QueryUtils.filter(context, getRows(context));
10 List<Map<String, Object>> countResponse =
11 new List<Map<String, Object>>();
12 Map<String, Object> countRow =
13 new Map<String, Object>();
14 countRow.put(
15 context.tableSelection.columnsSelected.get(0).columnName,
16 response.size());
17 countResponse.add(countRow);
18 return DataSource.TableResult.get(context,
19 countResponse);
20 } else {
21 List<Map<String,Object>> filteredRows =
22 DataSource.QueryUtils.filter(context, getRows(context));
23 List<Map<String,Object>> sortedRows =
24 DataSource.QueryUtils.sort(context, filteredRows);
25 List<Map<String,Object>> limitedRows =
26 DataSource.QueryUtils.applyLimitAndOffset(context,
27 sortedRows);
28 return DataSource.TableResult.get(context, limitedRows);
29 }
30 }
31// ...search
search メソッドは、外部オブジェクトの SOSL クエリによって呼び出されるか、外部オブジェクトも検索する Salesforce グローバル検索をユーザが実行したときに呼び出されます。DataSource.SearchContext は複数のオブジェクトに対する統合検索が可能なため、複数のテーブルを選択できます。ただし、次の例では、カスタムアダプタが 1 つのテーブルしか認識していません。
1// ...
2 override global List<DataSource.TableResult> search(
3 DataSource.SearchContext context) {
4 List<DataSource.TableResult> results =
5 new List<DataSource.TableResult>();
6 for (DataSource.TableSelection tableSelection :
7 context.tableSelections) {
8 results.add(DataSource.TableResult.get(tableSelection,
9 getRows(context)));
10 }
11 return results;
12 }
13// ...- makeGetCallout は、外部システムにコールアウトを実行します。
- foundRow は、コールアウトの結果の値に基づいて行に値を入力します。foundRow メソッドは、項目名や項目値の変更など、返された項目値に変更を行うために使用されます。
このスニペットに上記のメソッドは含まれませんが、「Connection クラス」に詳細な例が記載されています。通常、結果セットを縮小するために SearchContext または QueryContext の検索条件が使用されますが、この例では簡易化のため、コンテキストオブジェクトは使用していません。
1// ...
2 // Helper method to get record values from the external system for the Sample table.
3 private List<Map<String, Object>> getRows () {
4 // Get row field values for the Sample table from the external system via a callout.
5 HttpResponse response = makeGetCallout();
6 // Parse the JSON response and populate the rows.
7 Map<String, Object> m = (Map<String, Object>)JSON.deserializeUntyped(
8 response.getBody());
9 Map<String, Object> error = (Map<String, Object>)m.get('error');
10 if (error != null) {
11 throwException(string.valueOf(error.get('message')));
12 }
13 List<Map<String,Object>> rows = new List<Map<String,Object>>();
14 List<Object> jsonRows = (List<Object>)m.get('value');
15 if (jsonRows == null) {
16 rows.add(foundRow(m));
17 } else {
18 for (Object jsonRow : jsonRows) {
19 Map<String,Object> row = (Map<String,Object>)jsonRow;
20 rows.add(foundRow(row));
21 }
22 }
23 return rows;
24 }
25// ...upsertRows
upsertRows メソッドは、外部オブジェクトレコードが作成または更新されるときに呼び出されます。外部オブジェクトレコードは、Salesforce ユーザインターフェースまたは DML を使用して作成または更新できます。次の例は、upsertRows メソッドのサンプル実装を示しています。この例では、渡された UpsertContext を使用してどのテーブルが選択されたかを判断し、選択されたテーブルの名前が Sample の場合にのみ更新/挿入���実行します。更新/挿入操作は、新しいレコードの挿入と既存のレコードの更新のいずれかに分けられます。これらの操作は、コールアウトを使用して外部システムで実行されます。コールアウト応答から取得した結果を基に DataSource.UpsertResult の配列に値が入力されます。コールアウトは行ごとに実行されるため、次の例では Apex のコールアウト数の制限に達する可能性があります。
1// ...
2 global override List<DataSource.UpsertResult> upsertRows(DataSource.UpsertContext
3 context) {
4 if (context.tableSelected == 'Sample') {
5 List<DataSource.UpsertResult> results = new List<DataSource.UpsertResult>();
6 List<Map<String, Object>> rows = context.rows;
7
8 for (Map<String, Object> row : rows){
9 // Make a callout to insert or update records in the external system.
10 HttpResponse response;
11 // Determine whether to insert or update a record.
12 if (row.get('ExternalId') == null){
13 // Send a POST HTTP request to insert new external record.
14 // Make an Apex callout and get HttpResponse.
15 response = makePostCallout(
16 '{"name":"' + row.get('Name') + '","ExternalId":"' +
17 row.get('ExternalId') + '"');
18 }
19 else {
20 // Send a PUT HTTP request to update an existing external record.
21 // Make an Apex callout and get HttpResponse.
22 response = makePutCallout(
23 '{"name":"' + row.get('Name') + '","ExternalId":"' +
24 row.get('ExternalId') + '"',
25 String.valueOf(row.get('ExternalId')));
26 }
27
28 // Check the returned response.
29 // Deserialize the response.
30 Map<String, Object> m = (Map<String, Object>)JSON.deserializeUntyped(
31 response.getBody());
32 if (response.getStatusCode() == 200){
33 results.add(DataSource.UpsertResult.success(
34 String.valueOf(m.get('id'))));
35 }
36 else {
37 results.add(DataSource.UpsertResult.failure(
38 String.valueOf(m.get('id')),
39 'The callout resulted in an error: ' +
40 response.getStatusCode()));
41 }
42 }
43 return results;
44 }
45 return null;
46 }
47// ...deleteRows
deleteRows メソッドは、外部オブジェクトレコードが削除されるときに呼び出されます。外部オブジェクトレコードは、Salesforce ユーザインターフェースまたは DML を使用して削除できます。次の例は、deleteRows メソッドのサンプル実装を示しています。この例では、渡された DeleteContext を使用してどのテーブルが選択されたかを判断し、選択されたテーブルの名前が Sample の場合にのみ削除を実行します。削除は、各外部 ID のコールアウトを使用して外部システムで実行されます。コールアウト応答から取得した結果を基に DataSource.DeleteResult の配列に値が入力されます。コールアウトは ID ごとに実行されるため、次の例では Apex のコールアウト数の制限に達する可能性があります。
1// ...
2 global override List<DataSource.DeleteResult> deleteRows(DataSource.DeleteContext
3 context) {
4 if (context.tableSelected == 'Sample'){
5 List<DataSource.DeleteResult> results = new List<DataSource.DeleteResult>();
6 for (String externalId : context.externalIds){
7 HttpResponse response = makeDeleteCallout(externalId);
8 if (response.getStatusCode() == 200){
9 results.add(DataSource.DeleteResult.success(externalId));
10 }
11 else {
12 results.add(DataSource.DeleteResult.failure(externalId,
13 'Callout delete error:'
14 + response.getBody()));
15 }
16 }
17 return results;
18 }
19 return null;
20 }
21// ...