# 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://na122.salesforce.com/"
    #>                      apiVersion
    #>                          "48.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://na122.salesforce.com/"
    #>                      apiVersion
    #>                          "48.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 0033s000014AlBuAAK    true

    # replicated in salesforcer package
    result2 <- salesforcer::rforcecom.create(session, objectName=object, fields)
    result2
    #>                   id success
    #> 1 0033s000014AlBzAAK    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 0033s000014AlC4AAK    true
    #> 2 0033s000014AlC9AAK    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 0033s000014AlCEAA0 TRUE
    #> 2 0033s000014AlCFAA0 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 0033s000013wlpjAAA
    #> 2 0033s000013wlpkAAA
    #> 3 0033s000014AG4HAAW
    #> 4 0033s0000149ZoCAAU
    #> 5 0033s0000149ZoDAAU

    # replicated in salesforcer package
    result2 <- salesforcer::rforcecom.query(session, soqlQuery = this_soql)
    result2
    #> # A tibble: 5 x 1
    #>   Id
    #>   <chr>
    #> 1 0033s000013wlpjAAA
    #> 2 0033s000013wlpkAAA
    #> 3 0033s000014AG4HAAW
    #> 4 0033s0000149ZoCAAU
    #> 5 0033s0000149ZoDAAU

    # the better way in salesforcer to query
    salesforcer_results <- sf_query(this_soql)
    salesforcer_results
    #> # A tibble: 5 x 1
    #>   Id
    #>   <chr>
    #> 1 0033s000013wlpjAAA
    #> 2 0033s000013wlpkAAA
    #> 3 0033s000014AG4HAAW
    #> 4 0033s0000149ZoCAAU
    #> 5 0033s0000149ZoDAAU

## 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: 68 x 39
    #>   aggregatable aiPredictionFie… autoNumber byteLength calculated caseSensitive
    #>   <chr>        <chr>            <chr>      <chr>      <chr>      <chr>
    #> 1 true         false            false      18         false      false
    #> 2 false        false            false      0          false      false
    #> 3 true         false            false      18         false      false
    #> 4 true         false            false      765        false      false
    #> 5 true         false            false      120        false      false
    #> # … with 63 more rows, and 33 more variables: 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.