Things have changed after that post and finally the platform supports all DML statements: insert, update and delete!
To make the magic work I had to make:
- some changes on the heroku-crest MondoDB NodeJS proxy to better support for PUT/DELETE/POST methods
- some changes on the Apex side
Follow the post instructions to setup up your Heroku app.
The core changes are the support for the methods.
Open the MongoDBDataSrouceProvider.cls class:
1 2 3 4 5 6 7 8 9 10 11 12 | override global List<datasource.capability> getCapabilities() { List<datasource.capability> capabilities = new List<datasource.capability>(); capabilities.add(DataSource.Capability.ROW_QUERY); capabilities.add(DataSource.Capability.SEARCH); //new capabilities added capabilities.add(DataSource.Capability.ROW_CREATE); capabilities.add(DataSource.Capability.ROW_UPDATE); capabilities.add(DataSource.Capability.ROW_DELETE); return capabilities; } </datasource.capability></datasource.capability></datasource.capability> |
The provider has been added with more capabilities, CREATE, UPDATE and DELETE.
Let's open the MongoDBDataSourceConnectio.cls class and look at the 2 new methods:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | global override List<DataSource.UpsertResult> upsertRows(DataSource.UpsertContext context) { List<DataSource.UpsertResult> results = new List<DataSource.UpsertResult>(); List<Map<String, Object>> rows = context.rows; Http h = new Http(); for (Integer i = 0 ; i < rows.size(); i++){ Map<String,Object> row = rows[i]; HttpRequest request = new HttpRequest(); request.setHeader( 'Content-Type' , 'application/json' ); request.setTimeout( 60000 ); Map<String,Object> invoice = new Map<String,Object>(); if (String.isBlank((String)row.get( 'ExternalId' ))){ request.setMethod( 'POST' ); request.setEndpoint(DB_ENDPOINT_NC); } else { request.setMethod( 'PUT' ); request.setEndpoint(DB_ENDPOINT_NC+ '/' +row.get( 'ExternalId' )); } invoice.put( 'accountid' , row.get( 'Account' )); invoice.put( 'contractid' , row.get( 'Contract' )); invoice.put( 'created' , row.get( 'CreatedDate' )); invoice.put( 'amount' , row.get( 'Amount' )); invoice.put( 'description' , row.get( 'Description' )); request.setBody(JSON.serialize(invoice)); HttpResponse response = h.send(request); List<Object> mList = (List<Object>)JSON.deserializeUntyped(response.getBody()); Map<String, Object> m = (Map<String, Object>)mList[ 0 ]; if (response.getStatusCode() == 200 ){ String objId = String.valueOf(m.get( '_id' )); if (String.isBlank(objId)){ objId = String.valueOf(row.get( 'ExternalId' )); } results.add(DataSource.UpsertResult.success(objId)); } else { results.add(DataSource.UpsertResult.failure( String.valueOf(row.get( 'ExternalId' )), 'The callout resulted in an error: ' + response.getStatusCode()+ ' - ' +response.getBody())); } } return results; } global override List<DataSource.DeleteResult> deleteRows(DataSource.DeleteContext context) { List<DataSource.DeleteResult> results = new List<DataSource.DeleteResult>(); Http h = new Http(); for (String externalId : context.externalIds){ HttpRequest request = new HttpRequest(); request.setHeader( 'Content-Type' , 'application/json' ); request.setTimeout( 60000 ); request.setMethod( 'DELETE' ); request.setEndpoint(DB_ENDPOINT_NC+ '/' +externalId); HttpResponse response = h.send(request); if (response.getStatusCode() == 200 || response.getStatusCode() == 201 ){ results.add(DataSource.DeleteResult.success(String.valueOf(externalId))); } else { results.add(DataSource.DeleteResult.failure( String.valueOf(externalId), 'The callout resulted in an error: ' + response.getStatusCode()+ ' - ' +response.getBody())); } } return results; } |
WARNING: this code is not optimized for bulk upsert/delete because it makes a callout for every record.
It's a proove of concept, so I challenge you to bulkify the class!
How can you insert an external object provided by a Lightning Connect adapter?
The Database class has been provided with new methods:
- deleteAsync
- insertAsync
- updateAsync
These methods are used to make the calls to the remote system and actually do the work!
1 2 3 4 5 | Database.insertAsync( new List<MongoDB_Invoice__x>{ new MongoDB_Invoice__x(Amount__c= 1 , Description__c = 'Async Test 1' ), new MongoDB_Invoice__x(Amount__c= 2 , Description__c = 'Async Test 2' ) }); Database.deleteAsync([Select Id From MongoDB_Invoice__x Where Description__c = 'Async Test 1' ]); |
Every method has an alternative method that provides a callback class, which allows to make further actions after the records are upserted/deleted.
For instance, the asyncUpdate has an optional second parameter of type Database.AsyncSaveCallback that can be created to execute some logic after a specific record is done (the class is called every time a record is updated).
Every asyncDML method returns a List of Database.DeleteResult or Database.SaveResult that contains a link to the asynchrounous operation that can be retrieved by calling the Database.getAsyncLocator(result) method and passing the value to the Database.getAsyncSaveResult(asyncLocator) or Database.getAsyncDeleteResult(asyncLocator): this way you can get the status of the asynchronous operation.
No comments:
Post a Comment