# Transitioning from RForcecom

#### Steven M. Mortimer

#### 2018-03-12

While writing the salesforcer package we were keenly aware that many folks are already using the RForcecom package to connect to Salesforce. In order to foster adoption and switching between the packages salesforcer replicates the functionality of many RForcecom functions so that you will only need to swap out `library(RForcecom)` for `library(salesforcer)` and still have your production tested scripts perform as usual.

### Authentication

salesforcer supports OAuth 2.0 authentication which is preferred, but for backward compatibility provides the username-password authentication routine implemented by RForcecom. Here is an example running the function from each of the packages side-by-side and producing the same result.

    # the RForcecom way
    session1 <- RForcecom::rforcecom.login(username, paste0(password, security_token),
                                           apiVersion=getOption("salesforcer.api_version"))
    session1['sessionID'] <- "{MASKED}"
    session1
    #>                      sessionID                    instanceURL
    #>                     "{MASKED}" "https://na50.salesforce.com/"
    #>                     apiVersion
    #>                         "46.0"

    # replicated in salesforcer package
    session2 <- salesforcer::rforcecom.login(username, paste0(password, security_token),
                                             apiVersion=getOption("salesforcer.api_version"))
    session2['sessionID'] <- "{MASKED}"
    session2
    #>                      sessionID                    instanceURL
    #>                     "{MASKED}" "https://na50.salesforce.com/"
    #>                     apiVersion
    #>                         "46.0"

Note that we must set the API version here because calls to session will not create a new sessionId and then we are stuck with version 35.0 (the default from RForcecom::rforcecom.login). Some functions in salesforcer implement API calls that are only available after version 35.0.

### CRUD Operations

“CRUD” operations (Create, Retrieve, Update, Delete) in the RForcecom package only operate on one record at a time. One benefit to using the salesforcer package is that these operations will accept a named vector (one record) or an entire `data.frame` or `tbl_df` of records to churn through. However, rest assured that the replicated functions behave exactly the same way if you are hesitant to making the switch.

    object <- "Contact"
    fields <- c(FirstName="Test", LastName="Contact-Create-Compatibility")

    # the RForcecom way
    result1 <- RForcecom::rforcecom.create(session, objectName=object, fields)
    result1
    #>                   id success
    #> 1 0036A00000wzmRYQAY    true

    # replicated in salesforcer package
    result2 <- salesforcer::rforcecom.create(session, objectName=object, fields)
    result2
    #>                   id success
    #> 1 0036A00000wzmRdQAI    TRUE

Here is an example showing the reduction in code of using salesforcer if you would like to create multiple records.

    n <- 2
    new_contacts <- tibble(FirstName = rep("Test", n),
                           LastName = paste0("Contact-Create-", 1:n))

    # the RForcecom way
    rforcecom_results <- NULL
    for(i in 1:nrow(new_contacts)){
      temp <- RForcecom::rforcecom.create(session,
                                          objectName = "Contact",
                                          fields = unlist(slice(new_contacts,i)))
      rforcecom_results <- bind_rows(rforcecom_results, temp)
    }
    rforcecom_results
    #>                   id success
    #> 1 0036A00000wzmRiQAI    true
    #> 2 0036A00000wzmRnQAI    true

    # the better way in salesforcer to do multiple records
    salesforcer_results <- sf_create(new_contacts, object_name="Contact")
    salesforcer_results
    #> # A tibble: 2 x 2
    #>   id                 success
    #>   <chr>              <lgl>
    #> 1 0036A00000wzmRsQAI TRUE
    #> 2 0036A00000wzmRtQAI TRUE

### Query

salesforcer also has better printing and type-casting when returning query result thanks to features of the readr package.

    this_soql <- "SELECT Id, Email FROM Contact LIMIT 5"

    # the RForcecom way
    result1 <- RForcecom::rforcecom.query(session, soqlQuery = this_soql)
    result1
    #>                   Id
    #> 1 0036A00000wzkYVQAY
    #> 2 0036A00000wzkUiQAI
    #> 3 0036A00000wzjj3QAA
    #> 4 0036A00000wzk1MQAQ
    #> 5 0036A00000wzk1NQAQ

    # replicated in salesforcer package
    result2 <- salesforcer::rforcecom.query(session, soqlQuery = this_soql)
    result2
    #> # A tibble: 5 x 2
    #>   Id                 Email
    #>   <chr>              <lgl>
    #> 1 0036A00000wzkYVQAY NA
    #> 2 0036A00000wzkUiQAI NA
    #> 3 0036A00000wzjj3QAA NA
    #> 4 0036A00000wzk1MQAQ NA
    #> 5 0036A00000wzk1NQAQ NA

    # the better way in salesforcer to query
    salesforcer_results <- sf_query(this_soql)
    salesforcer_results
    #> # A tibble: 5 x 2
    #>   Id                 Email
    #>   <chr>              <lgl>
    #> 1 0036A00000wzkYVQAY NA
    #> 2 0036A00000wzkUiQAI NA
    #> 3 0036A00000wzjj3QAA NA
    #> 4 0036A00000wzk1MQAQ NA
    #> 5 0036A00000wzk1NQAQ NA

### Describe

The RForcecom package has the function `rforcecom.getObjectDescription()` which returns a `data.frame` with one row per field on an object. The same function in salesforcer is named `sf_describe_object_fields()` and also has better printing and datatype casting by using tibbles.

    # the RForcecom way
    result1 <- RForcecom::rforcecom.getObjectDescription(session, objectName='Account')

    # backwards compatible in the salesforcer package
    result2 <- salesforcer::rforcecom.getObjectDescription(session, objectName='Account')

    # the better way in salesforcer to get object fields
    result3 <- salesforcer::sf_describe_object_fields('Account')
    result3
    #> # A tibble: 67 x 39
    #>    aggregatable aiPredictionFie… autoNumber byteLength calculated
    #>    <chr>        <chr>            <chr>      <chr>      <chr>
    #>  1 true         false            false      18         false
    #>  2 false        false            false      0          false
    #>  3 true         false            false      18         false
    #>  4 true         false            false      765        false
    #>  5 true         false            false      120        false
    #>  6 true         false            false      18         false
    #>  7 true         false            false      765        false
    #>  8 true         false            false      120        false
    #>  9 true         false            false      240        false
    #> 10 true         false            false      60         false
    #> # … with 57 more rows, and 34 more variables: caseSensitive <chr>,
    #> #   compoundFieldName <chr>, createable <chr>, custom <chr>,
    #> #   defaultValue <list>, defaultedOnCreate <chr>,
    #> #   deprecatedAndHidden <chr>, digits <chr>, externalId <chr>,
    #> #   extraTypeInfo <chr>, filterable <chr>, groupable <chr>,
    #> #   idLookup <chr>, label <chr>, length <chr>, name <chr>,
    #> #   nameField <chr>, namePointing <chr>, nillable <chr>,
    #> #   permissionable <chr>, picklistValues <list>,
    #> #   polymorphicForeignKey <chr>, precision <chr>, queryByDistance <chr>,
    #> #   referenceTo <chr>, relationshipName <chr>, restrictedPicklist <chr>,
    #> #   scale <chr>, searchPrefilterable <chr>, soapType <chr>,
    #> #   sortable <chr>, type <chr>, unique <chr>, updateable <chr>

In the future more features will be migrated from RForcecom to make the transition as seamless as possible.